dev
dart 203 lines 8.14 KB
Raw
1 import 'package:cake_wallet/core/auth_service.dart';
2 import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item.dart';
3 import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
4 import 'package:cake_wallet/generated/i18n.dart';
5 import 'package:cake_wallet/new-ui/modal_navigator.dart';
6 import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
7 import 'package:cake_wallet/routes.dart';
8 import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
9 import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
10 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
11 import 'package:cw_core/wallet_info.dart';
12 import "package:cw_core/wallet_type.dart";
13 import 'package:flutter/material.dart';
14 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
15
16 bool _trueFunc(DashboardViewModel _) => true;
17
18 bool _falseFunc(DashboardViewModel _) => false;
19
20 bool _isBtc(DashboardViewModel vm) => vm.wallet.type == WalletType.bitcoin;
21
22 bool _hasLightning(DashboardViewModel vm) => vm.hasLightning;
23
24 bool _hasMweb(DashboardViewModel vm) => vm.hasMweb;
25
26 bool _hasWalletConnect(DashboardViewModel vm) => vm.hasWalletConnect;
27
28 bool _requiresKeyImageSync(DashboardViewModel vm) =>
29 vm.wallet.type == WalletType.monero &&
30 [HardwareWalletType.cupcake, HardwareWalletType.trezor].contains(vm.wallet.hardwareWalletType);
31
32 class SettingsListItem {
33 const SettingsListItem(
34 this.iconPath,
35 this.title,
36 this.route, {
37 this.requireAuth = false,
38 this.use2fa = _falseFunc,
39 this.condition = _trueFunc,
40 this.routeArgs,
41 });
42
43 final String iconPath;
44 final String title;
45 final String route;
46 final Object? routeArgs;
47 final bool requireAuth;
48 final bool Function(DashboardViewModel) use2fa;
49 final bool Function(DashboardViewModel) condition;
50 }
51
52 class SettingsSectionData {
53 const SettingsSectionData(this.title, this.titleIconPath, this.items);
54
55 final String title;
56 final String titleIconPath;
57 final List<SettingsListItem> items;
58
59 static SettingsSectionData walletSettings =
60 SettingsSectionData(S.current.wallet_settings, "assets/new-ui/wallet-setting.svg", [
61 SettingsListItem(
62 "assets/new-ui/settings_row_icons/nodes.svg", S.current.nodes, Routes.manageNodes),
63 SettingsListItem(
64 "assets/new-ui/settings_row_icons/privacy.svg", S.current.privacy, Routes.privacyPage),
65 SettingsListItem(
66 "assets/new-ui/settings_row_icons/seed.svg", S.current.seed_and_keys, Routes.showKeys,
67 routeArgs: true,
68 requireAuth: true,
69 use2fa: (vm) => vm.settingsStore.shouldRequireTOTP2FAForAllSecurityAndBackupSettings),
70 SettingsListItem("assets/new-ui/settings_row_icons/lightning_username.svg",
71 "Lightning ${S.current.username}", Routes.lightningUsernamePage,
72 condition: _hasLightning),
73 SettingsListItem("assets/new-ui/settings_row_icons/wc.svg", S.current.walletConnect,
74 Routes.walletConnectConnectionsListing,
75 condition: _hasWalletConnect),
76 //SettingsListItem("assets/new-ui/settings_row_icons/silent-payments.svg", S.current.silent_payments_settings, Routes.silentPaymentsSettings, condition: _isBtc),
77 //SettingsListItem("assets/new-ui/settings_row_icons/mweb.svg", S.current.litecoin_mweb_settings, Routes.mwebSettings, condition: _hasMweb),
78 SettingsListItem(
79 "assets/new-ui/settings_row_icons/sync-balance.svg",
80 S.current.resync_device,
81 Routes.syncKeyImagesDevices,
82 routeArgs: {'export-outputs': 'export-outputs'},
83 condition: _requiresKeyImageSync,
84 ),
85 SettingsListItem(
86 "assets/new-ui/settings_row_icons/other.svg", S.current.other, Routes.otherSettingsPage),
87 ]);
88
89 static SettingsSectionData appSettings =
90 SettingsSectionData(S.current.app_settings, "assets/new-ui/cake-setting.svg", [
91 SettingsListItem("assets/new-ui/settings_row_icons/connections.svg", S.current.connections,
92 Routes.connectionSync),
93 // SettingsListItem("assets/new-ui/settings_row_icons/defaults.svg", "Defaults", ""),
94 SettingsListItem("assets/new-ui/settings_row_icons/display.svg", S.current.display,
95 Routes.displaySettingsPage),
96 SettingsListItem("assets/new-ui/settings_row_icons/security.svg", S.current.security,
97 Routes.securityBackupPage),
98 SettingsListItem("assets/new-ui/settings_row_icons/backup.svg", S.current.backup, Routes.backup,
99 requireAuth: true,
100 use2fa: (vm) => vm.settingsStore.shouldRequireTOTP2FAForAllSecurityAndBackupSettings),
101 ]);
102
103 static SettingsSectionData otherSettings = SettingsSectionData("", "", [
104 SettingsListItem(
105 "assets/new-ui/settings_row_icons/support.svg", S.current.settings_support, Routes.support),
106 SettingsListItem(
107 "assets/new-ui/settings_row_icons/info.svg", S.current.about, Routes.aboutPage),
108 ]);
109
110 static List<SettingsSectionData> all = [walletSettings, appSettings, otherSettings];
111 }
112
113 class NewSettingsPage extends StatelessWidget {
114 const NewSettingsPage({super.key, required this.dashboardViewModel, required this.authService});
115
116 final DashboardViewModel dashboardViewModel;
117 final AuthService authService;
118
119 @override
120 Widget build(BuildContext context) {
121 return ModalNavigator(
122 parentContext: context,
123 rootPage: SettingsMainPage(
124 dashboardViewModel: dashboardViewModel,
125 authService: authService,
126 ));
127 }
128 }
129
130 class SettingsMainPage extends StatelessWidget {
131 const SettingsMainPage({super.key, required this.dashboardViewModel, required this.authService});
132
133 final DashboardViewModel dashboardViewModel;
134 final AuthService authService;
135
136 @override
137 Widget build(BuildContext context) {
138 List<ListItem> buildItems(SettingsSectionData section) => section.items
139 .map((item) => item.condition(dashboardViewModel)
140 ? ListItemRegularRow(
141 keyValue: item.title,
142 label: item.title,
143 iconPath: item.iconPath,
144 onTap: () {
145 if (item.route.isNotEmpty) {
146 if (item.requireAuth) {
147 authService.authenticateAction(context,
148 conditionToDetermineIfToUse2FA: item.use2fa(dashboardViewModel),
149 route: item.route);
150 } else {
151 Navigator.of(context).pushNamed(item.route, arguments: item.routeArgs);
152 }
153 }
154 })
155 : null)
156 .whereType<ListItem>()
157 .toList();
158
159 return Container(
160 color: Theme.of(context).colorScheme.surface,
161 child: Column(children: [
162 ModalTopBar(
163 title: S.of(context).settings_title,
164 leadingIcon: Icon(Icons.close),
165 leadingSemanticLabel: S.of(context).close,
166 onLeadingPressed: Navigator.of(context, rootNavigator: true).pop,
167 onTrailingPressed: () {},
168 ),
169 Expanded(
170 child: ListView(controller: ModalScrollController.of(context), children: [
171 Padding(
172 padding: const EdgeInsets.symmetric(horizontal: 20.0),
173 child: Column(
174 spacing: 16,
175 children: SettingsSectionData.all.expand((section) {
176 return [
177 if (section.titleIconPath.isNotEmpty)
178 Padding(
179 padding: const EdgeInsets.only(top: 8.0),
180 child: Row(
181 spacing: 8,
182 children: [
183 CakeImageWidget(
184 imageUrl: section.titleIconPath,
185 colorFilter: ColorFilter.mode(
186 Theme.of(context).colorScheme.onSurfaceVariant,
187 BlendMode.srcIn,
188 )),
189 Text(section.title, style: Theme.of(context).textTheme.titleMedium),
190 ],
191 ),
192 ),
193 NewListSections(sections: {section.title: buildItems(section)}),
194 ];
195 }).toList(),
196 ),
197 ),
198 ]),
199 ),
200 ]),
201 );
202 }
203 }