Files
hash-wallet/lib/new-ui/pages/settings_page.dart
T
d7ebf42814 Cw 1551 quick bitcoin wallet sync (#3446)
* add Wallet Accounts page and integrate UI

* account model refactor

* add walletInfoAccount table and API

* add WalletAccountList API

* add multi-account support for Electrum wallets

* add Bitcoin lightning card and card style handling

* refine account filtering and card selection

* update current account balance on wallet changes

* update configure.dar

* Use named parameters for card design

* Add Bitcoin account handling and refactor lookup

* refactor dashboard

* refactor cards UI and account balance handling

* Improve Bitcoin account selection and balances

* restrict unspent coin usage to current account

* filter transactions by current Bitcoin account

* refactor electrum wallet

* refactor address generation

* add accountIndex to address fetch logic

* Update configure.dart

* reload transactions on Bitcoin account change

* restore multiple BTC accounts and improve fetch

* show account balance with in btc

* track account index in Bitcoin transactions

* discover btc BIP39 accounts during restore

* fix account switching and card ordering bugs

* fix card customizer

* limit account name length in modal

* update BTC account list balance display

* auto-reformat

* formating fix

* skip HD map validation

* fix 0 balance issue

* minor fix

* quick bitcoin wallet sync

* restore shuffle change output

* restore address lookup fix

* Update electrum.dart

* remove account customizer

* Merge branch 'CW-1142-Add-accounts-feature-to-BTC' into CW-1551-Quick-Bitcoin-Wallet-Sync

* probe only segwit in account discovery

* add account discovery limit and tracking

* Improve Electrum sync account handling [skip ci]

* remove legacy monero account and address list UI

* rework BTC account balance refres

* avoid unnecessary BTC account reloads

* refactor account header in addresses page

* fix blank popup when editing an account

* fix: dedupe UTXO balance

* minor fix

* add Bitcoin current account API

* Apply batched suggestions from code review [skip ci]

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

* address PR review comments [skip ci]

* remove account customizer and fix accounts init

* restrict extra BTC accounts to SegWit

* add BTC multi-account toggle

* Fix BTC sync gating and account balance update

* minor fix

* Update electrum_wallet.dart

* store selected account on WalletInfo

* Refine wallet account reset visibility

* refactor BTC address prep and move accounts page

* refactor account stack and customizer routing

* migrate legacy Lightning card styles

* unify dashboard account change state

* fix account routing and Electrum balances

* fix account setup and wallet cards UI

* disable Bitcoin Accounts for all hardware

* merge conflicts fix

* minor fixes

* update cards_view [skip ci]

* reverted cards view update [skip ci]

* fix asset name

* moved the transaction filtering into the electrum wallet

* localization

* disable accounts for watch-only wallets

* fix: stop card render from switching the wallet account

* fix: restore Lightning transactions in tx history

* minor fix

* fix: skip duplicate legacy address generation [skip ci]

* fix: correct account balance/design mismatch bugs

* addressing review comments

---------

Co-authored-by: Robert Malikowski <malikowskirobert@gmail.com>
Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
2026-10-03 00:44:57 +02:00

214 lines
8.5 KiB
Dart

import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item.dart';
import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/new-ui/modal_navigator.dart';
import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cw_core/wallet_info.dart';
import "package:cw_core/wallet_type.dart";
import 'package:flutter/material.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
bool _trueFunc(DashboardViewModel _) => true;
bool _falseFunc(DashboardViewModel _) => false;
bool _isBtc(DashboardViewModel vm) => vm.wallet.type == WalletType.bitcoin;
bool _hasLightning(DashboardViewModel vm) => vm.hasLightning;
bool _hasMweb(DashboardViewModel vm) => vm.hasMweb;
bool _hasWalletConnect(DashboardViewModel vm) => vm.hasWalletConnect;
bool _requiresKeyImageSync(DashboardViewModel vm) =>
vm.wallet.type == WalletType.monero &&
[HardwareWalletType.cupcake, HardwareWalletType.trezor].contains(vm.wallet.hardwareWalletType);
class SettingsListItem {
const SettingsListItem(
this.iconPath,
this.title,
this.route, {
this.requireAuth = false,
this.use2fa = _falseFunc,
this.condition = _trueFunc,
this.routeArgs,
this.routeArgsBuilder,
});
final String iconPath;
final String title;
final String route;
final Object? routeArgs;
final Object? Function(DashboardViewModel)? routeArgsBuilder;
final bool requireAuth;
final bool Function(DashboardViewModel) use2fa;
final bool Function(DashboardViewModel) condition;
}
class SettingsSectionData {
const SettingsSectionData(this.title, this.titleIconPath, this.items);
final String title;
final String titleIconPath;
final List<SettingsListItem> items;
static SettingsSectionData walletSettings =
SettingsSectionData(S.current.wallet_settings, "assets/new-ui/wallet-setting.svg", [
SettingsListItem(
"assets/new-ui/settings_row_icons/accounts.svg",
S.current.accounts,
Routes.walletAccountsPage,
condition: (vm) => vm.wallet.hasAccountsSupport,
routeArgsBuilder: (vm) => vm,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/nodes.svg", S.current.nodes, Routes.manageNodes),
SettingsListItem(
"assets/new-ui/settings_row_icons/privacy.svg", S.current.privacy, Routes.privacyPage),
SettingsListItem("assets/new-ui/settings_row_icons/seed.svg", S.current.recovery_and_keys,
Routes.showKeysDisclaimer),
SettingsListItem("assets/new-ui/settings_row_icons/lightning_username.svg",
"Lightning ${S.current.username}", Routes.lightningUsernamePage,
condition: _hasLightning),
SettingsListItem("assets/new-ui/settings_row_icons/wc.svg", S.current.walletConnect,
Routes.walletConnectConnectionsListing,
condition: _hasWalletConnect),
//SettingsListItem("assets/new-ui/settings_row_icons/silent-payments.svg", S.current.silent_payments_settings, Routes.silentPaymentsSettings, condition: _isBtc),
//SettingsListItem("assets/new-ui/settings_row_icons/mweb.svg", S.current.litecoin_mweb_settings, Routes.mwebSettings, condition: _hasMweb),
SettingsListItem(
"assets/new-ui/settings_row_icons/sync-balance.svg",
S.current.resync_device,
Routes.syncKeyImagesDevices,
routeArgs: {'export-outputs': 'export-outputs'},
condition: _requiresKeyImageSync,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/other.svg", S.current.other, Routes.otherSettingsPage),
]);
static SettingsSectionData appSettings =
SettingsSectionData(S.current.app_settings, "assets/new-ui/cake-setting.svg", [
SettingsListItem("assets/new-ui/settings_row_icons/connections.svg", S.current.connections,
Routes.connectionSync),
// SettingsListItem("assets/new-ui/settings_row_icons/defaults.svg", "Defaults", ""),
SettingsListItem("assets/new-ui/settings_row_icons/display.svg", S.current.display,
Routes.displaySettingsPage),
SettingsListItem("assets/new-ui/settings_row_icons/security.svg", S.current.security,
Routes.securityBackupPage),
SettingsListItem("assets/new-ui/settings_row_icons/backup.svg", S.current.backup, Routes.backup,
requireAuth: true,
use2fa: (vm) => vm.settingsStore.shouldRequireTOTP2FAForAllSecurityAndBackupSettings),
]);
static SettingsSectionData otherSettings = SettingsSectionData("", "", [
SettingsListItem(
"assets/new-ui/settings_row_icons/support.svg", S.current.settings_support, Routes.support),
SettingsListItem(
"assets/new-ui/settings_row_icons/info.svg", S.current.about, Routes.aboutPage),
]);
static List<SettingsSectionData> all = [walletSettings, appSettings, otherSettings];
}
class NewSettingsPage extends StatelessWidget {
const NewSettingsPage({super.key, required this.dashboardViewModel, required this.authService});
final DashboardViewModel dashboardViewModel;
final AuthService authService;
@override
Widget build(BuildContext context) {
return ModalNavigator(
parentContext: context,
rootPage: SettingsMainPage(
dashboardViewModel: dashboardViewModel,
authService: authService,
));
}
}
class SettingsMainPage extends StatelessWidget {
const SettingsMainPage({super.key, required this.dashboardViewModel, required this.authService});
final DashboardViewModel dashboardViewModel;
final AuthService authService;
@override
Widget build(BuildContext context) {
List<ListItem> buildItems(SettingsSectionData section) => section.items
.map((item) => item.condition(dashboardViewModel)
? ListItemRegularRow(
keyValue: item.route,
label: item.title,
iconPath: item.iconPath,
onTap: () {
if (item.route.isNotEmpty) {
if (item.requireAuth) {
authService.authenticateAction(context,
conditionToDetermineIfToUse2FA: item.use2fa(dashboardViewModel),
route: item.route);
} else {
Navigator.of(context).pushNamed(
item.route,
arguments:
item.routeArgsBuilder?.call(dashboardViewModel) ?? item.routeArgs,
);
}
}
})
: null)
.whereType<ListItem>()
.toList();
return Container(
color: Theme.of(context).colorScheme.surface,
child: Column(children: [
ModalTopBar(
title: S.of(context).settings_title,
leadingIcon: Icon(Icons.close),
leadingSemanticLabel: S.of(context).close,
onLeadingPressed: Navigator.of(context, rootNavigator: true).pop,
onTrailingPressed: () {},
),
Expanded(
child: ListView(controller: ModalScrollController.of(context), children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Column(
spacing: 16,
children: SettingsSectionData.all.expand((section) {
return [
if (section.titleIconPath.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Row(
spacing: 8,
children: [
CakeImageWidget(
imageUrl: section.titleIconPath,
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.onSurfaceVariant,
BlendMode.srcIn,
)),
Text(section.title, style: Theme.of(context).textTheme.titleMedium),
],
),
),
NewListSections(sections: {section.title: buildItems(section)}),
];
}).toList(),
),
),
]),
),
]),
);
}
}