New Settings (#3065)

* Update display_settings_page.dart * Update settings_choices_cell.dart * Update settings_theme_choice.dart * Convert display_settings_page.dart to NewListSection * Cleanup [skip ci] * Minor * Minor [skip ci] * Add SizedBox to scroll view * Upgrade receive_top_bar.dart with gradient and optional child content * Adjust animations * Add modal_page_wrapper.dart * Add option to hide AppBar for BasePage [skip ci] * New settings all final (#3067) * Conflict * ModalPageWrapper improved abstraction * display_settings_page.dart minor update * connection_sync_page.dart redesign * Conflict * manage_nodes_page.dart initial redesign * other settings initial * Conflict * add optional subtitle to standard_list.dart * add connection_sync_view_model.dart * Add missing images * Conflict * Update list item widgets * Conflict * Conflict * Conflict * minor updates * Conflict * Fixes + move Mweb to privacy page * Conflict * Remove observer from modal_page_wrapper.dart * Conflict * Conflict * Refactor settings_page.dart with suggestions * Suggestion fixes * Conflicts + fix About page * Fix sync bar conflict * Update Connections page title [skip ci] * Trigger CI * Fix Lightning and Payjoin log export * Update MWEB node page * Add FeatureFlag to AutomaticNodeSwitching * Fix address text on privacy_page.dart * Move WalletConnect from connection_sync_page.dart to settings_page.dart * Add WalletConnect icon * Fix settings icons * Make text strings use S.of(context) and fix About string in settings_page.dart * Display settings page fixes * modal_page_wrapper.dart minor suggestions * Missingimage * Add spacing to list_item_selector_widget.dart * Fix error on manage_nodes_page.dart

tuxsudo committed Mar 14, 2026 at 13:15 UTC 3815fc30c67e0b6db354531fd5d5f21fb0f302f8
80 files changed +1952 -1334
assets/new-ui/black_accent.svg.vec
Binary files /dev/null and b/assets/new-ui/black_accent.svg.vec differ
assets/new-ui/cake-setting.svg.vec
Binary files /dev/null and b/assets/new-ui/cake-setting.svg.vec differ
assets/new-ui/chooser.svg.vec
Binary files a/assets/new-ui/chooser.svg.vec and b/assets/new-ui/chooser.svg.vec differ
assets/new-ui/dark.svg.vec
Binary files /dev/null and b/assets/new-ui/dark.svg.vec differ
assets/new-ui/light.svg.vec
Binary files /dev/null and b/assets/new-ui/light.svg.vec differ
assets/new-ui/privacy.svg.vec
Binary files a/assets/new-ui/privacy.svg.vec and b/assets/new-ui/privacy.svg.vec differ
assets/new-ui/security.svg.vec
Binary files a/assets/new-ui/security.svg.vec and b/assets/new-ui/security.svg.vec differ
assets/new-ui/settings_row_icons/privacy.svg.vec
Binary files a/assets/new-ui/settings_row_icons/privacy.svg.vec and b/assets/new-ui/settings_row_icons/privacy.svg.vec differ
assets/new-ui/settings_row_icons/security.svg.vec
Binary files a/assets/new-ui/settings_row_icons/security.svg.vec and b/assets/new-ui/settings_row_icons/security.svg.vec differ
assets/new-ui/settings_row_icons/wc.svg.vec
Binary files /dev/null and b/assets/new-ui/settings_row_icons/wc.svg.vec differ
assets/new-ui/wallet-setting.svg.vec
Binary files /dev/null and b/assets/new-ui/wallet-setting.svg.vec differ
assets/new-ui/wc.svg.vec
Binary files /dev/null and b/assets/new-ui/wc.svg.vec differ
lib/di.dart
+7 -4
@@ -252,6 +252,7 @@ import 'package:cake_wallet/view_model/send/fees_view_model.dart';
252 import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
253 import 'package:cake_wallet/view_model/send/send_view_model.dart';
254 import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
255 +import 'package:cake_wallet/view_model/settings/connection_sync_view_model.dart';
256 import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
257 import 'package:cake_wallet/view_model/settings/mweb_settings_view_model.dart';
258 import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
@@ -1131,7 +1132,9 @@ Future<void> setup({
1132 return PowNodeListViewModel(_powNodeSource, appStore);
1133 });
1134
1134 - getIt.registerFactory(() => ConnectionSyncPage(getIt.get<DashboardViewModel>()));
1135 + getIt.registerFactory(() => ConnectionSyncViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!));
1136 +
1137 + getIt.registerFactory(() => ConnectionSyncPage(getIt.get<ConnectionSyncViewModel>()));
1138
1139 getIt.registerFactory(() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(),
1140 getIt.get<AuthService>(), getIt.get<AppStore>().wallet!.isHardwareWallet));
@@ -1140,7 +1143,7 @@ Future<void> setup({
1143
1144 getIt.registerFactory(() => TrocadorProvidersPage(getIt.get<TrocadorProvidersViewModel>()));
1145
1143 - getIt.registerFactory(() => DomainLookupsPage(getIt.get<PrivacySettingsViewModel>()));
1146 + getIt.registerFactory(() => DomainLookupsPage(getIt.get<ConnectionSyncViewModel>()));
1147
1148 getIt.registerFactory(() => DisplaySettingsPage(getIt.get<DisplaySettingsViewModel>()));
1149
@@ -1691,9 +1694,9 @@ Future<void> setup({
1694
1695 getIt.registerFactoryParam<ManageNodesPage, bool, void>((bool isPow, _) {
1696 if (isPow) {
1694 - return ManageNodesPage(isPow, powNodeListViewModel: getIt.get<PowNodeListViewModel>());
1697 + return ManageNodesPage(isPow, powNodeListViewModel: getIt.get<PowNodeListViewModel>(), dashboardViewModel: getIt.get<DashboardViewModel>());
1698 }
1696 - return ManageNodesPage(isPow, nodeListViewModel: getIt.get<NodeListViewModel>());
1699 + return ManageNodesPage(isPow, nodeListViewModel: getIt.get<NodeListViewModel>(), dashboardViewModel: getIt.get<DashboardViewModel>());
1700 });
1701
1702 getIt.registerFactory(
lib/new-ui/pages/about_page.dart
+54 -55
@@ -2,11 +2,11 @@ import 'dart:math';
2
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/widgets/modal_page_wrapper.dart';
6 import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
7 import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
8 import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
9 import 'package:flutter/material.dart';
9 -import 'package:flutter_svg/svg.dart';
10 import 'package:url_launcher/url_launcher.dart';
11
12 // written by people who happened to read my slack message in 2025
@@ -52,61 +52,60 @@ class _AboutPageState extends State<AboutPage> {
52
53 @override
54 Widget build(BuildContext context) {
55 - return Container(
56 - color: Theme.of(context).colorScheme.surface,
57 - child: Column(children: [
58 - ModalTopBar(
59 - title: S.of(context).about,
60 - leadingIcon: Icon(Icons.arrow_back_ios_new),
61 - onLeadingPressed: Navigator.of(context).pop,
62 - ),
63 - Column(
64 - children: [
65 - Column(
66 - spacing: 16,
67 - children: [
68 - SizedBox(),
69 - GestureDetector(
70 - onTap: _easterEgg,
71 - child: CakeImageWidget(
72 - imageUrl: "assets/new-ui/cake_squircle_icon.svg",
73 - width: 128,
74 - height: 128,
75 - ),
76 - ),
77 - Row(
78 - mainAxisAlignment: MainAxisAlignment.center,
79 - spacing: 8,
80 - children: [
81 - Text(
82 - "Cake Wallet",
83 - style: TextStyle(fontSize: 32, fontWeight: FontWeight.w500),
55 + return ModalPageWrapper(
56 + topBar: ModalTopBar(
57 + title: S.of(context).about,
58 + leadingIcon: Icon(Icons.arrow_back_ios_new),
59 + onLeadingPressed: Navigator.of(context).pop,
60 + ),
61 + content: Container(
62 + color: Theme.of(context).colorScheme.surface,
63 + child: Column(children: [
64 + Column(
65 + children: [
66 + Column(
67 + spacing: 16,
68 + children: [
69 + SizedBox(),
70 + GestureDetector(
71 + onTap: _easterEgg,
72 + child: CakeImageWidget(
73 + imageUrl: "assets/new-ui/cake_squircle_icon.svg",
74 + width: 128,
75 + height: 128,
76 ),
85 - Text(widget.appVersion,
86 - style: TextStyle(
87 - fontSize: 32,
88 - fontWeight: FontWeight.w500,
89 - color: Theme.of(context).colorScheme.onSurfaceVariant))
90 - ],
91 - ),
92 - Padding(
93 - padding: const EdgeInsets.symmetric(horizontal: 12.0),
94 - child: Wrap(
77 + ),
78 + Row(
79 + mainAxisAlignment: MainAxisAlignment.center,
80 + spacing: 8,
81 children: [
82 Text(
97 - _bottomText,
98 - textAlign: TextAlign.center,
99 - style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
83 + "Cake Wallet",
84 + style: TextStyle(fontSize: 32, fontWeight: FontWeight.w500),
85 ),
86 + Text(widget.appVersion,
87 + style: TextStyle(
88 + fontSize: 32,
89 + fontWeight: FontWeight.w500,
90 + color: Theme.of(context).colorScheme.onSurfaceVariant))
91 ],
92 ),
103 - ),
104 - ],
105 - ),
106 - SizedBox(height: 32),
107 - Padding(
108 - padding: const EdgeInsets.symmetric(horizontal: 16.0),
109 - child: NewListSections(sections: {
93 + Padding(
94 + padding: const EdgeInsets.symmetric(horizontal: 12.0),
95 + child: Wrap(
96 + children: [
97 + Text(
98 + _bottomText,
99 + textAlign: TextAlign.center,
100 + style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
101 + ),
102 + ],
103 + ),
104 + ),
105 + ],
106 + ),
107 + SizedBox(height: 32),
108 + NewListSections(sections: {
109 "": [
110 ListItemRegularRow(
111 keyValue: "official website",
@@ -146,10 +145,10 @@ class _AboutPageState extends State<AboutPage> {
145 foregroundColor: Theme.of(context).colorScheme.primary,
146 trailingIconSize: 10)
147 ]
149 - }),
150 - )
151 - ],
152 - )
153 - ]));
148 + })
149 + ],
150 + )
151 + ])),
152 + );
153 }
154 }
lib/new-ui/pages/settings_page.dart
+56 -35
@@ -9,6 +9,7 @@ import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
9 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
10 import 'package:cw_core/wallet_info.dart';
11 import 'package:flutter/material.dart';
12 +import 'package:flutter_svg/svg.dart';
13 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
14 import "package:cw_core/wallet_type.dart";
15
@@ -18,8 +19,12 @@ 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 _isCupcake(DashboardViewModel vm) => vm.wallet.hardwareWalletType == HardwareWalletType.cupcake;
29
30 class SettingsListItem {
@@ -42,21 +47,21 @@ class SettingsSectionData {
47 const SettingsSectionData(this.title, this.titleIconPath, this.items);
48
49 static SettingsSectionData walletSettings =
45 - SettingsSectionData(S.current.wallet_settings, "assets/new-ui/wallet_settings.svg", [
50 + SettingsSectionData(S.current.wallet_settings, "assets/new-ui/wallet-setting.svg", [
51 SettingsListItem("assets/new-ui/settings_row_icons/nodes.svg", S.current.nodes, Routes.manageNodes),
52 SettingsListItem("assets/new-ui/settings_row_icons/privacy.svg", S.current.privacy, Routes.privacyPage),
53 SettingsListItem("assets/new-ui/settings_row_icons/seed.svg", S.current.seed_and_keys, Routes.showKeys,
54 routeArgs: true, requireAuth: true, use2fa: (vm)=>vm.settingsStore.shouldRequireTOTP2FAForAllSecurityAndBackupSettings),
50 - SettingsListItem("assets/new-ui/settings_row_icons/lightning_username.svg",
51 - "Lightning ${S.current.username}", Routes.lightningUsernamePage, condition: _isBtc),
52 - SettingsListItem("assets/new-ui/settings_row_icons/silent-payments.svg", S.current.silent_payments_settings, Routes.silentPaymentsSettings, condition: _isBtc),
53 - SettingsListItem("assets/new-ui/settings_row_icons/mweb.svg", S.current.litecoin_mweb_settings, Routes.mwebSettings, condition: _hasMweb),
55 + SettingsListItem("assets/new-ui/settings_row_icons/lightning_username.svg", "Lightning ${S.current.username}", Routes.lightningUsernamePage, condition: _hasLightning),
56 + SettingsListItem("assets/new-ui/settings_row_icons/wc.svg", S.current.walletConnect, Routes.walletConnectConnectionsListing, condition: _hasWalletConnect),
57 + //SettingsListItem("assets/new-ui/settings_row_icons/silent-payments.svg", S.current.silent_payments_settings, Routes.silentPaymentsSettings, condition: _isBtc),
58 + //SettingsListItem("assets/new-ui/settings_row_icons/mweb.svg", S.current.litecoin_mweb_settings, Routes.mwebSettings, condition: _hasMweb),
59 SettingsListItem("assets/new-ui/settings_row_icons/cupcake.svg", S.current.export_outputs, Routes.urqrAnimatedPage, routeArgs: {'export-outputs': 'export-outputs'}, condition: _isCupcake),
60 SettingsListItem("assets/new-ui/settings_row_icons/other.svg", S.current.other, Routes.otherSettingsPage),
61 ]);
62
63 static SettingsSectionData appSettings =
59 - SettingsSectionData(S.current.app_settings, "assets/new-ui/app_settings.svg", [
64 + SettingsSectionData(S.current.app_settings, "assets/new-ui/cake-setting.svg", [
65 SettingsListItem("assets/new-ui/settings_row_icons/connections.svg", S.current.connections, Routes.connectionSync),
66 // SettingsListItem("assets/new-ui/settings_row_icons/defaults.svg", "Defaults", ""),
67 SettingsListItem("assets/new-ui/settings_row_icons/display.svg", S.current.display, Routes.displaySettingsPage),
@@ -97,29 +102,26 @@ class SettingsMainPage extends StatelessWidget {
102
103 @override
104 Widget build(BuildContext context) {
100 - Map<String, List<ListItem>> sections =
101 - Map.fromEntries(SettingsSectionData.all.map((section) => MapEntry(
102 - section.title,
103 - section.items
104 - .map((item) => item.condition(dashboardViewModel)
105 - ? ListItemRegularRow(
106 - keyValue: item.title,
107 - label: item.title,
108 - iconPath: item.iconPath,
109 - onTap: () {
110 - if (item.route.isNotEmpty) {
111 - if(item.requireAuth) {
112 - authService.authenticateAction(context,
113 - conditionToDetermineIfToUse2FA: item.use2fa(dashboardViewModel),
114 - route: item.route);
115 - } else {
116 - Navigator.of(context).pushNamed(item.route, arguments: item.routeArgs);
117 - }
118 - }
119 - })
120 - : null)
121 - .whereType<ListItem>()
122 - .toList())));
105 + List<ListItem> buildItems(SettingsSectionData section) => section.items
106 + .map((item) => item.condition(dashboardViewModel)
107 + ? ListItemRegularRow(
108 + keyValue: item.title,
109 + label: item.title,
110 + iconPath: item.iconPath,
111 + onTap: () {
112 + if (item.route.isNotEmpty) {
113 + if (item.requireAuth) {
114 + authService.authenticateAction(context,
115 + conditionToDetermineIfToUse2FA: item.use2fa(dashboardViewModel),
116 + route: item.route);
117 + } else {
118 + Navigator.of(context).pushNamed(item.route, arguments: item.routeArgs);
119 + }
120 + }
121 + })
122 + : null)
123 + .whereType<ListItem>()
124 + .toList();
125
126 return Container(
127 color: Theme.of(context).colorScheme.surface,
@@ -131,12 +133,31 @@ class SettingsMainPage extends StatelessWidget {
133 onTrailingPressed: () {},
134 ),
135 Expanded(
134 - child: ListView(
135 - controller: ModalScrollController.of(context),
136 - children: [Padding(
137 - padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 20.0),
138 - child: NewListSections(
139 - sections: sections,
136 + child: ListView(controller: ModalScrollController.of(context), children: [
137 + Padding(
138 + padding: const EdgeInsets.symmetric(horizontal: 20.0),
139 + child: Column(
140 + spacing: 16,
141 + children: SettingsSectionData.all.expand((section) {
142 + return [
143 + if (section.titleIconPath.isNotEmpty)
144 + Padding(
145 + padding: const EdgeInsets.only(top: 8.0),
146 + child: Row(
147 + spacing: 8,
148 + children: [
149 + SvgPicture.asset(section.titleIconPath,
150 + colorFilter: ColorFilter.mode(
151 + Theme.of(context).colorScheme.onSurfaceVariant,
152 + BlendMode.srcIn,
153 + )),
154 + Text(section.title, style: Theme.of(context).textTheme.titleMedium),
155 + ],
156 + ),
157 + ),
158 + NewListSections(sections: {section.title: buildItems(section)}),
159 + ];
160 + }).toList(),
161 ),
162 ),]
163 ),
lib/new-ui/widgets/coins_page/top_bar_widget/sync_bar.dart
+12 -4
@@ -1,12 +1,14 @@
1 import 'package:cake_wallet/core/sync_status_title.dart';
2 +import 'package:cake_wallet/di.dart';
3 import 'package:cake_wallet/new-ui/widgets/coins_page/top_bar_widget/pulsing_dot.dart';
3 -import 'package:cake_wallet/routes.dart';
4 +import 'package:cake_wallet/src/screens/settings/manage_nodes_page.dart';
5 import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
6 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
7 import 'package:cw_core/sync_status.dart';
8 import 'package:flutter/material.dart';
9 import 'package:flutter_mobx/flutter_mobx.dart';
10 import 'package:flutter_svg/flutter_svg.dart';
11 +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
12
13 class SyncBar extends StatelessWidget {
14 SyncBar({super.key, required this.dashboardViewModel, required this.isSyncHeavy});
@@ -62,7 +64,13 @@ class SyncBar extends StatelessWidget {
64 if (_showFullBar())
65 GestureDetector(
66 onTap: () {
65 - Navigator.of(context, rootNavigator: true).pushNamed(Routes.connectionSync);
67 + CupertinoScaffold.showCupertinoModalBottomSheet(
68 + context: context,
69 + barrierColor: Colors.black.withAlpha(85),
70 + builder: (context) => FractionallySizedBox(
71 + child: Material(
72 + child: getIt.get<ManageNodesPage>(param1: false),
73 + )));
74 },
75 child: AnimatedSwitcher(
76 duration: Duration(milliseconds: 100),
@@ -162,7 +170,7 @@ class SyncBar extends StatelessWidget {
170 children.add(CakeImageWidget(imageUrl:
171 "assets/new-ui/mweb_sync.svg",
172 colorFilter:
165 - ColorFilter.mode(Theme.of(context).colorScheme.onSurfaceVariant, BlendMode.srcIn),
173 + ColorFilter.mode(Theme.of(context).colorScheme.onSurfaceVariant, BlendMode.srcIn),
174 ));
175 }
176 if (dashboardViewModel.hasSilentPayments) {
@@ -186,4 +194,4 @@ class SyncBar extends StatelessWidget {
194 bool _showDot() {
195 return !isSyncHeavy && progressStatuses.contains(dashboardViewModel.status.runtimeType);
196 }
189 -}
197 +}
\ No newline at end of file
lib/new-ui/widgets/modal_page_wrapper.dart new
+88
@@ -0,0 +1,88 @@
1 +import 'package:cake_wallet/new-ui/widgets/modal_header.dart';
2 +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
3 +import 'package:flutter/material.dart';
4 +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
5 +
6 +void nothing(){}
7 +
8 +class ModalPageWrapper extends StatelessWidget {
9 + ModalPageWrapper(
10 + {super.key,
11 + required this.content,
12 + required this.topBar,
13 + this.header,
14 + this.bottomContent,
15 + this.horizontalPadding = 18.0,
16 + this.verticalPadding = 72.0}) {
17 + }
18 +
19 + final Widget content;
20 + final Widget? bottomContent;
21 + final ModalTopBar topBar;
22 + final ModalHeader? header;
23 + final double horizontalPadding;
24 + final double verticalPadding;
25 +
26 + @override
27 + Widget build(BuildContext context) {
28 + const gradientSize = 84;
29 +
30 + return Container(
31 + color: Theme.of(context).colorScheme.surface,
32 + child: Scaffold(
33 + resizeToAvoidBottomInset: true,
34 + body: Stack(
35 + alignment: Alignment.topCenter,
36 + children: [
37 + Positioned.fill(
38 + child: Padding(
39 + padding: EdgeInsets.symmetric(horizontal: horizontalPadding),
40 + child: CustomScrollView(
41 + controller: ModalScrollController.of(context),
42 + physics: ClampingScrollPhysics(),
43 + slivers: [
44 + SliverToBoxAdapter(child: SizedBox(height: verticalPadding)),
45 + if (header != null) ...[
46 + SliverToBoxAdapter(child: header),
47 + SliverToBoxAdapter(child: SizedBox(height: 20)),
48 + ],
49 + SliverSafeArea(sliver: SliverToBoxAdapter(child: content)),
50 + SliverToBoxAdapter(child: SizedBox(height: verticalPadding)),
51 + ],
52 + )
53 + )),
54 + if (bottomContent != null)
55 + Positioned(
56 + bottom: 12,
57 + left: horizontalPadding,
58 + right: horizontalPadding,
59 + child: SafeArea(child: bottomContent!),
60 + ),
61 + Container(
62 + height: (MediaQuery.of(context).padding.top + gradientSize),
63 + decoration: BoxDecoration(
64 + gradient: LinearGradient(
65 + begin: Alignment.bottomCenter,
66 + end: Alignment.topCenter,
67 + colors: <Color>[
68 + Theme.of(context).colorScheme.surface.withAlpha(5),
69 + Theme.of(context).colorScheme.surface.withAlpha(25),
70 + Theme.of(context).colorScheme.surface.withAlpha(50),
71 + Theme.of(context).colorScheme.surface.withAlpha(100),
72 + Theme.of(context).colorScheme.surface.withAlpha(150),
73 + Theme.of(context).colorScheme.surface.withAlpha(200),
74 + Theme.of(context).colorScheme.surface.withAlpha(235),
75 + Theme.of(context).colorScheme.surface.withAlpha(255),
76 + Theme.of(context).colorScheme.surface.withAlpha(255),
77 + Theme.of(context).colorScheme.surface.withAlpha(255),
78 + ],
79 + ),
80 + ),
81 + ),
82 + topBar,
83 + ],
84 + ),
85 + ),
86 + );
87 + }
88 +}
lib/new-ui/widgets/receive_page/receive_top_bar.dart
+20 -20
@@ -6,14 +6,14 @@ void nothing(){}
6 class ModalTopBar extends StatelessWidget {
7 ModalTopBar(
8 {super.key,
9 - required this.title,
9 + required this.title,
10 this.subtitle,
11 - this.onLeadingPressed=nothing,
12 - this.onTrailingPressed=nothing,
13 - this.leadingIcon,
14 - this.trailingIcon,
15 - this.leadingWidget,
16 - this.trailingWidget}) {
11 + this.onLeadingPressed=nothing,
12 + this.onTrailingPressed=nothing,
13 + this.leadingIcon,
14 + this.trailingIcon,
15 + this.leadingWidget,
16 + this.trailingWidget}) {
17 if(leadingIcon != null && leadingWidget != null) {
18 throw Exception("Cannot have both leadingIcon and leadingWidget");
19 }
@@ -38,10 +38,10 @@ class ModalTopBar extends StatelessWidget {
38 return Padding(
39 padding: const EdgeInsets.all(18),
40 child: Stack(
41 - alignment: Alignment.center,
41 + alignment: Alignment.topCenter,
42 children: [
43 - Align(
44 - alignment: Alignment.center,
43 + Positioned(
44 + top: 6,
45 child: Row(
46 mainAxisSize: MainAxisSize.max,
47 mainAxisAlignment: MainAxisAlignment.center,
@@ -72,11 +72,11 @@ class ModalTopBar extends StatelessWidget {
72 if (leadingIcon != null || leadingWidget != null)
73 leadingIcon != null
74 ? ModernButton(
75 - key: ValueKey(leadingIcon.hashCode),
76 - size: buttonSize,
77 - onPressed: onLeadingPressed,
78 - icon: leadingIcon!,
79 - iconColor: Theme.of(context).colorScheme.onSurfaceVariant)
75 + key: ValueKey(leadingIcon.hashCode),
76 + size: buttonSize,
77 + onPressed: onLeadingPressed,
78 + icon: leadingIcon!,
79 + iconColor: Theme.of(context).colorScheme.onSurfaceVariant)
80 : leadingWidget!
81 else
82 Container(width: buttonSize),
@@ -85,10 +85,10 @@ class ModalTopBar extends StatelessWidget {
85 duration: const Duration(milliseconds: 200),
86 child: trailingIcon != null
87 ? ModernButton(
88 - key: ValueKey(trailingIcon.hashCode),
89 - size: buttonSize,
90 - onPressed: onTrailingPressed,
91 - icon: trailingIcon!,)
88 + key: ValueKey(trailingIcon.hashCode),
89 + size: buttonSize,
90 + onPressed: onTrailingPressed,
91 + icon: trailingIcon!,)
92 : trailingWidget!,
93 )
94 else
@@ -99,4 +99,4 @@ class ModalTopBar extends StatelessWidget {
99 ),
100 );
101 }
102 -}
102 +}
\ No newline at end of file
lib/src/screens/base_page.dart
+16 -17
@@ -47,6 +47,8 @@ abstract class BasePage extends StatelessWidget {
47
48 AppBarStyle get appBarStyle => AppBarStyle.regular;
49
50 + bool get hideAppBar => false;
51 +
52 Widget Function(BuildContext, Widget)? get rootWrapper => null;
53
54 MaterialThemeBase get currentTheme => getIt.get<ThemeStore>().currentTheme;
@@ -191,24 +193,21 @@ abstract class BasePage extends StatelessWidget {
193 : null,
194 // color: Colors.grey[200],
195 ),
194 - child: Padding(
195 - padding: const EdgeInsets.only(top:6.0),
196 - child: Scaffold(
197 - key: _scaffoldKey,
198 - backgroundColor: pageBackgroundColor(context),
199 - resizeToAvoidBottomInset: resizeToAvoidBottomInset,
200 - extendBodyBehindAppBar: extendBodyBehindAppBar,
201 - endDrawer: endDrawer,
202 - appBar: appBar(context),
203 - body: SafeArea(
204 - left: false,
205 - right: false,
206 - top: false,
207 - bottom: Platform.isAndroid,
208 - child: body(context),
209 - ),
210 - floatingActionButton: floatingActionButton(context),
196 + child: Scaffold(
197 + key: _scaffoldKey,
198 + backgroundColor: pageBackgroundColor(context),
199 + resizeToAvoidBottomInset: resizeToAvoidBottomInset,
200 + extendBodyBehindAppBar: extendBodyBehindAppBar,
201 + endDrawer: endDrawer,
202 + appBar: hideAppBar ? null : appBar(context),
203 + body: SafeArea(
204 + left: false,
205 + right: false,
206 + top: false,
207 + bottom: Platform.isAndroid,
208 + child: body(context),
209 ),
210 + floatingActionButton: floatingActionButton(context),
211 ),
212 );
213 },
lib/src/screens/nodes/widgets/node_form.dart
+2
@@ -5,6 +5,7 @@ import 'package:cake_wallet/entities/new_ui_entities/list_item/list_Item_checkbo
5 import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_text_field.dart';
6 import 'package:cake_wallet/generated/i18n.dart';
7 import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
8 +import 'package:cake_wallet/utils/feature_flag.dart';
9 import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
10 import 'package:flutter/material.dart';
11 import 'package:flutter_mobx/flutter_mobx.dart';
@@ -140,6 +141,7 @@ class NodeFormState extends State<NodeForm> {
141 initialValue: vm.socksProxyAddress,
142 validator: SocksProxyNodeAddressValidator(),
143 ),
144 + if(FeatureFlag.isAutomaticNodeSwitchingEnabled)
145 ListItemCheckbox(
146 keyValue: vm.autoSwitchingUIKey,
147 label: S.current.enable_for_auto_switching,
lib/src/screens/nodes/widgets/node_list_row.dart
+2 -1
@@ -7,11 +7,12 @@ import 'package:flutter/material.dart';
7 class NodeListRow extends StandardListRow {
8 NodeListRow(
9 {required String title,
10 + String? subtitle,
11 required this.node,
12 required void Function(BuildContext context) onTap,
13 required bool isSelected,
14 required this.isPow})
14 - : super(title: title, onTap: onTap, isSelected: isSelected);
15 + : super(title: title, onTap: onTap, isSelected: isSelected, subtitle: subtitle);
16
17 final Node node;
18 final bool isPow;
lib/src/screens/settings/connection_sync_page.dart
+191 -91
@@ -1,119 +1,219 @@
1 import 'dart:io';
2
3 +import 'package:cake_wallet/entities/exchange_api_mode.dart';
4 +import 'package:cake_wallet/entities/fiat_api_mode.dart';
5 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
6 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_selector.dart';
7 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart';
8 import 'package:cake_wallet/generated/i18n.dart';
4 -import 'package:cake_wallet/reactions/wallet_connect.dart';
9 +import 'package:cake_wallet/new-ui/widgets/modal_header.dart';
10 +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart';
11 +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
12 import 'package:cake_wallet/routes.dart';
13 import 'package:cake_wallet/src/screens/base_page.dart';
7 -import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
8 -import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
9 -import 'package:cake_wallet/src/screens/settings/widgets/wallet_connect_button.dart';
14 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
15 +import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
16 +import 'package:cake_wallet/src/widgets/picker.dart';
17 import 'package:cake_wallet/utils/feature_flag.dart';
18 import 'package:cake_wallet/utils/show_pop_up.dart';
13 -import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
19 +import 'package:cake_wallet/view_model/settings/connection_sync_view_model.dart';
20 import 'package:flutter/material.dart';
21 import 'package:flutter_mobx/flutter_mobx.dart';
22
23 class ConnectionSyncPage extends BasePage {
18 - ConnectionSyncPage(this.dashboardViewModel);
24 + ConnectionSyncPage(this._connectionSyncViewModel);
25
26 @override
21 - String get title => S.current.connection_sync;
27 + bool get hideAppBar => true;
28
23 - final DashboardViewModel dashboardViewModel;
29 + final ConnectionSyncViewModel _connectionSyncViewModel;
30
31 @override
32 Widget body(BuildContext context) {
27 - return Container(
28 - padding: EdgeInsets.only(top: 10),
29 - child: Column(
33 + return ModalPageWrapper(
34 + topBar: ModalTopBar(
35 + title: "",
36 + leadingIcon: Icon(Icons.arrow_back_ios_new),
37 + onLeadingPressed: () => Navigator.of(context).pop()),
38 + header: ModalHeader(
39 + iconPath: "assets/new-ui/settings_row_icons/connections.svg",
40 + message: S.of(context).connections_desc,
41 + title: S.of(context).connections),
42 + content: Column(
43 mainAxisSize: MainAxisSize.min,
44 children: [
32 - SettingsCellWithArrow(
33 - title: S.current.reconnect,
34 - handler: (context) => _presentReconnectAlert(context),
35 - ),
36 - if (dashboardViewModel.hasRescan) ...[
37 - SettingsCellWithArrow(
38 - title: dashboardViewModel.hasSilentPayments
39 - ? S.current.silent_payments_scanning
40 - : S.current.rescan,
41 - handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
42 - ),
43 - ],
44 - SettingsCellWithArrow(
45 - title: S.current.manage_nodes,
46 - handler: (context) => Navigator.of(context).pushNamed(Routes.manageNodes),
47 - ),
48 - if (Platform.isAndroid && FeatureFlag.isBackgroundSyncEnabled) ...[
49 - SettingsCellWithArrow(
50 - title: S.current.background_sync,
51 - handler: (context) => Navigator.of(context).pushNamed(Routes.backgroundSync),
52 - ),
53 - ],
45 Observer(
55 - builder: (context) {
56 - if (!dashboardViewModel.hasPowNodes) return const SizedBox();
46 + builder: (context) =>
47 + NewListSections(
48 + sections: {
49 + "": [
50 + if (FeatureFlag.isInAppTorEnabled)
51 + ListItemToggle(
52 + keyValue: "enable_builtin_tor",
53 + label: S.of(context).enable_builtin_tor,
54 + value: _connectionSyncViewModel.builtinTor,
55 + onChanged: (val) {
56 + _connectionSyncViewModel.setBuiltinTor(val, context);
57 + }),
58 + ListItemToggle(
59 + keyValue: "disable_automatic_exchange_status_updates",
60 + label: S.of(context).disable_automatic_exchange_status_updates,
61 + value: _connectionSyncViewModel.disableAutomaticExchangeStatusUpdates,
62 + onChanged: (val) {
63 + _connectionSyncViewModel.setDisableAutomaticExchangeStatusUpdates(val);
64 + }),
65 + if (_connectionSyncViewModel.canUseBlinkProtection)
66 + ListItemToggle(
67 + keyValue: "can_use_blink_protection",
68 + label: S.of(context).use_blink_protection,
69 + value: _connectionSyncViewModel.useBlinkProtection,
70 + onChanged: (val) {
71 + _connectionSyncViewModel.setUseBlinkProtection(val);
72 + }),
73 + if (_connectionSyncViewModel.canUseEtherscan)
74 + ListItemToggle(
75 + keyValue: "can_use_etherscan",
76 + label: S.of(context).etherscan_history,
77 + value: _connectionSyncViewModel.useEtherscan,
78 + onChanged: (val) {
79 + _connectionSyncViewModel.setUseEtherscan(val);
80 + }),
81 + if (_connectionSyncViewModel.canUsePolygonScan)
82 + ListItemToggle(
83 + keyValue: "can_use_polygonscan",
84 + label: S.of(context).polygonscan_history,
85 + value: _connectionSyncViewModel.usePolygonScan,
86 + onChanged: (val) {
87 + _connectionSyncViewModel.setUsePolygonScan(val);
88 + }),
89 + if (_connectionSyncViewModel.canUseBaseScan)
90 + ListItemToggle(
91 + keyValue: "can_use_basescan",
92 + label: S.of(context).basescan_history,
93 + value: _connectionSyncViewModel.canUseBaseScan,
94 + onChanged: (val) {
95 + _connectionSyncViewModel.setUseBaseScan(val);
96 + }),
97 + if (_connectionSyncViewModel.canUseArbiScan)
98 + ListItemToggle(
99 + keyValue: "can_use_arbiscan",
100 + label: S.of(context).arbiscan_history,
101 + value: _connectionSyncViewModel.useArbiScan,
102 + onChanged: (val) {
103 + _connectionSyncViewModel.setUsePolygonScan(val);
104 + }),
105 + if (_connectionSyncViewModel.canUseBscScan)
106 + ListItemToggle(
107 + keyValue: "can_use_bscscan",
108 + label: S.of(context).bscscan_history,
109 + value: _connectionSyncViewModel.useBscScan,
110 + onChanged: (val) {
111 + _connectionSyncViewModel.setUseBscScan(val);
112 + }),
113 + if (_connectionSyncViewModel.canUseTronGrid)
114 + ListItemToggle(
115 + keyValue: "can_use_trongrid",
116 + label: S.of(context).trongrid_history,
117 + value: _connectionSyncViewModel.useTronGrid,
118 + onChanged: (val) {
119 + _connectionSyncViewModel.setUsePolygonScan(val);
120 + }),
121 + if (_connectionSyncViewModel.canUseMempoolFeeAPI)
122 + ListItemToggle(
123 + keyValue: "enable_mempool_api",
124 + label: S.of(context).enable_mempool_api,
125 + value: _connectionSyncViewModel.useMempoolFeeAPI,
126 + onChanged: (bool isEnabled) async {
127 + if (!isEnabled) {
128 + final bool confirmation = await showPopUp<bool>(
129 + context: context,
130 + builder: (BuildContext context) {
131 + return AlertWithTwoActions(
132 + alertTitle: S.of(context).warning,
133 + alertContent: S.of(context).disable_fee_api_warning,
134 + rightButtonText: S.of(context).confirm,
135 + leftButtonText: S.of(context).cancel,
136 + actionRightButton: () => Navigator.of(context).pop(true),
137 + actionLeftButton: () => Navigator.of(context).pop(false));
138 + }) ??
139 + false;
140 + if (confirmation) {
141 + _connectionSyncViewModel.setUseMempoolFeeAPI(isEnabled);
142 + }
143 + return;
144 + }
145 +
146 + _connectionSyncViewModel.setUseMempoolFeeAPI(isEnabled);
147 + }),
148 + if (Platform.isAndroid && FeatureFlag.isBackgroundSyncEnabled)
149 + ListItemRegularRow(
150 + keyValue: "background_sync",
151 + label: S.of(context).background_sync,
152 + onTap: () => Navigator.of(context).pushNamed(Routes.backgroundSync)
153 + ),
154 + if (_connectionSyncViewModel.hasPowNodes)
155 + ListItemRegularRow(
156 + keyValue: "manage_pow_nodes",
157 + label: S.of(context).manage_pow_nodes,
158 + onTap: () => Navigator.of(context).pushNamed(Routes.managePowNodes),
159 + ),
160 + ListItemSelector(
161 + keyValue: "fiat_api",
162 + label: S.of(context).fiat_api,
163 + options: [_connectionSyncViewModel.fiatApiMode.title],
164 + onTap: () async {
165 + final items = FiatApiMode.all;
166 +
167 + final selectedAtIndex =
168 + items.indexOf(_connectionSyncViewModel.fiatApiMode);
169 +
170 + await showPopUp<void>(
171 + context: context,
172 + builder: (_) => Picker(
173 + items: items,
174 + selectedAtIndex: selectedAtIndex,
175 + mainAxisAlignment: MainAxisAlignment.start,
176 + onItemSelected: (FiatApiMode fiatApiMode) {
177 + _connectionSyncViewModel.setFiatMode(fiatApiMode);
178 + },
179 + isSeparated: false,
180 + ),
181 + );
182 + }),
183 + ListItemSelector(
184 + keyValue: "swap",
185 + label: S.of(context).swap,
186 + options: [_connectionSyncViewModel.exchangeStatus.title],
187 + onTap: () async {
188 + final items = ExchangeApiMode.all;
189
58 - return Column(
59 - children: [
60 - SettingsCellWithArrow(
61 - title: S.current.manage_pow_nodes,
62 - handler: (context) => Navigator.of(context).pushNamed(Routes.managePowNodes),
63 - ),
64 - ],
65 - );
66 - },
190 + final selectedAtIndex =
191 + items.indexOf(_connectionSyncViewModel.exchangeStatus);
192 +
193 + await showPopUp<void>(
194 + context: context,
195 + builder: (_) => Picker(
196 + items: items,
197 + selectedAtIndex: selectedAtIndex,
198 + mainAxisAlignment: MainAxisAlignment.start,
199 + onItemSelected: (ExchangeApiMode mode) {
200 + _connectionSyncViewModel.setExchangeApiMode(mode);
201 + },
202 + isSeparated: false,
203 + ),
204 + );
205 + }),
206 + ListItemRegularRow(
207 + keyValue: "domain_lookups",
208 + label: S.of(context).domain_looks_up,
209 + onTap: () => Navigator.of(context).pushNamed(Routes.domainLookupsPage)
210 + ),
211 + ],
212 + }
213 + )
214 ),
68 - if (isWalletConnectCompatibleChain(dashboardViewModel.wallet.type) &&
69 - !dashboardViewModel.wallet.isHardwareWallet) ...[ // ToDo: Remove this line once WalletConnect is implemented
70 - WalletConnectTile(
71 - onTap: () => Navigator.of(context).pushNamed(Routes.walletConnectConnectionsListing),
72 - ),
73 - ],
74 - if (FeatureFlag.isInAppTorEnabled)
75 - Observer(builder: (context) {
76 - return SettingsSwitcherCell(
77 - leading: Container(
78 - padding: EdgeInsets.symmetric(horizontal: 4, vertical: 1),
79 - decoration: BoxDecoration(
80 - color: Colors.red.shade100,
81 - borderRadius: BorderRadius.circular(3),
82 - ),
83 - child: Text(
84 - 'Alpha',
85 - style: TextStyle(
86 - color: Colors.red.shade700,
87 - fontSize: 8,
88 - fontWeight: FontWeight.bold,
89 - ),
90 - ),
91 - ),
92 - title: S.current.enable_builtin_tor,
93 - value: dashboardViewModel.builtinTor,
94 - onValueChange: (_, bool value) => dashboardViewModel.setBuiltinTor(value, context),
95 - );
96 - }),
215 ],
216 ),
217 );
218 }
101 -
102 - Future<void> _presentReconnectAlert(BuildContext context) async {
103 - await showPopUp<void>(
104 - context: context,
105 - builder: (BuildContext context) {
106 - return AlertWithTwoActions(
107 - alertTitle: S.of(context).reconnection,
108 - alertContent: S.of(context).reconnect_alert_text,
109 - rightButtonText: S.of(context).ok,
110 - leftButtonText: S.of(context).cancel,
111 - actionRightButton: () async {
112 - Navigator.of(context).pop();
113 - await dashboardViewModel.reconnect();
114 - },
115 - actionLeftButton: () => Navigator.of(context).pop());
116 - },
117 - );
118 - }
219 }
lib/src/screens/settings/display_settings_page.dart
+222 -163
@@ -1,14 +1,18 @@
1 import 'package:cake_wallet/entities/bitcoin_amount_display_mode.dart';
2 import 'package:cake_wallet/entities/fiat_currency.dart';
3 import 'package:cake_wallet/entities/language_service.dart';
4 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
5 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_selector.dart';
6 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart';
7 import 'package:cake_wallet/entities/sync_status_display_mode.dart';
8 import 'package:cake_wallet/generated/i18n.dart';
9 import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
10 import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
8 -import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
9 -import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
11 import 'package:cake_wallet/src/screens/settings/widgets/settings_theme_choice.dart';
12 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
13 +import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
14 +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart';
15 +import 'package:cake_wallet/src/widgets/picker.dart';
16 import 'package:cake_wallet/src/widgets/standard_list.dart';
17 import 'package:cake_wallet/utils/device_info.dart';
18 import 'package:cake_wallet/utils/feature_flag.dart';
@@ -19,7 +23,6 @@ import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart
23 import 'package:flutter/material.dart';
24 import 'package:flutter_mobx/flutter_mobx.dart';
25 import 'package:image_picker/image_picker.dart';
22 -import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
26
27 class DisplaySettingsPage extends StatelessWidget {
28 DisplaySettingsPage(this._displaySettingsViewModel);
@@ -29,172 +32,228 @@ class DisplaySettingsPage extends StatelessWidget {
32
33 @override
34 Widget build(BuildContext context) {
32 - return Container(
33 - color: Theme.of(context).colorScheme.surface,
34 - child: SafeArea(
35 - top: false,
36 - child: Column(
37 - children: [
38 - ModalTopBar(title: S.of(context).display_settings,leadingIcon: Icon(Icons.arrow_back_ios_new),onLeadingPressed: () => Navigator.of(context).pop()),
39 - Expanded(
40 - child: SingleChildScrollView(
41 - controller: ModalScrollController.of(context),
42 - physics: ClampingScrollPhysics(),
43 - child: Observer(builder: (_) {
44 - return Container(
45 - padding: EdgeInsets.only(top: 10),
46 - child: Column(
47 - crossAxisAlignment: CrossAxisAlignment.start,
48 - children: [
49 - SettingsSwitcherCell(
50 - title: S.of(context).apps,
51 - value: _displaySettingsViewModel.shouldShowMarketPlaceInDashboard,
52 - onValueChange: (_, bool value) {
53 - _displaySettingsViewModel.setShouldShowMarketPlaceInDashbaord(value);
54 - },
55 - ),
56 - SettingsSwitcherCell(
57 - title: S.of(context).show_address_book_popup,
58 - value: _displaySettingsViewModel.showAddressBookPopup,
59 - onValueChange: (_, bool value) {
60 - _displaySettingsViewModel.setShowAddressBookPopup(value);
61 - },
62 - ),
63 - if (_displaySettingsViewModel.showZcashCardSetting)
64 - SettingsSwitcherCell(
65 - title: S.of(context).show_zcash_card,
66 - value: _displaySettingsViewModel.showZcashCard,
67 - onValueChange: (_, bool value) {
68 - _displaySettingsViewModel.setShowZcashCard(value);
69 - },
70 - ),
71 - SettingsPickerCell<SyncStatusDisplayMode>(
72 - title: S.current.sync_status_display_mode,
73 - items: SyncStatusDisplayMode.values.toList(),
74 - selectedItem: _displaySettingsViewModel.syncStatusDisplayMode,
75 - onItemSelected: (SyncStatusDisplayMode mode) =>
76 - _displaySettingsViewModel.setSyncStatusDisplayMode(mode),
77 - displayItem: (SyncStatusDisplayMode mode) => mode.title,
78 - isGridView: false,
79 - ),
80 - if (_displaySettingsViewModel.showDisplayAmountsInSatoshiSetting)
81 - SettingsPickerCell<BitcoinAmountDisplayMode>(
82 - title: S.of(context).bitcoin_amount_display,
83 - items: BitcoinAmountDisplayMode.all,
84 - selectedItem: _displaySettingsViewModel.displayAmountsInSatoshi,
85 - onItemSelected: _displaySettingsViewModel.setDisplayAmountsInSatoshi,
86 - displayItem: (mode) => mode.title,
87 - isGridView: false,
88 - ),
89 - //if (!isHaven) it does not work correctly
90 - if (!_displaySettingsViewModel.disabledFiatApiMode)
91 - SettingsPickerCell<FiatCurrency>(
92 - title: S.of(context).settings_currency,
93 - searchHintText: S.of(context).search_currency,
94 - items: FiatCurrency.all,
95 - selectedItem: _displaySettingsViewModel.fiatCurrency,
96 - onItemSelected: (FiatCurrency currency) =>
97 - _displaySettingsViewModel.setFiatCurrency(currency),
98 - images: FiatCurrency.all
99 - .map((e) => Image.asset("assets/images/flags/${e.countryCode}.png"))
100 - .toList(),
101 - isGridView: true,
102 - matchingCriteria: (FiatCurrency currency, String searchText) {
103 - return currency.title.toLowerCase().contains(searchText) ||
104 - currency.fullName.toLowerCase().contains(searchText);
105 - },
106 - ),
107 - SettingsPickerCell<String>(
108 - title: S.of(context).settings_change_language,
109 - searchHintText: S.of(context).search_language,
110 - items: LanguageService.list.keys.toList(),
111 - displayItem: (dynamic code) {
112 - return LanguageService.list[code] ?? '';
113 - },
114 - selectedItem: _displaySettingsViewModel.languageCode,
115 - onItemSelected: _displaySettingsViewModel.onLanguageSelected,
116 - images: LanguageService.list.keys
117 - .map((e) => Image.asset(
118 - "assets/images/flags/${LanguageService.localeCountryCode[e]}.png"))
119 - .toList(),
120 - matchingCriteria: (String code, String searchText) {
121 - return LanguageService.list[code]?.toLowerCase().contains(searchText) ?? false;
35 + return ModalPageWrapper(
36 + topBar: ModalTopBar(
37 + title: S.of(context).display,
38 + leadingIcon: Icon(Icons.arrow_back_ios_new),
39 + onLeadingPressed: () => Navigator.of(context).pop(),
40 + ),
41 + content: Column(
42 + spacing: 16,
43 + crossAxisAlignment: CrossAxisAlignment.start,
44 + children: [
45 + if (responsiveLayoutUtil.shouldRenderMobileUI &&
46 + DeviceInfo.instance.isMobile) ...[
47 + Padding(
48 + padding: const EdgeInsets.only(left: 14, top: 14),
49 + child: Text(
50 + S.of(context).appearance,
51 + style: Theme.of(context).textTheme.labelLarge?.copyWith(
52 + height: 0.2,
53 + color: Theme.of(context).colorScheme.onSurfaceVariant,
54 + ),
55 + ),
56 + ),
57 + Container(
58 + decoration: ShapeDecoration(
59 + color: Theme.of(context).colorScheme.surfaceContainerHigh,
60 + shape: RoundedSuperellipseBorder(
61 + borderRadius: BorderRadius.circular(18))),
62 + child: Column(
63 + children: [
64 + SettingsChoicesCell(
65 + ChoicesListItem<ThemeMode>(
66 + title: "",
67 + items: ThemeMode.values,
68 + selectedItem: _displaySettingsViewModel.themeMode,
69 + onItemSelected: (ThemeMode themeMode) =>
70 + _displaySettingsViewModel.setThemeMode(themeMode),
71 + displayItem: (ThemeMode themeMode) {
72 + return themeMode.name[0].toUpperCase() +
73 + themeMode.name.substring(1).toLowerCase();
74 },
75 ),
124 -
125 - if (FeatureFlag.customBackgroundEnabled)
126 - StandardListRow(
127 - title: "Custom background",
128 - isSelected: false,
129 - onTap: (_) => _pickImage(context),
130 - ),
131 -
132 - if (responsiveLayoutUtil.shouldRenderMobileUI && DeviceInfo.instance.isMobile) ...[
133 - SizedBox(height: 24),
134 - Padding(
135 - padding: const EdgeInsets.only(left: 24),
136 - child: Text(
137 - S.current.appearance,
138 - style: Theme.of(context).textTheme.bodyMedium?.copyWith(
139 - fontWeight: FontWeight.w400,
140 - fontSize: 14,
141 - height: 22 / 14,
142 - color: Theme.of(context).colorScheme.onSurface,
143 - ),
76 + useGenericColor: false,
77 + padding: EdgeInsets.all(14),
78 + ),
79 + Container(
80 + decoration: ShapeDecoration(
81 + color: Theme.of(context).colorScheme.surfaceContainer,
82 + shape: RoundedSuperellipseBorder(
83 + borderRadius: BorderRadius.circular(18))),
84 + child: Column(
85 + children: [
86 + Semantics(
87 + label: S.of(context).color_theme,
88 + child: SettingsThemeChoicesCell(_displaySettingsViewModel),
89 ),
145 - ),
146 - SizedBox(height: 12),
147 - Container(
148 - margin: EdgeInsets.symmetric(horizontal: 20),
149 - decoration: BoxDecoration(
150 - color: Theme.of(context).colorScheme.surfaceContainer,
151 - borderRadius: BorderRadius.circular(16),
152 - ),
153 - child: Column(
154 - children: [
155 - SettingsChoicesCell(
156 - ChoicesListItem<ThemeMode>(
157 - title: "",
158 - items: ThemeMode.values,
159 - selectedItem: _displaySettingsViewModel.themeMode,
160 - onItemSelected: (ThemeMode themeMode) =>
161 - _displaySettingsViewModel.setThemeMode(themeMode),
162 - displayItem: (ThemeMode themeMode) {
163 - return themeMode.name[0].toUpperCase() +
164 - themeMode.name.substring(1).toLowerCase();
165 - },
166 - ),
167 - useGenericColor: false,
168 - padding: EdgeInsets.all(12),
90 + ],
91 + ),
92 + ),
93 + ],
94 + ),
95 + ),
96 + ],
97 + Observer(
98 + builder: (_) => NewListSections(
99 + sections: {
100 + "": [
101 + ListItemToggle(
102 + keyValue: "apps",
103 + label: S.of(context).apps,
104 + value: _displaySettingsViewModel.shouldShowMarketPlaceInDashboard,
105 + onChanged: (val) {
106 + _displaySettingsViewModel.setShouldShowMarketPlaceInDashbaord(val);
107 + }),
108 + ListItemToggle(
109 + keyValue: "display_settings_show_address_book_popup",
110 + label: S.of(context).show_address_book_popup,
111 + value: _displaySettingsViewModel.showAddressBookPopup,
112 + onChanged: (val) {
113 + _displaySettingsViewModel.setShowAddressBookPopup(val);
114 + }),
115 + ListItemToggle(
116 + keyValue: "display_settings_disable_buy_button",
117 + label: S.of(context).disable_buy,
118 + value: _displaySettingsViewModel.disableTradeOption,
119 + onChanged: (val) {
120 + _displaySettingsViewModel.setDisableTradeOption(val);
121 + }),
122 + if (_displaySettingsViewModel.showZcashCardSetting)
123 + ListItemToggle(
124 + keyValue: "display_settings_show_zcashcard",
125 + label: S.of(context).show_zcash_card,
126 + value: _displaySettingsViewModel.showZcashCard,
127 + onChanged: (val) {
128 + _displaySettingsViewModel.setShowZcashCard(val);
129 + }),
130 + ListItemSelector(
131 + keyValue: "display_settings_sync_status_display",
132 + label: S.of(context).sync_status_display_mode,
133 + options: [_displaySettingsViewModel.syncStatusDisplayMode.title],
134 + onTap: () async {
135 + final items = SyncStatusDisplayMode.values.toList();
136 +
137 + final selectedAtIndex =
138 + items.indexOf(_displaySettingsViewModel.syncStatusDisplayMode);
139 +
140 + await showPopUp<void>(
141 + context: context,
142 + builder: (_) => Picker(
143 + items: items,
144 + selectedAtIndex: selectedAtIndex,
145 + mainAxisAlignment: MainAxisAlignment.start,
146 + onItemSelected: (SyncStatusDisplayMode mode) {
147 + _displaySettingsViewModel.setSyncStatusDisplayMode(mode);
148 + },
149 + displayItem: (SyncStatusDisplayMode mode) => mode.title,
150 + isSeparated: false,
151 + ),
152 + );
153 + }),
154 + if (_displaySettingsViewModel.showDisplayAmountsInSatoshiSetting)
155 + ListItemRegularRow(
156 + keyValue: "display_settings_bitcoin_amount_display",
157 + label: S.of(context).bitcoin_amount_display,
158 + trailingText: _displaySettingsViewModel.displayAmountsInSatoshi.title,
159 + onTap: () async {
160 + final items = BitcoinAmountDisplayMode.all;
161 +
162 + final selectedAtIndex =
163 + items.indexOf(_displaySettingsViewModel.displayAmountsInSatoshi);
164 +
165 + await showPopUp<void>(
166 + context: context,
167 + builder: (_) => Picker(
168 + items: items,
169 + selectedAtIndex: selectedAtIndex,
170 + mainAxisAlignment: MainAxisAlignment.start,
171 + onItemSelected: _displaySettingsViewModel.setDisplayAmountsInSatoshi,
172 + displayItem: (BitcoinAmountDisplayMode mode) => mode.title,
173 + isSeparated: false,
174 ),
170 - Container(
171 - decoration: BoxDecoration(
172 - color: Theme.of(context).colorScheme.surfaceContainerHigh,
173 - borderRadius: BorderRadius.circular(16),
174 - ),
175 - child: Column(
176 - children: [
177 - Semantics(
178 - label: S.of(context).color_theme,
179 - child: SettingsThemeChoicesCell(_displaySettingsViewModel),
180 - ),
181 - ],
182 - ),
175 + );
176 + }),
177 + if (!_displaySettingsViewModel.disabledFiatApiMode)
178 + ListItemSelector(
179 + keyValue: "display_settings_fiat_currency",
180 + label: S.of(context).settings_currency,
181 + options: [_displaySettingsViewModel.fiatCurrency.title],
182 + onTap: () async {
183 + final items = FiatCurrency.all;
184 +
185 + final selectedAtIndex =
186 + items.indexOf(_displaySettingsViewModel.fiatCurrency);
187 +
188 + await showPopUp<void>(
189 + context: context,
190 + builder: (_) => Picker(
191 + items: items,
192 + selectedAtIndex: selectedAtIndex,
193 + mainAxisAlignment: MainAxisAlignment.start,
194 + onItemSelected: (FiatCurrency currency) {
195 + _displaySettingsViewModel.setFiatCurrency(currency);
196 + },
197 + images: FiatCurrency.all
198 + .map((e) => Image.asset("assets/images/flags/${e.countryCode}.png"))
199 + .toList(),
200 + hintText: S.of(context).search_currency,
201 + isGridView: true,
202 + matchingCriteria: (FiatCurrency currency, String searchText) {
203 + return currency.title.toLowerCase().contains(searchText) ||
204 + currency.fullName.toLowerCase().contains(searchText);
205 + },
206 + isSeparated: false,
207 +
208 ),
184 - ],
185 - ),
186 - ),
187 - ],
188 - ],
189 - ),
190 - );
191 - }),
209 + );
210 + }),
211 + ListItemSelector(
212 + keyValue: "display_settings_language",
213 + label: S.of(context).settings_change_language,
214 + options: [LanguageService.list[_displaySettingsViewModel.languageCode] ?? ''],
215 + onTap: () async {
216 + final items = LanguageService.list.keys.toList();
217 +
218 + final selectedAtIndex =
219 + items.indexOf(_displaySettingsViewModel.languageCode);
220 +
221 + await showPopUp<void>(
222 + context: context,
223 + builder: (_) => Picker(
224 + displayItem: (dynamic code) {
225 + return LanguageService.list[code] ?? '';
226 + },
227 + items: items,
228 + selectedAtIndex: selectedAtIndex,
229 + mainAxisAlignment: MainAxisAlignment.start,
230 + onItemSelected: _displaySettingsViewModel.onLanguageSelected,
231 + images: LanguageService.list.keys
232 + .map((e) => Image.asset(
233 + "assets/images/flags/${LanguageService.localeCountryCode[e]}.png"))
234 + .toList(),
235 + hintText: S.of(context).search_language,
236 + matchingCriteria: (String code, String searchText) {
237 + return LanguageService.list[code]?.toLowerCase().contains(searchText) ?? false;
238 + },
239 + isSeparated: true,
240 +
241 + ),
242 + );
243 + }),
244 + ],
245 + },
246 + ),
247 ),
193 - ),
194 - ],
195 - ),
196 - ),
197 - );
248 + if (FeatureFlag.customBackgroundEnabled)
249 + StandardListRow(
250 + title: "Custom background",
251 + isSelected: false,
252 + onTap: (_) => _pickImage(context),
253 + ),
254 + ],
255 + ),
256 + );
257 }
258
259 // Function to pick an image from the gallery
lib/src/screens/settings/domain_lookups_page.dart
+19 -19
@@ -1,17 +1,17 @@
1 import 'package:cake_wallet/generated/i18n.dart';
2 import 'package:cake_wallet/src/screens/base_page.dart';
3 import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
4 -import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
4 +import 'package:cake_wallet/view_model/settings/connection_sync_view_model.dart';
5 import 'package:flutter/material.dart';
6 import 'package:flutter_mobx/flutter_mobx.dart';
7
8 class DomainLookupsPage extends BasePage {
9 - DomainLookupsPage(this._privacySettingsViewModel);
9 + DomainLookupsPage(this._connectionsSyncViewModel);
10
11 @override
12 String get title => S.current.domain_looks_up;
13
14 - final PrivacySettingsViewModel _privacySettingsViewModel;
14 + final ConnectionSyncViewModel _connectionsSyncViewModel;
15
16 @override
17 Widget body(BuildContext context) {
@@ -23,36 +23,36 @@ class DomainLookupsPage extends BasePage {
23 children: [
24 SettingsSwitcherCell(
25 title: 'Twitter',
26 - value: _privacySettingsViewModel.lookupTwitter,
27 - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsTwitter(value)),
26 + value: _connectionsSyncViewModel.lookupTwitter,
27 + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsTwitter(value)),
28 SettingsSwitcherCell(
29 title: 'Mastodon',
30 - value: _privacySettingsViewModel.looksUpMastodon,
31 - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsMastodon(value)),
30 + value: _connectionsSyncViewModel.looksUpMastodon,
31 + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsMastodon(value)),
32 SettingsSwitcherCell(
33 title: 'Yat service',
34 - value: _privacySettingsViewModel.looksUpYatService,
35 - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsYatService(value)),
34 + value: _connectionsSyncViewModel.looksUpYatService,
35 + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsYatService(value)),
36 SettingsSwitcherCell(
37 title: 'Unstoppable Domains',
38 - value: _privacySettingsViewModel.looksUpUnstoppableDomains,
39 - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsUnstoppableDomains(value)),
38 + value: _connectionsSyncViewModel.looksUpUnstoppableDomains,
39 + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsUnstoppableDomains(value)),
40 SettingsSwitcherCell(
41 title: 'OpenAlias',
42 - value: _privacySettingsViewModel.looksUpOpenAlias,
43 - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsOpenAlias(value)),
42 + value: _connectionsSyncViewModel.looksUpOpenAlias,
43 + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsOpenAlias(value)),
44 SettingsSwitcherCell(
45 title: 'Ethereum Name Service',
46 - value: _privacySettingsViewModel.looksUpENS,
47 - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsENS(value)),
46 + value: _connectionsSyncViewModel.looksUpENS,
47 + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsENS(value)),
48 SettingsSwitcherCell(
49 title: '.well-known',
50 - value: _privacySettingsViewModel.looksUpWellKnown,
51 - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsWellKnown(value)),
50 + value: _connectionsSyncViewModel.looksUpWellKnown,
51 + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsWellKnown(value)),
52 SettingsSwitcherCell(
53 title: 'Zano Aliases',
54 - value: _privacySettingsViewModel.lookupsZanoAlias,
55 - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsZanoAlias(value)),
54 + value: _connectionsSyncViewModel.lookupsZanoAlias,
55 + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsZanoAlias(value)),
56
57 //if (!isHaven) it does not work correctly
58 ],
lib/src/screens/settings/manage_nodes_page.dart
+81 -42
@@ -1,4 +1,8 @@
1 import 'package:cake_wallet/generated/i18n.dart';
2 +import 'package:cake_wallet/new-ui/widgets/modal_header.dart';
3 +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart';
4 +import 'package:cake_wallet/new-ui/widgets/modern_button.dart';
5 +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
6 import 'package:cake_wallet/routes.dart';
7 import 'package:cake_wallet/src/screens/base_page.dart';
8 import 'package:cake_wallet/src/screens/nodes/widgets/node_list_row.dart';
@@ -7,6 +11,7 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
11 import 'package:cake_wallet/src/widgets/standard_list.dart';
12 import 'package:cake_wallet/utils/feature_flag.dart';
13 import 'package:cake_wallet/utils/show_pop_up.dart';
14 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
15 import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
16 import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
17 import 'package:flutter/material.dart';
@@ -14,30 +19,46 @@ import 'package:flutter_mobx/flutter_mobx.dart';
19 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
20
21 class ManageNodesPage extends BasePage {
17 - ManageNodesPage(this.isPow, {this.nodeListViewModel, this.powNodeListViewModel})
22 + ManageNodesPage(this.isPow, {this.nodeListViewModel, this.powNodeListViewModel, this.dashboardViewModel})
23 : assert((isPow && powNodeListViewModel != null) || (!isPow && nodeListViewModel != null)),
24 assert(powNodeListViewModel == null || nodeListViewModel == null);
25
26 + final DashboardViewModel? dashboardViewModel;
27 final NodeListViewModel? nodeListViewModel;
28 final PowNodeListViewModel? powNodeListViewModel;
29 final bool isPow;
30
31 + @override
32 + bool get hideAppBar => true;
33 +
34 @override
35 String get title => S.current.manage_nodes;
36
37 @override
38 Widget body(BuildContext context) {
30 - return Padding(
31 - padding: EdgeInsets.only(top: 10),
32 - child: Column(
39 + return ModalPageWrapper(
40 + horizontalPadding: 0,
41 + topBar: ModalTopBar(
42 + title: S.of(context).manage_nodes,
43 + leadingIcon: Icon(Icons.arrow_back_ios_new),
44 + onLeadingPressed: () => Navigator.of(context).pop(),
45 + trailingWidget: Row(
46 + spacing: 8,
47 + children: [
48 + if (dashboardViewModel?.hasRescan ?? true)
49 + ModernButton(
50 + size: 36,
51 + icon: Icon(Icons.history),
52 + onPressed: () => Navigator.of(context).pushNamed(Routes.rescan)),
53 + ModernButton(
54 + size: 36,
55 + icon: Icon(Icons.add),
56 + onPressed: () => Navigator.of(context).pushNamed(isPow ? Routes.newPowNode : Routes.newNode))
57 + ],
58 + ),
59 + ),
60 + content: Column(
61 children: [
34 - Semantics(
35 - button: true,
36 - child: NodeHeaderListRow(
37 - title: S.of(context).add_new_node,
38 - onTap: (_) async => await Navigator.of(context).pushNamed(isPow ? Routes.newPowNode : Routes.newNode),
39 - ),
40 - ),
62 if (FeatureFlag.isAutomaticNodeSwitchingEnabled)
63 Observer(
64 builder: (_) => SettingsSwitcherCell(
@@ -60,32 +81,34 @@ class ManageNodesPage extends BasePage {
81 builder: (BuildContext context) {
82 int itemsCount =
83 nodeListViewModel?.nodes.length ?? powNodeListViewModel!.nodes.length;
63 - return Flexible(
64 - child: SectionStandardList(
65 - scrollController: ModalScrollController.of(context),
66 - sectionCount: 1,
67 - dividerPadding: EdgeInsets.symmetric(horizontal: 24),
68 - itemCounter: (int sectionIndex) => itemsCount,
69 - itemBuilder: (_, index) {
70 - return Observer(
71 - builder: (context) {
72 - final node =
73 - nodeListViewModel?.nodes[index] ?? powNodeListViewModel!.nodes[index];
74 - late bool isSelected;
75 - if (isPow) {
76 - isSelected = node.keyIndex == powNodeListViewModel!.currentNode.keyIndex;
77 - } else {
78 - isSelected = node.keyIndex == nodeListViewModel!.currentNode.keyIndex;
79 - }
80 - final nodeListRow = NodeListRow(
81 - title: node.uriRaw,
82 - node: node,
83 - isSelected: isSelected,
84 - isPow: isPow,
85 - onTap: (_) async {
86 - if (isSelected) {
87 - return;
88 - }
84 + return SectionStandardList(
85 + scrollController: ModalScrollController.of(context),
86 + sectionCount: 1,
87 + shrinkWrap: true,
88 + physics: NeverScrollableScrollPhysics(),
89 + dividerPadding: EdgeInsets.symmetric(horizontal: 24),
90 + itemCounter: (int sectionIndex) => itemsCount,
91 + itemBuilder: (_, index) {
92 + return Observer(
93 + builder: (context) {
94 + final node =
95 + nodeListViewModel?.nodes[index] ?? powNodeListViewModel!.nodes[index];
96 + late bool isSelected;
97 + if (isPow) {
98 + isSelected = node.keyIndex == powNodeListViewModel!.currentNode.keyIndex;
99 + } else {
100 + isSelected = node.keyIndex == nodeListViewModel!.currentNode.keyIndex;
101 + }
102 + final nodeListRow = NodeListRow(
103 + title: node.uriRaw,
104 + subtitle: node.label!,
105 + node: node,
106 + isSelected: isSelected,
107 + isPow: isPow,
108 + onTap: (_) async {
109 + if (isSelected) {
110 + return;
111 + }
112
113 await showPopUp<void>(
114 context: context,
@@ -110,11 +133,10 @@ class ManageNodesPage extends BasePage {
133 );
134 },
135 );
113 - return nodeListRow;
114 - },
115 - );
116 - },
117 - ),
136 + return nodeListRow;
137 + },
138 + );
139 + },
140 );
141 },
142 ),
@@ -122,4 +144,21 @@ class ManageNodesPage extends BasePage {
144 ),
145 );
146 }
147 + Future<void> _presentReconnectAlert(BuildContext context) async {
148 + await showPopUp<void>(
149 + context: context,
150 + builder: (BuildContext context) {
151 + return AlertWithTwoActions(
152 + alertTitle: S.of(context).reconnection,
153 + alertContent: S.of(context).reconnect_alert_text,
154 + rightButtonText: S.of(context).ok,
155 + leftButtonText: S.of(context).cancel,
156 + actionRightButton: () async {
157 + Navigator.of(context).pop();
158 + await dashboardViewModel!.reconnect();
159 + },
160 + actionLeftButton: () => Navigator.of(context).pop());
161 + },
162 + );
163 + }
164 }
lib/src/screens/settings/mweb_node_page.dart
+46 -38
@@ -1,56 +1,64 @@
1 -import 'package:cake_wallet/src/screens/base_page.dart';
2 -import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
1 +import 'package:cake_wallet/core/node_address_validator.dart';
2 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_text_field.dart';
3 +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart';
4 +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
5 +import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
6 import 'package:cake_wallet/src/widgets/primary_button.dart';
7 import 'package:cake_wallet/generated/i18n.dart';
8 import 'package:cake_wallet/view_model/settings/mweb_settings_view_model.dart';
9 import 'package:flutter/material.dart';
7 -import 'package:flutter_mobx/flutter_mobx.dart';
8 -
9 -class MwebNodePage extends BasePage {
10 - MwebNodePage(this.mwebSettingsViewModelBase)
11 - : _nodeUriController = TextEditingController(text: mwebSettingsViewModelBase.mwebNodeUri),
12 - super();
10 +class MwebNodePage extends StatefulWidget {
11 + const MwebNodePage(this.mwebSettingsViewModelBase, {super.key});
12
13 final MwebSettingsViewModelBase mwebSettingsViewModelBase;
15 - final TextEditingController _nodeUriController;
14
15 @override
18 - String get title => S.current.litecoin_mweb_node;
16 + State<MwebNodePage> createState() => _MwebNodePageState();
17 +}
18 +
19 +class _MwebNodePageState extends State<MwebNodePage> {
20 + late final TextEditingController _nodeUriController =
21 + TextEditingController(text: widget.mwebSettingsViewModelBase.mwebNodeUri);
22 +
23 + @override
24 + void dispose() {
25 + _nodeUriController.dispose();
26 + super.dispose();
27 + }
28
29 @override
21 - Widget body(BuildContext context) {
22 - return Stack(
23 - fit: StackFit.expand,
24 - children: [
25 - Container(
26 - padding: EdgeInsets.symmetric(horizontal: 24),
27 - child: Row(
28 - children: <Widget>[
29 - Expanded(
30 - child: BaseTextFormField(controller: _nodeUriController),
31 - )
32 - ],
33 - ),
30 + Widget build(BuildContext context) {
31 + return ModalPageWrapper(
32 + topBar: ModalTopBar(
33 + title: S.current.litecoin_mweb_settings,
34 + onLeadingPressed: Navigator.of(context).pop,
35 + leadingIcon: Icon(Icons.arrow_back_ios_new)),
36 + content: Container(
37 + child: NewListSections(
38 + controllers: {
39 + widget.mwebSettingsViewModelBase.mwebNodeUri: _nodeUriController,
40 + },
41 + sections: {
42 + 'main': [
43 + ListItemTextField(
44 + keyValue: widget.mwebSettingsViewModelBase.mwebNodeUri,
45 + label: S.current.node_address,
46 + validator: NodePathValidator(),
47 + ),
48 + ]
49 + }),
50 ),
35 - Positioned(
36 - child: Observer(
37 - builder: (_) => LoadingPrimaryButton(
38 - onPressed: () => save(context),
39 - text: S.of(context).save,
40 - color: Theme.of(context).colorScheme.primary,
41 - textColor: Theme.of(context).colorScheme.onPrimary,
42 - ),
43 - ),
44 - bottom: 24,
45 - left: 24,
46 - right: 24,
47 - )
48 - ],
51 + bottomContent: LoadingPrimaryButton(
52 + onPressed: () => save(context),
53 + text: S.of(context).save,
54 + color: Theme.of(context).colorScheme.primary,
55 + textColor: Theme.of(context).colorScheme.onPrimary,
56 + ),
57 );
58 }
59
60 void save(BuildContext context) {
53 - mwebSettingsViewModelBase.setMwebNodeUri(_nodeUriController.text);
61 + widget.mwebSettingsViewModelBase.setMwebNodeUri(_nodeUriController.text);
62 Navigator.pop(context);
63 }
64 }
lib/src/screens/settings/other_settings_page.dart
+199 -154
@@ -1,21 +1,24 @@
1 import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
3 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_selector.dart';
4 import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
5 import 'package:cake_wallet/generated/i18n.dart';
6 +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart';
7 +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
8 import 'package:cake_wallet/routes.dart';
9 import 'package:cake_wallet/src/screens/base_page.dart';
10 import 'package:cake_wallet/src/screens/dev/moneroc_cache_debug.dart';
7 -import 'package:cake_wallet/src/screens/settings/widgets/setting_priority_picker_cell.dart';
8 -import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
9 -import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
10 -import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart';
11 +import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
12 +import 'package:cake_wallet/src/widgets/picker.dart';
13 import 'package:cake_wallet/utils/feature_flag.dart';
14 import 'package:cake_wallet/utils/share_util.dart';
15 +import 'package:cake_wallet/utils/show_pop_up.dart';
16 import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
17 import 'package:cw_core/wallet_info.dart';
18 +import 'package:cw_core/transaction_priority.dart';
19 import 'package:cw_core/wallet_type.dart';
20 import 'package:cw_core/db/sqlite.dart';
21 import 'package:flutter/material.dart';
18 -import 'package:flutter_mobx/flutter_mobx.dart';
22
23 class OtherSettingsPage extends BasePage {
24 OtherSettingsPage(this._otherSettingsViewModel) {
@@ -25,164 +28,206 @@ class OtherSettingsPage extends BasePage {
28 }
29
30 @override
28 - String get title => S.current.other_settings;
31 + bool get hideAppBar => true;
32
33 final OtherSettingsViewModel _otherSettingsViewModel;
34
35 +
36 @override
33 - Widget body(BuildContext context) => Observer(
34 - builder: (_) => Container(
35 - padding: EdgeInsets.only(top: 10),
36 - child: Column(
37 - children: [
38 - Expanded(
39 - child: SingleChildScrollView(
40 - child: Column(
41 - children: [
42 - if (_otherSettingsViewModel.displayTransactionPriority)
43 - _otherSettingsViewModel.walletType == WalletType.bitcoin
44 - ? SettingsPriorityPickerCell(
45 - title: S.current.settings_fee_priority,
46 - items: priorityForWalletType(_otherSettingsViewModel.walletType),
47 - displayItem: _otherSettingsViewModel.getDisplayBitcoinPriority,
48 - selectedItem: _otherSettingsViewModel.transactionPriority,
49 - customItemIndex: _otherSettingsViewModel.customPriorityItemIndex,
50 - onItemSelected: _otherSettingsViewModel.onDisplayBitcoinPrioritySelected,
51 - customValue: _otherSettingsViewModel.customBitcoinFeeRate,
52 - maxValue: _otherSettingsViewModel.maxCustomFeeRate?.toDouble(),
53 - )
54 - : SettingsPickerCell(
55 - title: S.current.settings_fee_priority,
56 - items: priorityForWalletType(_otherSettingsViewModel.walletType),
57 - displayItem: _otherSettingsViewModel.getDisplayPriority,
58 - selectedItem: _otherSettingsViewModel.transactionPriority,
59 - onItemSelected: _otherSettingsViewModel.onDisplayPrioritySelected,
60 - ),
61 - if (_otherSettingsViewModel.changeRepresentativeEnabled)
62 - SettingsCellWithArrow(
63 - title: S.current.change_rep,
64 - handler: (context) => Navigator.of(context).pushNamed(Routes.changeRep),
65 - ),
66 - if (_otherSettingsViewModel.changeHardwareWalletTypeEnabled)
67 - SettingsCellWithArrow(
68 - title: "Hardware wallet manufacturer",
69 - handler: (context) => Navigator.of(context)
70 - .pushNamed(Routes.restoreWalletFromHardwareWallet, arguments: {
71 - "showUnavailable": false,
72 - "availableHardwareWalletTypes": [
73 - HardwareWalletType.cupcake,
74 - HardwareWalletType.coldcard,
75 - HardwareWalletType.seedsigner,
76 - ],
77 - "onSelect": (BuildContext context, HardwareWalletType hwType) async {
78 - await _otherSettingsViewModel.onHardwareWalletTypeChanged(hwType);
79 - Navigator.pop(context);
37 + Widget body(BuildContext context) {
38 + return ModalPageWrapper(
39 + topBar: ModalTopBar(
40 + title: S.of(context).other,
41 + leadingIcon: Icon(Icons.arrow_back_ios_new),
42 + onLeadingPressed: () => Navigator.of(context).pop(),
43 + ),
44 + // header: ModalHeader(
45 + // iconPath: "assets/new-ui/settings_row_icons/other.svg",
46 + // message: "Other settings",
47 + // title: S.of(context).other_settings),
48 + content: NewListSections(
49 + sections: {
50 + "": [
51 + if (_otherSettingsViewModel.displayTransactionPriority)
52 + _otherSettingsViewModel.walletType == WalletType.bitcoin
53 + ? ListItemSelector(
54 + keyValue: "fee_priority",
55 + label: S.of(context).settings_fee_priority,
56 + options: [_otherSettingsViewModel.transactionPriority.title],
57 + onTap: () async {
58 +
59 + final items = priorityForWalletType(_otherSettingsViewModel.walletType);
60 +
61 + var selectedAtIndex = items.indexOf(_otherSettingsViewModel.transactionPriority);
62 + double sliderValue = _otherSettingsViewModel.customBitcoinFeeRate ?? 0.0;
63 +
64 + await showPopUp<void>(
65 + context: context,
66 + builder: (BuildContext context) {
67 + return StatefulBuilder(
68 + builder: (BuildContext context, StateSetter setState) {
69 + return Picker(
70 + items: items,
71 + displayItem: (TransactionPriority item) => _otherSettingsViewModel.getDisplayBitcoinPriority(item, sliderValue.round()),
72 + selectedAtIndex: selectedAtIndex,
73 + customItemIndex: _otherSettingsViewModel.customPriorityItemIndex,
74 + maxValue: _otherSettingsViewModel.maxCustomFeeRate?.toDouble(),
75 + headerEnabled: false,
76 + closeOnItemSelected: false,
77 + mainAxisAlignment: MainAxisAlignment.center,
78 + sliderValue: sliderValue,
79 + onSliderChanged: (double newValue) =>
80 + setState(() => sliderValue = newValue),
81 + onItemSelected: (TransactionPriority priority) {
82 + setState(() => selectedAtIndex = items.indexOf(priority));
83 + _otherSettingsViewModel.onDisplayBitcoinPrioritySelected.call(priority, sliderValue);
84 },
81 - }),
82 - ),
83 - if (_otherSettingsViewModel.walletType == WalletType.bitcoin) ...[
84 - SettingsCellWithArrow(
85 - title: S.of(context).export_lightning_logs,
86 - handler: onExportLNLog,
87 - ),
88 - SettingsCellWithArrow(
89 - title: S.of(context).export_payjoin_logs,
90 - handler: onExportPJLog,
91 - ),
92 - ],
93 - SettingsCellWithArrow(
94 - title: S.current.settings_terms_and_conditions,
95 - handler: (context) => Navigator.of(context).pushNamed(Routes.readDisclaimer),
96 - ),
97 - if (FeatureFlag.hasDevOptions &&
98 - _otherSettingsViewModel.walletType == WalletType.monero)
99 - SettingsCellWithArrow(
100 - title: '[dev] monero background sync',
101 - handler: (context) =>
102 - Navigator.of(context).pushNamed(Routes.devMoneroBackgroundSync),
103 - ),
104 - if (FeatureFlag.hasDevOptions &&
105 - [WalletType.monero, WalletType.wownero, WalletType.zano]
106 - .contains(_otherSettingsViewModel.walletType))
107 - SettingsCellWithArrow(
108 - title: '[dev] xmr call profiler',
109 - handler: (context) =>
110 - Navigator.of(context).pushNamed(Routes.devMoneroCallProfiler),
111 - ),
112 - if (FeatureFlag.hasDevOptions &&
113 - [WalletType.monero].contains(_otherSettingsViewModel.walletType))
114 - SettingsCellWithArrow(
115 - title: '[dev] xmr wallet cache debug',
116 - handler: (context) =>
117 - Navigator.of(context).pushNamed(Routes.devMoneroWalletCacheDebug),
118 - ),
119 - if (FeatureFlag.hasDevOptions)
120 - SettingsCellWithArrow(
121 - title: '[dev] shared preferences',
122 - handler: (context) =>
123 - Navigator.of(context).pushNamed(Routes.devSharedPreferences),
124 - ),
125 - if (FeatureFlag.hasDevOptions)
126 - SettingsCellWithArrow(
127 - title: '[dev] secure storage preferences',
128 - handler: (context) =>
129 - Navigator.of(context).pushNamed(Routes.devSecurePreferences),
130 - ),
131 - if (FeatureFlag.hasDevOptions)
132 - SettingsCellWithArrow(
133 - title: '[dev] background sync logs',
134 - handler: (context) =>
135 - Navigator.of(context).pushNamed(Routes.devBackgroundSyncLogs),
136 - ),
137 - if (FeatureFlag.hasDevOptions)
138 - SettingsCellWithArrow(
139 - title: '[dev] socket health logs',
140 - handler: (context) => Navigator.of(context).pushNamed(Routes.devSocketHealthLogs),
141 - ),
142 - if (FeatureFlag.hasDevOptions)
143 - SettingsCellWithArrow(
144 - title: '[dev] network requests logs',
145 - handler: (context) => Navigator.of(context).pushNamed(Routes.devNetworkRequests),
146 - ),
147 - if (FeatureFlag.hasDevOptions)
148 - SettingsCellWithArrow(
149 - title: '[dev] exchange provider logs',
150 - handler: (context) =>
151 - Navigator.of(context).pushNamed(Routes.devExchangeProviderLogs),
152 - ),
153 - if (FeatureFlag.hasDevOptions)
154 - SettingsCellWithArrow(
155 - title: '[dev] *QR tools',
156 - handler: (context) => Navigator.of(context).pushNamed(Routes.devQRTools),
157 - ),
158 - if (FeatureFlag.hasDevOptions)
159 - SettingsCellWithArrow(
160 - title: '[dev] exchange provider logs',
161 - handler: (BuildContext context) =>
162 - Navigator.of(context).pushNamed(Routes.devExchangeProviderLogs),
163 - ),
164 - if (FeatureFlag.hasDevOptions)
165 - SettingsCellWithArrow(
166 - title: '[dev] browse sqlite db',
167 - handler: (BuildContext context) async {
168 - final data = await dumpDb();
169 - Navigator.of(context).push(
170 - MaterialPageRoute(builder: (context) => JsonExplorerPage(data: data, title: 'sqlite db')),
171 - );
172 - }
173 - ),
174 - ],
85 + );
86 + },
87 + );
88 + },
89 + );
90 + _otherSettingsViewModel.onDisplayBitcoinPrioritySelected.call(items[selectedAtIndex], sliderValue);
91 + }
92 + )
93 + : ListItemSelector(
94 + keyValue: "fee_priority",
95 + label: S.of(context).settings_fee_priority,
96 + options: [_otherSettingsViewModel.transactionPriority.title],
97 + onTap: () async {
98 + final selectedAtIndex = priorityForWalletType(_otherSettingsViewModel.walletType).indexOf(_otherSettingsViewModel.transactionPriority,);
99 +
100 + await showPopUp<void>(
101 + context: context,
102 + builder: (_) => Picker(
103 + items: priorityForWalletType(_otherSettingsViewModel.walletType),
104 + displayItem: _otherSettingsViewModel.getDisplayPriority,
105 + selectedAtIndex: selectedAtIndex,
106 + mainAxisAlignment: MainAxisAlignment.start,
107 + onItemSelected: (TransactionPriority item) => _otherSettingsViewModel.onDisplayBitcoinPrioritySelected.call(item, 0),
108 + isSeparated: false,
109 ),
176 - ),
110 + );
111 + },
112 + ),
113 + if(_otherSettingsViewModel.changeRepresentativeEnabled)
114 + ListItemRegularRow(
115 + keyValue: "change_rep",
116 + label: S.of(context).change_rep,
117 + onTap: () => Navigator.of(context).pushNamed(Routes.changeRep)
118 + ),
119 + if (_otherSettingsViewModel.changeHardwareWalletTypeEnabled)
120 + ListItemRegularRow(
121 + keyValue: "hardware_wallet_manufacturer",
122 + label: "Hardware wallet manufacturer",
123 + onTap: () => Navigator.of(context)
124 + .pushNamed(Routes.restoreWalletFromHardwareWallet, arguments: {
125 + "showUnavailable": false,
126 + "availableHardwareWalletTypes": [
127 + HardwareWalletType.cupcake,
128 + HardwareWalletType.coldcard,
129 + HardwareWalletType.seedsigner,
130 + ],
131 + "onSelect": (BuildContext context, HardwareWalletType hwType) async {
132 + await _otherSettingsViewModel.onHardwareWalletTypeChanged(hwType);
133 + Navigator.pop(context);
134 + },
135 + }),
136 + ),
137 + ListItemRegularRow(
138 + keyValue: "security_backup_page_sign_and_verify",
139 + label: S.of(context).sign_verify_title,
140 + onTap: () {
141 + Navigator.of(context).pushNamed(Routes.signPage);
142 + }),
143 + ],
144 + if(FeatureFlag.hasDevOptions)
145 + "dev": [
146 + if(_otherSettingsViewModel.walletType == WalletType.bitcoin) ...[
147 + ListItemRegularRow(
148 + keyValue: "export_lightning_logs",
149 + label: S.of(context).export_lightning_logs,
150 + onTap: () => onExportLNLog(context)
151 ),
178 - SettingsVersionCell(
179 - title: S.of(context).version(_otherSettingsViewModel.currentVersion),
152 + ListItemRegularRow(
153 + keyValue: "export_payjoin_logs",
154 + label: S.of(context).export_payjoin_logs,
155 + onTap: () => onExportPJLog(context)
156 ),
157 ],
182 - ),
183 - ),
184 - );
185 -
158 + if (FeatureFlag.hasDevOptions &&
159 + _otherSettingsViewModel.walletType == WalletType.monero)
160 + ListItemRegularRow(
161 + keyValue: "[dev] monero background sync",
162 + label: "[dev] monero background sync",
163 + onTap: () => Navigator.of(context).pushNamed(Routes.devMoneroBackgroundSync)
164 + ),
165 + if (FeatureFlag.hasDevOptions &&
166 + [WalletType.monero, WalletType.wownero, WalletType.zano]
167 + .contains(_otherSettingsViewModel.walletType))
168 + ListItemRegularRow(
169 + keyValue: "[dev] xmr call profiler",
170 + label: "[dev] xmr call profiler",
171 + onTap: () => Navigator.of(context).pushNamed(Routes.devMoneroCallProfiler)
172 + ),
173 + if (FeatureFlag.hasDevOptions &&
174 + [WalletType.monero].contains(_otherSettingsViewModel.walletType))
175 + ListItemRegularRow(
176 + keyValue: '[dev] xmr wallet cache debug',
177 + label: '[dev] xmr wallet cache debug',
178 + onTap: () => Navigator.of(context).pushNamed(Routes.devMoneroWalletCacheDebug)
179 + ),
180 + ListItemRegularRow(
181 + keyValue: '[dev] shared preferences',
182 + label: '[dev] shared preferences',
183 + onTap: () => Navigator.of(context).pushNamed(Routes.devSharedPreferences)
184 + ),
185 + ListItemRegularRow(
186 + keyValue: '[dev] secure storage preferences',
187 + label: '[dev] secure storage preferences',
188 + onTap: () => Navigator.of(context).pushNamed(Routes.devSecurePreferences)
189 + ),
190 + ListItemRegularRow(
191 + keyValue: '[dev] background sync logs',
192 + label: '[dev] background sync logs',
193 + onTap: () => Navigator.of(context).pushNamed(Routes.devBackgroundSyncLogs)
194 + ),
195 + ListItemRegularRow(
196 + keyValue: '[dev] socket health logs',
197 + label: '[dev] socket health logs',
198 + onTap: () => Navigator.of(context).pushNamed(Routes.devSocketHealthLogs)
199 + ),
200 + ListItemRegularRow(
201 + keyValue: '[dev] network requests logs',
202 + label: '[dev] network requests logs',
203 + onTap: () => Navigator.of(context).pushNamed(Routes.devNetworkRequests)
204 + ),
205 + ListItemRegularRow(
206 + keyValue: '[dev] exchange provider logs',
207 + label: '[dev] exchange provider logs',
208 + onTap: () => Navigator.of(context).pushNamed(Routes.devExchangeProviderLogs)
209 + ),
210 + ListItemRegularRow(
211 + keyValue: '[dev] *QR tools',
212 + label: '[dev] *QR tools',
213 + onTap: () => Navigator.of(context).pushNamed(Routes.devExchangeProviderLogs)
214 + ),
215 + ListItemRegularRow(
216 + keyValue: '[dev] browse sqlite db',
217 + label: '[dev] browse sqlite db',
218 + onTap: () async {
219 + final data = await dumpDb();
220 + Navigator.of(context).push(
221 + MaterialPageRoute(builder: (context) =>
222 + JsonExplorerPage(data: data, title: 'sqlite db')),
223 + );
224 + }
225 + ),
226 + ]
227 + }
228 + ),
229 + );
230 + }
231 Future<void> onExportLNLog(BuildContext context) async {
232 final file = await _otherSettingsViewModel.getLightningLog();
233
lib/src/screens/settings/privacy_page.dart
+88 -192
@@ -1,15 +1,12 @@
1 -import 'package:cake_wallet/entities/exchange_api_mode.dart';
2 -import 'package:cake_wallet/entities/fiat_api_mode.dart';
1 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
2 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart';
3 import 'package:cake_wallet/generated/i18n.dart';
4 +import 'package:cake_wallet/new-ui/widgets/modal_header.dart';
5 +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.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/screens/base_page.dart';
6 -import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
7 -import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
8 -import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
9 -import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
10 -import 'package:cake_wallet/utils/device_info.dart';
11 -import 'package:cake_wallet/utils/show_pop_up.dart';
12 -import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
9 +import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
10 import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
11 import 'package:flutter/material.dart';
12 import 'package:flutter_mobx/flutter_mobx.dart';
@@ -18,195 +15,94 @@ class PrivacyPage extends BasePage {
15 PrivacyPage(this._privacySettingsViewModel);
16
17 @override
21 - String get title => S.current.privacy_settings;
18 + bool get hideAppBar => true;
19
20 final PrivacySettingsViewModel _privacySettingsViewModel;
21
22 @override
23 Widget body(BuildContext context) {
27 - return SingleChildScrollView(
28 - child: Container(
29 - padding: EdgeInsets.only(top: 10),
30 - child: Observer(builder: (_) {
31 - return Column(
32 - mainAxisSize: MainAxisSize.min,
33 - children: [
34 - SettingsChoicesCell(
35 - ChoicesListItem<FiatApiMode>(
36 - title: S.current.fiat_api,
37 - items: FiatApiMode.all,
38 - selectedItem: _privacySettingsViewModel.fiatApiMode,
39 - onItemSelected: (FiatApiMode fiatApiMode) =>
40 - _privacySettingsViewModel.setFiatMode(fiatApiMode),
41 - ),
42 - ),
43 - SettingsChoicesCell(
44 - ChoicesListItem<ExchangeApiMode>(
45 - title: S.current.swap,
46 - items: ExchangeApiMode.all,
47 - selectedItem: _privacySettingsViewModel.exchangeStatus,
48 - onItemSelected: (ExchangeApiMode mode) =>
49 - _privacySettingsViewModel.setExchangeApiMode(mode),
50 - ),
51 - ),
52 - if (_privacySettingsViewModel.canUseLightning)
53 - SettingsSwitcherCell(
54 - title: S.of(context).enable_lightning,
55 - value: _privacySettingsViewModel.useLightning,
56 - onValueChange: (_, value) => _privacySettingsViewModel.setUseLightning(value),
57 - ),
58 - if (_privacySettingsViewModel.canUsePayjoin)
59 - SettingsSwitcherCell(
60 - title: S.of(context).use_payjoin,
61 - value: _privacySettingsViewModel.usePayjoin,
62 - onValueChange: (BuildContext _, bool value) {
63 - _privacySettingsViewModel.setUsePayjoin(value);
64 - },
65 - ),
66 - SettingsSwitcherCell(
67 - title: S.current.settings_save_recipient_address,
68 - value: _privacySettingsViewModel.shouldSaveRecipientAddress,
69 - onValueChange: (BuildContext _, bool value) {
70 - _privacySettingsViewModel.setShouldSaveRecipientAddress(value);
71 - }),
72 - if (_privacySettingsViewModel.isAutoGenerateSubaddressesVisible)
73 - SettingsSwitcherCell(
74 - title: _privacySettingsViewModel.isMoneroWallet
75 - ? S.current.auto_generate_subaddresses
76 - : S.current.auto_generate_addresses,
77 - value: _privacySettingsViewModel.isAutoGenerateSubaddressesEnabled,
78 - onValueChange: (BuildContext _, bool value) {
79 - _privacySettingsViewModel.setAutoGenerateSubaddresses(value);
80 - },
81 - ),
82 - if (DeviceInfo.instance.isMobile)
83 - SettingsSwitcherCell(
84 - title: S.current.prevent_screenshots,
85 - value: _privacySettingsViewModel.isAppSecure,
86 - onValueChange: (BuildContext _, bool value) {
87 - _privacySettingsViewModel.setIsAppSecure(value);
88 - },
89 - ),
90 - SettingsSwitcherCell(
91 - title: S.current.disable_buy,
92 - value: _privacySettingsViewModel.disableTradeOption,
93 - onValueChange: (BuildContext _, bool value) {
94 - _privacySettingsViewModel.setDisableTradeOption(value);
95 - },
96 - ),
97 - SettingsSwitcherCell(
98 - title: S.current.disable_automatic_exchange_status_updates,
99 - value: _privacySettingsViewModel.disableAutomaticExchangeStatusUpdates,
100 - onValueChange: (BuildContext _, bool value) {
101 - _privacySettingsViewModel.setDisableAutomaticExchangeStatusUpdates(value);
102 - },
103 - ),
104 - // SettingsSwitcherCell(
105 - // title: S.current.disable_bulletin,
106 - // value: _privacySettingsViewModel.disableBulletin,
107 - // onValueChange: (BuildContext _, bool value) {
108 - // _privacySettingsViewModel.setDisableBulletin(value);
109 - // },
110 - // ),
111 - if (_privacySettingsViewModel.canUseBlinkProtection)
112 - SettingsSwitcherCell(
113 - title: S.current.use_blink_protection,
114 - value: _privacySettingsViewModel.useBlinkProtection,
115 - onValueChange: (BuildContext _, bool value) {
116 - _privacySettingsViewModel.setUseBlinkProtection(value);
117 - },
118 - ),
119 - if (_privacySettingsViewModel.canUseEtherscan)
120 - SettingsSwitcherCell(
121 - title: S.current.etherscan_history,
122 - value: _privacySettingsViewModel.useEtherscan,
123 - onValueChange: (BuildContext _, bool value) {
124 - _privacySettingsViewModel.setUseEtherscan(value);
125 - },
126 - ),
127 - if (_privacySettingsViewModel.canUsePolygonScan)
128 - SettingsSwitcherCell(
129 - title: S.current.polygonscan_history,
130 - value: _privacySettingsViewModel.usePolygonScan,
131 - onValueChange: (BuildContext _, bool value) {
132 - _privacySettingsViewModel.setUsePolygonScan(value);
133 - },
134 - ),
135 - if (_privacySettingsViewModel.canUseBaseScan)
136 - SettingsSwitcherCell(
137 - title: S.current.basescan_history,
138 - value: _privacySettingsViewModel.useBaseScan,
139 - onValueChange: (BuildContext _, bool value) {
140 - _privacySettingsViewModel.setUseBaseScan(value);
141 - },
142 - ),
143 - if (_privacySettingsViewModel.canUseArbiScan)
144 - SettingsSwitcherCell(
145 - title: S.current.arbiscan_history,
146 - value: _privacySettingsViewModel.useArbiScan,
147 - onValueChange: (BuildContext _, bool value) {
148 - _privacySettingsViewModel.setUseArbiScan(value);
149 - },
150 - ),
151 - if (_privacySettingsViewModel.canUseBscScan)
152 - SettingsSwitcherCell(
153 - title: S.current.bscscan_history,
154 - value: _privacySettingsViewModel.useBscScan,
155 - onValueChange: (BuildContext _, bool value) {
156 - _privacySettingsViewModel.setUseBscScan(value);
157 - },
158 - ),
159 - if (_privacySettingsViewModel.canUseTronGrid)
160 - SettingsSwitcherCell(
161 - title: S.current.trongrid_history,
162 - value: _privacySettingsViewModel.useTronGrid,
163 - onValueChange: (BuildContext _, bool value) {
164 - _privacySettingsViewModel.setUseTronGrid(value);
165 - },
166 - ),
167 - if (_privacySettingsViewModel.canUseMempoolFeeAPI)
168 - SettingsSwitcherCell(
169 - title: S.current.enable_mempool_api,
170 - value: _privacySettingsViewModel.useMempoolFeeAPI,
171 - onValueChange: (BuildContext _, bool isEnabled) async {
172 - if (!isEnabled) {
173 - final bool confirmation = await showPopUp<bool>(
174 - context: context,
175 - builder: (BuildContext context) {
176 - return AlertWithTwoActions(
177 - alertTitle: S.of(context).warning,
178 - alertContent: S.of(context).disable_fee_api_warning,
179 - rightButtonText: S.of(context).confirm,
180 - leftButtonText: S.of(context).cancel,
181 - actionRightButton: () => Navigator.of(context).pop(true),
182 - actionLeftButton: () => Navigator.of(context).pop(false));
183 - }) ??
184 - false;
185 - if (confirmation) {
186 - _privacySettingsViewModel.setUseMempoolFeeAPI(isEnabled);
187 - }
188 - return;
189 - }
190 -
191 - _privacySettingsViewModel.setUseMempoolFeeAPI(isEnabled);
192 - },
193 - ),
194 - SettingsCellWithArrow(
195 - title: S.current.domain_looks_up,
196 - handler: (context) => Navigator.of(context).pushNamed(Routes.domainLookupsPage),
197 - ),
198 - if(_privacySettingsViewModel.hasCoinControl)
199 - SettingsCellWithArrow(
200 - title: "Coin Control",
201 - handler: (context) => Navigator.of(context).pushNamed(Routes.unspentCoinsList),
24 + return ModalPageWrapper(
25 + topBar: ModalTopBar(
26 + title: "",
27 + leadingIcon: Icon(Icons.arrow_back_ios_new),
28 + onLeadingPressed: () => Navigator.of(context).pop(),
29 + ),
30 + header: ModalHeader(
31 + iconPath: "assets/new-ui/settings_row_icons/privacy.svg",
32 + message: S.of(context).privacy_desc,
33 + title: S.of(context).privacy),
34 + content: SingleChildScrollView(
35 + child: Container(
36 + child: Observer(builder: (_) {
37 + return Column(
38 + mainAxisSize: MainAxisSize.min,
39 + children: [
40 + NewListSections(
41 + sections: {
42 + "1": [
43 + if (_privacySettingsViewModel.isAutoGenerateSubaddressesVisible)
44 + ListItemToggle(
45 + keyValue: "auto_generate_subaddresses",
46 + label: _privacySettingsViewModel.isMoneroWallet
47 + ? S.of(context).auto_generate_subaddresses
48 + : S.of(context).auto_generate_addresses,
49 + value: _privacySettingsViewModel.isAutoGenerateSubaddressesEnabled,
50 + onChanged: (val) {
51 + _privacySettingsViewModel.setAutoGenerateSubaddresses(val);
52 + }),
53 + ListItemToggle(
54 + keyValue: "save_recipient_address",
55 + label: S.of(context).settings_save_recipient_address,
56 + value: _privacySettingsViewModel.shouldSaveRecipientAddress,
57 + onChanged: (val) {
58 + _privacySettingsViewModel.setShouldSaveRecipientAddress(val);
59 + }),
60 + if (_privacySettingsViewModel.canUsePayjoin)
61 + ListItemToggle(
62 + keyValue: "use_payjoin",
63 + label: S.of(context).use_payjoin,
64 + value: _privacySettingsViewModel.usePayjoin,
65 + onChanged: (val) {
66 + _privacySettingsViewModel.setUsePayjoin(val);
67 + }),
68 + if (_privacySettingsViewModel.canUseLightning)
69 + ListItemToggle(
70 + keyValue: "enable_lightning",
71 + label: S.of(context).enable_lightning,
72 + value: _privacySettingsViewModel.useLightning,
73 + onChanged: (val) {
74 + _privacySettingsViewModel.setUseLightning(val);
75 + }),
76 + ],
77 + "": [
78 + if (_privacySettingsViewModel.isBitcoin)
79 + ListItemRegularRow(
80 + iconPath: "assets/new-ui/settings_row_icons/silent-payments.svg",
81 + keyValue: "silent_payments",
82 + label: S.of(context).silent_payments,
83 + onTap: () =>
84 + Navigator.of(context).pushNamed(Routes.silentPaymentsSettings)),
85 + if (_privacySettingsViewModel.isLitecoin)
86 + ListItemRegularRow(
87 + iconPath: "assets/new-ui/settings_row_icons/mweb.svg",
88 + keyValue: "mweb",
89 + label: "MWEB",
90 + onTap: () =>
91 + Navigator.of(context).pushNamed(Routes.mwebSettings)),
92 + if (_privacySettingsViewModel.hasCoinControl)
93 + ListItemRegularRow(
94 + iconPath: "assets/new-ui/settings_row_icons/coin-control.svg",
95 + keyValue: "coin_control",
96 + label: "Coin Control",
97 + onTap: () =>
98 + Navigator.of(context).pushNamed(Routes.unspentCoinsList)),
99 + ],
100 + }
101 ),
203 - // SettingsCellWithArrow(
204 - // title: 'Trocador providers',
205 - // handler: (context) => Navigator.of(context).pushNamed(Routes.trocadorProvidersPage),
206 - // ),
207 - ],
208 - );
209 - }),
102 + ],
103 + );
104 + }),
105 + ),
106 ),
107 );
108 }
lib/src/screens/settings/security_backup_page.dart
+151 -156
@@ -2,9 +2,12 @@ import 'dart:io';
2
3 import 'package:cake_wallet/core/auth_service.dart';
4 import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
5 +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_selector.dart';
6 import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart';
7 import 'package:cake_wallet/entities/pin_code_required_duration.dart';
8 import 'package:cake_wallet/new-ui/widgets/modal_header.dart';
9 +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart';
10 +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
11 import 'package:cake_wallet/routes.dart';
12 import 'package:cake_wallet/src/screens/base_page.dart';
13 import 'package:cake_wallet/generated/i18n.dart';
@@ -14,7 +17,6 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
17 import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
18 import 'package:cake_wallet/src/widgets/picker.dart';
19 import 'package:cake_wallet/utils/device_info.dart';
17 -import 'package:cake_wallet/store/settings_store.dart';
20 import 'package:cake_wallet/utils/feature_flag.dart';
21 import 'package:cake_wallet/utils/show_pop_up.dart';
22 import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
@@ -28,7 +30,10 @@ class SecurityBackupPage extends BasePage {
30 final AuthService _authService;
31
32 @override
31 - String get title => S.current.security;
33 + bool get hideAppBar => true;
34 +
35 + @override
36 + String get title => S.current.security_and_backup;
37
38 final SecuritySettingsViewModel _securitySettingsViewModel;
39
@@ -36,170 +41,160 @@ class SecurityBackupPage extends BasePage {
41
42 @override
43 Widget body(BuildContext context) {
39 - return Container(
40 - padding: EdgeInsets.only(top: 10),
41 - child: Padding(
42 - padding: const EdgeInsets.symmetric(horizontal: 18.0),
43 - child: Column(
44 - spacing: 16,
45 - mainAxisSize: MainAxisSize.min,
46 - children: [
47 - ModalHeader(
48 - iconPath: "assets/new-ui/settings_row_icons/security.svg",
49 - message: S.of(context).privacy_and_security_desc,
50 - title: S.of(context).security),
51 - Observer(
52 - builder: (_) => NewListSections(sections: {
53 - "": [
54 - if (DeviceInfo.instance.isMobile || Platform.isMacOS || Platform.isLinux)
55 - ListItemToggle(
56 - keyValue: "security_backup_page_allow_biometrics_button_key",
57 - label: S.current.settings_allow_biometrical_authentication,
58 - value: _securitySettingsViewModel.allowBiometricalAuthentication,
59 - onChanged: (bool value) {
60 - if (value) {
61 - _authService.authenticateAction(
62 - context,
63 - onAuthSuccess: (isAuthenticatedSuccessfully) async {
64 - if (isAuthenticatedSuccessfully) {
65 - if (await _securitySettingsViewModel.biometricAuthenticated()) {
66 - _securitySettingsViewModel.setAllowBiometricalAuthentication(
67 - isAuthenticatedSuccessfully);
68 - }
69 - } else {
44 + return ModalPageWrapper(
45 + topBar: ModalTopBar(
46 + title: "",
47 + leadingIcon: Icon(Icons.arrow_back_ios_new),
48 + onLeadingPressed: () => Navigator.of(context).pop()),
49 + header: ModalHeader(
50 + iconPath: "assets/new-ui/settings_row_icons/security.svg",
51 + message: S.of(context).privacy_and_security_desc,
52 + title: S.of(context).security),
53 + content: Column(
54 + spacing: 16,
55 + mainAxisSize: MainAxisSize.min,
56 + children: [
57 + Observer(
58 + builder: (_) => NewListSections(sections: {
59 + "": [
60 + if (DeviceInfo.instance.isMobile || Platform.isMacOS || Platform.isLinux)
61 + ListItemToggle(
62 + keyValue: "security_backup_page_allow_biometrics_button_key",
63 + label: S.current.settings_allow_biometrical_authentication,
64 + value: _securitySettingsViewModel.allowBiometricalAuthentication,
65 + onChanged: (bool value) {
66 + if (value) {
67 + _authService.authenticateAction(
68 + context,
69 + onAuthSuccess: (isAuthenticatedSuccessfully) async {
70 + if (isAuthenticatedSuccessfully) {
71 + if (await _securitySettingsViewModel.biometricAuthenticated()) {
72 _securitySettingsViewModel.setAllowBiometricalAuthentication(
73 isAuthenticatedSuccessfully);
74 }
73 - },
74 - conditionToDetermineIfToUse2FA: _securitySettingsViewModel
75 - .shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
76 - );
77 - } else {
78 - _securitySettingsViewModel.setAllowBiometricalAuthentication(value);
79 - }
80 - }),
81 - if (FeatureFlag.duressPinEnabled)
82 - ListItemToggle(
83 - keyValue: "security_backup_page_duress_pin_button_key",
84 - label: "Duress PIN",
85 - value: _securitySettingsViewModel.enableDuressPin,
86 - onChanged: (bool value) {
87 - _authService
88 - .authenticateAction(context, route: Routes.securityBackupDuressPin,
89 - onAuthSuccess: (isAuthenticatedSuccessfully) async {
90 - if (isAuthenticatedSuccessfully) {
91 - if (!value) {
92 - _securitySettingsViewModel.setEnableDuressPin(value);
93 - _securitySettingsViewModel.clearDuressPin();
94 - return;
75 + } else {
76 + _securitySettingsViewModel.setAllowBiometricalAuthentication(
77 + isAuthenticatedSuccessfully);
78 }
96 - final res = await _showDuressPinDescription(context);
97 - if (res) {
98 - final confirmation = await _showDuressPinConfirmation(context);
79 + },
80 + conditionToDetermineIfToUse2FA: _securitySettingsViewModel
81 + .shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
82 + );
83 + } else {
84 + _securitySettingsViewModel.setAllowBiometricalAuthentication(value);
85 + }
86 + }),
87 + if (DeviceInfo.instance.isMobile)
88 + ListItemToggle(
89 + keyValue: "display_settings_prevent_screen_capture",
90 + label: S.of(context).prevent_screenshots,
91 + value: _securitySettingsViewModel.isAppSecure,
92 + onChanged: (val) {
93 + _securitySettingsViewModel.setIsAppSecure(val);
94 + }),
95 + if (FeatureFlag.duressPinEnabled)
96 + ListItemToggle(
97 + keyValue: "security_backup_page_duress_pin_button_key",
98 + label: "Duress PIN",
99 + value: _securitySettingsViewModel.enableDuressPin,
100 + onChanged: (bool value) {
101 + _authService
102 + .authenticateAction(context, route: Routes.securityBackupDuressPin,
103 + onAuthSuccess: (isAuthenticatedSuccessfully) async {
104 + if (isAuthenticatedSuccessfully) {
105 + if (!value) {
106 + _securitySettingsViewModel.setEnableDuressPin(value);
107 + _securitySettingsViewModel.clearDuressPin();
108 + return;
109 + }
110 + final res = await _showDuressPinDescription(context);
111 + if (res) {
112 + final confirmation = await _showDuressPinConfirmation(context);
113
100 - if (confirmation) {
101 - Navigator.of(context).pushNamed(
102 - Routes.setupDuressPin,
103 - arguments:
104 - (PinCodeState<PinCodeWidget> pinCtx, String _) async {
105 - pinCtx.close();
106 - _securitySettingsViewModel.setEnableDuressPin(true);
107 - },
108 - );
109 - }
114 + if (confirmation) {
115 + Navigator.of(context).pushNamed(
116 + Routes.setupDuressPin,
117 + arguments:
118 + (PinCodeState<PinCodeWidget> pinCtx, String _) async {
119 + pinCtx.close();
120 + _securitySettingsViewModel.setEnableDuressPin(true);
121 + },
122 + );
123 }
124 }
112 - },
113 - conditionToDetermineIfToUse2FA: _securitySettingsViewModel
114 - .shouldRequireTOTP2FAForAllSecurityAndBackupSettings);
115 - }),
116 - ListItemRegularRow(
117 - keyValue: "security_backup_page_require_pin_after_button_key",
118 - label: S.current.require_pin_after,
119 - trailingText: _securitySettingsViewModel.pinCodeRequiredDuration.toString(),
120 - onTap: () async {
121 - final items = PinCodeRequiredDuration.values;
125 + }
126 + },
127 + conditionToDetermineIfToUse2FA: _securitySettingsViewModel
128 + .shouldRequireTOTP2FAForAllSecurityAndBackupSettings);
129 + }),
130 + ListItemSelector(
131 + keyValue: "security_backup_page_require_pin_after_button_key",
132 + label: S.current.require_pin_after,
133 + options: [_securitySettingsViewModel.pinCodeRequiredDuration.toString()],
134 + onTap: () async {
135 + final items = PinCodeRequiredDuration.values;
136
123 - final selectedAtIndex =
124 - items.indexOf(_securitySettingsViewModel.pinCodeRequiredDuration);
137 + final selectedAtIndex =
138 + items.indexOf(_securitySettingsViewModel.pinCodeRequiredDuration);
139
126 - await showPopUp<void>(
127 - context: context,
128 - builder: (_) => Picker(
129 - items: items,
130 - selectedAtIndex: selectedAtIndex,
131 - mainAxisAlignment: MainAxisAlignment.start,
132 - onItemSelected: (PinCodeRequiredDuration item) {
133 - _securitySettingsViewModel.setPinCodeRequiredDuration(item);
134 - },
135 - isSeparated: false,
136 - ),
137 - );
138 - }),
139 - // if (!_isHardwareWallet)
140 - // ListItemRegularRow(
141 - // keyValue: "security_backup_page_show_keys_button_key",
142 - // label: S.current.show_keys,
143 - // onTap: () {
144 - // _authService.authenticateAction(
145 - // context,
146 - // route: Routes.showKeys,
147 - // conditionToDetermineIfToUse2FA: _securitySettingsViewModel
148 - // .shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
149 - // );
150 - // }),
151 - // if (!SettingsStoreBase.walletPasswordDirectInput)
152 - // ListItemRegularRow(
153 - // keyValue: "security_backup_page_change_password_button_key",
154 - // label: S.current.create_backup,
155 - // onTap: () {
156 - // _authService.authenticateAction(
157 - // context,
158 - // route: Routes.backup,
159 - // conditionToDetermineIfToUse2FA: _securitySettingsViewModel
160 - // .shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
161 - // );
162 - // }),
163 - ListItemRegularRow(
164 - keyValue: "security_backup_page_change_pin_button_key",
165 - label: S.current.settings_change_pin,
166 - onTap: () {
167 - _authService.authenticateAction(
168 - context,
169 - route: Routes.setupPin,
170 - arguments: (PinCodeState<PinCodeWidget> setupPinContext, String _) {
171 - setupPinContext.close();
140 + await showPopUp<void>(
141 + context: context,
142 + builder: (_) => Picker(
143 + items: items,
144 + selectedAtIndex: selectedAtIndex,
145 + mainAxisAlignment: MainAxisAlignment.start,
146 + onItemSelected: (PinCodeRequiredDuration item) {
147 + _securitySettingsViewModel.setPinCodeRequiredDuration(item);
148 },
173 - conditionToDetermineIfToUse2FA: _securitySettingsViewModel
174 - .shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
175 - );
176 - }),
177 - ListItemRegularRow(
178 - keyValue: "security_backup_page_sign_and_verify",
179 - label: S.current.sign_verify_title,
180 - onTap: () {
181 - Navigator.of(context).pushNamed(Routes.signPage);
182 - }),
183 - ListItemRegularRow(
184 - keyValue: "security_backup_page_totp_2fa_button_key",
185 - label: _securitySettingsViewModel.useTotp2FA
186 - ? S.current.modify_2fa
187 - : S.current.setup_2fa,
188 - onTap: () {
189 - _authService.authenticateAction(
190 - context,
191 - route: _securitySettingsViewModel.useTotp2FA
192 - ? Routes.modify2FAPage
193 - : Routes.setup2faInfoPage,
194 - conditionToDetermineIfToUse2FA: _securitySettingsViewModel
195 - .shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
196 - );
197 - })
198 - ]
199 - }),
200 - ),
201 - ],
202 - ),
149 + isSeparated: false,
150 + ),
151 + );
152 + }),
153 + // if (!_isHardwareWallet)
154 + // ListItemRegularRow(
155 + // keyValue: "security_backup_page_show_keys_button_key",
156 + // label: S.current.show_keys,
157 + // onTap: () {
158 + // _authService.authenticateAction(
159 + // context,
160 + // route: Routes.showKeys,
161 + // conditionToDetermineIfToUse2FA: _securitySettingsViewModel
162 + // .shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
163 + // );
164 + // }),
165 + ListItemRegularRow(
166 + keyValue: "security_backup_page_change_pin_button_key",
167 + label: S.current.settings_change_pin,
168 + onTap: () {
169 + _authService.authenticateAction(
170 + context,
171 + route: Routes.setupPin,
172 + arguments: (PinCodeState<PinCodeWidget> setupPinContext, String _) {
173 + setupPinContext.close();
174 + },
175 + conditionToDetermineIfToUse2FA: _securitySettingsViewModel
176 + .shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
177 + );
178 + }),
179 + ListItemRegularRow(
180 + keyValue: "security_backup_page_totp_2fa_button_key",
181 + label: _securitySettingsViewModel.useTotp2FA
182 + ? S.current.modify_2fa
183 + : S.current.setup_2fa,
184 + onTap: () {
185 + _authService.authenticateAction(
186 + context,
187 + route: _securitySettingsViewModel.useTotp2FA
188 + ? Routes.modify2FAPage
189 + : Routes.setup2faInfoPage,
190 + conditionToDetermineIfToUse2FA: _securitySettingsViewModel
191 + .shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
192 + );
193 + })
194 + ]
195 + }),
196 + ),
197 + ],
198 ),
199 );
200 }
lib/src/screens/settings/widgets/settings_choices_cell.dart
+57 -31
@@ -12,9 +12,13 @@ class SettingsChoicesCell extends StatelessWidget {
12
13 @override
14 Widget build(BuildContext context) {
15 + final items = choicesListItem.items;
16 + final selectedIndex = items.indexOf(choicesListItem.selectedItem);
17 + final itemCount = items.length;
18 +
19 return Container(
20 color: useGenericColor ? Theme.of(context).colorScheme.surface : null,
17 - padding: padding ?? EdgeInsets.only(left: 24, right: 24, top: 16, bottom: 16),
21 + padding: padding ?? const EdgeInsets.only(left: 24, right: 24, top: 16, bottom: 16),
22 child: Column(
23 mainAxisSize: MainAxisSize.min,
24 crossAxisAlignment: CrossAxisAlignment.start,
@@ -33,46 +37,68 @@ class SettingsChoicesCell extends StatelessWidget {
37 Center(
38 child: Container(
39 decoration: BoxDecoration(
36 - borderRadius: BorderRadius.circular(10),
40 + borderRadius: BorderRadius.circular(12),
41 border: useGenericColor
42 ? null
43 : Border.all(
44 color: Theme.of(context).colorScheme.surfaceContainerHighest,
45 width: 1.5,
46 ),
43 - color:
44 - useGenericColor ? Theme.of(context).colorScheme.surfaceContainerHighest : null,
47 + color: useGenericColor
48 + ? Theme.of(context).colorScheme.surfaceContainerHighest
49 + : null,
50 ),
46 - child: Row(
47 - mainAxisAlignment: MainAxisAlignment.center,
48 - children: choicesListItem.items.map((dynamic e) {
49 - final isSelected = choicesListItem.selectedItem == e;
50 - return Expanded(
51 - child: GestureDetector(
52 - onTap: () {
53 - choicesListItem.onItemSelected.call(e);
54 - },
55 - child: Container(
56 - padding: EdgeInsets.symmetric(vertical: 8),
57 - decoration: BoxDecoration(
58 - borderRadius: BorderRadius.circular(10),
59 - color: isSelected ? Theme.of(context).colorScheme.primary : null,
60 - ),
61 - child: Center(
62 - child: Text(
63 - choicesListItem.displayItem.call(e),
64 - style: Theme.of(context).textTheme.bodyMedium?.copyWith(
65 - color: isSelected
66 - ? Theme.of(context).colorScheme.onPrimary
67 - : Theme.of(context).colorScheme.onSurfaceVariant,
68 - fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
69 - ),
51 + child: LayoutBuilder(
52 + builder: (context, constraints) {
53 + final itemWidth = constraints.maxWidth / itemCount;
54 + return Stack(
55 + children: [
56 + if (selectedIndex >= 0)
57 + AnimatedPositioned(
58 + duration: const Duration(milliseconds: 450),
59 + curve: Curves.easeInOut,
60 + left: selectedIndex * itemWidth,
61 + top: 0,
62 + bottom: 0,
63 + width: itemWidth,
64 + child: Container(
65 + decoration: BoxDecoration(
66 + borderRadius: BorderRadius.circular(12),
67 + color: Theme.of(context).colorScheme.primary,
68 + ),
69 ),
70 ),
71 + Row(
72 + children: items.map((dynamic e) {
73 + final isSelected = choicesListItem.selectedItem == e;
74 + return Expanded(
75 + child: GestureDetector(
76 + onTap: () => choicesListItem.onItemSelected.call(e),
77 + child: Container(
78 + padding: const EdgeInsets.symmetric(vertical: 8),
79 + color: Colors.transparent,
80 + child: Center(
81 + child: AnimatedDefaultTextStyle(
82 + duration: const Duration(milliseconds: 220),
83 + curve: Curves.easeInOut,
84 + style: Theme.of(context).textTheme.bodyMedium!.copyWith(
85 + color: isSelected
86 + ? Theme.of(context).colorScheme.onPrimary
87 + : Theme.of(context).colorScheme.onSurfaceVariant,
88 + fontWeight:
89 + isSelected ? FontWeight.w600 : FontWeight.normal,
90 + ),
91 + child: Text(choicesListItem.displayItem.call(e)),
92 + ),
93 + ),
94 + ),
95 + ),
96 + );
97 + }).toList(),
98 ),
73 - ),
99 + ],
100 );
75 - }).toList(),
101 + },
102 ),
103 ),
104 ),
@@ -80,4 +106,4 @@ class SettingsChoicesCell extends StatelessWidget {
106 ),
107 );
108 }
83 -}
109 +}
\ No newline at end of file
lib/src/screens/settings/widgets/settings_switcher_cell.dart
+3 -1
@@ -13,6 +13,7 @@ class SettingsSwitcherCell extends StandardListRow {
13 Key? key,
14 this.padding,
15 this.switchBackgroundColor,
16 + this.height = 56,
17 }) : super(title: title, isSelected: false, decoration: decoration, onTap: onTap, key: key);
18
19 final bool value;
@@ -20,6 +21,7 @@ class SettingsSwitcherCell extends StandardListRow {
21 final void Function(BuildContext context, bool value)? onValueChange;
22 final Widget? leading;
23 final EdgeInsets? padding;
24 + final double? height;
25
26 @override
27 Widget buildTrailing(BuildContext context) => StandardSwitch(
@@ -33,7 +35,7 @@ class SettingsSwitcherCell extends StandardListRow {
35 final leading = buildLeading(context);
36 final trailing = buildTrailing(context);
37 return Container(
36 - height: 56,
38 + height: height,
39 padding: padding ?? EdgeInsets.only(left: 12, right: 12),
40 child: TextButton(
41 onPressed: () {
lib/src/screens/settings/widgets/settings_theme_choice.dart
+104 -63
@@ -12,9 +12,9 @@ class SettingsThemeChoicesCell extends StatelessWidget {
12
13 final DisplaySettingsViewModel _displaySettingsViewModel;
14
15 - final double cellHeight = 25;
15 + final double cellHeight = 12;
16 final double cellWidth = 12;
17 - final double cellRadius = 8;
17 + final double cellRadius = 18;
18
19 @override
20 Widget build(BuildContext context) {
@@ -28,14 +28,17 @@ class SettingsThemeChoicesCell extends StatelessWidget {
28 final previewHeight = _getResponsivePreviewHeight(screenHeight);
29 final previewWidth = previewHeight * 0.6;
30
31 - return Container(
31 + return AnimatedContainer(
32 + duration: const Duration(milliseconds: 350),
33 + curve: Curves.easeInOut,
34 height: getHeight(context, currentTheme, currentTheme.hasAccentColors),
33 - padding: EdgeInsets.all(12),
35 + padding: EdgeInsets.all(14),
36 child: Column(
37 mainAxisSize: MainAxisSize.min,
38 crossAxisAlignment: CrossAxisAlignment.start,
39 children: [
38 - Expanded(
40 + SizedBox(
41 + height: previewHeight,
42 child: ListView.builder(
43 itemCount: availableThemes.length,
44 scrollDirection: Axis.horizontal,
@@ -50,16 +53,16 @@ class SettingsThemeChoicesCell extends StatelessWidget {
53 onTap: () {
54 _displaySettingsViewModel.onThemeSelected(theme);
55 },
53 - child: Container(
56 + child: AnimatedContainer(
57 + duration: const Duration(milliseconds: 350),
58 + curve: Curves.easeInOut,
59 margin: EdgeInsets.only(right: 24),
55 - decoration: BoxDecoration(
56 - borderRadius: BorderRadius.circular(cellRadius),
57 - border: isSelected
58 - ? Border.all(
59 - color: Theme.of(context).colorScheme.primary,
60 + decoration: ShapeDecoration(
61 + shape: RoundedSuperellipseBorder(borderRadius: BorderRadius.circular(cellRadius),
62 + side: BorderSide(
63 + color: isSelected ? Theme.of(context).colorScheme.primary : Colors.transparent,
64 strokeAlign: BorderSide.strokeAlignOutside)
61 - : null,
62 - ),
65 + )),
66 child: ClipRRect(
67 borderRadius: BorderRadius.circular(cellRadius),
68 child: CakeImageWidget(
@@ -75,56 +78,94 @@ class SettingsThemeChoicesCell extends StatelessWidget {
78 },
79 ),
80 ),
78 - if (_displaySettingsViewModel.currentTheme.hasAccentColors) ...[
79 - SizedBox(height: cellHeight),
80 - Row(
81 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
82 - children: [
83 - Text(
84 - S.of(context).accent_color,
85 - style: Theme.of(context).textTheme.bodyMedium,
86 - ),
87 - Container(
88 - child: Row(
89 - children: availableAccentColors.map((accentColor) {
90 - final isSelected = _displaySettingsViewModel
91 - .isAccentColorSelected(accentColor.name.toLowerCase());
92 - return GestureDetector(
93 - onTap: () {
94 - _displaySettingsViewModel
95 - .onAccentColorSelected(accentColor.name.toLowerCase());
96 - },
97 - child: Container(
98 - width: 26,
99 - height: 26,
100 - margin: EdgeInsets.only(right: 11),
101 - decoration: BoxDecoration(
102 - borderRadius: BorderRadius.circular(16),
103 - border: isSelected
104 - ? Border.all(
105 - color: Theme.of(context).colorScheme.onSurfaceVariant,
106 - width: 3)
107 - : null,
108 - color: accentColor.color,
109 - ),
110 - ),
111 - );
112 - }).toList(),
113 - ),
114 - ),
115 - ],
81 + AnimatedSwitcher(
82 + duration: const Duration(milliseconds: 350),
83 + switchInCurve: Curves.easeOut,
84 + switchOutCurve: Curves.easeIn,
85 + transitionBuilder: (child, animation) => FadeTransition(
86 + opacity: animation,
87 + child: SizeTransition(
88 + sizeFactor: animation,
89 + axisAlignment: -1,
90 + child: child,
91 + ),
92 ),
117 - ],
93 + child: _displaySettingsViewModel.currentTheme.hasAccentColors
94 + ? Column(
95 + key: const ValueKey('accent'),
96 + mainAxisSize: MainAxisSize.min,
97 + children: [
98 + Padding(
99 + padding: EdgeInsets.only(top: 14),
100 + child: Container(height: 1, color: Theme.of(context).colorScheme.outlineVariant)
101 + ),
102 + SizedBox(height: cellHeight),
103 + Row(
104 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
105 + children: [
106 + Text(
107 + S.of(context).accent_color,
108 + style: Theme.of(context).textTheme.bodyMedium,
109 + ),
110 + Row(
111 + spacing: 4,
112 + children: availableAccentColors.map((accentColor) {
113 + final isSelected = _displaySettingsViewModel
114 + .isAccentColorSelected(accentColor.name.toLowerCase());
115 + return GestureDetector(
116 + onTap: () {
117 + _displaySettingsViewModel
118 + .onAccentColorSelected(accentColor.name.toLowerCase());
119 + },
120 + child: Stack(
121 + children: [
122 + AnimatedOpacity(
123 + duration: Duration(milliseconds: 350),
124 + opacity: isSelected ? 1 : 0,
125 + child: Container(
126 + width:28,height:28,decoration: BoxDecoration(borderRadius: BorderRadius.circular(99999999),border: Border.all(color:Theme.of(context)
127 + .colorScheme
128 + .onSurface))
129 + ),
130 + ),
131 + AnimatedScale(
132 + duration: Duration(milliseconds: 350),
133 + scale: isSelected ? 0.8 : 1,
134 + child: Container(
135 + width: 28,
136 + height: 28,
137 + decoration: BoxDecoration(
138 + borderRadius: BorderRadius.circular(99999999),
139 + color: accentColor.color),
140 + ),
141 + ),
142 + ],
143 + ),
144 + );
145 + }).toList(),
146 + ),
147 + ],
148 + ),
149 + ],
150 + )
151 + : const SizedBox.shrink(key: ValueKey('no-accent')),
152 + ),
153 if (_displaySettingsViewModel.currentTheme is BlackTheme)
119 - SettingsSwitcherCell(
120 - title: S.current.oled_mode,
121 - value: _displaySettingsViewModel.isBlackThemeOledEnabled,
122 - onValueChange: (_, bool value) {
123 - _displaySettingsViewModel.setBlackThemeOled(value);
124 - },
125 - padding: EdgeInsets.zero,
126 - switchBackgroundColor: currentTheme.colorScheme.secondaryContainer,
154 + Padding(
155 + padding: EdgeInsets.only(top: 12, bottom: 4),
156 + child: Container(height: 1, color: Theme.of(context).colorScheme.outlineVariant)
157 ),
158 + if (_displaySettingsViewModel.currentTheme is BlackTheme)
159 + SettingsSwitcherCell(
160 + height: 40,
161 + title: S.current.oled_mode,
162 + value: _displaySettingsViewModel.isBlackThemeOledEnabled,
163 + onValueChange: (_, bool value) {
164 + _displaySettingsViewModel.setBlackThemeOled(value);
165 + },
166 + padding: EdgeInsets.zero,
167 + switchBackgroundColor: currentTheme.colorScheme.secondaryContainer,
168 + ),
169 ],
170 ),
171 );
@@ -135,14 +176,14 @@ class SettingsThemeChoicesCell extends StatelessWidget {
176 double getHeight(BuildContext context, MaterialThemeBase theme, bool hasAccentColors) {
177 final screenHeight = MediaQuery.of(context).size.height;
178
138 - double baseHeight = (screenHeight * 0.25).clamp(150.0, screenHeight * 0.5);
179 + double baseHeight = (screenHeight * 0.253).clamp(150.0, screenHeight * 0.5);
180
181 if (hasAccentColors) {
141 - baseHeight += (screenHeight * 0.05).clamp(35.0, 60.0);
182 + baseHeight += (screenHeight * 0.60).clamp(35.0, 60.0);
183 }
184
185 if (theme is BlackTheme) {
145 - baseHeight += (screenHeight * 0.08).clamp(48.0, 96.0);
186 + baseHeight += (screenHeight * 0.059).clamp(48.0, 96.0);
187 }
188
189 return baseHeight;
lib/src/widgets/new_list_row/list_Item_style_wrapper.dart
+6 -5
@@ -6,20 +6,21 @@ class ListItemStyleWrapper extends StatelessWidget {
6 required this.isFirstInSection,
7 required this.isLastInSection,
8 required this.builder,
9 - this.hasImage,
9 this.onTap,
10 this.height = 50,
11 + this.iconPath,
12 });
13
14 + final String? iconPath;
15 final bool isFirstInSection;
16 final bool isLastInSection;
16 - final bool ?hasImage;
17 final double height;
18 final VoidCallback? onTap;
19 final Widget Function(BuildContext context, TextStyle textStyle, TextStyle labelStyle) builder;
20
21 @override
22 Widget build(BuildContext context) {
23 +
24 final theme = Theme.of(context);
25
26 final textStyle = TextStyle(
@@ -60,17 +61,17 @@ class ListItemStyleWrapper extends StatelessWidget {
61 child: Padding(
62 padding: const EdgeInsets.symmetric(horizontal: 12),
63 child: builder(context, textStyle, labelStyle))))),
63 - if(hasImage == true && isLastInSection == false) Container(
64 + if(iconPath != null && isLastInSection == false) Container(
65 color: theme.colorScheme.surfaceContainer,
66 child: Padding(
66 - padding: const EdgeInsets.only(left: 48, right: 13),
67 + padding: const EdgeInsets.only(left: 50, right: 13),
68 child: Container(height: 1, color: theme.colorScheme.outlineVariant),
69 ),
70 )
71 else if(!isLastInSection) Container(
72 color: theme.colorScheme.surfaceContainer,
73 child: Padding(
73 - padding: const EdgeInsets.symmetric(horizontal: 13),
74 + padding: const EdgeInsets.symmetric(horizontal: 12),
75 child: Container(height: 1, color: theme.colorScheme.outlineVariant),
76 ),
77 )
lib/src/widgets/new_list_row/list_item_checkbox_widget.dart
+4 -3
@@ -37,6 +37,7 @@ class _ListItemCheckboxWidgetState extends State<ListItemCheckboxWidget> {
37 @override
38 Widget build(BuildContext context) {
39 return ListItemStyleWrapper(
40 + iconPath: widget.iconPath,
41 onTap: widget.onTap ?? () {
42 widget.onChanged(!widget.value);
43 },
@@ -53,11 +54,11 @@ class _ListItemCheckboxWidgetState extends State<ListItemCheckboxWidget> {
54 children: [
55 if (widget.iconPath != null)
56 widget.iconPath!.toLowerCase().endsWith("svg")
56 - ? CakeImageWidget(imageUrl:widget.iconPath!, height: 24, width: 24)
57 + ? CakeImageWidget(imageUrl:widget.iconPath!, height: 26, width: 26)
58 : Image.asset(
59 widget.iconPath!,
59 - width: 24,
60 - height: 24,
60 + width: 26,
61 + height: 26,
62 ),
63 Expanded(
64 child: Column(
lib/src/widgets/new_list_row/list_item_regular_row_widget.dart
+1 -3
@@ -12,7 +12,6 @@ class ListItemRegularRowWidget extends StatelessWidget {
12 this.trailingText,
13 this.iconPath,
14 this.onTap,
15 - this.hasImage,
15 this.isFirstInSection = false,
16 this.isLastInSection = false,
17 this.showArrow = true,
@@ -28,7 +27,6 @@ class ListItemRegularRowWidget extends StatelessWidget {
27 final String? trailingText;
28 final String? iconPath;
29 final VoidCallback? onTap;
31 - final bool? hasImage;
30 final bool isFirstInSection;
31 final bool isLastInSection;
32 final bool showArrow;
@@ -46,7 +44,7 @@ class ListItemRegularRowWidget extends StatelessWidget {
44
45 return ListItemStyleWrapper(
46 onTap: onTap,
49 - hasImage: iconPath != null ? true : false,
47 + iconPath: iconPath,
48 isFirstInSection: isFirstInSection,
49 isLastInSection: isLastInSection,
50 height: subtitle != null ? 64 : 50,
lib/src/widgets/new_list_row/list_item_selector_widget.dart
+19 -19
@@ -33,25 +33,25 @@ class ListItemSelectorWidget extends StatelessWidget {
33 isLastInSection: isLastInSection,
34 builder: (context, textStyle, labelStyle) {
35 return Row(
36 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
37 - children: [
38 - Flexible(child: Text(label, style: textStyle)),
39 - Row(
40 - children: [
41 - Text(
42 - options[selectedIndex],
43 - style: labelStyle,
44 - ),
45 - CakeImageWidget(imageUrl:
46 - "assets/new-ui/chooser.svg",
47 - colorFilter:
48 - ColorFilter.mode(theme.colorScheme.onSurfaceVariant, BlendMode.srcIn),
49 - ),
50 - SizedBox(width: 8)
51 - ],
52 - ),
53 - ],
36 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
37 + children: [
38 + Flexible(child: Text(label, style: textStyle)),
39 + Row(
40 + spacing: 8,
41 + children: [
42 + Text(
43 + options[selectedIndex],
44 + style: labelStyle,
45 + ),
46 + CakeImageWidget(imageUrl:
47 + "assets/new-ui/chooser.svg",
48 + colorFilter:
49 + ColorFilter.mode(theme.colorScheme.onSurfaceVariant, BlendMode.srcIn),
50 + ),
51 + ],
52 + ),
53 + ],
54 );
55 });
56 }
57 -}
57 +}
\ No newline at end of file
lib/src/widgets/standard_list.dart
+44 -5
@@ -6,12 +6,14 @@ class StandardListRow extends StatelessWidget {
6 StandardListRow({
7 required this.title,
8 required this.isSelected,
9 + this.subtitle,
10 this.onTap,
11 this.decoration,
12 super.key,
13 });
14
15 final String title;
16 + final String? subtitle;
17 final bool isSelected;
18 final void Function(BuildContext context)? onTap;
19 final Decoration? decoration;
@@ -48,18 +50,52 @@ class StandardListRow extends StatelessWidget {
50 Widget? buildLeading(BuildContext context) => null;
51
52 Widget buildCenter(BuildContext context, {required bool hasLeftOffset}) {
53 +
54 return Expanded(
55 child: Row(
56 mainAxisAlignment: MainAxisAlignment.start,
57 children: [
58 if (hasLeftOffset) SizedBox(width: 10),
59 Expanded(
57 - child: Text(
58 - title,
59 - style: Theme.of(context).textTheme.bodyMedium?.copyWith(
60 - color: titleColor(context),
61 - fontWeight: isSelected ? FontWeight.w800 : FontWeight.w400,
60 + child: Column(
61 + mainAxisSize: MainAxisSize.min,
62 + children: [
63 + if (subtitle != null && subtitle!.isNotEmpty)
64 + Align(
65 + alignment: Alignment.centerLeft,
66 + child: Text(
67 + textAlign: TextAlign.left,
68 + subtitle!,
69 + style: Theme.of(context).textTheme.labelMedium?.copyWith(
70 + color: titleColor(context),
71 + fontWeight: isSelected ? FontWeight.w800 : FontWeight.w400,
72 + ),
73 + ),
74 + ),
75 + if (subtitle != null && subtitle!.isNotEmpty)
76 + Align(
77 + alignment: Alignment.centerLeft,
78 + child: Text(
79 + textAlign: TextAlign.left,
80 + title,
81 + style: Theme.of(context).textTheme.labelSmall?.copyWith(
82 + color: Theme.of(context).colorScheme.onSurfaceVariant,
83 + fontWeight: isSelected ? FontWeight.w800 : FontWeight.w400,
84 + ),
85 + ),
86 + )
87 + else
88 + Align(
89 + alignment: Alignment.centerLeft,
90 + child: Text(
91 + title,
92 + style: Theme.of(context).textTheme.bodyMedium?.copyWith(
93 + color: titleColor(context),
94 + fontWeight: isSelected ? FontWeight.w800 : FontWeight.w400,
95 + ),
96 ),
97 + ),
98 + ],
99 ),
100 )
101 ],
@@ -138,6 +174,7 @@ class SectionStandardList extends StatelessWidget {
174 this.hasTopSeparator = false,
175 this.scrollController,
176 this.physics,
177 + this.shrinkWrap = false,
178 }) : totalRows = [];
179
180 final int sectionCount;
@@ -150,6 +187,7 @@ class SectionStandardList extends StatelessWidget {
187 final EdgeInsets dividerPadding;
188 final ScrollController? scrollController;
189 final ScrollPhysics? physics;
190 + final bool shrinkWrap;
191
192 List<Widget> transform(
193 bool hasTopSeparator,
@@ -208,6 +246,7 @@ class SectionStandardList extends StatelessWidget {
246 return ListView.separated(
247 controller: scrollController,
248 physics: physics,
249 + shrinkWrap: shrinkWrap,
250 separatorBuilder: (_, index) {
251 final row = totalRows[index];
252
lib/view_model/dashboard/dashboard_view_model.dart
+4
@@ -671,6 +671,10 @@ abstract class DashboardViewModelBase with Store {
671 bool get hasLightning =>
672 wallet.type == WalletType.bitcoin && wallet.isSoftwareWallet && bitcoin!.useLightning(wallet);
673
674 + @computed
675 + bool get hasWalletConnect =>
676 + isWalletConnectCompatibleChain(wallet.type) && !wallet.isHardwareWallet;
677 +
678 @computed
679 bool get isTestnet => wallet.type == WalletType.bitcoin && bitcoin!.isTestnet(wallet);
680
lib/view_model/settings/connection_sync_view_model.dart new
+236
@@ -0,0 +1,236 @@
1 +import 'dart:async';
2 +
3 +import 'package:cake_wallet/entities/exchange_api_mode.dart';
4 +import 'package:cake_wallet/entities/fiat_api_mode.dart';
5 +import 'package:cake_wallet/evm/evm.dart';
6 +import 'package:cake_wallet/generated/i18n.dart';
7 +import 'package:cake_wallet/reactions/wallet_connect.dart';
8 +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
9 +import 'package:cake_wallet/store/app_store.dart';
10 +import 'package:cake_wallet/store/settings_store.dart';
11 +import 'package:cake_wallet/tron/tron.dart';
12 +import 'package:cake_wallet/utils/show_pop_up.dart';
13 +import 'package:cake_wallet/utils/tor.dart';
14 +import 'package:cw_core/balance.dart';
15 +import 'package:cw_core/transaction_history.dart';
16 +import 'package:cw_core/transaction_info.dart';
17 +import 'package:cw_core/wallet_base.dart';
18 +import 'package:cw_core/wallet_type.dart';
19 +import 'package:flutter/material.dart';
20 +import 'package:mobx/mobx.dart';
21 +
22 +part 'connection_sync_view_model.g.dart';
23 +
24 +class ConnectionSyncViewModel = ConnectionSyncViewModelBase with _$ConnectionSyncViewModel;
25 +
26 +abstract class ConnectionSyncViewModelBase with Store {
27 + ConnectionSyncViewModelBase(this._settingsStore, this._wallet);
28 +
29 + final SettingsStore _settingsStore;
30 + final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> _wallet;
31 +
32 + @computed
33 + bool get lookupTwitter => _settingsStore.lookupsTwitter;
34 +
35 + @computed
36 + bool get lookupsZanoAlias => _settingsStore.lookupsZanoAlias;
37 +
38 + @computed
39 + bool get looksUpMastodon => _settingsStore.lookupsMastodon;
40 +
41 + @computed
42 + bool get looksUpYatService => _settingsStore.lookupsYatService;
43 +
44 + @computed
45 + bool get looksUpUnstoppableDomains => _settingsStore.lookupsUnstoppableDomains;
46 +
47 + @computed
48 + bool get looksUpOpenAlias => _settingsStore.lookupsOpenAlias;
49 +
50 + @computed
51 + bool get looksUpENS => _settingsStore.lookupsENS;
52 +
53 + @computed
54 + bool get looksUpWellKnown => _settingsStore.lookupsWellKnown;
55 +
56 + @computed
57 + ExchangeApiMode get exchangeStatus => _settingsStore.exchangeStatus;
58 +
59 + @computed
60 + FiatApiMode get fiatApiMode => _settingsStore.fiatApiMode;
61 +
62 + @computed
63 + bool get disableAutomaticExchangeStatusUpdates =>
64 + _settingsStore.disableAutomaticExchangeStatusUpdates;
65 +
66 + @computed
67 + bool get builtinTor => _settingsStore.currentBuiltinTor;
68 +
69 +
70 + @computed
71 + bool get hasPowNodes => [WalletType.nano, WalletType.banano].contains(_wallet.type);
72 +
73 + @computed
74 + bool get useMempoolFeeAPI => _settingsStore.useMempoolFeeAPI;
75 +
76 + @computed
77 + bool get canUseMempoolFeeAPI => _wallet.type == WalletType.bitcoin;
78 +
79 + @computed
80 + bool get useBlinkProtection => _settingsStore.useBlinkProtection;
81 +
82 + bool get canUseBlinkProtection => canSupportBlinkProtection(_wallet.chainId);
83 +
84 + @computed
85 + bool get useEtherscan => _settingsStore.useEtherscan;
86 +
87 + @computed
88 + bool get usePolygonScan => _settingsStore.usePolygonScan;
89 +
90 + @computed
91 + bool get useBaseScan => _settingsStore.useBaseScan;
92 +
93 + @computed
94 + bool get useArbiScan => _settingsStore.useArbiScan;
95 +
96 + @computed
97 + bool get useBscScan => _settingsStore.useBscScan;
98 +
99 + @computed
100 + bool get useTronGrid => _settingsStore.useTronGrid;
101 +
102 + @computed
103 + bool get canUseEtherscan => _wallet.chainId == 1;
104 +
105 + @computed
106 + bool get canUsePolygonScan => _wallet.chainId == 137;
107 +
108 + @computed
109 + bool get canUseBaseScan => _wallet.chainId == 8453;
110 +
111 + @computed
112 + bool get canUseArbiScan => _wallet.chainId == 42161;
113 +
114 + @computed
115 + bool get canUseBscScan => _wallet.chainId == 56;
116 +
117 + @computed
118 + bool get canUseTronGrid => _wallet.type == WalletType.tron;
119 +
120 + @action
121 + void setLookupsTwitter(bool value) => _settingsStore.lookupsTwitter = value;
122 +
123 + @action
124 + void setLookupsZanoAlias(bool value) => _settingsStore.lookupsZanoAlias = value;
125 +
126 + @action
127 + void setLookupsMastodon(bool value) => _settingsStore.lookupsMastodon = value;
128 +
129 + @action
130 + void setLookupsENS(bool value) => _settingsStore.lookupsENS = value;
131 +
132 + @action
133 + void setLookupsWellKnown(bool value) => _settingsStore.lookupsWellKnown = value;
134 +
135 + @action
136 + void setLookupsYatService(bool value) => _settingsStore.lookupsYatService = value;
137 +
138 + @action
139 + void setLookupsUnstoppableDomains(bool value) => _settingsStore.lookupsUnstoppableDomains = value;
140 +
141 + @action
142 + void setLookupsOpenAlias(bool value) => _settingsStore.lookupsOpenAlias = value;
143 +
144 + @action
145 + void setUseMempoolFeeAPI(bool value) => _settingsStore.useMempoolFeeAPI = value;
146 +
147 + @action
148 + void setDisableAutomaticExchangeStatusUpdates(bool value) =>
149 + _settingsStore.disableAutomaticExchangeStatusUpdates = value;
150 +
151 + @action
152 + void setFiatMode(FiatApiMode fiatApiMode) => _settingsStore.fiatApiMode = fiatApiMode;
153 +
154 + @action
155 + void setExchangeApiMode(ExchangeApiMode value) => _settingsStore.exchangeStatus = value;
156 +
157 + @action
158 + void setUseBlinkProtection(bool value) => _settingsStore.useBlinkProtection = value;
159 +
160 + @action
161 + void setUseEtherscan(bool value) {
162 + _settingsStore.useEtherscan = value;
163 + evm!.updateScanProviderUsageState(_wallet, value);
164 + }
165 +
166 + @action
167 + void setUsePolygonScan(bool value) {
168 + _settingsStore.usePolygonScan = value;
169 + evm!.updateScanProviderUsageState(_wallet, value);
170 + }
171 +
172 + @action
173 + void setUseBaseScan(bool value) {
174 + _settingsStore.useBaseScan = value;
175 + evm!.updateScanProviderUsageState(_wallet, value);
176 + }
177 +
178 + @action
179 + void setUseTronGrid(bool value) {
180 + _settingsStore.useTronGrid = value;
181 + tron!.updateTronGridUsageState(_wallet, value);
182 + }
183 +
184 + @action
185 + void setUseArbiScan(bool value) {
186 + _settingsStore.useArbiScan = value;
187 + evm!.updateScanProviderUsageState(_wallet, value);
188 + }
189 +
190 + @action
191 + void setUseBscScan(bool value) {
192 + _settingsStore.useBscScan = value;
193 + evm!.updateScanProviderUsageState(_wallet, value);
194 + }
195 +
196 + @action
197 + void setBuiltinTor(bool value, BuildContext context) {
198 + if (value) {
199 + unawaited(
200 + showPopUp<bool>(
201 + context: context,
202 + builder: (BuildContext context) {
203 + return AlertWithOneAction(
204 + alertTitle: S.of(context).tor_connection,
205 + alertContent: S.of(context).tor_experimental,
206 + buttonText: S.of(context).ok,
207 + buttonAction: () => Navigator.of(context).pop(true),
208 + );
209 + },
210 + ),
211 + );
212 + }
213 + _settingsStore.currentBuiltinTor = value;
214 + if (value) {
215 + unawaited(ensureTorStarted(context: context).then((_) async {
216 + if (_settingsStore.currentBuiltinTor == false) return;
217 + int? chainId;
218 + if (isEVMCompatibleChain(_wallet.type)) {
219 + chainId = evm!.getSelectedChainId(_wallet);
220 + }
221 + await _wallet.connectToNode(
222 + node: _settingsStore.getCurrentNode(_wallet.type, chainId: chainId));
223 + }));
224 + } else {
225 + unawaited(ensureTorStopped(context: context).then((_) async {
226 + if (_settingsStore.currentBuiltinTor == true) return;
227 + int? chainId;
228 + if (isEVMCompatibleChain(_wallet.type)) {
229 + chainId = evm!.getSelectedChainId(_wallet);
230 + }
231 + await _wallet.connectToNode(
232 + node: _settingsStore.getCurrentNode(_wallet.type, chainId: chainId));
233 + }));
234 + }
235 + }
236 +}
lib/view_model/settings/display_settings_view_model.dart
+10 -4
@@ -24,6 +24,9 @@ abstract class DisplaySettingsViewModelBase with Store {
24 SettingsStore get _settingsStore => _appStore.settingsStore;
25 final ThemeStore _themeStore;
26
27 + @computed
28 + bool get disableTradeOption => _settingsStore.disableTradeOption;
29 +
30 @computed
31 FiatCurrency get fiatCurrency => _settingsStore.fiatCurrency;
32
@@ -110,6 +113,9 @@ abstract class DisplaySettingsViewModelBase with Store {
113 return [];
114 }
115
116 + @action
117 + void setDisableTradeOption(bool value) => _settingsStore.disableTradeOption = value;
118 +
119 @action
120 void setBalanceDisplayMode(BalanceDisplayMode value) => _settingsStore.balanceDisplayMode = value;
121
@@ -246,18 +252,18 @@ abstract class DisplaySettingsViewModelBase with Store {
252 String getImageForTheme(MaterialThemeBase theme) {
253 switch (theme.title) {
254 case 'Dark Theme':
249 - return 'assets/images/dark.svg';
255 + return 'assets/new-ui/dark.svg';
256 case 'Light Theme':
251 - return 'assets/images/light.svg';
257 + return 'assets/new-ui/light.svg';
258 case 'Black Theme (Cake Primary)':
259 case 'Black Theme (BCH Green)':
260 case 'Black Theme (Bitcoin Yellow)':
261 case 'Black Theme (Monero Orange)':
262 case 'Black Theme (Tron Red)':
263 case 'Black Theme (Frosting Purple)':
258 - return 'assets/images/black_accent.svg';
264 + return 'assets/new-ui/black_accent.svg';
265 default:
260 - return 'assets/images/dark.svg';
266 + return 'assets/new-ui/dark.svg';
267 }
268 }
269 }
lib/view_model/settings/other_settings_view_model.dart
+32
@@ -1,6 +1,7 @@
1 import 'dart:io';
2
3 import 'package:cake_wallet/bitcoin/bitcoin.dart';
4 +import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
5 import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
6 import 'package:cake_wallet/store/settings_store.dart';
7 import 'package:cake_wallet/utils/package_info.dart';
@@ -57,6 +58,33 @@ abstract class OtherSettingsViewModelBase with Store {
58 return priority;
59 }
60
61 + @computed
62 + bool get isAutoGenerateSubaddressesEnabled =>
63 + _settingsStore.autoGenerateSubaddressStatus != AutoGenerateSubaddressStatus.disabled;
64 +
65 + @action
66 + void setAutoGenerateSubaddresses(bool value) {
67 + _wallet.isEnabledAutoGenerateSubaddress = value;
68 + _settingsStore.autoGenerateSubaddressStatus =
69 + value ? AutoGenerateSubaddressStatus.enabled : AutoGenerateSubaddressStatus.disabled;
70 + }
71 +
72 + bool get isAutoGenerateSubaddressesVisible => [
73 + WalletType.monero,
74 + WalletType.wownero,
75 + WalletType.bitcoin,
76 + WalletType.litecoin,
77 + WalletType.bitcoinCash,
78 + WalletType.dogecoin,
79 + WalletType.decred
80 + ].contains(_wallet.type);
81 +
82 + @computed
83 + bool get isMoneroWallet => _wallet.type == WalletType.monero;
84 +
85 + @computed
86 + bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress;
87 +
88 @computed
89 bool get changeRepresentativeEnabled =>
90 [WalletType.nano, WalletType.banano].contains(_wallet.type);
@@ -127,6 +155,10 @@ abstract class OtherSettingsViewModelBase with Store {
155 @computed
156 double get customBitcoinFeeRate => _settingsStore.customBitcoinFeeRate.toDouble();
157
158 + @action
159 + void setShouldSaveRecipientAddress(bool value) =>
160 + _settingsStore.shouldSaveRecipientAddress = value;
161 +
162 int? get customPriorityItemIndex {
163 final priorities = priorityForWalletType(walletType);
164 final customItem = priorities
lib/view_model/settings/privacy_settings_view_model.dart
+8 -117
@@ -1,10 +1,6 @@
1 import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
3 -import 'package:cake_wallet/entities/exchange_api_mode.dart';
4 -import 'package:cake_wallet/evm/evm.dart';
3 import 'package:cake_wallet/store/settings_store.dart';
6 -import 'package:cake_wallet/tron/tron.dart';
7 -import 'package:cake_wallet/reactions/wallet_connect.dart';
4 import 'package:cake_wallet/utils/device_info.dart';
5 import 'package:cw_core/balance.dart';
6 import 'package:cw_core/transaction_history.dart';
@@ -12,7 +8,6 @@ import 'package:cw_core/transaction_info.dart';
8 import 'package:cw_core/wallet_base.dart';
9 import 'package:cw_core/wallet_type.dart';
10 import 'package:mobx/mobx.dart';
15 -import 'package:cake_wallet/entities/fiat_api_mode.dart';
11
12 part 'privacy_settings_view_model.g.dart';
13
@@ -25,7 +20,10 @@ abstract class PrivacySettingsViewModelBase with Store {
20 final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> _wallet;
21
22 @computed
28 - ExchangeApiMode get exchangeStatus => _settingsStore.exchangeStatus;
23 + bool get isBitcoin => _wallet.type == WalletType.bitcoin;
24 +
25 + @computed
26 + bool get isLitecoin => _wallet.type == WalletType.litecoin;
27
28 @computed
29 bool get isAutoGenerateSubaddressesEnabled =>
@@ -65,9 +63,6 @@ abstract class PrivacySettingsViewModelBase with Store {
63 @computed
64 bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress;
65
68 - @computed
69 - FiatApiMode get fiatApiMode => _settingsStore.fiatApiMode;
70 -
66 @computed
67 bool get isAppSecure => _settingsStore.isAppSecure;
68
@@ -81,32 +76,6 @@ abstract class PrivacySettingsViewModelBase with Store {
76 @computed
77 bool get disableBulletin => _settingsStore.disableBulletin;
78
84 - @computed
85 - bool get useEtherscan => _settingsStore.useEtherscan;
86 -
87 - @computed
88 - bool get usePolygonScan => _settingsStore.usePolygonScan;
89 -
90 - @computed
91 - bool get useBaseScan => _settingsStore.useBaseScan;
92 -
93 - @computed
94 - bool get useArbiScan => _settingsStore.useArbiScan;
95 -
96 - @computed
97 - bool get useBscScan => _settingsStore.useBscScan;
98 -
99 - @computed
100 - bool get useTronGrid => _settingsStore.useTronGrid;
101 -
102 - @computed
103 - bool get useMempoolFeeAPI => _settingsStore.useMempoolFeeAPI;
104 -
105 - @computed
106 - bool get useBlinkProtection => _settingsStore.useBlinkProtection;
107 -
108 - bool get canUseBlinkProtection => canSupportBlinkProtection(_wallet.chainId);
109 -
79 @computed
80 bool get lookupTwitter => _settingsStore.lookupsTwitter;
81
@@ -135,36 +104,18 @@ abstract class PrivacySettingsViewModelBase with Store {
104 bool get usePayjoin => _settingsStore.usePayjoin;
105
106 @computed
138 - bool get useLightning => _wallet.type == WalletType.bitcoin && bitcoin!.useLightning(_wallet);
139 -
140 - bool get canUseEtherscan => _wallet.chainId == 1;
141 -
142 - bool get canUsePolygonScan => _wallet.chainId == 137;
143 -
144 - bool get canUseBaseScan => _wallet.chainId == 8453;
145 -
146 - bool get canUseArbiScan => _wallet.chainId == 42161;
147 -
148 - bool get canUseBscScan => _wallet.chainId == 56;
149 -
150 - bool get canUseTronGrid => _wallet.type == WalletType.tron;
151 -
152 - bool get canUseMempoolFeeAPI => _wallet.type == WalletType.bitcoin;
153 -
107 bool get canUsePayjoin => _wallet.type == WalletType.bitcoin && DeviceInfo.instance.isMobile;
108
109 + @computed
110 bool get canUseLightning => _wallet.type == WalletType.bitcoin;
111
112 + @computed
113 + bool get useLightning => _wallet.type == WalletType.bitcoin && bitcoin!.useLightning(_wallet);
114 +
115 @action
116 void setShouldSaveRecipientAddress(bool value) =>
117 _settingsStore.shouldSaveRecipientAddress = value;
118
162 - @action
163 - void setExchangeApiMode(ExchangeApiMode value) => _settingsStore.exchangeStatus = value;
164 -
165 - @action
166 - void setFiatMode(FiatApiMode fiatApiMode) => _settingsStore.fiatApiMode = fiatApiMode;
167 -
119 @action
120 void setIsAppSecure(bool value) => _settingsStore.isAppSecure = value;
121
@@ -178,66 +129,6 @@ abstract class PrivacySettingsViewModelBase with Store {
129 @action
130 void setDisableBulletin(bool value) => _settingsStore.disableBulletin = value;
131
181 - @action
182 - void setLookupsTwitter(bool value) => _settingsStore.lookupsTwitter = value;
183 -
184 - @action
185 - void setLookupsZanoAlias(bool value) => _settingsStore.lookupsZanoAlias = value;
186 -
187 - @action
188 - void setLookupsMastodon(bool value) => _settingsStore.lookupsMastodon = value;
189 -
190 - @action
191 - void setLookupsENS(bool value) => _settingsStore.lookupsENS = value;
192 -
193 - @action
194 - void setLookupsWellKnown(bool value) => _settingsStore.lookupsWellKnown = value;
195 -
196 - @action
197 - void setLookupsYatService(bool value) => _settingsStore.lookupsYatService = value;
198 -
199 - @action
200 - void setLookupsUnstoppableDomains(bool value) => _settingsStore.lookupsUnstoppableDomains = value;
201 -
202 - @action
203 - void setLookupsOpenAlias(bool value) => _settingsStore.lookupsOpenAlias = value;
204 -
205 - @action
206 - void setUseEtherscan(bool value) {
207 - _settingsStore.useEtherscan = value;
208 - evm!.updateScanProviderUsageState(_wallet, value);
209 - }
210 -
211 - @action
212 - void setUsePolygonScan(bool value) {
213 - _settingsStore.usePolygonScan = value;
214 - evm!.updateScanProviderUsageState(_wallet, value);
215 - }
216 -
217 - @action
218 - void setUseBaseScan(bool value) {
219 - _settingsStore.useBaseScan = value;
220 - evm!.updateScanProviderUsageState(_wallet, value);
221 - }
222 -
223 - @action
224 - void setUseTronGrid(bool value) {
225 - _settingsStore.useTronGrid = value;
226 - tron!.updateTronGridUsageState(_wallet, value);
227 - }
228 -
229 - @action
230 - void setUseArbiScan(bool value) {
231 - _settingsStore.useArbiScan = value;
232 - evm!.updateScanProviderUsageState(_wallet, value);
233 - }
234 -
235 - @action
236 - void setUseBscScan(bool value) {
237 - _settingsStore.useBscScan = value;
238 - evm!.updateScanProviderUsageState(_wallet, value);
239 - }
240 -
132 @action
133 void setUseMempoolFeeAPI(bool value) => _settingsStore.useMempoolFeeAPI = value;
134
lib/view_model/settings/security_settings_view_model.dart
+6
@@ -15,6 +15,9 @@ abstract class SecuritySettingsViewModelBase with Store {
15 final SettingsStore _settingsStore;
16 final AuthService _authService;
17
18 + @computed
19 + bool get isAppSecure => _settingsStore.isAppSecure;
20 +
21 @computed
22 bool get allowBiometricalAuthentication => _settingsStore.allowBiometricalAuthentication;
23
@@ -36,6 +39,9 @@ abstract class SecuritySettingsViewModelBase with Store {
39 return await _biometricAuth.canCheckBiometrics() && await _biometricAuth.isAuthenticated();
40 }
41
42 + @action
43 + void setIsAppSecure(bool value) => _settingsStore.isAppSecure = value;
44 +
45 @action
46 void setAllowBiometricalAuthentication(bool value) =>
47 _settingsStore.allowBiometricalAuthentication = value;
res/pictures/black_accent.svg renamed
res/pictures/chooser.svg
+2 -9
@@ -1,10 +1,3 @@
1 -<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
2 - <g clip-path="url(#clip0_14441_461975)">
3 - <path d="M8.51392 11.9985L5 8.48462L5.66456 7.82006L8.51392 10.6576L11.3633 7.82006L12.0278 8.48462L8.51392 11.9985ZM5.67404 4.16738L5 3.51245L8.51392 -0.00146484L12.0278 3.51245L11.3538 4.16738L8.51392 1.33947L5.67404 4.16738Z" fill="white"/>
4 - </g>
5 - <defs>
6 - <clipPath id="clip0_14441_461975">
7 - <rect width="12" height="12" fill="white"/>
8 - </clipPath>
9 - </defs>
1 +<svg width="8" height="13" viewBox="0 0 8 13" fill="none" xmlns="http://www.w3.org/2000/svg">
2 +<path d="M3.76917 12.8717L0 9.1025L0.712833 8.38967L3.76917 11.4333L6.8255 8.38967L7.53833 9.1025L3.76917 12.8717ZM0.723 4.47167L0 3.76917L3.76917 0L7.53833 3.76917L6.81533 4.47167L3.76917 1.43833L0.723 4.47167Z" fill="#8C9FBB"/>
3 </svg>
res/pictures/dark.svg renamed
res/pictures/light.svg renamed
res/pictures/settings_row_icons/privacy.svg
+33 -38
@@ -1,40 +1,35 @@
1 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2 - <g clip-path="url(#clip0_16845_60754)">
3 - <g clip-path="url(#clip1_16845_60754)">
4 - <path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint0_linear_16845_60754)"/>
5 - <path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint1_linear_16845_60754)"/>
6 - <path d="M11.8691 3.35876C14.2163 3.35876 16.1192 5.26162 16.1192 7.60881V9.85891H17.4943C18.1155 9.85897 18.6191 10.3625 18.6191 10.9838V18.2337C18.6191 18.855 18.1155 19.3586 17.4943 19.3586H6.24403C5.62276 19.3586 5.11914 18.855 5.11914 18.2337V10.9838C5.11916 10.3625 5.62278 9.85897 6.24403 9.85891H7.61908V7.60881C7.6191 5.26165 9.52197 3.3588 11.8691 3.35876ZM11.8691 13.0787C11.049 13.0787 10.384 13.7436 10.384 14.5638C10.384 15.3839 11.049 16.0489 11.8691 16.0489C12.6893 16.0489 13.3543 15.3839 13.3543 14.5638C13.3543 13.7436 12.6893 13.0787 11.8691 13.0787ZM11.8691 5.35871C10.6265 5.35875 9.61938 6.36621 9.61936 7.60881V9.85891H14.1193V7.60881C14.1192 6.36619 13.1118 5.35871 11.8691 5.35871Z" fill="white"/>
7 - <path d="M11.8691 3.35876C14.2163 3.35876 16.1192 5.26162 16.1192 7.60881V9.85891H17.4943C18.1155 9.85897 18.6191 10.3625 18.6191 10.9838V18.2337C18.6191 18.855 18.1155 19.3586 17.4943 19.3586H6.24403C5.62276 19.3586 5.11914 18.855 5.11914 18.2337V10.9838C5.11916 10.3625 5.62278 9.85897 6.24403 9.85891H7.61908V7.60881C7.6191 5.26165 9.52197 3.3588 11.8691 3.35876ZM11.8691 13.0787C11.049 13.0787 10.384 13.7436 10.384 14.5638C10.384 15.3839 11.049 16.0489 11.8691 16.0489C12.6893 16.0489 13.3543 15.3839 13.3543 14.5638C13.3543 13.7436 12.6893 13.0787 11.8691 13.0787ZM11.8691 5.35871C10.6265 5.35875 9.61938 6.36621 9.61936 7.60881V9.85891H14.1193V7.60881C14.1192 6.36619 13.1118 5.35871 11.8691 5.35871Z" fill="url(#paint2_linear_16845_60754)"/>
8 - <path d="M11.8691 3.35876C14.2163 3.35876 16.1192 5.26162 16.1192 7.60881V9.85891H17.4943C18.1155 9.85897 18.6191 10.3625 18.6191 10.9838V18.2337C18.6191 18.855 18.1155 19.3586 17.4943 19.3586H6.24403C5.62276 19.3586 5.11914 18.855 5.11914 18.2337V10.9838C5.11916 10.3625 5.62278 9.85897 6.24403 9.85891H7.61908V7.60881C7.6191 5.26165 9.52197 3.3588 11.8691 3.35876ZM11.8691 13.0787C11.049 13.0787 10.384 13.7436 10.384 14.5638C10.384 15.3839 11.049 16.0489 11.8691 16.0489C12.6893 16.0489 13.3543 15.3839 13.3543 14.5638C13.3543 13.7436 12.6893 13.0787 11.8691 13.0787ZM11.8691 5.35871C10.6265 5.35875 9.61938 6.36621 9.61936 7.60881V9.85891H14.1193V7.60881C14.1192 6.36619 13.1118 5.35871 11.8691 5.35871Z" fill="url(#paint3_linear_16845_60754)"/>
9 - <path d="M11.8691 3.35876C14.2163 3.35876 16.1192 5.26162 16.1192 7.60881V9.85891H17.4943C18.1155 9.85897 18.6191 10.3625 18.6191 10.9838V18.2337C18.6191 18.855 18.1155 19.3586 17.4943 19.3586H6.24403C5.62276 19.3586 5.11914 18.855 5.11914 18.2337V10.9838C5.11916 10.3625 5.62278 9.85897 6.24403 9.85891H7.61908V7.60881C7.6191 5.26165 9.52197 3.3588 11.8691 3.35876ZM11.8691 13.0787C11.049 13.0787 10.384 13.7436 10.384 14.5638C10.384 15.3839 11.049 16.0489 11.8691 16.0489C12.6893 16.0489 13.3543 15.3839 13.3543 14.5638C13.3543 13.7436 12.6893 13.0787 11.8691 13.0787ZM11.8691 5.35871C10.6265 5.35875 9.61938 6.36621 9.61936 7.60881V9.85891H14.1193V7.60881C14.1192 6.36619 13.1118 5.35871 11.8691 5.35871Z" fill="url(#paint4_linear_16845_60754)"/>
10 - </g>
11 - </g>
12 - <defs>
13 - <linearGradient id="paint0_linear_16845_60754" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
14 - <stop stop-color="#8F8F8F"/>
15 - <stop offset="1" stop-color="#6D6D6D"/>
16 - </linearGradient>
17 - <linearGradient id="paint1_linear_16845_60754" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
18 - <stop stop-color="#F7931A"/>
19 - <stop offset="1" stop-color="#F67300"/>
20 - </linearGradient>
21 - <linearGradient id="paint2_linear_16845_60754" x1="11.8691" y1="3.35876" x2="11.8691" y2="19.3586" gradientUnits="userSpaceOnUse">
22 - <stop stop-color="white"/>
23 - <stop offset="1" stop-color="#A4B8FF"/>
24 - </linearGradient>
25 - <linearGradient id="paint3_linear_16845_60754" x1="11.8691" y1="3.35876" x2="11.8691" y2="19.3586" gradientUnits="userSpaceOnUse">
26 - <stop stop-color="white"/>
27 - <stop offset="1" stop-color="#A4CEFF"/>
28 - </linearGradient>
29 - <linearGradient id="paint4_linear_16845_60754" x1="11.8691" y1="3.35876" x2="11.8691" y2="19.3586" gradientUnits="userSpaceOnUse">
30 - <stop stop-color="#5F330B"/>
31 - <stop offset="1" stop-color="#462100"/>
32 - </linearGradient>
33 - <clipPath id="clip0_16845_60754">
34 - <rect width="24" height="24" fill="white"/>
35 - </clipPath>
36 - <clipPath id="clip1_16845_60754">
37 - <rect width="24" height="24" fill="white"/>
38 - </clipPath>
39 - </defs>
2 +<g clip-path="url(#clip0_16529_391320)">
3 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint0_linear_16529_391320)"/>
4 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint1_linear_16529_391320)"/>
5 +<path d="M11.8711 3.3584C14.2183 3.3584 16.1211 5.26126 16.1212 7.60844V9.85854H17.4962C18.1175 9.8586 18.6211 10.3622 18.6211 10.9834V18.2334C18.6211 18.8547 18.1175 19.3582 17.4962 19.3583H6.24598C5.62471 19.3582 5.12109 18.8547 5.12109 18.2334V10.9834C5.12112 10.3622 5.62473 9.8586 6.24598 9.85854H7.62103V7.60844C7.62105 5.26128 9.52393 3.35844 11.8711 3.3584ZM11.8711 13.0783C11.051 13.0783 10.386 13.7433 10.386 14.5634C10.386 15.3835 11.051 16.0485 11.8711 16.0485C12.6912 16.0485 13.3562 15.3835 13.3562 14.5634C13.3562 13.7433 12.6912 13.0783 11.8711 13.0783ZM11.8711 5.35834C10.6285 5.35838 9.62133 6.36584 9.62131 7.60844V9.85854H14.1212V7.60844C14.1212 6.36582 13.1137 5.35834 11.8711 5.35834Z" fill="white"/>
6 +<path d="M11.8711 3.3584C14.2183 3.3584 16.1211 5.26126 16.1212 7.60844V9.85854H17.4962C18.1175 9.8586 18.6211 10.3622 18.6211 10.9834V18.2334C18.6211 18.8547 18.1175 19.3582 17.4962 19.3583H6.24598C5.62471 19.3582 5.12109 18.8547 5.12109 18.2334V10.9834C5.12112 10.3622 5.62473 9.8586 6.24598 9.85854H7.62103V7.60844C7.62105 5.26128 9.52393 3.35844 11.8711 3.3584ZM11.8711 13.0783C11.051 13.0783 10.386 13.7433 10.386 14.5634C10.386 15.3835 11.051 16.0485 11.8711 16.0485C12.6912 16.0485 13.3562 15.3835 13.3562 14.5634C13.3562 13.7433 12.6912 13.0783 11.8711 13.0783ZM11.8711 5.35834C10.6285 5.35838 9.62133 6.36584 9.62131 7.60844V9.85854H14.1212V7.60844C14.1212 6.36582 13.1137 5.35834 11.8711 5.35834Z" fill="url(#paint2_linear_16529_391320)"/>
7 +<path d="M11.8711 3.3584C14.2183 3.3584 16.1211 5.26126 16.1212 7.60844V9.85854H17.4962C18.1175 9.8586 18.6211 10.3622 18.6211 10.9834V18.2334C18.6211 18.8547 18.1175 19.3582 17.4962 19.3583H6.24598C5.62471 19.3582 5.12109 18.8547 5.12109 18.2334V10.9834C5.12112 10.3622 5.62473 9.8586 6.24598 9.85854H7.62103V7.60844C7.62105 5.26128 9.52393 3.35844 11.8711 3.3584ZM11.8711 13.0783C11.051 13.0783 10.386 13.7433 10.386 14.5634C10.386 15.3835 11.051 16.0485 11.8711 16.0485C12.6912 16.0485 13.3562 15.3835 13.3562 14.5634C13.3562 13.7433 12.6912 13.0783 11.8711 13.0783ZM11.8711 5.35834C10.6285 5.35838 9.62133 6.36584 9.62131 7.60844V9.85854H14.1212V7.60844C14.1212 6.36582 13.1137 5.35834 11.8711 5.35834Z" fill="url(#paint3_linear_16529_391320)"/>
8 +<path d="M11.8711 3.3584C14.2183 3.3584 16.1211 5.26126 16.1212 7.60844V9.85854H17.4962C18.1175 9.8586 18.6211 10.3622 18.6211 10.9834V18.2334C18.6211 18.8547 18.1175 19.3582 17.4962 19.3583H6.24598C5.62471 19.3582 5.12109 18.8547 5.12109 18.2334V10.9834C5.12112 10.3622 5.62473 9.8586 6.24598 9.85854H7.62103V7.60844C7.62105 5.26128 9.52393 3.35844 11.8711 3.3584ZM11.8711 13.0783C11.051 13.0783 10.386 13.7433 10.386 14.5634C10.386 15.3835 11.051 16.0485 11.8711 16.0485C12.6912 16.0485 13.3562 15.3835 13.3562 14.5634C13.3562 13.7433 12.6912 13.0783 11.8711 13.0783ZM11.8711 5.35834C10.6285 5.35838 9.62133 6.36584 9.62131 7.60844V9.85854H14.1212V7.60844C14.1212 6.36582 13.1137 5.35834 11.8711 5.35834Z" fill="url(#paint4_linear_16529_391320)"/>
9 +</g>
10 +<defs>
11 +<linearGradient id="paint0_linear_16529_391320" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
12 +<stop stop-color="#8F8F8F"/>
13 +<stop offset="1" stop-color="#6D6D6D"/>
14 +</linearGradient>
15 +<linearGradient id="paint1_linear_16529_391320" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
16 +<stop stop-color="#F7931A"/>
17 +<stop offset="1" stop-color="#F67300"/>
18 +</linearGradient>
19 +<linearGradient id="paint2_linear_16529_391320" x1="11.8711" y1="3.3584" x2="11.8711" y2="19.3583" gradientUnits="userSpaceOnUse">
20 +<stop stop-color="white"/>
21 +<stop offset="1" stop-color="#A4B8FF"/>
22 +</linearGradient>
23 +<linearGradient id="paint3_linear_16529_391320" x1="11.8711" y1="3.3584" x2="11.8711" y2="19.3583" gradientUnits="userSpaceOnUse">
24 +<stop stop-color="white"/>
25 +<stop offset="1" stop-color="#A4CEFF"/>
26 +</linearGradient>
27 +<linearGradient id="paint4_linear_16529_391320" x1="11.8711" y1="3.3584" x2="11.8711" y2="19.3583" gradientUnits="userSpaceOnUse">
28 +<stop stop-color="#5F330B"/>
29 +<stop offset="1" stop-color="#462100"/>
30 +</linearGradient>
31 +<clipPath id="clip0_16529_391320">
32 +<rect width="24" height="24" fill="white"/>
33 +</clipPath>
34 +</defs>
35 </svg>
res/pictures/settings_row_icons/security.svg
+40 -45
@@ -1,47 +1,42 @@
1 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2 - <g clip-path="url(#clip0_16845_60955)">
3 - <g clip-path="url(#clip1_16845_60955)">
4 - <path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="black"/>
5 - <path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint0_linear_16845_60955)"/>
6 - <path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint1_linear_16845_60955)"/>
7 - <path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint2_linear_16845_60955)"/>
8 - <path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="#2C5CF6"/>
9 - <path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint3_linear_16845_60955)"/>
10 - <path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint4_linear_16845_60955)"/>
11 - <path d="M12 20.8489C9.98136 20.2984 8.31007 19.1102 6.98613 17.2843C5.66204 15.4584 5 13.417 5 11.1602V5.79006L12 3.16949L19 5.79006V11.1602C19 13.417 18.338 15.4584 17.0139 17.2843C15.6899 19.1102 14.0186 20.2984 12 20.8489ZM12 19.3736C13.5089 18.9069 14.7689 17.9852 15.78 16.6086C16.7911 15.2319 17.3822 13.6958 17.5533 12.0002H12V4.6591L6.4 6.75023V11.5714C6.4 11.6862 6.41556 11.8291 6.44667 12.0002H12V19.3736Z" fill="#E3E3E3"/>
12 - <path d="M12 20.8489C9.98136 20.2984 8.31007 19.1102 6.98613 17.2843C5.66204 15.4584 5 13.417 5 11.1602V5.79006L12 3.16949L19 5.79006V11.1602C19 13.417 18.338 15.4584 17.0139 17.2843C15.6899 19.1102 14.0186 20.2984 12 20.8489ZM12 19.3736C13.5089 18.9069 14.7689 17.9852 15.78 16.6086C16.7911 15.2319 17.3822 13.6958 17.5533 12.0002H12V4.6591L6.4 6.75023V11.5714C6.4 11.6862 6.41556 11.8291 6.44667 12.0002H12V19.3736Z" fill="url(#paint5_linear_16845_60955)"/>
13 - </g>
14 - </g>
15 - <defs>
16 - <linearGradient id="paint0_linear_16845_60955" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
17 - <stop stop-color="#2C2C2C"/>
18 - <stop offset="1" stop-color="#191919"/>
19 - </linearGradient>
20 - <linearGradient id="paint1_linear_16845_60955" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
21 - <stop stop-color="#351C83"/>
22 - <stop offset="1" stop-color="#0C0033"/>
23 - </linearGradient>
24 - <linearGradient id="paint2_linear_16845_60955" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
25 - <stop stop-color="#FF6200"/>
26 - <stop offset="1" stop-color="#E20F0F"/>
27 - </linearGradient>
28 - <linearGradient id="paint3_linear_16845_60955" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
29 - <stop stop-color="#2C5CF6"/>
30 - <stop offset="1" stop-color="#0F37FF"/>
31 - </linearGradient>
32 - <linearGradient id="paint4_linear_16845_60955" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
33 - <stop stop-color="#3B96FF"/>
34 - <stop offset="1" stop-color="#0044F0"/>
35 - </linearGradient>
36 - <linearGradient id="paint5_linear_16845_60955" x1="12" y1="3.16949" x2="12" y2="20.8489" gradientUnits="userSpaceOnUse">
37 - <stop stop-color="white"/>
38 - <stop offset="1" stop-color="#A4CEFF"/>
39 - </linearGradient>
40 - <clipPath id="clip0_16845_60955">
41 - <rect width="24" height="24" fill="white"/>
42 - </clipPath>
43 - <clipPath id="clip1_16845_60955">
44 - <rect width="24" height="24" fill="white"/>
45 - </clipPath>
46 - </defs>
2 +<g clip-path="url(#clip0_16529_391334)">
3 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="black"/>
4 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint0_linear_16529_391334)"/>
5 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint1_linear_16529_391334)"/>
6 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint2_linear_16529_391334)"/>
7 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="#2C5CF6"/>
8 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint3_linear_16529_391334)"/>
9 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint4_linear_16529_391334)"/>
10 +<path d="M12 20.8494C9.98136 20.2988 8.31007 19.1106 6.98613 17.2847C5.66204 15.4588 5 13.4175 5 11.1607V5.79049L12 3.16992L19 5.79049V11.1607C19 13.4175 18.338 15.4588 17.0139 17.2847C15.6899 19.1106 14.0186 20.2988 12 20.8494ZM12 19.374C13.5089 18.9073 14.7689 17.9857 15.78 16.609C16.7911 15.2323 17.3822 13.6962 17.5533 12.0007H12V4.65952L6.4 6.75066V11.5718C6.4 11.6866 6.41556 11.8295 6.44667 12.0007H12V19.374Z" fill="#E3E3E3"/>
11 +<path d="M12 20.8494C9.98136 20.2988 8.31007 19.1106 6.98613 17.2847C5.66204 15.4588 5 13.4175 5 11.1607V5.79049L12 3.16992L19 5.79049V11.1607C19 13.4175 18.338 15.4588 17.0139 17.2847C15.6899 19.1106 14.0186 20.2988 12 20.8494ZM12 19.374C13.5089 18.9073 14.7689 17.9857 15.78 16.609C16.7911 15.2323 17.3822 13.6962 17.5533 12.0007H12V4.65952L6.4 6.75066V11.5718C6.4 11.6866 6.41556 11.8295 6.44667 12.0007H12V19.374Z" fill="url(#paint5_linear_16529_391334)"/>
12 +</g>
13 +<defs>
14 +<linearGradient id="paint0_linear_16529_391334" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
15 +<stop stop-color="#2C2C2C"/>
16 +<stop offset="1" stop-color="#191919"/>
17 +</linearGradient>
18 +<linearGradient id="paint1_linear_16529_391334" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
19 +<stop stop-color="#351C83"/>
20 +<stop offset="1" stop-color="#0C0033"/>
21 +</linearGradient>
22 +<linearGradient id="paint2_linear_16529_391334" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
23 +<stop stop-color="#FF6200"/>
24 +<stop offset="1" stop-color="#E20F0F"/>
25 +</linearGradient>
26 +<linearGradient id="paint3_linear_16529_391334" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
27 +<stop stop-color="#2C5CF6"/>
28 +<stop offset="1" stop-color="#0F37FF"/>
29 +</linearGradient>
30 +<linearGradient id="paint4_linear_16529_391334" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
31 +<stop stop-color="#3B96FF"/>
32 +<stop offset="1" stop-color="#0044F0"/>
33 +</linearGradient>
34 +<linearGradient id="paint5_linear_16529_391334" x1="12" y1="3.16992" x2="12" y2="20.8494" gradientUnits="userSpaceOnUse">
35 +<stop stop-color="white"/>
36 +<stop offset="1" stop-color="#A4CEFF"/>
37 +</linearGradient>
38 +<clipPath id="clip0_16529_391334">
39 +<rect width="24" height="24" fill="white"/>
40 +</clipPath>
41 +</defs>
42 </svg>
res/pictures/settings_row_icons/wc.svg new
+29
@@ -0,0 +1,29 @@
1 +<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2 +<g clip-path="url(#clip0_17329_949648)">
3 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint0_linear_17329_949648)"/>
4 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint1_linear_17329_949648)"/>
5 +<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint2_linear_17329_949648)"/>
6 +<path d="M21.6004 12.2103L15.9535 17.8165L12.0004 13.8926L8.04727 17.8165L2.40039 12.2103L4.0931 10.5301L8.04727 14.454L12.0004 10.5301L15.9535 14.454L19.9077 10.5301L21.6004 12.2103ZM5.78997 8.85195C9.62131 5.04933 14.3815 5.04937 18.2129 8.85195L16.5181 10.5332C13.6046 7.64263 10.3981 7.64269 7.48477 10.5342L5.78997 8.85195Z" fill="url(#paint3_linear_17329_949648)"/>
7 +</g>
8 +<defs>
9 +<linearGradient id="paint0_linear_17329_949648" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
10 +<stop stop-color="#0082F8"/>
11 +<stop offset="1" stop-color="#0666FF"/>
12 +</linearGradient>
13 +<linearGradient id="paint1_linear_17329_949648" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
14 +<stop stop-color="#2B9AFF"/>
15 +<stop offset="1" stop-color="#0666FF"/>
16 +</linearGradient>
17 +<linearGradient id="paint2_linear_17329_949648" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
18 +<stop stop-color="#3396FF"/>
19 +<stop offset="1" stop-color="#007CFF"/>
20 +</linearGradient>
21 +<linearGradient id="paint3_linear_17329_949648" x1="12.0004" y1="6" x2="12.0004" y2="17.8165" gradientUnits="userSpaceOnUse">
22 +<stop stop-color="white"/>
23 +<stop offset="1" stop-color="#BFDEFF"/>
24 +</linearGradient>
25 +<clipPath id="clip0_17329_949648">
26 +<rect width="24" height="24" fill="white"/>
27 +</clipPath>
28 +</defs>
29 +</svg>
res/values/strings_ar.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "متصل",
243 "connection_sync": "الاتصال والمزامنة",
244 "connections": "الاتصالات",
245 + "connections_desc": "إدارة الاتصالات بالخدمات وواجهات برمجة التطبيقات التابعة لجهات خارجية.",
246 "connectWalletPrompt": "قم بتوصيل محفظتك عبر WalletConnect لإجراء المعاملات",
247 "contact": "جهة اتصال",
248 "contact_list_contacts": "جهات الاتصال",
@@ -756,6 +757,7 @@
757 "privacy": "الخصوصية",
758 "privacy_and_security": "الخصوصية والأمان",
759 "privacy_and_security_desc": "قم بتكوين إعدادات المصادقة والأمان وإعداد المصادقة الثنائية (2FA) في Cake.",
760 + "privacy_desc": "تغيير إعدادات الخصوصية وتبديل ميزات الخصوصية الخاصة.",
761 "privacy_features": "ميزات الخصوصية",
762 "privacy_policy": "سياسة الخصوصية",
763 "privacy_settings": "إعدادات الخصوصية",
res/values/strings_bg.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Свързан",
243 "connection_sync": "Връзка и синхронизация",
244 "connections": "Връзки",
245 + "connections_desc": "Управлявайте връзки към услуги и API на трети страни.",
246 "connectWalletPrompt": "Свържете портфейла си с WalletConnect, за да извършвате транзакции",
247 "contact": "Контакт",
248 "contact_list_contacts": "Контакти",
@@ -756,6 +757,7 @@
757 "privacy": "Поверителност",
758 "privacy_and_security": "Поверителност и сигурност",
759 "privacy_and_security_desc": "Конфигурирайте настройките за удостоверяване и сигурност и настройте Cake 2FA.",
760 + "privacy_desc": "Променете настройките за поверителност и превключете специални функции за поверителност.",
761 "privacy_features": "Функции за поверителност",
762 "privacy_policy": "Политика за поверителност",
763 "privacy_settings": "Настройки за поверителност",
res/values/strings_cs.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Připojeno",
243 "connection_sync": "Připojení a synchronizace",
244 "connections": "Připojení",
245 + "connections_desc": "Správa připojení ke službám a rozhraním API třetích stran.",
246 "connectWalletPrompt": "Připojte svou peněženku přes WalletConnect a provádějte transakce",
247 "contact": "Kontakt",
248 "contact_list_contacts": "Kontakty",
@@ -756,6 +757,7 @@
757 "privacy": "Soukromí",
758 "privacy_and_security": "Soukromí a zabezpečení",
759 "privacy_and_security_desc": "Nakonfigurujte nastavení ověřování a zabezpečení a nastavte Cake 2FA.",
760 + "privacy_desc": "Změňte nastavení ochrany osobních údajů a přepínejte speciální funkce ochrany osobních údajů.",
761 "privacy_features": "Funkce soukromí",
762 "privacy_policy": "Zásady ochrany osobních údajů",
763 "privacy_settings": "Nastavení soukromí",
res/values/strings_de.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Verbunden",
243 "connection_sync": "Verbindung und Synchronisierung",
244 "connections": "Verbindungen",
245 + "connections_desc": "Verwalten Sie Verbindungen zu Diensten und APIs von Drittanbietern.",
246 "connectWalletPrompt": "Verbinden Sie Ihr Wallet mit WalletConnect, um Transaktionen durchzuführen",
247 "contact": "Kontakt",
248 "contact_list_contacts": "Kontakte",
@@ -757,6 +758,7 @@
758 "privacy": "Privatsphäre",
759 "privacy_and_security": "Datenschutz & Sicherheit",
760 "privacy_and_security_desc": "Konfigurieren Sie Authentifizierungs- und Sicherheitseinstellungen und richten Sie Cake 2FA ein.",
761 + "privacy_desc": "Ändern Sie die Datenschutzeinstellungen und schalten Sie spezielle Datenschutzfunktionen ein.",
762 "privacy_features": "Datenschutzfunktionen",
763 "privacy_policy": "Datenschutzerklärung",
764 "privacy_settings": "Datenschutzeinstellungen",
res/values/strings_en.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Connected",
243 "connection_sync": "Connection and sync",
244 "connections": "Connections",
245 + "connections_desc": "Manage connections to services and third party APIs.",
246 "connectWalletPrompt": "Connect your wallet with WalletConnect to make transactions",
247 "contact": "Contact",
248 "contact_list_contacts": "Contacts",
@@ -757,6 +758,7 @@
758 "privacy": "Privacy",
759 "privacy_and_security": "Privacy & Security",
760 "privacy_and_security_desc": "Configure authentication and security settings and setup Cake 2FA.",
761 + "privacy_desc": "Change privacy settings and toggle special privacy features.",
762 "privacy_features": "Privacy features",
763 "privacy_policy": "Privacy Policy",
764 "privacy_settings": "Privacy settings",
res/values/strings_es.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Conectado",
243 "connection_sync": "Conexión y sincronización",
244 "connections": "Conexiones",
245 + "connections_desc": "Administrar conexiones a servicios y API de terceros.",
246 "connectWalletPrompt": "Conecta tu billetera con WalletConnect para realizar transacciones",
247 "contact": "Contacto",
248 "contact_list_contacts": "Contactos",
@@ -757,6 +758,7 @@
758 "privacy": "Privacidad",
759 "privacy_and_security": "Privacidad y seguridad",
760 "privacy_and_security_desc": "Configure los ajustes de autenticación y seguridad y configure Cake 2FA.",
761 + "privacy_desc": "Cambie la configuración de privacidad y alterne funciones de privacidad especiales.",
762 "privacy_features": "Funciones de privacidad",
763 "privacy_policy": "Política de privacidad",
764 "privacy_settings": "Configuración de privacidad",
res/values/strings_fa.arb
+2
@@ -240,6 +240,7 @@
240 "connected": "متصل",
241 "connection_sync": "اتصال و همگام‌سازی",
242 "connections": "اتصالات",
243 + "connections_desc": "اتصالات به سرویس ها و API های شخص ثالث را مدیریت کنید.",
244 "connectWalletPrompt": "برای انجام تراکنش‌ها، کیف پول خود را از طریق WalletConnect متصل کنید",
245 "contact": "مخاطب",
246 "contact_list_contacts": "مخاطبین",
@@ -755,6 +756,7 @@
756 "privacy": "حریم خصوصی",
757 "privacy_and_security": "حریم خصوصی و امنیت",
758 "privacy_and_security_desc": "تنظیمات احراز هویت و امنیت را پیکربندی کنید و Cake 2FA را راه‌اندازی کنید.",
759 + "privacy_desc": "تنظیمات حریم خصوصی را تغییر دهید و ویژگی های حریم خصوصی را تغییر دهید.",
760 "privacy_features": "ویژگی‌های حریم خصوصی",
761 "privacy_policy": "سیاست حفظ حریم خصوصی",
762 "privacy_settings": "تنظیمات حریم خصوصی",
res/values/strings_fr.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Connecté",
243 "connection_sync": "Connexion et synchronisation",
244 "connections": "Connexions",
245 + "connections_desc": "Gérez les connexions aux services et aux API tierces.",
246 "connectWalletPrompt": "Connectez votre portefeuille avec WalletConnect pour effectuer des transactions",
247 "contact": "Contact",
248 "contact_list_contacts": "Contacts",
@@ -756,6 +757,7 @@
757 "privacy": "Confidentialité",
758 "privacy_and_security": "Confidentialité et sécurité",
759 "privacy_and_security_desc": "Configurez les paramètres d'authentification et de sécurité, et configurez Cake 2FA.",
760 + "privacy_desc": "Modifiez les paramètres de confidentialité et activez les fonctionnalités de confidentialité spéciales.",
761 "privacy_features": "Fonctionnalités de confidentialité",
762 "privacy_policy": "Politique de confidentialité",
763 "privacy_settings": "Paramètres de confidentialité",
res/values/strings_gn.arb
+2
@@ -192,6 +192,7 @@
192 "connect_your_hardware_wallet_ios": "Embojoaju nde billetera hardware Bluetooth ndive",
193 "connection_sync": "Joaju ha ñembojuehe",
194 "connections": "Jeikeha",
195 + "connections_desc": "Emohenda joaju umi servicio ha API mbohapýha rehegua.",
196 "connectWalletPrompt": "Embojoaju nde billetera WalletConnect ndive hag̃ua rejapo transacción",
197 "contact": "Contacto",
198 "contact_list_contacts": "Ñe'ẽngára",
@@ -589,6 +590,7 @@
590 "privacy": "Ñemigua",
591 "privacy_and_security": "Privasida ha Tekorosã",
592 "privacy_and_security_desc": "Emohenda ñemboheko hag̃ua jehechajey hag̃ua hag̃ua hag̃ua hag̃ua seguridad ha emboheko Cake 2FA.",
593 + "privacy_desc": "Emoambue ñemigua ñemboheko ha embohasa ñemigua mba’ekuaarã especial.",
594 "privacy_features": "Tembiapoite ñemigua",
595 "privacy_policy": "Purureko ñemi rehegua",
596 "privacy_settings": "Ñemohenda ñemigua",
res/values/strings_ha.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "An haɗa",
243 "connection_sync": "Haɗi da aiki tare",
244 "connections": "Haɗe-haɗe",
245 + "connections_desc": "Sarrafa haɗin kai zuwa ayyuka da APIs na ɓangare na uku.",
246 "connectWalletPrompt": "Haɗa walat ɗinka da WalletConnect don yin ma'amaloli",
247 "contact": "Tuntuɓa",
248 "contact_list_contacts": "Lambobin sadarwa",
@@ -758,6 +759,7 @@
759 "privacy": "Sirri",
760 "privacy_and_security": "Sirri & Tsaro",
761 "privacy_and_security_desc": "Saita tabbatarwa da saitunan tsaro, sannan ka saita Cake 2FA.",
762 + "privacy_desc": "Canja saitunan keɓantawa kuma kunna fasalolin keɓantawa na musamman.",
763 "privacy_features": "Siffofin keɓantawa",
764 "privacy_policy": "Manufar Sirri",
765 "privacy_settings": "Saitunan keɓantawa",
res/values/strings_hi.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "कनेक्टेड",
243 "connection_sync": "कनेक्शन और सिंक",
244 "connections": "कनेक्शन",
245 + "connections_desc": "सेवाओं और तृतीय पक्ष एपीआई से कनेक्शन प्रबंधित करें।",
246 "connectWalletPrompt": "लेन-देन करने के लिए अपने वॉलेट को WalletConnect से कनेक्ट करें",
247 "contact": "संपर्क",
248 "contact_list_contacts": "संपर्क",
@@ -757,6 +758,7 @@
758 "privacy": "गोपनीयता",
759 "privacy_and_security": "निजता और सुरक्षा",
760 "privacy_and_security_desc": "प्रमाणीकरण और सुरक्षा सेटिंग्स कॉन्फ़िगर करें और Cake 2FA सेट अप करें।",
761 + "privacy_desc": "गोपनीयता सेटिंग्स बदलें और विशेष गोपनीयता सुविधाओं को टॉगल करें।",
762 "privacy_features": "गोपनीयता सुविधाएँ",
763 "privacy_policy": "गोपनीयता नीति",
764 "privacy_settings": "गोपनीयता सेटिंग्स",
res/values/strings_hr.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Povezano",
243 "connection_sync": "Povezivanje i sinkronizacija",
244 "connections": "Veze",
245 + "connections_desc": "Upravljajte vezama s uslugama i API-jima trećih strana.",
246 "connectWalletPrompt": "Povežite svoj novčanik s WalletConnectom za izvršavanje transakcija",
247 "contact": "Kontakt",
248 "contact_list_contacts": "Kontakti",
@@ -756,6 +757,7 @@
757 "privacy": "Privatnost",
758 "privacy_and_security": "Privatnost i sigurnost",
759 "privacy_and_security_desc": "Konfigurirajte postavke provjere autentičnosti i sigurnosti te postavite Cake 2FA.",
760 + "privacy_desc": "Promijenite postavke privatnosti i uključite/isključite posebne značajke privatnosti.",
761 "privacy_features": "Značajke privatnosti",
762 "privacy_policy": "Pravila privatnosti",
763 "privacy_settings": "Postavke privatnosti",
res/values/strings_hy.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Միացված",
243 "connection_sync": "Կապ և համաժամեցում",
244 "connections": "Միացումներ",
245 + "connections_desc": "Կառավարեք կապերը ծառայությունների և երրորդ կողմի API-ների հետ:",
246 "connectWalletPrompt": "Միացրեք ձեր դրամապանակը WalletConnect-ի միջոցով՝ գործարքներ կատարելու համար",
247 "contact": "Կոնտակտ",
248 "contact_list_contacts": "Կոնտակտներ",
@@ -755,6 +756,7 @@
756 "privacy": "Գաղտնիություն",
757 "privacy_and_security": "Գաղտնիություն և անվտանգություն",
758 "privacy_and_security_desc": "Կազմաձևեք նույնականացման և անվտանգության կարգավորումները և կարգավորեք Cake 2FA-ն։",
759 + "privacy_desc": "Փոխեք գաղտնիության կարգավորումները և միացրեք գաղտնիության հատուկ գործառույթները:",
760 "privacy_features": "Գաղտնիության գործառույթներ",
761 "privacy_policy": "Գաղտնիության քաղաքականություն",
762 "privacy_settings": "Գաղտնիության կարգավորումներ",
res/values/strings_id.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Terhubung",
243 "connection_sync": "Koneksi dan sinkronisasi",
244 "connections": "Koneksi",
245 + "connections_desc": "Kelola koneksi ke layanan dan API pihak ketiga.",
246 "connectWalletPrompt": "Hubungkan dompet Anda dengan WalletConnect untuk melakukan transaksi",
247 "contact": "Kontak",
248 "contact_list_contacts": "Kontak",
@@ -758,6 +759,7 @@
759 "privacy": "Privasi",
760 "privacy_and_security": "Privasi & Keamanan",
761 "privacy_and_security_desc": "Konfigurasikan pengaturan autentikasi dan keamanan serta siapkan Cake 2FA.",
762 + "privacy_desc": "Ubah pengaturan privasi dan aktifkan fitur privasi khusus.",
763 "privacy_features": "Fitur privasi",
764 "privacy_policy": "Kebijakan Privasi",
765 "privacy_settings": "Pengaturan Privasi",
res/values/strings_it.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Connesso",
243 "connection_sync": "Connessione e sincronizzazione",
244 "connections": "Connessioni",
245 + "connections_desc": "Gestisci le connessioni a servizi e API di terze parti.",
246 "connectWalletPrompt": "Collega il tuo wallet con WalletConnect per effettuare transazioni",
247 "contact": "Contatto",
248 "contact_list_contacts": "Contatti",
@@ -757,6 +758,7 @@
758 "privacy": "Privacy",
759 "privacy_and_security": "Privacy e sicurezza",
760 "privacy_and_security_desc": "Configura le impostazioni di autenticazione e sicurezza e imposta Cake 2FA.",
761 + "privacy_desc": "Modifica le impostazioni sulla privacy e attiva le funzionalità speciali sulla privacy.",
762 "privacy_features": "Funzionalità per la privacy",
763 "privacy_policy": "Informativa sulla privacy",
764 "privacy_settings": "Impostazioni sulla privacy",
res/values/strings_ja.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "接続済み",
243 "connection_sync": "接続と同期",
244 "connections": "接続",
245 + "connections_desc": "サービスおよびサードパーティ API への接続を管理します。",
246 "connectWalletPrompt": "WalletConnect でウォレットを接続して取引を行う",
247 "contact": "連絡先",
248 "contact_list_contacts": "連絡先",
@@ -757,6 +758,7 @@
758 "privacy": "プライバシー",
759 "privacy_and_security": "プライバシーとセキュリティ",
760 "privacy_and_security_desc": "認証とセキュリティの設定を構成し、Cake 2FA をセットアップします。",
761 + "privacy_desc": "プライバシー設定を変更し、特別なプライバシー機能を切り替えます。",
762 "privacy_features": "プライバシー機能",
763 "privacy_policy": "プライバシーポリシー",
764 "privacy_settings": "プライバシー設定",
res/values/strings_ko.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "연결됨",
243 "connection_sync": "연결 및 동기화",
244 "connections": "연결",
245 + "connections_desc": "서비스 및 타사 API에 대한 연결을 관리합니다.",
246 "connectWalletPrompt": "거래를 하려면 WalletConnect로 지갑을 연결하세요",
247 "contact": "연락처",
248 "contact_list_contacts": "연락처",
@@ -757,6 +758,7 @@
758 "privacy": "개인정보 보호",
759 "privacy_and_security": "개인정보 보호 및 보안",
760 "privacy_and_security_desc": "인증 및 보안 설정을 구성하고 Cake 2FA를 설정합니다.",
761 + "privacy_desc": "개인정보 보호 설정을 변경하고 특별 개인정보 보호 기능을 전환하세요.",
762 "privacy_features": "개인정보 보호 기능",
763 "privacy_policy": "개인정보처리방침",
764 "privacy_settings": "개인정보 보호 설정",
res/values/strings_my.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "ချိတ်ဆက်ပြီး",
243 "connection_sync": "ချိတ်ဆက်မှုနှင့် ထပ်တူညီစေခြင်း",
244 "connections": "ချိတ်ဆက်မှုများ",
245 + "connections_desc": "ဝန်ဆောင်မှုများနှင့် ပြင်ပကုမ္ပဏီ API များသို့ ချိတ်ဆက်မှုများကို စီမံပါ။",
246 "connectWalletPrompt": "ငွေလွှဲပြောင်းမှုများ ပြုလုပ်ရန် WalletConnect ဖြင့် သင့်ပိုက်ဆံအိတ်ကို ချိတ်ဆက်ပါ",
247 "contact": "ဆက်သွယ်ရန်",
248 "contact_list_contacts": "အဆက်အသွယ်များ",
@@ -756,6 +757,7 @@
757 "privacy": "ကိုယ်ရေးလုံခြုံမှု",
758 "privacy_and_security": "ကိုယ်ရေးကိုယ်တာနှင့် လုံခြုံရေး",
759 "privacy_and_security_desc": "အထောက်အထားစိစစ်ခြင်းနှင့် လုံခြုံရေးဆက်တင်များကို ပြင်ဆင်သတ်မှတ်ပြီး Cake 2FA ကို စနစ်ထည့်သွင်းပါ။",
760 + "privacy_desc": "ကိုယ်ရေးကိုယ်တာဆက်တင်များကိုပြောင်းလဲပြီး အထူးကိုယ်ရေးကိုယ်တာအင်္ဂါရပ်များကို ပြောင်းပါ။",
761 "privacy_features": "ကိုယ်ရေးလုံခြုံရေး အင်္ဂါရပ်များ",
762 "privacy_policy": "ကိုယ်ရေးအချက်အလက်မူဝါဒ",
763 "privacy_settings": "ကိုယ်ရေးကိုယ်တာ ဆက်တင်များ",
res/values/strings_nl.arb
+2
@@ -240,6 +240,7 @@
240 "connected": "Verbonden",
241 "connection_sync": "Verbinding en synchronisatie",
242 "connections": "Verbindingen",
243 + "connections_desc": "Beheer verbindingen met services en API's van derden.",
244 "connectWalletPrompt": "Verbind je wallet met WalletConnect om transacties uit te voeren",
245 "contact": "Contact",
246 "contact_list_contacts": "Contacten",
@@ -753,6 +754,7 @@
754 "privacy": "Privacy",
755 "privacy_and_security": "Privacy en beveiliging",
756 "privacy_and_security_desc": "Configureer de authenticatie- en beveiligingsinstellingen en stel Cake 2FA in.",
757 + "privacy_desc": "Wijzig privacy-instellingen en schakel speciale privacyfuncties in.",
758 "privacy_features": "Privacyfuncties",
759 "privacy_policy": "Privacybeleid",
760 "privacy_settings": "Privacy-instellingen",
res/values/strings_pl.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Połączono",
243 "connection_sync": "Połączenie i synchronizacja",
244 "connections": "Połączenia",
245 + "connections_desc": "Zarządzaj połączeniami z usługami i interfejsami API stron trzecich.",
246 "connectWalletPrompt": "Połącz swój portfel z WalletConnect, aby wykonywać transakcje",
247 "contact": "Kontakt",
248 "contact_list_contacts": "Kontakty",
@@ -755,6 +756,7 @@
756 "privacy": "Prywatność",
757 "privacy_and_security": "Prywatność i bezpieczeństwo",
758 "privacy_and_security_desc": "Skonfiguruj ustawienia uwierzytelniania i zabezpieczeń oraz skonfiguruj Cake 2FA.",
759 + "privacy_desc": "Zmień ustawienia prywatności i przełącz specjalne funkcje prywatności.",
760 "privacy_features": "Funkcje prywatności",
761 "privacy_policy": "Polityka prywatności",
762 "privacy_settings": "Ustawienia prywatności",
res/values/strings_pt.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Conectado",
243 "connection_sync": "Conexão e sincronização",
244 "connections": "Conexões",
245 + "connections_desc": "Gerencie conexões com serviços e APIs de terceiros.",
246 "connectWalletPrompt": "Conecte sua carteira ao WalletConnect para realizar transações",
247 "contact": "Contato",
248 "contact_list_contacts": "Contatos",
@@ -758,6 +759,7 @@
759 "privacy": "Privacidade",
760 "privacy_and_security": "Privacidade e Segurança",
761 "privacy_and_security_desc": "Configure as definições de autenticação e segurança e configure o Cake 2FA.",
762 + "privacy_desc": "Altere as configurações de privacidade e ative recursos especiais de privacidade.",
763 "privacy_features": "Recursos de privacidade",
764 "privacy_policy": "Política de Privacidade",
765 "privacy_settings": "Configurações de privacidade",
res/values/strings_ru.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Подключено",
243 "connection_sync": "Подключение и синхронизация",
244 "connections": "Подключения",
245 + "connections_desc": "Управляйте подключениями к сервисам и сторонним API.",
246 "connectWalletPrompt": "Подключите свой кошелек к WalletConnect, чтобы совершать транзакции",
247 "contact": "Контакт",
248 "contact_list_contacts": "Контакты",
@@ -757,6 +758,7 @@
758 "privacy": "Конфиденциальность",
759 "privacy_and_security": "Конфиденциальность и безопасность",
760 "privacy_and_security_desc": "Настройте параметры аутентификации и безопасности, а также настройте Cake 2FA.",
761 + "privacy_desc": "Измените настройки конфиденциальности и включите специальные функции конфиденциальности.",
762 "privacy_features": "Функции конфиденциальности",
763 "privacy_policy": "Политика конфиденциальности",
764 "privacy_settings": "Настройки конфиденциальности",
res/values/strings_th.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "เชื่อมต่อแล้ว",
243 "connection_sync": "การเชื่อมต่อและซิงค์",
244 "connections": "การเชื่อมต่อ",
245 + "connections_desc": "จัดการการเชื่อมต่อกับบริการและ API ของบุคคลที่สาม",
246 "connectWalletPrompt": "เชื่อมต่อกระเป๋าเงินของคุณกับ WalletConnect เพื่อทำธุรกรรม",
247 "contact": "ผู้ติดต่อ",
248 "contact_list_contacts": "รายชื่อผู้ติดต่อ",
@@ -756,6 +757,7 @@
757 "privacy": "ความเป็นส่วนตัว",
758 "privacy_and_security": "ความเป็นส่วนตัวและความปลอดภัย",
759 "privacy_and_security_desc": "กำหนดค่าการยืนยันตัวตนและการตั้งค่าความปลอดภัย และตั้งค่า Cake 2FA",
760 + "privacy_desc": "เปลี่ยนการตั้งค่าความเป็นส่วนตัวและสลับคุณสมบัติความเป็นส่วนตัวพิเศษ",
761 "privacy_features": "ฟีเจอร์ความเป็นส่วนตัว",
762 "privacy_policy": "นโยบายความเป็นส่วนตัว",
763 "privacy_settings": "การตั้งค่าความเป็นส่วนตัว",
res/values/strings_tl.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Nakakonekta",
243 "connection_sync": "Koneksyon at pag-sync",
244 "connections": "Mga koneksyon",
245 + "connections_desc": "Pamahalaan ang mga koneksyon sa mga serbisyo at mga third party na API.",
246 "connectWalletPrompt": "Ikonekta ang iyong wallet sa WalletConnect para makapag-transact",
247 "contact": "Kontak",
248 "contact_list_contacts": "Mga Contact",
@@ -756,6 +757,7 @@
757 "privacy": "Pagkapribado",
758 "privacy_and_security": "Pagkapribado at Seguridad",
759 "privacy_and_security_desc": "I-configure ang mga setting ng pagpapatotoo at seguridad at i-set up ang Cake 2FA.",
760 + "privacy_desc": "Baguhin ang mga setting ng privacy at i-toggle ang mga espesyal na feature sa privacy.",
761 "privacy_features": "Mga tampok sa privacy",
762 "privacy_policy": "Patakaran sa Privacy",
763 "privacy_settings": "Mga setting sa privacy",
res/values/strings_tr.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Bağlı",
243 "connection_sync": "Bağlantı ve senkronizasyon",
244 "connections": "Bağlantılar",
245 + "connections_desc": "Hizmetlere ve üçüncü taraf API'lere olan bağlantıları yönetin.",
246 "connectWalletPrompt": "İşlem yapmak için cüzdanınızı WalletConnect ile bağlayın",
247 "contact": "Kişi",
248 "contact_list_contacts": "Kişiler",
@@ -756,6 +757,7 @@
757 "privacy": "Gizlilik",
758 "privacy_and_security": "Gizlilik ve Güvenlik",
759 "privacy_and_security_desc": "Kimlik doğrulama ve güvenlik ayarlarını yapılandırın ve Cake 2FA'yı ayarlayın.",
760 + "privacy_desc": "Gizlilik ayarlarını değiştirin ve özel gizlilik özelliklerini değiştirin.",
761 "privacy_features": "Gizlilik özellikleri",
762 "privacy_policy": "Gizlilik Politikası",
763 "privacy_settings": "Gizlilik ayarları",
res/values/strings_uk.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Підключено",
243 "connection_sync": "Підключення та синхронізація",
244 "connections": "Підключення",
245 + "connections_desc": "Керуйте підключеннями до служб і сторонніх API.",
246 "connectWalletPrompt": "Підключіть свій гаманець через WalletConnect, щоб здійснювати транзакції",
247 "contact": "Контакт",
248 "contact_list_contacts": "Контакти",
@@ -756,6 +757,7 @@
757 "privacy": "Конфіденційність",
758 "privacy_and_security": "Конфіденційність і безпека",
759 "privacy_and_security_desc": "Налаштуйте параметри автентифікації та безпеки й налаштуйте Cake 2FA.",
760 + "privacy_desc": "Змініть налаштування конфіденційності та ввімкніть спеціальні функції конфіденційності.",
761 "privacy_features": "Функції приватності",
762 "privacy_policy": "Політика конфіденційності",
763 "privacy_settings": "Налаштування конфіденційності",
res/values/strings_ur.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "منسلک",
243 "connection_sync": "کنکشن اور ہم آہنگی",
244 "connections": "کنکشنز",
245 + "connections_desc": "سروسز اور تھرڈ پارٹی APIs کے کنکشنز کا نظم کریں۔",
246 "connectWalletPrompt": "لین دین کرنے کے لیے WalletConnect کے ذریعے اپنا والیٹ کنیکٹ کریں",
247 "contact": "رابطہ",
248 "contact_list_contacts": "رابطے",
@@ -758,6 +759,7 @@
759 "privacy": "رازداری",
760 "privacy_and_security": "رازداری اور سیکیورٹی",
761 "privacy_and_security_desc": "تصدیق اور سیکیورٹی کی ترتیبات کو کنفیگر کریں اور Cake 2FA سیٹ اپ کریں۔",
762 + "privacy_desc": "رازداری کی ترتیبات کو تبدیل کریں اور خصوصی رازداری کی خصوصیات کو ٹوگل کریں۔",
763 "privacy_features": "رازداری کی خصوصیات",
764 "privacy_policy": "رازداری کی پالیسی",
765 "privacy_settings": "پرائیویسی کی ترتیبات",
res/values/strings_vi.arb
+2
@@ -241,6 +241,7 @@
241 "connected": "Đã kết nối",
242 "connection_sync": "Kết nối và đồng bộ",
243 "connections": "Kết nối",
244 + "connections_desc": "Quản lý kết nối với các dịch vụ và API của bên thứ ba.",
245 "connectWalletPrompt": "Kết nối ví của bạn với WalletConnect để thực hiện các giao dịch",
246 "contact": "Liên hệ",
247 "contact_list_contacts": "Liên hệ",
@@ -754,6 +755,7 @@
755 "privacy": "Quyền riêng tư",
756 "privacy_and_security": "Quyền riêng tư & Bảo mật",
757 "privacy_and_security_desc": "Định cấu hình cài đặt xác thực và bảo mật, đồng thời thiết lập Cake 2FA.",
758 + "privacy_desc": "Thay đổi cài đặt quyền riêng tư và chuyển đổi các tính năng bảo mật đặc biệt.",
759 "privacy_features": "Tính năng quyền riêng tư",
760 "privacy_policy": "Chính sách bảo mật",
761 "privacy_settings": "Cài đặt quyền riêng tư",
res/values/strings_yo.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "Ti sopọ",
243 "connection_sync": "Ìsopọ̀ àti ìbámu",
244 "connections": "Awọn asopọ",
245 + "connections_desc": "Ṣakoso awọn asopọ si awọn iṣẹ ati awọn API ẹnikẹta.",
246 "connectWalletPrompt": "So apamọwọ rẹ pọ̀ mọ́ WalletConnect láti ṣe àwọn ìdúnàdúrà",
247 "contact": "Olùbáṣepọ̀",
248 "contact_list_contacts": "Àwọn olùbásọ̀rọ̀",
@@ -757,6 +758,7 @@
758 "privacy": "Àṣírí",
759 "privacy_and_security": "Ìpamọ́ & Ààbò",
760 "privacy_and_security_desc": "Ṣètò ìfàṣẹsí àti àwọn àtúnṣe aabo, kí o sì ṣètò Cake 2FA.",
761 + "privacy_desc": "Yi eto ipamọ pada ki o yi awọn ẹya aṣiri pataki pada.",
762 "privacy_features": "Awọn ẹya ìpamọ́",
763 "privacy_policy": "Ilana Aṣírí",
764 "privacy_settings": "Àwọn ààtò ìpamọ́",
res/values/strings_zh.arb
+2
@@ -242,6 +242,7 @@
242 "connected": "已连接",
243 "connection_sync": "连接与同步",
244 "connections": "连接",
245 + "connections_desc": "管理与服务和第三方 API 的连接。",
246 "connectWalletPrompt": "通过 WalletConnect 连接您的钱包以进行交易",
247 "contact": "联系人",
248 "contact_list_contacts": "联系人",
@@ -756,6 +757,7 @@
757 "privacy": "隐私",
758 "privacy_and_security": "隐私与安全",
759 "privacy_and_security_desc": "配置身份验证与安全设置,并设置 Cake 2FA。",
760 + "privacy_desc": "更改隐私设置并切换特殊隐私功能。",
761 "privacy_features": "隐私功能",
762 "privacy_policy": "隐私政策",
763 "privacy_settings": "隐私设置",