diff --git a/assets/new-ui/black_accent.svg.vec b/assets/new-ui/black_accent.svg.vec new file mode 100644 index 000000000..5d087f000 Binary files /dev/null and b/assets/new-ui/black_accent.svg.vec differ diff --git a/assets/new-ui/cake-setting.svg.vec b/assets/new-ui/cake-setting.svg.vec new file mode 100644 index 000000000..33efbf6b1 Binary files /dev/null and b/assets/new-ui/cake-setting.svg.vec differ diff --git a/assets/new-ui/chooser.svg.vec b/assets/new-ui/chooser.svg.vec index 69befbc78..4f8ed1364 100644 Binary files a/assets/new-ui/chooser.svg.vec and b/assets/new-ui/chooser.svg.vec differ diff --git a/assets/new-ui/dark.svg.vec b/assets/new-ui/dark.svg.vec new file mode 100644 index 000000000..d270f2152 Binary files /dev/null and b/assets/new-ui/dark.svg.vec differ diff --git a/assets/new-ui/light.svg.vec b/assets/new-ui/light.svg.vec new file mode 100644 index 000000000..7971583f3 Binary files /dev/null and b/assets/new-ui/light.svg.vec differ diff --git a/assets/new-ui/privacy.svg.vec b/assets/new-ui/privacy.svg.vec index f8d6e3e47..e50f9641b 100644 Binary files a/assets/new-ui/privacy.svg.vec and b/assets/new-ui/privacy.svg.vec differ diff --git a/assets/new-ui/security.svg.vec b/assets/new-ui/security.svg.vec index 4ed940fcd..97a589e92 100644 Binary files a/assets/new-ui/security.svg.vec and b/assets/new-ui/security.svg.vec differ diff --git a/assets/new-ui/settings_row_icons/privacy.svg.vec b/assets/new-ui/settings_row_icons/privacy.svg.vec index f8d6e3e47..e50f9641b 100644 Binary files a/assets/new-ui/settings_row_icons/privacy.svg.vec and b/assets/new-ui/settings_row_icons/privacy.svg.vec differ diff --git a/assets/new-ui/settings_row_icons/security.svg.vec b/assets/new-ui/settings_row_icons/security.svg.vec index 4ed940fcd..97a589e92 100644 Binary files a/assets/new-ui/settings_row_icons/security.svg.vec and b/assets/new-ui/settings_row_icons/security.svg.vec differ diff --git a/assets/new-ui/settings_row_icons/wc.svg.vec b/assets/new-ui/settings_row_icons/wc.svg.vec new file mode 100644 index 000000000..a071b14ee Binary files /dev/null and b/assets/new-ui/settings_row_icons/wc.svg.vec differ diff --git a/assets/new-ui/wallet-setting.svg.vec b/assets/new-ui/wallet-setting.svg.vec new file mode 100644 index 000000000..22d32c474 Binary files /dev/null and b/assets/new-ui/wallet-setting.svg.vec differ diff --git a/assets/new-ui/wc.svg.vec b/assets/new-ui/wc.svg.vec new file mode 100644 index 000000000..a071b14ee Binary files /dev/null and b/assets/new-ui/wc.svg.vec differ diff --git a/lib/di.dart b/lib/di.dart index a6b5c740a..156a36247 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -252,6 +252,7 @@ import 'package:cake_wallet/view_model/send/fees_view_model.dart'; import 'package:cake_wallet/view_model/send/send_template_view_model.dart'; import 'package:cake_wallet/view_model/send/send_view_model.dart'; import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart'; +import 'package:cake_wallet/view_model/settings/connection_sync_view_model.dart'; import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/mweb_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart'; @@ -1131,7 +1132,9 @@ Future setup({ return PowNodeListViewModel(_powNodeSource, appStore); }); - getIt.registerFactory(() => ConnectionSyncPage(getIt.get())); + getIt.registerFactory(() => ConnectionSyncViewModel(getIt.get(), getIt.get().wallet!)); + + getIt.registerFactory(() => ConnectionSyncPage(getIt.get())); getIt.registerFactory(() => SecurityBackupPage(getIt.get(), getIt.get(), getIt.get().wallet!.isHardwareWallet)); @@ -1140,7 +1143,7 @@ Future setup({ getIt.registerFactory(() => TrocadorProvidersPage(getIt.get())); - getIt.registerFactory(() => DomainLookupsPage(getIt.get())); + getIt.registerFactory(() => DomainLookupsPage(getIt.get())); getIt.registerFactory(() => DisplaySettingsPage(getIt.get())); @@ -1691,9 +1694,9 @@ Future setup({ getIt.registerFactoryParam((bool isPow, _) { if (isPow) { - return ManageNodesPage(isPow, powNodeListViewModel: getIt.get()); + return ManageNodesPage(isPow, powNodeListViewModel: getIt.get(), dashboardViewModel: getIt.get()); } - return ManageNodesPage(isPow, nodeListViewModel: getIt.get()); + return ManageNodesPage(isPow, nodeListViewModel: getIt.get(), dashboardViewModel: getIt.get()); }); getIt.registerFactory( diff --git a/lib/new-ui/pages/about_page.dart b/lib/new-ui/pages/about_page.dart index 7a9a15acc..a869ba1a3 100644 --- a/lib/new-ui/pages/about_page.dart +++ b/lib/new-ui/pages/about_page.dart @@ -2,11 +2,11 @@ import 'dart:math'; import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart'; import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart'; import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart'; import 'package:cake_wallet/src/widgets/cake_image_widget.dart'; import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; import 'package:url_launcher/url_launcher.dart'; // written by people who happened to read my slack message in 2025 @@ -52,61 +52,60 @@ class _AboutPageState extends State { @override Widget build(BuildContext context) { - return Container( - color: Theme.of(context).colorScheme.surface, - child: Column(children: [ - ModalTopBar( - title: S.of(context).about, - leadingIcon: Icon(Icons.arrow_back_ios_new), - onLeadingPressed: Navigator.of(context).pop, - ), - Column( - children: [ - Column( - spacing: 16, - children: [ - SizedBox(), - GestureDetector( - onTap: _easterEgg, - child: CakeImageWidget( - imageUrl: "assets/new-ui/cake_squircle_icon.svg", - width: 128, - height: 128, - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - spacing: 8, - children: [ - Text( - "Cake Wallet", - style: TextStyle(fontSize: 32, fontWeight: FontWeight.w500), + return ModalPageWrapper( + topBar: ModalTopBar( + title: S.of(context).about, + leadingIcon: Icon(Icons.arrow_back_ios_new), + onLeadingPressed: Navigator.of(context).pop, + ), + content: Container( + color: Theme.of(context).colorScheme.surface, + child: Column(children: [ + Column( + children: [ + Column( + spacing: 16, + children: [ + SizedBox(), + GestureDetector( + onTap: _easterEgg, + child: CakeImageWidget( + imageUrl: "assets/new-ui/cake_squircle_icon.svg", + width: 128, + height: 128, ), - Text(widget.appVersion, - style: TextStyle( - fontSize: 32, - fontWeight: FontWeight.w500, - color: Theme.of(context).colorScheme.onSurfaceVariant)) - ], - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: Wrap( + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 8, children: [ Text( - _bottomText, - textAlign: TextAlign.center, - style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant), + "Cake Wallet", + style: TextStyle(fontSize: 32, fontWeight: FontWeight.w500), ), + Text(widget.appVersion, + style: TextStyle( + fontSize: 32, + fontWeight: FontWeight.w500, + color: Theme.of(context).colorScheme.onSurfaceVariant)) ], ), - ), - ], - ), - SizedBox(height: 32), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: NewListSections(sections: { + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: Wrap( + children: [ + Text( + _bottomText, + textAlign: TextAlign.center, + style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant), + ), + ], + ), + ), + ], + ), + SizedBox(height: 32), + NewListSections(sections: { "": [ ListItemRegularRow( keyValue: "official website", @@ -146,10 +145,10 @@ class _AboutPageState extends State { foregroundColor: Theme.of(context).colorScheme.primary, trailingIconSize: 10) ] - }), - ) - ], - ) - ])); + }) + ], + ) + ])), + ); } } diff --git a/lib/new-ui/pages/settings_page.dart b/lib/new-ui/pages/settings_page.dart index 470d745b2..76446f0f9 100644 --- a/lib/new-ui/pages/settings_page.dart +++ b/lib/new-ui/pages/settings_page.dart @@ -9,6 +9,7 @@ import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; import "package:cw_core/wallet_type.dart"; @@ -18,8 +19,12 @@ bool _falseFunc(DashboardViewModel _) => false; bool _isBtc(DashboardViewModel vm) => vm.wallet.type == WalletType.bitcoin; +bool _hasLightning(DashboardViewModel vm) => vm.hasLightning; + bool _hasMweb(DashboardViewModel vm) => vm.hasMweb; +bool _hasWalletConnect(DashboardViewModel vm) => vm.hasWalletConnect; + bool _isCupcake(DashboardViewModel vm) => vm.wallet.hardwareWalletType == HardwareWalletType.cupcake; class SettingsListItem { @@ -42,21 +47,21 @@ class SettingsSectionData { const SettingsSectionData(this.title, this.titleIconPath, this.items); static SettingsSectionData walletSettings = - SettingsSectionData(S.current.wallet_settings, "assets/new-ui/wallet_settings.svg", [ + SettingsSectionData(S.current.wallet_settings, "assets/new-ui/wallet-setting.svg", [ SettingsListItem("assets/new-ui/settings_row_icons/nodes.svg", S.current.nodes, Routes.manageNodes), SettingsListItem("assets/new-ui/settings_row_icons/privacy.svg", S.current.privacy, Routes.privacyPage), SettingsListItem("assets/new-ui/settings_row_icons/seed.svg", S.current.seed_and_keys, Routes.showKeys, routeArgs: true, requireAuth: true, use2fa: (vm)=>vm.settingsStore.shouldRequireTOTP2FAForAllSecurityAndBackupSettings), - SettingsListItem("assets/new-ui/settings_row_icons/lightning_username.svg", - "Lightning ${S.current.username}", Routes.lightningUsernamePage, condition: _isBtc), - SettingsListItem("assets/new-ui/settings_row_icons/silent-payments.svg", S.current.silent_payments_settings, Routes.silentPaymentsSettings, condition: _isBtc), - SettingsListItem("assets/new-ui/settings_row_icons/mweb.svg", S.current.litecoin_mweb_settings, Routes.mwebSettings, condition: _hasMweb), + SettingsListItem("assets/new-ui/settings_row_icons/lightning_username.svg", "Lightning ${S.current.username}", Routes.lightningUsernamePage, condition: _hasLightning), + SettingsListItem("assets/new-ui/settings_row_icons/wc.svg", S.current.walletConnect, Routes.walletConnectConnectionsListing, condition: _hasWalletConnect), + //SettingsListItem("assets/new-ui/settings_row_icons/silent-payments.svg", S.current.silent_payments_settings, Routes.silentPaymentsSettings, condition: _isBtc), + //SettingsListItem("assets/new-ui/settings_row_icons/mweb.svg", S.current.litecoin_mweb_settings, Routes.mwebSettings, condition: _hasMweb), SettingsListItem("assets/new-ui/settings_row_icons/cupcake.svg", S.current.export_outputs, Routes.urqrAnimatedPage, routeArgs: {'export-outputs': 'export-outputs'}, condition: _isCupcake), SettingsListItem("assets/new-ui/settings_row_icons/other.svg", S.current.other, Routes.otherSettingsPage), ]); static SettingsSectionData appSettings = - SettingsSectionData(S.current.app_settings, "assets/new-ui/app_settings.svg", [ + SettingsSectionData(S.current.app_settings, "assets/new-ui/cake-setting.svg", [ SettingsListItem("assets/new-ui/settings_row_icons/connections.svg", S.current.connections, Routes.connectionSync), // SettingsListItem("assets/new-ui/settings_row_icons/defaults.svg", "Defaults", ""), SettingsListItem("assets/new-ui/settings_row_icons/display.svg", S.current.display, Routes.displaySettingsPage), @@ -97,29 +102,26 @@ class SettingsMainPage extends StatelessWidget { @override Widget build(BuildContext context) { - Map> sections = - Map.fromEntries(SettingsSectionData.all.map((section) => MapEntry( - section.title, - section.items - .map((item) => item.condition(dashboardViewModel) - ? ListItemRegularRow( - keyValue: item.title, - label: item.title, - iconPath: item.iconPath, - onTap: () { - if (item.route.isNotEmpty) { - if(item.requireAuth) { - authService.authenticateAction(context, - conditionToDetermineIfToUse2FA: item.use2fa(dashboardViewModel), - route: item.route); - } else { - Navigator.of(context).pushNamed(item.route, arguments: item.routeArgs); - } - } - }) - : null) - .whereType() - .toList()))); + List buildItems(SettingsSectionData section) => section.items + .map((item) => item.condition(dashboardViewModel) + ? ListItemRegularRow( + keyValue: item.title, + label: item.title, + iconPath: item.iconPath, + onTap: () { + if (item.route.isNotEmpty) { + if (item.requireAuth) { + authService.authenticateAction(context, + conditionToDetermineIfToUse2FA: item.use2fa(dashboardViewModel), + route: item.route); + } else { + Navigator.of(context).pushNamed(item.route, arguments: item.routeArgs); + } + } + }) + : null) + .whereType() + .toList(); return Container( color: Theme.of(context).colorScheme.surface, @@ -131,12 +133,31 @@ class SettingsMainPage extends StatelessWidget { onTrailingPressed: () {}, ), Expanded( - child: ListView( - controller: ModalScrollController.of(context), - children: [Padding( - padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 20.0), - child: NewListSections( - sections: sections, + child: ListView(controller: ModalScrollController.of(context), children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + spacing: 16, + children: SettingsSectionData.all.expand((section) { + return [ + if (section.titleIconPath.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Row( + spacing: 8, + children: [ + SvgPicture.asset(section.titleIconPath, + colorFilter: ColorFilter.mode( + Theme.of(context).colorScheme.onSurfaceVariant, + BlendMode.srcIn, + )), + Text(section.title, style: Theme.of(context).textTheme.titleMedium), + ], + ), + ), + NewListSections(sections: {section.title: buildItems(section)}), + ]; + }).toList(), ), ),] ), diff --git a/lib/new-ui/widgets/coins_page/top_bar_widget/sync_bar.dart b/lib/new-ui/widgets/coins_page/top_bar_widget/sync_bar.dart index 2c55d97fc..45e28bbbd 100644 --- a/lib/new-ui/widgets/coins_page/top_bar_widget/sync_bar.dart +++ b/lib/new-ui/widgets/coins_page/top_bar_widget/sync_bar.dart @@ -1,12 +1,14 @@ import 'package:cake_wallet/core/sync_status_title.dart'; +import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/new-ui/widgets/coins_page/top_bar_widget/pulsing_dot.dart'; -import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/screens/settings/manage_nodes_page.dart'; import 'package:cake_wallet/src/widgets/cake_image_widget.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cw_core/sync_status.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; class SyncBar extends StatelessWidget { SyncBar({super.key, required this.dashboardViewModel, required this.isSyncHeavy}); @@ -62,7 +64,13 @@ class SyncBar extends StatelessWidget { if (_showFullBar()) GestureDetector( onTap: () { - Navigator.of(context, rootNavigator: true).pushNamed(Routes.connectionSync); + CupertinoScaffold.showCupertinoModalBottomSheet( + context: context, + barrierColor: Colors.black.withAlpha(85), + builder: (context) => FractionallySizedBox( + child: Material( + child: getIt.get(param1: false), + ))); }, child: AnimatedSwitcher( duration: Duration(milliseconds: 100), @@ -162,7 +170,7 @@ class SyncBar extends StatelessWidget { children.add(CakeImageWidget(imageUrl: "assets/new-ui/mweb_sync.svg", colorFilter: - ColorFilter.mode(Theme.of(context).colorScheme.onSurfaceVariant, BlendMode.srcIn), + ColorFilter.mode(Theme.of(context).colorScheme.onSurfaceVariant, BlendMode.srcIn), )); } if (dashboardViewModel.hasSilentPayments) { @@ -186,4 +194,4 @@ class SyncBar extends StatelessWidget { bool _showDot() { return !isSyncHeavy && progressStatuses.contains(dashboardViewModel.status.runtimeType); } -} +} \ No newline at end of file diff --git a/lib/new-ui/widgets/modal_page_wrapper.dart b/lib/new-ui/widgets/modal_page_wrapper.dart new file mode 100644 index 000000000..717b2078c --- /dev/null +++ b/lib/new-ui/widgets/modal_page_wrapper.dart @@ -0,0 +1,88 @@ +import 'package:cake_wallet/new-ui/widgets/modal_header.dart'; +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart'; +import 'package:flutter/material.dart'; +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; + +void nothing(){} + +class ModalPageWrapper extends StatelessWidget { + ModalPageWrapper( + {super.key, + required this.content, + required this.topBar, + this.header, + this.bottomContent, + this.horizontalPadding = 18.0, + this.verticalPadding = 72.0}) { + } + + final Widget content; + final Widget? bottomContent; + final ModalTopBar topBar; + final ModalHeader? header; + final double horizontalPadding; + final double verticalPadding; + + @override + Widget build(BuildContext context) { + const gradientSize = 84; + + return Container( + color: Theme.of(context).colorScheme.surface, + child: Scaffold( + resizeToAvoidBottomInset: true, + body: Stack( + alignment: Alignment.topCenter, + children: [ + Positioned.fill( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: horizontalPadding), + child: CustomScrollView( + controller: ModalScrollController.of(context), + physics: ClampingScrollPhysics(), + slivers: [ + SliverToBoxAdapter(child: SizedBox(height: verticalPadding)), + if (header != null) ...[ + SliverToBoxAdapter(child: header), + SliverToBoxAdapter(child: SizedBox(height: 20)), + ], + SliverSafeArea(sliver: SliverToBoxAdapter(child: content)), + SliverToBoxAdapter(child: SizedBox(height: verticalPadding)), + ], + ) + )), + if (bottomContent != null) + Positioned( + bottom: 12, + left: horizontalPadding, + right: horizontalPadding, + child: SafeArea(child: bottomContent!), + ), + Container( + height: (MediaQuery.of(context).padding.top + gradientSize), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + colors: [ + Theme.of(context).colorScheme.surface.withAlpha(5), + Theme.of(context).colorScheme.surface.withAlpha(25), + Theme.of(context).colorScheme.surface.withAlpha(50), + Theme.of(context).colorScheme.surface.withAlpha(100), + Theme.of(context).colorScheme.surface.withAlpha(150), + Theme.of(context).colorScheme.surface.withAlpha(200), + Theme.of(context).colorScheme.surface.withAlpha(235), + Theme.of(context).colorScheme.surface.withAlpha(255), + Theme.of(context).colorScheme.surface.withAlpha(255), + Theme.of(context).colorScheme.surface.withAlpha(255), + ], + ), + ), + ), + topBar, + ], + ), + ), + ); + } +} diff --git a/lib/new-ui/widgets/receive_page/receive_top_bar.dart b/lib/new-ui/widgets/receive_page/receive_top_bar.dart index f92f00e7e..9de76d6e1 100644 --- a/lib/new-ui/widgets/receive_page/receive_top_bar.dart +++ b/lib/new-ui/widgets/receive_page/receive_top_bar.dart @@ -6,14 +6,14 @@ void nothing(){} class ModalTopBar extends StatelessWidget { ModalTopBar( {super.key, - required this.title, + required this.title, this.subtitle, - this.onLeadingPressed=nothing, - this.onTrailingPressed=nothing, - this.leadingIcon, - this.trailingIcon, - this.leadingWidget, - this.trailingWidget}) { + this.onLeadingPressed=nothing, + this.onTrailingPressed=nothing, + this.leadingIcon, + this.trailingIcon, + this.leadingWidget, + this.trailingWidget}) { if(leadingIcon != null && leadingWidget != null) { throw Exception("Cannot have both leadingIcon and leadingWidget"); } @@ -38,10 +38,10 @@ class ModalTopBar extends StatelessWidget { return Padding( padding: const EdgeInsets.all(18), child: Stack( - alignment: Alignment.center, + alignment: Alignment.topCenter, children: [ - Align( - alignment: Alignment.center, + Positioned( + top: 6, child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, @@ -72,11 +72,11 @@ class ModalTopBar extends StatelessWidget { if (leadingIcon != null || leadingWidget != null) leadingIcon != null ? ModernButton( - key: ValueKey(leadingIcon.hashCode), - size: buttonSize, - onPressed: onLeadingPressed, - icon: leadingIcon!, - iconColor: Theme.of(context).colorScheme.onSurfaceVariant) + key: ValueKey(leadingIcon.hashCode), + size: buttonSize, + onPressed: onLeadingPressed, + icon: leadingIcon!, + iconColor: Theme.of(context).colorScheme.onSurfaceVariant) : leadingWidget! else Container(width: buttonSize), @@ -85,10 +85,10 @@ class ModalTopBar extends StatelessWidget { duration: const Duration(milliseconds: 200), child: trailingIcon != null ? ModernButton( - key: ValueKey(trailingIcon.hashCode), - size: buttonSize, - onPressed: onTrailingPressed, - icon: trailingIcon!,) + key: ValueKey(trailingIcon.hashCode), + size: buttonSize, + onPressed: onTrailingPressed, + icon: trailingIcon!,) : trailingWidget!, ) else @@ -99,4 +99,4 @@ class ModalTopBar extends StatelessWidget { ), ); } -} +} \ No newline at end of file diff --git a/lib/src/screens/base_page.dart b/lib/src/screens/base_page.dart index e5f3781e1..4602c92b6 100644 --- a/lib/src/screens/base_page.dart +++ b/lib/src/screens/base_page.dart @@ -47,6 +47,8 @@ abstract class BasePage extends StatelessWidget { AppBarStyle get appBarStyle => AppBarStyle.regular; + bool get hideAppBar => false; + Widget Function(BuildContext, Widget)? get rootWrapper => null; MaterialThemeBase get currentTheme => getIt.get().currentTheme; @@ -191,24 +193,21 @@ abstract class BasePage extends StatelessWidget { : null, // color: Colors.grey[200], ), - child: Padding( - padding: const EdgeInsets.only(top:6.0), - child: Scaffold( - key: _scaffoldKey, - backgroundColor: pageBackgroundColor(context), - resizeToAvoidBottomInset: resizeToAvoidBottomInset, - extendBodyBehindAppBar: extendBodyBehindAppBar, - endDrawer: endDrawer, - appBar: appBar(context), - body: SafeArea( - left: false, - right: false, - top: false, - bottom: Platform.isAndroid, - child: body(context), - ), - floatingActionButton: floatingActionButton(context), + child: Scaffold( + key: _scaffoldKey, + backgroundColor: pageBackgroundColor(context), + resizeToAvoidBottomInset: resizeToAvoidBottomInset, + extendBodyBehindAppBar: extendBodyBehindAppBar, + endDrawer: endDrawer, + appBar: hideAppBar ? null : appBar(context), + body: SafeArea( + left: false, + right: false, + top: false, + bottom: Platform.isAndroid, + child: body(context), ), + floatingActionButton: floatingActionButton(context), ), ); }, diff --git a/lib/src/screens/nodes/widgets/node_form.dart b/lib/src/screens/nodes/widgets/node_form.dart index 96ef7d6df..525252d89 100644 --- a/lib/src/screens/nodes/widgets/node_form.dart +++ b/lib/src/screens/nodes/widgets/node_form.dart @@ -5,6 +5,7 @@ import 'package:cake_wallet/entities/new_ui_entities/list_item/list_Item_checkbo import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_text_field.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart'; +import 'package:cake_wallet/utils/feature_flag.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; @@ -140,6 +141,7 @@ class NodeFormState extends State { initialValue: vm.socksProxyAddress, validator: SocksProxyNodeAddressValidator(), ), + if(FeatureFlag.isAutomaticNodeSwitchingEnabled) ListItemCheckbox( keyValue: vm.autoSwitchingUIKey, label: S.current.enable_for_auto_switching, diff --git a/lib/src/screens/nodes/widgets/node_list_row.dart b/lib/src/screens/nodes/widgets/node_list_row.dart index 25d47775d..2e43ad3ff 100644 --- a/lib/src/screens/nodes/widgets/node_list_row.dart +++ b/lib/src/screens/nodes/widgets/node_list_row.dart @@ -7,11 +7,12 @@ import 'package:flutter/material.dart'; class NodeListRow extends StandardListRow { NodeListRow( {required String title, + String? subtitle, required this.node, required void Function(BuildContext context) onTap, required bool isSelected, required this.isPow}) - : super(title: title, onTap: onTap, isSelected: isSelected); + : super(title: title, onTap: onTap, isSelected: isSelected, subtitle: subtitle); final Node node; final bool isPow; diff --git a/lib/src/screens/settings/connection_sync_page.dart b/lib/src/screens/settings/connection_sync_page.dart index 61a88cf12..e609810f6 100644 --- a/lib/src/screens/settings/connection_sync_page.dart +++ b/lib/src/screens/settings/connection_sync_page.dart @@ -1,119 +1,219 @@ import 'dart:io'; +import 'package:cake_wallet/entities/exchange_api_mode.dart'; +import 'package:cake_wallet/entities/fiat_api_mode.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_selector.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/reactions/wallet_connect.dart'; +import 'package:cake_wallet/new-ui/widgets/modal_header.dart'; +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart'; +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/wallet_connect_button.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; +import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart'; +import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/utils/feature_flag.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; +import 'package:cake_wallet/view_model/settings/connection_sync_view_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; class ConnectionSyncPage extends BasePage { - ConnectionSyncPage(this.dashboardViewModel); + ConnectionSyncPage(this._connectionSyncViewModel); @override - String get title => S.current.connection_sync; + bool get hideAppBar => true; - final DashboardViewModel dashboardViewModel; + final ConnectionSyncViewModel _connectionSyncViewModel; @override Widget body(BuildContext context) { - return Container( - padding: EdgeInsets.only(top: 10), - child: Column( + return ModalPageWrapper( + topBar: ModalTopBar( + title: "", + leadingIcon: Icon(Icons.arrow_back_ios_new), + onLeadingPressed: () => Navigator.of(context).pop()), + header: ModalHeader( + iconPath: "assets/new-ui/settings_row_icons/connections.svg", + message: S.of(context).connections_desc, + title: S.of(context).connections), + content: Column( mainAxisSize: MainAxisSize.min, children: [ - SettingsCellWithArrow( - title: S.current.reconnect, - handler: (context) => _presentReconnectAlert(context), - ), - if (dashboardViewModel.hasRescan) ...[ - SettingsCellWithArrow( - title: dashboardViewModel.hasSilentPayments - ? S.current.silent_payments_scanning - : S.current.rescan, - handler: (context) => Navigator.of(context).pushNamed(Routes.rescan), - ), - ], - SettingsCellWithArrow( - title: S.current.manage_nodes, - handler: (context) => Navigator.of(context).pushNamed(Routes.manageNodes), - ), - if (Platform.isAndroid && FeatureFlag.isBackgroundSyncEnabled) ...[ - SettingsCellWithArrow( - title: S.current.background_sync, - handler: (context) => Navigator.of(context).pushNamed(Routes.backgroundSync), - ), - ], Observer( - builder: (context) { - if (!dashboardViewModel.hasPowNodes) return const SizedBox(); + builder: (context) => + NewListSections( + sections: { + "": [ + if (FeatureFlag.isInAppTorEnabled) + ListItemToggle( + keyValue: "enable_builtin_tor", + label: S.of(context).enable_builtin_tor, + value: _connectionSyncViewModel.builtinTor, + onChanged: (val) { + _connectionSyncViewModel.setBuiltinTor(val, context); + }), + ListItemToggle( + keyValue: "disable_automatic_exchange_status_updates", + label: S.of(context).disable_automatic_exchange_status_updates, + value: _connectionSyncViewModel.disableAutomaticExchangeStatusUpdates, + onChanged: (val) { + _connectionSyncViewModel.setDisableAutomaticExchangeStatusUpdates(val); + }), + if (_connectionSyncViewModel.canUseBlinkProtection) + ListItemToggle( + keyValue: "can_use_blink_protection", + label: S.of(context).use_blink_protection, + value: _connectionSyncViewModel.useBlinkProtection, + onChanged: (val) { + _connectionSyncViewModel.setUseBlinkProtection(val); + }), + if (_connectionSyncViewModel.canUseEtherscan) + ListItemToggle( + keyValue: "can_use_etherscan", + label: S.of(context).etherscan_history, + value: _connectionSyncViewModel.useEtherscan, + onChanged: (val) { + _connectionSyncViewModel.setUseEtherscan(val); + }), + if (_connectionSyncViewModel.canUsePolygonScan) + ListItemToggle( + keyValue: "can_use_polygonscan", + label: S.of(context).polygonscan_history, + value: _connectionSyncViewModel.usePolygonScan, + onChanged: (val) { + _connectionSyncViewModel.setUsePolygonScan(val); + }), + if (_connectionSyncViewModel.canUseBaseScan) + ListItemToggle( + keyValue: "can_use_basescan", + label: S.of(context).basescan_history, + value: _connectionSyncViewModel.canUseBaseScan, + onChanged: (val) { + _connectionSyncViewModel.setUseBaseScan(val); + }), + if (_connectionSyncViewModel.canUseArbiScan) + ListItemToggle( + keyValue: "can_use_arbiscan", + label: S.of(context).arbiscan_history, + value: _connectionSyncViewModel.useArbiScan, + onChanged: (val) { + _connectionSyncViewModel.setUsePolygonScan(val); + }), + if (_connectionSyncViewModel.canUseBscScan) + ListItemToggle( + keyValue: "can_use_bscscan", + label: S.of(context).bscscan_history, + value: _connectionSyncViewModel.useBscScan, + onChanged: (val) { + _connectionSyncViewModel.setUseBscScan(val); + }), + if (_connectionSyncViewModel.canUseTronGrid) + ListItemToggle( + keyValue: "can_use_trongrid", + label: S.of(context).trongrid_history, + value: _connectionSyncViewModel.useTronGrid, + onChanged: (val) { + _connectionSyncViewModel.setUsePolygonScan(val); + }), + if (_connectionSyncViewModel.canUseMempoolFeeAPI) + ListItemToggle( + keyValue: "enable_mempool_api", + label: S.of(context).enable_mempool_api, + value: _connectionSyncViewModel.useMempoolFeeAPI, + onChanged: (bool isEnabled) async { + if (!isEnabled) { + final bool confirmation = await showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: S.of(context).warning, + alertContent: S.of(context).disable_fee_api_warning, + rightButtonText: S.of(context).confirm, + leftButtonText: S.of(context).cancel, + actionRightButton: () => Navigator.of(context).pop(true), + actionLeftButton: () => Navigator.of(context).pop(false)); + }) ?? + false; + if (confirmation) { + _connectionSyncViewModel.setUseMempoolFeeAPI(isEnabled); + } + return; + } - return Column( - children: [ - SettingsCellWithArrow( - title: S.current.manage_pow_nodes, - handler: (context) => Navigator.of(context).pushNamed(Routes.managePowNodes), - ), - ], - ); - }, + _connectionSyncViewModel.setUseMempoolFeeAPI(isEnabled); + }), + if (Platform.isAndroid && FeatureFlag.isBackgroundSyncEnabled) + ListItemRegularRow( + keyValue: "background_sync", + label: S.of(context).background_sync, + onTap: () => Navigator.of(context).pushNamed(Routes.backgroundSync) + ), + if (_connectionSyncViewModel.hasPowNodes) + ListItemRegularRow( + keyValue: "manage_pow_nodes", + label: S.of(context).manage_pow_nodes, + onTap: () => Navigator.of(context).pushNamed(Routes.managePowNodes), + ), + ListItemSelector( + keyValue: "fiat_api", + label: S.of(context).fiat_api, + options: [_connectionSyncViewModel.fiatApiMode.title], + onTap: () async { + final items = FiatApiMode.all; + + final selectedAtIndex = + items.indexOf(_connectionSyncViewModel.fiatApiMode); + + await showPopUp( + context: context, + builder: (_) => Picker( + items: items, + selectedAtIndex: selectedAtIndex, + mainAxisAlignment: MainAxisAlignment.start, + onItemSelected: (FiatApiMode fiatApiMode) { + _connectionSyncViewModel.setFiatMode(fiatApiMode); + }, + isSeparated: false, + ), + ); + }), + ListItemSelector( + keyValue: "swap", + label: S.of(context).swap, + options: [_connectionSyncViewModel.exchangeStatus.title], + onTap: () async { + final items = ExchangeApiMode.all; + + final selectedAtIndex = + items.indexOf(_connectionSyncViewModel.exchangeStatus); + + await showPopUp( + context: context, + builder: (_) => Picker( + items: items, + selectedAtIndex: selectedAtIndex, + mainAxisAlignment: MainAxisAlignment.start, + onItemSelected: (ExchangeApiMode mode) { + _connectionSyncViewModel.setExchangeApiMode(mode); + }, + isSeparated: false, + ), + ); + }), + ListItemRegularRow( + keyValue: "domain_lookups", + label: S.of(context).domain_looks_up, + onTap: () => Navigator.of(context).pushNamed(Routes.domainLookupsPage) + ), + ], + } + ) ), - if (isWalletConnectCompatibleChain(dashboardViewModel.wallet.type) && - !dashboardViewModel.wallet.isHardwareWallet) ...[ // ToDo: Remove this line once WalletConnect is implemented - WalletConnectTile( - onTap: () => Navigator.of(context).pushNamed(Routes.walletConnectConnectionsListing), - ), - ], - if (FeatureFlag.isInAppTorEnabled) - Observer(builder: (context) { - return SettingsSwitcherCell( - leading: Container( - padding: EdgeInsets.symmetric(horizontal: 4, vertical: 1), - decoration: BoxDecoration( - color: Colors.red.shade100, - borderRadius: BorderRadius.circular(3), - ), - child: Text( - 'Alpha', - style: TextStyle( - color: Colors.red.shade700, - fontSize: 8, - fontWeight: FontWeight.bold, - ), - ), - ), - title: S.current.enable_builtin_tor, - value: dashboardViewModel.builtinTor, - onValueChange: (_, bool value) => dashboardViewModel.setBuiltinTor(value, context), - ); - }), ], ), ); } - - Future _presentReconnectAlert(BuildContext context) async { - await showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithTwoActions( - alertTitle: S.of(context).reconnection, - alertContent: S.of(context).reconnect_alert_text, - rightButtonText: S.of(context).ok, - leftButtonText: S.of(context).cancel, - actionRightButton: () async { - Navigator.of(context).pop(); - await dashboardViewModel.reconnect(); - }, - actionLeftButton: () => Navigator.of(context).pop()); - }, - ); - } } diff --git a/lib/src/screens/settings/display_settings_page.dart b/lib/src/screens/settings/display_settings_page.dart index 05a32262a..c10efc9d2 100644 --- a/lib/src/screens/settings/display_settings_page.dart +++ b/lib/src/screens/settings/display_settings_page.dart @@ -1,14 +1,18 @@ import 'package:cake_wallet/entities/bitcoin_amount_display_mode.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/language_service.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_selector.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart'; import 'package:cake_wallet/entities/sync_status_display_mode.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_theme_choice.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; +import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart'; +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart'; +import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/feature_flag.dart'; @@ -19,7 +23,6 @@ import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; class DisplaySettingsPage extends StatelessWidget { DisplaySettingsPage(this._displaySettingsViewModel); @@ -29,172 +32,228 @@ class DisplaySettingsPage extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - color: Theme.of(context).colorScheme.surface, - child: SafeArea( - top: false, - child: Column( - children: [ - ModalTopBar(title: S.of(context).display_settings,leadingIcon: Icon(Icons.arrow_back_ios_new),onLeadingPressed: () => Navigator.of(context).pop()), - Expanded( - child: SingleChildScrollView( - controller: ModalScrollController.of(context), - physics: ClampingScrollPhysics(), - child: Observer(builder: (_) { - return Container( - padding: EdgeInsets.only(top: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SettingsSwitcherCell( - title: S.of(context).apps, - value: _displaySettingsViewModel.shouldShowMarketPlaceInDashboard, - onValueChange: (_, bool value) { - _displaySettingsViewModel.setShouldShowMarketPlaceInDashbaord(value); - }, - ), - SettingsSwitcherCell( - title: S.of(context).show_address_book_popup, - value: _displaySettingsViewModel.showAddressBookPopup, - onValueChange: (_, bool value) { - _displaySettingsViewModel.setShowAddressBookPopup(value); - }, - ), - if (_displaySettingsViewModel.showZcashCardSetting) - SettingsSwitcherCell( - title: S.of(context).show_zcash_card, - value: _displaySettingsViewModel.showZcashCard, - onValueChange: (_, bool value) { - _displaySettingsViewModel.setShowZcashCard(value); - }, - ), - SettingsPickerCell( - title: S.current.sync_status_display_mode, - items: SyncStatusDisplayMode.values.toList(), - selectedItem: _displaySettingsViewModel.syncStatusDisplayMode, - onItemSelected: (SyncStatusDisplayMode mode) => - _displaySettingsViewModel.setSyncStatusDisplayMode(mode), - displayItem: (SyncStatusDisplayMode mode) => mode.title, - isGridView: false, - ), - if (_displaySettingsViewModel.showDisplayAmountsInSatoshiSetting) - SettingsPickerCell( - title: S.of(context).bitcoin_amount_display, - items: BitcoinAmountDisplayMode.all, - selectedItem: _displaySettingsViewModel.displayAmountsInSatoshi, - onItemSelected: _displaySettingsViewModel.setDisplayAmountsInSatoshi, - displayItem: (mode) => mode.title, - isGridView: false, - ), - //if (!isHaven) it does not work correctly - if (!_displaySettingsViewModel.disabledFiatApiMode) - SettingsPickerCell( - title: S.of(context).settings_currency, - searchHintText: S.of(context).search_currency, - items: FiatCurrency.all, - selectedItem: _displaySettingsViewModel.fiatCurrency, - onItemSelected: (FiatCurrency currency) => - _displaySettingsViewModel.setFiatCurrency(currency), - images: FiatCurrency.all - .map((e) => Image.asset("assets/images/flags/${e.countryCode}.png")) - .toList(), - isGridView: true, - matchingCriteria: (FiatCurrency currency, String searchText) { - return currency.title.toLowerCase().contains(searchText) || - currency.fullName.toLowerCase().contains(searchText); - }, - ), - SettingsPickerCell( - title: S.of(context).settings_change_language, - searchHintText: S.of(context).search_language, - items: LanguageService.list.keys.toList(), - displayItem: (dynamic code) { - return LanguageService.list[code] ?? ''; - }, - selectedItem: _displaySettingsViewModel.languageCode, - onItemSelected: _displaySettingsViewModel.onLanguageSelected, - images: LanguageService.list.keys - .map((e) => Image.asset( - "assets/images/flags/${LanguageService.localeCountryCode[e]}.png")) - .toList(), - matchingCriteria: (String code, String searchText) { - return LanguageService.list[code]?.toLowerCase().contains(searchText) ?? false; - }, - ), - - if (FeatureFlag.customBackgroundEnabled) - StandardListRow( - title: "Custom background", - isSelected: false, - onTap: (_) => _pickImage(context), - ), - - if (responsiveLayoutUtil.shouldRenderMobileUI && DeviceInfo.instance.isMobile) ...[ - SizedBox(height: 24), - Padding( - padding: const EdgeInsets.only(left: 24), - child: Text( - S.current.appearance, - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w400, - fontSize: 14, - height: 22 / 14, - color: Theme.of(context).colorScheme.onSurface, - ), - ), - ), - SizedBox(height: 12), - Container( - margin: EdgeInsets.symmetric(horizontal: 20), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainer, - borderRadius: BorderRadius.circular(16), - ), - child: Column( - children: [ - SettingsChoicesCell( - ChoicesListItem( - title: "", - items: ThemeMode.values, - selectedItem: _displaySettingsViewModel.themeMode, - onItemSelected: (ThemeMode themeMode) => - _displaySettingsViewModel.setThemeMode(themeMode), - displayItem: (ThemeMode themeMode) { - return themeMode.name[0].toUpperCase() + - themeMode.name.substring(1).toLowerCase(); - }, - ), - useGenericColor: false, - padding: EdgeInsets.all(12), - ), - Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHigh, - borderRadius: BorderRadius.circular(16), - ), - child: Column( - children: [ - Semantics( - label: S.of(context).color_theme, - child: SettingsThemeChoicesCell(_displaySettingsViewModel), - ), - ], - ), - ), - ], - ), - ), - ], - ], - ), - ); - }), - ), - ), - ], - ), + return ModalPageWrapper( + topBar: ModalTopBar( + title: S.of(context).display, + leadingIcon: Icon(Icons.arrow_back_ios_new), + onLeadingPressed: () => Navigator.of(context).pop(), ), - ); + content: Column( + spacing: 16, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (responsiveLayoutUtil.shouldRenderMobileUI && + DeviceInfo.instance.isMobile) ...[ + Padding( + padding: const EdgeInsets.only(left: 14, top: 14), + child: Text( + S.of(context).appearance, + style: Theme.of(context).textTheme.labelLarge?.copyWith( + height: 0.2, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ), + Container( + decoration: ShapeDecoration( + color: Theme.of(context).colorScheme.surfaceContainerHigh, + shape: RoundedSuperellipseBorder( + borderRadius: BorderRadius.circular(18))), + child: Column( + children: [ + SettingsChoicesCell( + ChoicesListItem( + title: "", + items: ThemeMode.values, + selectedItem: _displaySettingsViewModel.themeMode, + onItemSelected: (ThemeMode themeMode) => + _displaySettingsViewModel.setThemeMode(themeMode), + displayItem: (ThemeMode themeMode) { + return themeMode.name[0].toUpperCase() + + themeMode.name.substring(1).toLowerCase(); + }, + ), + useGenericColor: false, + padding: EdgeInsets.all(14), + ), + Container( + decoration: ShapeDecoration( + color: Theme.of(context).colorScheme.surfaceContainer, + shape: RoundedSuperellipseBorder( + borderRadius: BorderRadius.circular(18))), + child: Column( + children: [ + Semantics( + label: S.of(context).color_theme, + child: SettingsThemeChoicesCell(_displaySettingsViewModel), + ), + ], + ), + ), + ], + ), + ), + ], + Observer( + builder: (_) => NewListSections( + sections: { + "": [ + ListItemToggle( + keyValue: "apps", + label: S.of(context).apps, + value: _displaySettingsViewModel.shouldShowMarketPlaceInDashboard, + onChanged: (val) { + _displaySettingsViewModel.setShouldShowMarketPlaceInDashbaord(val); + }), + ListItemToggle( + keyValue: "display_settings_show_address_book_popup", + label: S.of(context).show_address_book_popup, + value: _displaySettingsViewModel.showAddressBookPopup, + onChanged: (val) { + _displaySettingsViewModel.setShowAddressBookPopup(val); + }), + ListItemToggle( + keyValue: "display_settings_disable_buy_button", + label: S.of(context).disable_buy, + value: _displaySettingsViewModel.disableTradeOption, + onChanged: (val) { + _displaySettingsViewModel.setDisableTradeOption(val); + }), + if (_displaySettingsViewModel.showZcashCardSetting) + ListItemToggle( + keyValue: "display_settings_show_zcashcard", + label: S.of(context).show_zcash_card, + value: _displaySettingsViewModel.showZcashCard, + onChanged: (val) { + _displaySettingsViewModel.setShowZcashCard(val); + }), + ListItemSelector( + keyValue: "display_settings_sync_status_display", + label: S.of(context).sync_status_display_mode, + options: [_displaySettingsViewModel.syncStatusDisplayMode.title], + onTap: () async { + final items = SyncStatusDisplayMode.values.toList(); + + final selectedAtIndex = + items.indexOf(_displaySettingsViewModel.syncStatusDisplayMode); + + await showPopUp( + context: context, + builder: (_) => Picker( + items: items, + selectedAtIndex: selectedAtIndex, + mainAxisAlignment: MainAxisAlignment.start, + onItemSelected: (SyncStatusDisplayMode mode) { + _displaySettingsViewModel.setSyncStatusDisplayMode(mode); + }, + displayItem: (SyncStatusDisplayMode mode) => mode.title, + isSeparated: false, + ), + ); + }), + if (_displaySettingsViewModel.showDisplayAmountsInSatoshiSetting) + ListItemRegularRow( + keyValue: "display_settings_bitcoin_amount_display", + label: S.of(context).bitcoin_amount_display, + trailingText: _displaySettingsViewModel.displayAmountsInSatoshi.title, + onTap: () async { + final items = BitcoinAmountDisplayMode.all; + + final selectedAtIndex = + items.indexOf(_displaySettingsViewModel.displayAmountsInSatoshi); + + await showPopUp( + context: context, + builder: (_) => Picker( + items: items, + selectedAtIndex: selectedAtIndex, + mainAxisAlignment: MainAxisAlignment.start, + onItemSelected: _displaySettingsViewModel.setDisplayAmountsInSatoshi, + displayItem: (BitcoinAmountDisplayMode mode) => mode.title, + isSeparated: false, + ), + ); + }), + if (!_displaySettingsViewModel.disabledFiatApiMode) + ListItemSelector( + keyValue: "display_settings_fiat_currency", + label: S.of(context).settings_currency, + options: [_displaySettingsViewModel.fiatCurrency.title], + onTap: () async { + final items = FiatCurrency.all; + + final selectedAtIndex = + items.indexOf(_displaySettingsViewModel.fiatCurrency); + + await showPopUp( + context: context, + builder: (_) => Picker( + items: items, + selectedAtIndex: selectedAtIndex, + mainAxisAlignment: MainAxisAlignment.start, + onItemSelected: (FiatCurrency currency) { + _displaySettingsViewModel.setFiatCurrency(currency); + }, + images: FiatCurrency.all + .map((e) => Image.asset("assets/images/flags/${e.countryCode}.png")) + .toList(), + hintText: S.of(context).search_currency, + isGridView: true, + matchingCriteria: (FiatCurrency currency, String searchText) { + return currency.title.toLowerCase().contains(searchText) || + currency.fullName.toLowerCase().contains(searchText); + }, + isSeparated: false, + + ), + ); + }), + ListItemSelector( + keyValue: "display_settings_language", + label: S.of(context).settings_change_language, + options: [LanguageService.list[_displaySettingsViewModel.languageCode] ?? ''], + onTap: () async { + final items = LanguageService.list.keys.toList(); + + final selectedAtIndex = + items.indexOf(_displaySettingsViewModel.languageCode); + + await showPopUp( + context: context, + builder: (_) => Picker( + displayItem: (dynamic code) { + return LanguageService.list[code] ?? ''; + }, + items: items, + selectedAtIndex: selectedAtIndex, + mainAxisAlignment: MainAxisAlignment.start, + onItemSelected: _displaySettingsViewModel.onLanguageSelected, + images: LanguageService.list.keys + .map((e) => Image.asset( + "assets/images/flags/${LanguageService.localeCountryCode[e]}.png")) + .toList(), + hintText: S.of(context).search_language, + matchingCriteria: (String code, String searchText) { + return LanguageService.list[code]?.toLowerCase().contains(searchText) ?? false; + }, + isSeparated: true, + + ), + ); + }), + ], + }, + ), + ), + if (FeatureFlag.customBackgroundEnabled) + StandardListRow( + title: "Custom background", + isSelected: false, + onTap: (_) => _pickImage(context), + ), + ], + ), + ); } // Function to pick an image from the gallery diff --git a/lib/src/screens/settings/domain_lookups_page.dart b/lib/src/screens/settings/domain_lookups_page.dart index ed5916437..b566892aa 100644 --- a/lib/src/screens/settings/domain_lookups_page.dart +++ b/lib/src/screens/settings/domain_lookups_page.dart @@ -1,17 +1,17 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; -import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart'; +import 'package:cake_wallet/view_model/settings/connection_sync_view_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; class DomainLookupsPage extends BasePage { - DomainLookupsPage(this._privacySettingsViewModel); + DomainLookupsPage(this._connectionsSyncViewModel); @override String get title => S.current.domain_looks_up; - final PrivacySettingsViewModel _privacySettingsViewModel; + final ConnectionSyncViewModel _connectionsSyncViewModel; @override Widget body(BuildContext context) { @@ -23,36 +23,36 @@ class DomainLookupsPage extends BasePage { children: [ SettingsSwitcherCell( title: 'Twitter', - value: _privacySettingsViewModel.lookupTwitter, - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsTwitter(value)), + value: _connectionsSyncViewModel.lookupTwitter, + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsTwitter(value)), SettingsSwitcherCell( title: 'Mastodon', - value: _privacySettingsViewModel.looksUpMastodon, - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsMastodon(value)), + value: _connectionsSyncViewModel.looksUpMastodon, + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsMastodon(value)), SettingsSwitcherCell( title: 'Yat service', - value: _privacySettingsViewModel.looksUpYatService, - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsYatService(value)), + value: _connectionsSyncViewModel.looksUpYatService, + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsYatService(value)), SettingsSwitcherCell( title: 'Unstoppable Domains', - value: _privacySettingsViewModel.looksUpUnstoppableDomains, - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsUnstoppableDomains(value)), + value: _connectionsSyncViewModel.looksUpUnstoppableDomains, + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsUnstoppableDomains(value)), SettingsSwitcherCell( title: 'OpenAlias', - value: _privacySettingsViewModel.looksUpOpenAlias, - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsOpenAlias(value)), + value: _connectionsSyncViewModel.looksUpOpenAlias, + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsOpenAlias(value)), SettingsSwitcherCell( title: 'Ethereum Name Service', - value: _privacySettingsViewModel.looksUpENS, - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsENS(value)), + value: _connectionsSyncViewModel.looksUpENS, + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsENS(value)), SettingsSwitcherCell( title: '.well-known', - value: _privacySettingsViewModel.looksUpWellKnown, - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsWellKnown(value)), + value: _connectionsSyncViewModel.looksUpWellKnown, + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsWellKnown(value)), SettingsSwitcherCell( title: 'Zano Aliases', - value: _privacySettingsViewModel.lookupsZanoAlias, - onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsZanoAlias(value)), + value: _connectionsSyncViewModel.lookupsZanoAlias, + onValueChange: (_, bool value) => _connectionsSyncViewModel.setLookupsZanoAlias(value)), //if (!isHaven) it does not work correctly ], diff --git a/lib/src/screens/settings/manage_nodes_page.dart b/lib/src/screens/settings/manage_nodes_page.dart index b96ea8756..c1cd92526 100644 --- a/lib/src/screens/settings/manage_nodes_page.dart +++ b/lib/src/screens/settings/manage_nodes_page.dart @@ -1,4 +1,8 @@ import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/new-ui/widgets/modal_header.dart'; +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart'; +import 'package:cake_wallet/new-ui/widgets/modern_button.dart'; +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; 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'; import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/utils/feature_flag.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart'; import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart'; import 'package:flutter/material.dart'; @@ -14,30 +19,46 @@ import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; class ManageNodesPage extends BasePage { - ManageNodesPage(this.isPow, {this.nodeListViewModel, this.powNodeListViewModel}) + ManageNodesPage(this.isPow, {this.nodeListViewModel, this.powNodeListViewModel, this.dashboardViewModel}) : assert((isPow && powNodeListViewModel != null) || (!isPow && nodeListViewModel != null)), assert(powNodeListViewModel == null || nodeListViewModel == null); + final DashboardViewModel? dashboardViewModel; final NodeListViewModel? nodeListViewModel; final PowNodeListViewModel? powNodeListViewModel; final bool isPow; + @override + bool get hideAppBar => true; + @override String get title => S.current.manage_nodes; @override Widget body(BuildContext context) { - return Padding( - padding: EdgeInsets.only(top: 10), - child: Column( + return ModalPageWrapper( + horizontalPadding: 0, + topBar: ModalTopBar( + title: S.of(context).manage_nodes, + leadingIcon: Icon(Icons.arrow_back_ios_new), + onLeadingPressed: () => Navigator.of(context).pop(), + trailingWidget: Row( + spacing: 8, + children: [ + if (dashboardViewModel?.hasRescan ?? true) + ModernButton( + size: 36, + icon: Icon(Icons.history), + onPressed: () => Navigator.of(context).pushNamed(Routes.rescan)), + ModernButton( + size: 36, + icon: Icon(Icons.add), + onPressed: () => Navigator.of(context).pushNamed(isPow ? Routes.newPowNode : Routes.newNode)) + ], + ), + ), + content: Column( children: [ - Semantics( - button: true, - child: NodeHeaderListRow( - title: S.of(context).add_new_node, - onTap: (_) async => await Navigator.of(context).pushNamed(isPow ? Routes.newPowNode : Routes.newNode), - ), - ), if (FeatureFlag.isAutomaticNodeSwitchingEnabled) Observer( builder: (_) => SettingsSwitcherCell( @@ -60,32 +81,34 @@ class ManageNodesPage extends BasePage { builder: (BuildContext context) { int itemsCount = nodeListViewModel?.nodes.length ?? powNodeListViewModel!.nodes.length; - return Flexible( - child: SectionStandardList( - scrollController: ModalScrollController.of(context), - sectionCount: 1, - dividerPadding: EdgeInsets.symmetric(horizontal: 24), - itemCounter: (int sectionIndex) => itemsCount, - itemBuilder: (_, index) { - return Observer( - builder: (context) { - final node = - nodeListViewModel?.nodes[index] ?? powNodeListViewModel!.nodes[index]; - late bool isSelected; - if (isPow) { - isSelected = node.keyIndex == powNodeListViewModel!.currentNode.keyIndex; - } else { - isSelected = node.keyIndex == nodeListViewModel!.currentNode.keyIndex; - } - final nodeListRow = NodeListRow( - title: node.uriRaw, - node: node, - isSelected: isSelected, - isPow: isPow, - onTap: (_) async { - if (isSelected) { - return; - } + return SectionStandardList( + scrollController: ModalScrollController.of(context), + sectionCount: 1, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + dividerPadding: EdgeInsets.symmetric(horizontal: 24), + itemCounter: (int sectionIndex) => itemsCount, + itemBuilder: (_, index) { + return Observer( + builder: (context) { + final node = + nodeListViewModel?.nodes[index] ?? powNodeListViewModel!.nodes[index]; + late bool isSelected; + if (isPow) { + isSelected = node.keyIndex == powNodeListViewModel!.currentNode.keyIndex; + } else { + isSelected = node.keyIndex == nodeListViewModel!.currentNode.keyIndex; + } + final nodeListRow = NodeListRow( + title: node.uriRaw, + subtitle: node.label!, + node: node, + isSelected: isSelected, + isPow: isPow, + onTap: (_) async { + if (isSelected) { + return; + } await showPopUp( context: context, @@ -110,11 +133,10 @@ class ManageNodesPage extends BasePage { ); }, ); - return nodeListRow; - }, - ); - }, - ), + return nodeListRow; + }, + ); + }, ); }, ), @@ -122,4 +144,21 @@ class ManageNodesPage extends BasePage { ), ); } + Future _presentReconnectAlert(BuildContext context) async { + await showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: S.of(context).reconnection, + alertContent: S.of(context).reconnect_alert_text, + rightButtonText: S.of(context).ok, + leftButtonText: S.of(context).cancel, + actionRightButton: () async { + Navigator.of(context).pop(); + await dashboardViewModel!.reconnect(); + }, + actionLeftButton: () => Navigator.of(context).pop()); + }, + ); + } } diff --git a/lib/src/screens/settings/mweb_node_page.dart b/lib/src/screens/settings/mweb_node_page.dart index 3f153f42b..32ba6886c 100644 --- a/lib/src/screens/settings/mweb_node_page.dart +++ b/lib/src/screens/settings/mweb_node_page.dart @@ -1,56 +1,64 @@ -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; +import 'package:cake_wallet/core/node_address_validator.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_text_field.dart'; +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart'; +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart'; +import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/view_model/settings/mweb_settings_view_model.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; - -class MwebNodePage extends BasePage { - MwebNodePage(this.mwebSettingsViewModelBase) - : _nodeUriController = TextEditingController(text: mwebSettingsViewModelBase.mwebNodeUri), - super(); +class MwebNodePage extends StatefulWidget { + const MwebNodePage(this.mwebSettingsViewModelBase, {super.key}); final MwebSettingsViewModelBase mwebSettingsViewModelBase; - final TextEditingController _nodeUriController; @override - String get title => S.current.litecoin_mweb_node; + State createState() => _MwebNodePageState(); +} + +class _MwebNodePageState extends State { + late final TextEditingController _nodeUriController = + TextEditingController(text: widget.mwebSettingsViewModelBase.mwebNodeUri); @override - Widget body(BuildContext context) { - return Stack( - fit: StackFit.expand, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 24), - child: Row( - children: [ - Expanded( - child: BaseTextFormField(controller: _nodeUriController), - ) - ], - ), + void dispose() { + _nodeUriController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ModalPageWrapper( + topBar: ModalTopBar( + title: S.current.litecoin_mweb_settings, + onLeadingPressed: Navigator.of(context).pop, + leadingIcon: Icon(Icons.arrow_back_ios_new)), + content: Container( + child: NewListSections( + controllers: { + widget.mwebSettingsViewModelBase.mwebNodeUri: _nodeUriController, + }, + sections: { + 'main': [ + ListItemTextField( + keyValue: widget.mwebSettingsViewModelBase.mwebNodeUri, + label: S.current.node_address, + validator: NodePathValidator(), + ), + ] + }), ), - Positioned( - child: Observer( - builder: (_) => LoadingPrimaryButton( - onPressed: () => save(context), - text: S.of(context).save, - color: Theme.of(context).colorScheme.primary, - textColor: Theme.of(context).colorScheme.onPrimary, - ), - ), - bottom: 24, - left: 24, - right: 24, - ) - ], + bottomContent: LoadingPrimaryButton( + onPressed: () => save(context), + text: S.of(context).save, + color: Theme.of(context).colorScheme.primary, + textColor: Theme.of(context).colorScheme.onPrimary, + ), ); } void save(BuildContext context) { - mwebSettingsViewModelBase.setMwebNodeUri(_nodeUriController.text); + widget.mwebSettingsViewModelBase.setMwebNodeUri(_nodeUriController.text); Navigator.pop(context); } } diff --git a/lib/src/screens/settings/other_settings_page.dart b/lib/src/screens/settings/other_settings_page.dart index fb1059ecc..78456f699 100644 --- a/lib/src/screens/settings/other_settings_page.dart +++ b/lib/src/screens/settings/other_settings_page.dart @@ -1,21 +1,24 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_selector.dart'; import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart'; +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/dev/moneroc_cache_debug.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/setting_priority_picker_cell.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart'; +import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart'; +import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/utils/feature_flag.dart'; import 'package:cake_wallet/utils/share_util.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart'; import 'package:cw_core/wallet_info.dart'; +import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/db/sqlite.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; class OtherSettingsPage extends BasePage { OtherSettingsPage(this._otherSettingsViewModel) { @@ -25,164 +28,206 @@ class OtherSettingsPage extends BasePage { } @override - String get title => S.current.other_settings; + bool get hideAppBar => true; final OtherSettingsViewModel _otherSettingsViewModel; + @override - Widget body(BuildContext context) => Observer( - builder: (_) => Container( - padding: EdgeInsets.only(top: 10), - child: Column( - children: [ - Expanded( - child: SingleChildScrollView( - child: Column( - children: [ - if (_otherSettingsViewModel.displayTransactionPriority) - _otherSettingsViewModel.walletType == WalletType.bitcoin - ? SettingsPriorityPickerCell( - title: S.current.settings_fee_priority, - items: priorityForWalletType(_otherSettingsViewModel.walletType), - displayItem: _otherSettingsViewModel.getDisplayBitcoinPriority, - selectedItem: _otherSettingsViewModel.transactionPriority, - customItemIndex: _otherSettingsViewModel.customPriorityItemIndex, - onItemSelected: _otherSettingsViewModel.onDisplayBitcoinPrioritySelected, - customValue: _otherSettingsViewModel.customBitcoinFeeRate, - maxValue: _otherSettingsViewModel.maxCustomFeeRate?.toDouble(), - ) - : SettingsPickerCell( - title: S.current.settings_fee_priority, - items: priorityForWalletType(_otherSettingsViewModel.walletType), - displayItem: _otherSettingsViewModel.getDisplayPriority, - selectedItem: _otherSettingsViewModel.transactionPriority, - onItemSelected: _otherSettingsViewModel.onDisplayPrioritySelected, - ), - if (_otherSettingsViewModel.changeRepresentativeEnabled) - SettingsCellWithArrow( - title: S.current.change_rep, - handler: (context) => Navigator.of(context).pushNamed(Routes.changeRep), - ), - if (_otherSettingsViewModel.changeHardwareWalletTypeEnabled) - SettingsCellWithArrow( - title: "Hardware wallet manufacturer", - handler: (context) => Navigator.of(context) - .pushNamed(Routes.restoreWalletFromHardwareWallet, arguments: { - "showUnavailable": false, - "availableHardwareWalletTypes": [ - HardwareWalletType.cupcake, - HardwareWalletType.coldcard, - HardwareWalletType.seedsigner, - ], - "onSelect": (BuildContext context, HardwareWalletType hwType) async { - await _otherSettingsViewModel.onHardwareWalletTypeChanged(hwType); - Navigator.pop(context); + Widget body(BuildContext context) { + return ModalPageWrapper( + topBar: ModalTopBar( + title: S.of(context).other, + leadingIcon: Icon(Icons.arrow_back_ios_new), + onLeadingPressed: () => Navigator.of(context).pop(), + ), + // header: ModalHeader( + // iconPath: "assets/new-ui/settings_row_icons/other.svg", + // message: "Other settings", + // title: S.of(context).other_settings), + content: NewListSections( + sections: { + "": [ + if (_otherSettingsViewModel.displayTransactionPriority) + _otherSettingsViewModel.walletType == WalletType.bitcoin + ? ListItemSelector( + keyValue: "fee_priority", + label: S.of(context).settings_fee_priority, + options: [_otherSettingsViewModel.transactionPriority.title], + onTap: () async { + + final items = priorityForWalletType(_otherSettingsViewModel.walletType); + + var selectedAtIndex = items.indexOf(_otherSettingsViewModel.transactionPriority); + double sliderValue = _otherSettingsViewModel.customBitcoinFeeRate ?? 0.0; + + await showPopUp( + context: context, + builder: (BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Picker( + items: items, + displayItem: (TransactionPriority item) => _otherSettingsViewModel.getDisplayBitcoinPriority(item, sliderValue.round()), + selectedAtIndex: selectedAtIndex, + customItemIndex: _otherSettingsViewModel.customPriorityItemIndex, + maxValue: _otherSettingsViewModel.maxCustomFeeRate?.toDouble(), + headerEnabled: false, + closeOnItemSelected: false, + mainAxisAlignment: MainAxisAlignment.center, + sliderValue: sliderValue, + onSliderChanged: (double newValue) => + setState(() => sliderValue = newValue), + onItemSelected: (TransactionPriority priority) { + setState(() => selectedAtIndex = items.indexOf(priority)); + _otherSettingsViewModel.onDisplayBitcoinPrioritySelected.call(priority, sliderValue); }, - }), - ), - if (_otherSettingsViewModel.walletType == WalletType.bitcoin) ...[ - SettingsCellWithArrow( - title: S.of(context).export_lightning_logs, - handler: onExportLNLog, - ), - SettingsCellWithArrow( - title: S.of(context).export_payjoin_logs, - handler: onExportPJLog, - ), - ], - SettingsCellWithArrow( - title: S.current.settings_terms_and_conditions, - handler: (context) => Navigator.of(context).pushNamed(Routes.readDisclaimer), - ), - if (FeatureFlag.hasDevOptions && - _otherSettingsViewModel.walletType == WalletType.monero) - SettingsCellWithArrow( - title: '[dev] monero background sync', - handler: (context) => - Navigator.of(context).pushNamed(Routes.devMoneroBackgroundSync), - ), - if (FeatureFlag.hasDevOptions && - [WalletType.monero, WalletType.wownero, WalletType.zano] - .contains(_otherSettingsViewModel.walletType)) - SettingsCellWithArrow( - title: '[dev] xmr call profiler', - handler: (context) => - Navigator.of(context).pushNamed(Routes.devMoneroCallProfiler), - ), - if (FeatureFlag.hasDevOptions && - [WalletType.monero].contains(_otherSettingsViewModel.walletType)) - SettingsCellWithArrow( - title: '[dev] xmr wallet cache debug', - handler: (context) => - Navigator.of(context).pushNamed(Routes.devMoneroWalletCacheDebug), - ), - if (FeatureFlag.hasDevOptions) - SettingsCellWithArrow( - title: '[dev] shared preferences', - handler: (context) => - Navigator.of(context).pushNamed(Routes.devSharedPreferences), - ), - if (FeatureFlag.hasDevOptions) - SettingsCellWithArrow( - title: '[dev] secure storage preferences', - handler: (context) => - Navigator.of(context).pushNamed(Routes.devSecurePreferences), - ), - if (FeatureFlag.hasDevOptions) - SettingsCellWithArrow( - title: '[dev] background sync logs', - handler: (context) => - Navigator.of(context).pushNamed(Routes.devBackgroundSyncLogs), - ), - if (FeatureFlag.hasDevOptions) - SettingsCellWithArrow( - title: '[dev] socket health logs', - handler: (context) => Navigator.of(context).pushNamed(Routes.devSocketHealthLogs), - ), - if (FeatureFlag.hasDevOptions) - SettingsCellWithArrow( - title: '[dev] network requests logs', - handler: (context) => Navigator.of(context).pushNamed(Routes.devNetworkRequests), - ), - if (FeatureFlag.hasDevOptions) - SettingsCellWithArrow( - title: '[dev] exchange provider logs', - handler: (context) => - Navigator.of(context).pushNamed(Routes.devExchangeProviderLogs), - ), - if (FeatureFlag.hasDevOptions) - SettingsCellWithArrow( - title: '[dev] *QR tools', - handler: (context) => Navigator.of(context).pushNamed(Routes.devQRTools), - ), - if (FeatureFlag.hasDevOptions) - SettingsCellWithArrow( - title: '[dev] exchange provider logs', - handler: (BuildContext context) => - Navigator.of(context).pushNamed(Routes.devExchangeProviderLogs), - ), - if (FeatureFlag.hasDevOptions) - SettingsCellWithArrow( - title: '[dev] browse sqlite db', - handler: (BuildContext context) async { - final data = await dumpDb(); - Navigator.of(context).push( - MaterialPageRoute(builder: (context) => JsonExplorerPage(data: data, title: 'sqlite db')), - ); - } - ), - ], + ); + }, + ); + }, + ); + _otherSettingsViewModel.onDisplayBitcoinPrioritySelected.call(items[selectedAtIndex], sliderValue); + } + ) + : ListItemSelector( + keyValue: "fee_priority", + label: S.of(context).settings_fee_priority, + options: [_otherSettingsViewModel.transactionPriority.title], + onTap: () async { + final selectedAtIndex = priorityForWalletType(_otherSettingsViewModel.walletType).indexOf(_otherSettingsViewModel.transactionPriority,); + + await showPopUp( + context: context, + builder: (_) => Picker( + items: priorityForWalletType(_otherSettingsViewModel.walletType), + displayItem: _otherSettingsViewModel.getDisplayPriority, + selectedAtIndex: selectedAtIndex, + mainAxisAlignment: MainAxisAlignment.start, + onItemSelected: (TransactionPriority item) => _otherSettingsViewModel.onDisplayBitcoinPrioritySelected.call(item, 0), + isSeparated: false, ), - ), + ); + }, + ), + if(_otherSettingsViewModel.changeRepresentativeEnabled) + ListItemRegularRow( + keyValue: "change_rep", + label: S.of(context).change_rep, + onTap: () => Navigator.of(context).pushNamed(Routes.changeRep) + ), + if (_otherSettingsViewModel.changeHardwareWalletTypeEnabled) + ListItemRegularRow( + keyValue: "hardware_wallet_manufacturer", + label: "Hardware wallet manufacturer", + onTap: () => Navigator.of(context) + .pushNamed(Routes.restoreWalletFromHardwareWallet, arguments: { + "showUnavailable": false, + "availableHardwareWalletTypes": [ + HardwareWalletType.cupcake, + HardwareWalletType.coldcard, + HardwareWalletType.seedsigner, + ], + "onSelect": (BuildContext context, HardwareWalletType hwType) async { + await _otherSettingsViewModel.onHardwareWalletTypeChanged(hwType); + Navigator.pop(context); + }, + }), + ), + ListItemRegularRow( + keyValue: "security_backup_page_sign_and_verify", + label: S.of(context).sign_verify_title, + onTap: () { + Navigator.of(context).pushNamed(Routes.signPage); + }), + ], + if(FeatureFlag.hasDevOptions) + "dev": [ + if(_otherSettingsViewModel.walletType == WalletType.bitcoin) ...[ + ListItemRegularRow( + keyValue: "export_lightning_logs", + label: S.of(context).export_lightning_logs, + onTap: () => onExportLNLog(context) ), - SettingsVersionCell( - title: S.of(context).version(_otherSettingsViewModel.currentVersion), + ListItemRegularRow( + keyValue: "export_payjoin_logs", + label: S.of(context).export_payjoin_logs, + onTap: () => onExportPJLog(context) ), ], - ), - ), - ); - + if (FeatureFlag.hasDevOptions && + _otherSettingsViewModel.walletType == WalletType.monero) + ListItemRegularRow( + keyValue: "[dev] monero background sync", + label: "[dev] monero background sync", + onTap: () => Navigator.of(context).pushNamed(Routes.devMoneroBackgroundSync) + ), + if (FeatureFlag.hasDevOptions && + [WalletType.monero, WalletType.wownero, WalletType.zano] + .contains(_otherSettingsViewModel.walletType)) + ListItemRegularRow( + keyValue: "[dev] xmr call profiler", + label: "[dev] xmr call profiler", + onTap: () => Navigator.of(context).pushNamed(Routes.devMoneroCallProfiler) + ), + if (FeatureFlag.hasDevOptions && + [WalletType.monero].contains(_otherSettingsViewModel.walletType)) + ListItemRegularRow( + keyValue: '[dev] xmr wallet cache debug', + label: '[dev] xmr wallet cache debug', + onTap: () => Navigator.of(context).pushNamed(Routes.devMoneroWalletCacheDebug) + ), + ListItemRegularRow( + keyValue: '[dev] shared preferences', + label: '[dev] shared preferences', + onTap: () => Navigator.of(context).pushNamed(Routes.devSharedPreferences) + ), + ListItemRegularRow( + keyValue: '[dev] secure storage preferences', + label: '[dev] secure storage preferences', + onTap: () => Navigator.of(context).pushNamed(Routes.devSecurePreferences) + ), + ListItemRegularRow( + keyValue: '[dev] background sync logs', + label: '[dev] background sync logs', + onTap: () => Navigator.of(context).pushNamed(Routes.devBackgroundSyncLogs) + ), + ListItemRegularRow( + keyValue: '[dev] socket health logs', + label: '[dev] socket health logs', + onTap: () => Navigator.of(context).pushNamed(Routes.devSocketHealthLogs) + ), + ListItemRegularRow( + keyValue: '[dev] network requests logs', + label: '[dev] network requests logs', + onTap: () => Navigator.of(context).pushNamed(Routes.devNetworkRequests) + ), + ListItemRegularRow( + keyValue: '[dev] exchange provider logs', + label: '[dev] exchange provider logs', + onTap: () => Navigator.of(context).pushNamed(Routes.devExchangeProviderLogs) + ), + ListItemRegularRow( + keyValue: '[dev] *QR tools', + label: '[dev] *QR tools', + onTap: () => Navigator.of(context).pushNamed(Routes.devExchangeProviderLogs) + ), + ListItemRegularRow( + keyValue: '[dev] browse sqlite db', + label: '[dev] browse sqlite db', + onTap: () async { + final data = await dumpDb(); + Navigator.of(context).push( + MaterialPageRoute(builder: (context) => + JsonExplorerPage(data: data, title: 'sqlite db')), + ); + } + ), + ] + } + ), + ); + } Future onExportLNLog(BuildContext context) async { final file = await _otherSettingsViewModel.getLightningLog(); diff --git a/lib/src/screens/settings/privacy_page.dart b/lib/src/screens/settings/privacy_page.dart index 8eb1f7851..c16223132 100644 --- a/lib/src/screens/settings/privacy_page.dart +++ b/lib/src/screens/settings/privacy_page.dart @@ -1,15 +1,12 @@ -import 'package:cake_wallet/entities/exchange_api_mode.dart'; -import 'package:cake_wallet/entities/fiat_api_mode.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart'; import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/new-ui/widgets/modal_header.dart'; +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart'; +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart'; -import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; -import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; -import 'package:cake_wallet/utils/device_info.dart'; -import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/settings/choices_list_item.dart'; +import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart'; import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; @@ -18,195 +15,94 @@ class PrivacyPage extends BasePage { PrivacyPage(this._privacySettingsViewModel); @override - String get title => S.current.privacy_settings; + bool get hideAppBar => true; final PrivacySettingsViewModel _privacySettingsViewModel; @override Widget body(BuildContext context) { - return SingleChildScrollView( - child: Container( - padding: EdgeInsets.only(top: 10), - child: Observer(builder: (_) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - SettingsChoicesCell( - ChoicesListItem( - title: S.current.fiat_api, - items: FiatApiMode.all, - selectedItem: _privacySettingsViewModel.fiatApiMode, - onItemSelected: (FiatApiMode fiatApiMode) => - _privacySettingsViewModel.setFiatMode(fiatApiMode), + return ModalPageWrapper( + topBar: ModalTopBar( + title: "", + leadingIcon: Icon(Icons.arrow_back_ios_new), + onLeadingPressed: () => Navigator.of(context).pop(), + ), + header: ModalHeader( + iconPath: "assets/new-ui/settings_row_icons/privacy.svg", + message: S.of(context).privacy_desc, + title: S.of(context).privacy), + content: SingleChildScrollView( + child: Container( + child: Observer(builder: (_) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + NewListSections( + sections: { + "1": [ + if (_privacySettingsViewModel.isAutoGenerateSubaddressesVisible) + ListItemToggle( + keyValue: "auto_generate_subaddresses", + label: _privacySettingsViewModel.isMoneroWallet + ? S.of(context).auto_generate_subaddresses + : S.of(context).auto_generate_addresses, + value: _privacySettingsViewModel.isAutoGenerateSubaddressesEnabled, + onChanged: (val) { + _privacySettingsViewModel.setAutoGenerateSubaddresses(val); + }), + ListItemToggle( + keyValue: "save_recipient_address", + label: S.of(context).settings_save_recipient_address, + value: _privacySettingsViewModel.shouldSaveRecipientAddress, + onChanged: (val) { + _privacySettingsViewModel.setShouldSaveRecipientAddress(val); + }), + if (_privacySettingsViewModel.canUsePayjoin) + ListItemToggle( + keyValue: "use_payjoin", + label: S.of(context).use_payjoin, + value: _privacySettingsViewModel.usePayjoin, + onChanged: (val) { + _privacySettingsViewModel.setUsePayjoin(val); + }), + if (_privacySettingsViewModel.canUseLightning) + ListItemToggle( + keyValue: "enable_lightning", + label: S.of(context).enable_lightning, + value: _privacySettingsViewModel.useLightning, + onChanged: (val) { + _privacySettingsViewModel.setUseLightning(val); + }), + ], + "": [ + if (_privacySettingsViewModel.isBitcoin) + ListItemRegularRow( + iconPath: "assets/new-ui/settings_row_icons/silent-payments.svg", + keyValue: "silent_payments", + label: S.of(context).silent_payments, + onTap: () => + Navigator.of(context).pushNamed(Routes.silentPaymentsSettings)), + if (_privacySettingsViewModel.isLitecoin) + ListItemRegularRow( + iconPath: "assets/new-ui/settings_row_icons/mweb.svg", + keyValue: "mweb", + label: "MWEB", + onTap: () => + Navigator.of(context).pushNamed(Routes.mwebSettings)), + if (_privacySettingsViewModel.hasCoinControl) + ListItemRegularRow( + iconPath: "assets/new-ui/settings_row_icons/coin-control.svg", + keyValue: "coin_control", + label: "Coin Control", + onTap: () => + Navigator.of(context).pushNamed(Routes.unspentCoinsList)), + ], + } ), - ), - SettingsChoicesCell( - ChoicesListItem( - title: S.current.swap, - items: ExchangeApiMode.all, - selectedItem: _privacySettingsViewModel.exchangeStatus, - onItemSelected: (ExchangeApiMode mode) => - _privacySettingsViewModel.setExchangeApiMode(mode), - ), - ), - if (_privacySettingsViewModel.canUseLightning) - SettingsSwitcherCell( - title: S.of(context).enable_lightning, - value: _privacySettingsViewModel.useLightning, - onValueChange: (_, value) => _privacySettingsViewModel.setUseLightning(value), - ), - if (_privacySettingsViewModel.canUsePayjoin) - SettingsSwitcherCell( - title: S.of(context).use_payjoin, - value: _privacySettingsViewModel.usePayjoin, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setUsePayjoin(value); - }, - ), - SettingsSwitcherCell( - title: S.current.settings_save_recipient_address, - value: _privacySettingsViewModel.shouldSaveRecipientAddress, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setShouldSaveRecipientAddress(value); - }), - if (_privacySettingsViewModel.isAutoGenerateSubaddressesVisible) - SettingsSwitcherCell( - title: _privacySettingsViewModel.isMoneroWallet - ? S.current.auto_generate_subaddresses - : S.current.auto_generate_addresses, - value: _privacySettingsViewModel.isAutoGenerateSubaddressesEnabled, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setAutoGenerateSubaddresses(value); - }, - ), - if (DeviceInfo.instance.isMobile) - SettingsSwitcherCell( - title: S.current.prevent_screenshots, - value: _privacySettingsViewModel.isAppSecure, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setIsAppSecure(value); - }, - ), - SettingsSwitcherCell( - title: S.current.disable_buy, - value: _privacySettingsViewModel.disableTradeOption, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setDisableTradeOption(value); - }, - ), - SettingsSwitcherCell( - title: S.current.disable_automatic_exchange_status_updates, - value: _privacySettingsViewModel.disableAutomaticExchangeStatusUpdates, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setDisableAutomaticExchangeStatusUpdates(value); - }, - ), - // SettingsSwitcherCell( - // title: S.current.disable_bulletin, - // value: _privacySettingsViewModel.disableBulletin, - // onValueChange: (BuildContext _, bool value) { - // _privacySettingsViewModel.setDisableBulletin(value); - // }, - // ), - if (_privacySettingsViewModel.canUseBlinkProtection) - SettingsSwitcherCell( - title: S.current.use_blink_protection, - value: _privacySettingsViewModel.useBlinkProtection, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setUseBlinkProtection(value); - }, - ), - if (_privacySettingsViewModel.canUseEtherscan) - SettingsSwitcherCell( - title: S.current.etherscan_history, - value: _privacySettingsViewModel.useEtherscan, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setUseEtherscan(value); - }, - ), - if (_privacySettingsViewModel.canUsePolygonScan) - SettingsSwitcherCell( - title: S.current.polygonscan_history, - value: _privacySettingsViewModel.usePolygonScan, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setUsePolygonScan(value); - }, - ), - if (_privacySettingsViewModel.canUseBaseScan) - SettingsSwitcherCell( - title: S.current.basescan_history, - value: _privacySettingsViewModel.useBaseScan, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setUseBaseScan(value); - }, - ), - if (_privacySettingsViewModel.canUseArbiScan) - SettingsSwitcherCell( - title: S.current.arbiscan_history, - value: _privacySettingsViewModel.useArbiScan, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setUseArbiScan(value); - }, - ), - if (_privacySettingsViewModel.canUseBscScan) - SettingsSwitcherCell( - title: S.current.bscscan_history, - value: _privacySettingsViewModel.useBscScan, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setUseBscScan(value); - }, - ), - if (_privacySettingsViewModel.canUseTronGrid) - SettingsSwitcherCell( - title: S.current.trongrid_history, - value: _privacySettingsViewModel.useTronGrid, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setUseTronGrid(value); - }, - ), - if (_privacySettingsViewModel.canUseMempoolFeeAPI) - SettingsSwitcherCell( - title: S.current.enable_mempool_api, - value: _privacySettingsViewModel.useMempoolFeeAPI, - onValueChange: (BuildContext _, bool isEnabled) async { - if (!isEnabled) { - final bool confirmation = await showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithTwoActions( - alertTitle: S.of(context).warning, - alertContent: S.of(context).disable_fee_api_warning, - rightButtonText: S.of(context).confirm, - leftButtonText: S.of(context).cancel, - actionRightButton: () => Navigator.of(context).pop(true), - actionLeftButton: () => Navigator.of(context).pop(false)); - }) ?? - false; - if (confirmation) { - _privacySettingsViewModel.setUseMempoolFeeAPI(isEnabled); - } - return; - } - - _privacySettingsViewModel.setUseMempoolFeeAPI(isEnabled); - }, - ), - SettingsCellWithArrow( - title: S.current.domain_looks_up, - handler: (context) => Navigator.of(context).pushNamed(Routes.domainLookupsPage), - ), - if(_privacySettingsViewModel.hasCoinControl) - SettingsCellWithArrow( - title: "Coin Control", - handler: (context) => Navigator.of(context).pushNamed(Routes.unspentCoinsList), - ), - // SettingsCellWithArrow( - // title: 'Trocador providers', - // handler: (context) => Navigator.of(context).pushNamed(Routes.trocadorProvidersPage), - // ), - ], - ); - }), + ], + ); + }), + ), ), ); } diff --git a/lib/src/screens/settings/security_backup_page.dart b/lib/src/screens/settings/security_backup_page.dart index 714b69535..37fb7c710 100644 --- a/lib/src/screens/settings/security_backup_page.dart +++ b/lib/src/screens/settings/security_backup_page.dart @@ -2,9 +2,12 @@ import 'dart:io'; import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart'; +import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_selector.dart'; import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart'; import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/new-ui/widgets/modal_header.dart'; +import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart'; +import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/generated/i18n.dart'; @@ -14,7 +17,6 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart'; import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/utils/device_info.dart'; -import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/utils/feature_flag.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart'; @@ -28,7 +30,10 @@ class SecurityBackupPage extends BasePage { final AuthService _authService; @override - String get title => S.current.security; + bool get hideAppBar => true; + + @override + String get title => S.current.security_and_backup; final SecuritySettingsViewModel _securitySettingsViewModel; @@ -36,170 +41,160 @@ class SecurityBackupPage extends BasePage { @override Widget body(BuildContext context) { - return Container( - padding: EdgeInsets.only(top: 10), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 18.0), - child: Column( - spacing: 16, - mainAxisSize: MainAxisSize.min, - children: [ - ModalHeader( - iconPath: "assets/new-ui/settings_row_icons/security.svg", - message: S.of(context).privacy_and_security_desc, - title: S.of(context).security), - Observer( - builder: (_) => NewListSections(sections: { - "": [ - if (DeviceInfo.instance.isMobile || Platform.isMacOS || Platform.isLinux) - ListItemToggle( - keyValue: "security_backup_page_allow_biometrics_button_key", - label: S.current.settings_allow_biometrical_authentication, - value: _securitySettingsViewModel.allowBiometricalAuthentication, - onChanged: (bool value) { - if (value) { - _authService.authenticateAction( - context, - onAuthSuccess: (isAuthenticatedSuccessfully) async { - if (isAuthenticatedSuccessfully) { - if (await _securitySettingsViewModel.biometricAuthenticated()) { - _securitySettingsViewModel.setAllowBiometricalAuthentication( - isAuthenticatedSuccessfully); - } - } else { + return ModalPageWrapper( + topBar: ModalTopBar( + title: "", + leadingIcon: Icon(Icons.arrow_back_ios_new), + onLeadingPressed: () => Navigator.of(context).pop()), + header: ModalHeader( + iconPath: "assets/new-ui/settings_row_icons/security.svg", + message: S.of(context).privacy_and_security_desc, + title: S.of(context).security), + content: Column( + spacing: 16, + mainAxisSize: MainAxisSize.min, + children: [ + Observer( + builder: (_) => NewListSections(sections: { + "": [ + if (DeviceInfo.instance.isMobile || Platform.isMacOS || Platform.isLinux) + ListItemToggle( + keyValue: "security_backup_page_allow_biometrics_button_key", + label: S.current.settings_allow_biometrical_authentication, + value: _securitySettingsViewModel.allowBiometricalAuthentication, + onChanged: (bool value) { + if (value) { + _authService.authenticateAction( + context, + onAuthSuccess: (isAuthenticatedSuccessfully) async { + if (isAuthenticatedSuccessfully) { + if (await _securitySettingsViewModel.biometricAuthenticated()) { _securitySettingsViewModel.setAllowBiometricalAuthentication( isAuthenticatedSuccessfully); } - }, - conditionToDetermineIfToUse2FA: _securitySettingsViewModel - .shouldRequireTOTP2FAForAllSecurityAndBackupSettings, - ); - } else { - _securitySettingsViewModel.setAllowBiometricalAuthentication(value); - } - }), - if (FeatureFlag.duressPinEnabled) - ListItemToggle( - keyValue: "security_backup_page_duress_pin_button_key", - label: "Duress PIN", - value: _securitySettingsViewModel.enableDuressPin, - onChanged: (bool value) { - _authService - .authenticateAction(context, route: Routes.securityBackupDuressPin, - onAuthSuccess: (isAuthenticatedSuccessfully) async { - if (isAuthenticatedSuccessfully) { - if (!value) { - _securitySettingsViewModel.setEnableDuressPin(value); - _securitySettingsViewModel.clearDuressPin(); - return; + } else { + _securitySettingsViewModel.setAllowBiometricalAuthentication( + isAuthenticatedSuccessfully); } - final res = await _showDuressPinDescription(context); - if (res) { - final confirmation = await _showDuressPinConfirmation(context); + }, + conditionToDetermineIfToUse2FA: _securitySettingsViewModel + .shouldRequireTOTP2FAForAllSecurityAndBackupSettings, + ); + } else { + _securitySettingsViewModel.setAllowBiometricalAuthentication(value); + } + }), + if (DeviceInfo.instance.isMobile) + ListItemToggle( + keyValue: "display_settings_prevent_screen_capture", + label: S.of(context).prevent_screenshots, + value: _securitySettingsViewModel.isAppSecure, + onChanged: (val) { + _securitySettingsViewModel.setIsAppSecure(val); + }), + if (FeatureFlag.duressPinEnabled) + ListItemToggle( + keyValue: "security_backup_page_duress_pin_button_key", + label: "Duress PIN", + value: _securitySettingsViewModel.enableDuressPin, + onChanged: (bool value) { + _authService + .authenticateAction(context, route: Routes.securityBackupDuressPin, + onAuthSuccess: (isAuthenticatedSuccessfully) async { + if (isAuthenticatedSuccessfully) { + if (!value) { + _securitySettingsViewModel.setEnableDuressPin(value); + _securitySettingsViewModel.clearDuressPin(); + return; + } + final res = await _showDuressPinDescription(context); + if (res) { + final confirmation = await _showDuressPinConfirmation(context); - if (confirmation) { - Navigator.of(context).pushNamed( - Routes.setupDuressPin, - arguments: - (PinCodeState pinCtx, String _) async { - pinCtx.close(); - _securitySettingsViewModel.setEnableDuressPin(true); - }, - ); - } + if (confirmation) { + Navigator.of(context).pushNamed( + Routes.setupDuressPin, + arguments: + (PinCodeState pinCtx, String _) async { + pinCtx.close(); + _securitySettingsViewModel.setEnableDuressPin(true); + }, + ); } } - }, - conditionToDetermineIfToUse2FA: _securitySettingsViewModel - .shouldRequireTOTP2FAForAllSecurityAndBackupSettings); - }), - ListItemRegularRow( - keyValue: "security_backup_page_require_pin_after_button_key", - label: S.current.require_pin_after, - trailingText: _securitySettingsViewModel.pinCodeRequiredDuration.toString(), - onTap: () async { - final items = PinCodeRequiredDuration.values; + } + }, + conditionToDetermineIfToUse2FA: _securitySettingsViewModel + .shouldRequireTOTP2FAForAllSecurityAndBackupSettings); + }), + ListItemSelector( + keyValue: "security_backup_page_require_pin_after_button_key", + label: S.current.require_pin_after, + options: [_securitySettingsViewModel.pinCodeRequiredDuration.toString()], + onTap: () async { + final items = PinCodeRequiredDuration.values; - final selectedAtIndex = - items.indexOf(_securitySettingsViewModel.pinCodeRequiredDuration); + final selectedAtIndex = + items.indexOf(_securitySettingsViewModel.pinCodeRequiredDuration); - await showPopUp( - context: context, - builder: (_) => Picker( - items: items, - selectedAtIndex: selectedAtIndex, - mainAxisAlignment: MainAxisAlignment.start, - onItemSelected: (PinCodeRequiredDuration item) { - _securitySettingsViewModel.setPinCodeRequiredDuration(item); - }, - isSeparated: false, - ), - ); - }), - // if (!_isHardwareWallet) - // ListItemRegularRow( - // keyValue: "security_backup_page_show_keys_button_key", - // label: S.current.show_keys, - // onTap: () { - // _authService.authenticateAction( - // context, - // route: Routes.showKeys, - // conditionToDetermineIfToUse2FA: _securitySettingsViewModel - // .shouldRequireTOTP2FAForAllSecurityAndBackupSettings, - // ); - // }), - // if (!SettingsStoreBase.walletPasswordDirectInput) - // ListItemRegularRow( - // keyValue: "security_backup_page_change_password_button_key", - // label: S.current.create_backup, - // onTap: () { - // _authService.authenticateAction( - // context, - // route: Routes.backup, - // conditionToDetermineIfToUse2FA: _securitySettingsViewModel - // .shouldRequireTOTP2FAForAllSecurityAndBackupSettings, - // ); - // }), - ListItemRegularRow( - keyValue: "security_backup_page_change_pin_button_key", - label: S.current.settings_change_pin, - onTap: () { - _authService.authenticateAction( - context, - route: Routes.setupPin, - arguments: (PinCodeState setupPinContext, String _) { - setupPinContext.close(); + await showPopUp( + context: context, + builder: (_) => Picker( + items: items, + selectedAtIndex: selectedAtIndex, + mainAxisAlignment: MainAxisAlignment.start, + onItemSelected: (PinCodeRequiredDuration item) { + _securitySettingsViewModel.setPinCodeRequiredDuration(item); }, - conditionToDetermineIfToUse2FA: _securitySettingsViewModel - .shouldRequireTOTP2FAForAllSecurityAndBackupSettings, - ); - }), - ListItemRegularRow( - keyValue: "security_backup_page_sign_and_verify", - label: S.current.sign_verify_title, - onTap: () { - Navigator.of(context).pushNamed(Routes.signPage); - }), - ListItemRegularRow( - keyValue: "security_backup_page_totp_2fa_button_key", - label: _securitySettingsViewModel.useTotp2FA - ? S.current.modify_2fa - : S.current.setup_2fa, - onTap: () { - _authService.authenticateAction( - context, - route: _securitySettingsViewModel.useTotp2FA - ? Routes.modify2FAPage - : Routes.setup2faInfoPage, - conditionToDetermineIfToUse2FA: _securitySettingsViewModel - .shouldRequireTOTP2FAForAllSecurityAndBackupSettings, - ); - }) - ] - }), - ), - ], - ), + isSeparated: false, + ), + ); + }), + // if (!_isHardwareWallet) + // ListItemRegularRow( + // keyValue: "security_backup_page_show_keys_button_key", + // label: S.current.show_keys, + // onTap: () { + // _authService.authenticateAction( + // context, + // route: Routes.showKeys, + // conditionToDetermineIfToUse2FA: _securitySettingsViewModel + // .shouldRequireTOTP2FAForAllSecurityAndBackupSettings, + // ); + // }), + ListItemRegularRow( + keyValue: "security_backup_page_change_pin_button_key", + label: S.current.settings_change_pin, + onTap: () { + _authService.authenticateAction( + context, + route: Routes.setupPin, + arguments: (PinCodeState setupPinContext, String _) { + setupPinContext.close(); + }, + conditionToDetermineIfToUse2FA: _securitySettingsViewModel + .shouldRequireTOTP2FAForAllSecurityAndBackupSettings, + ); + }), + ListItemRegularRow( + keyValue: "security_backup_page_totp_2fa_button_key", + label: _securitySettingsViewModel.useTotp2FA + ? S.current.modify_2fa + : S.current.setup_2fa, + onTap: () { + _authService.authenticateAction( + context, + route: _securitySettingsViewModel.useTotp2FA + ? Routes.modify2FAPage + : Routes.setup2faInfoPage, + conditionToDetermineIfToUse2FA: _securitySettingsViewModel + .shouldRequireTOTP2FAForAllSecurityAndBackupSettings, + ); + }) + ] + }), + ), + ], ), ); } diff --git a/lib/src/screens/settings/widgets/settings_choices_cell.dart b/lib/src/screens/settings/widgets/settings_choices_cell.dart index 798093f8d..fdf81d569 100644 --- a/lib/src/screens/settings/widgets/settings_choices_cell.dart +++ b/lib/src/screens/settings/widgets/settings_choices_cell.dart @@ -12,9 +12,13 @@ class SettingsChoicesCell extends StatelessWidget { @override Widget build(BuildContext context) { + final items = choicesListItem.items; + final selectedIndex = items.indexOf(choicesListItem.selectedItem); + final itemCount = items.length; + return Container( color: useGenericColor ? Theme.of(context).colorScheme.surface : null, - padding: padding ?? EdgeInsets.only(left: 24, right: 24, top: 16, bottom: 16), + padding: padding ?? const EdgeInsets.only(left: 24, right: 24, top: 16, bottom: 16), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -33,46 +37,68 @@ class SettingsChoicesCell extends StatelessWidget { Center( child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), + borderRadius: BorderRadius.circular(12), border: useGenericColor ? null : Border.all( color: Theme.of(context).colorScheme.surfaceContainerHighest, width: 1.5, ), - color: - useGenericColor ? Theme.of(context).colorScheme.surfaceContainerHighest : null, + color: useGenericColor + ? Theme.of(context).colorScheme.surfaceContainerHighest + : null, ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: choicesListItem.items.map((dynamic e) { - final isSelected = choicesListItem.selectedItem == e; - return Expanded( - child: GestureDetector( - onTap: () { - choicesListItem.onItemSelected.call(e); - }, - child: Container( - padding: EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: isSelected ? Theme.of(context).colorScheme.primary : null, - ), - child: Center( - child: Text( - choicesListItem.displayItem.call(e), - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: isSelected - ? Theme.of(context).colorScheme.onPrimary - : Theme.of(context).colorScheme.onSurfaceVariant, - fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, - ), + child: LayoutBuilder( + builder: (context, constraints) { + final itemWidth = constraints.maxWidth / itemCount; + return Stack( + children: [ + if (selectedIndex >= 0) + AnimatedPositioned( + duration: const Duration(milliseconds: 450), + curve: Curves.easeInOut, + left: selectedIndex * itemWidth, + top: 0, + bottom: 0, + width: itemWidth, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Theme.of(context).colorScheme.primary, + ), ), ), + Row( + children: items.map((dynamic e) { + final isSelected = choicesListItem.selectedItem == e; + return Expanded( + child: GestureDetector( + onTap: () => choicesListItem.onItemSelected.call(e), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 8), + color: Colors.transparent, + child: Center( + child: AnimatedDefaultTextStyle( + duration: const Duration(milliseconds: 220), + curve: Curves.easeInOut, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: isSelected + ? Theme.of(context).colorScheme.onPrimary + : Theme.of(context).colorScheme.onSurfaceVariant, + fontWeight: + isSelected ? FontWeight.w600 : FontWeight.normal, + ), + child: Text(choicesListItem.displayItem.call(e)), + ), + ), + ), + ), + ); + }).toList(), ), - ), + ], ); - }).toList(), + }, ), ), ), @@ -80,4 +106,4 @@ class SettingsChoicesCell extends StatelessWidget { ), ); } -} +} \ No newline at end of file diff --git a/lib/src/screens/settings/widgets/settings_switcher_cell.dart b/lib/src/screens/settings/widgets/settings_switcher_cell.dart index 34019c2c8..1c18036a7 100644 --- a/lib/src/screens/settings/widgets/settings_switcher_cell.dart +++ b/lib/src/screens/settings/widgets/settings_switcher_cell.dart @@ -13,6 +13,7 @@ class SettingsSwitcherCell extends StandardListRow { Key? key, this.padding, this.switchBackgroundColor, + this.height = 56, }) : super(title: title, isSelected: false, decoration: decoration, onTap: onTap, key: key); final bool value; @@ -20,6 +21,7 @@ class SettingsSwitcherCell extends StandardListRow { final void Function(BuildContext context, bool value)? onValueChange; final Widget? leading; final EdgeInsets? padding; + final double? height; @override Widget buildTrailing(BuildContext context) => StandardSwitch( @@ -33,7 +35,7 @@ class SettingsSwitcherCell extends StandardListRow { final leading = buildLeading(context); final trailing = buildTrailing(context); return Container( - height: 56, + height: height, padding: padding ?? EdgeInsets.only(left: 12, right: 12), child: TextButton( onPressed: () { diff --git a/lib/src/screens/settings/widgets/settings_theme_choice.dart b/lib/src/screens/settings/widgets/settings_theme_choice.dart index ed6d8ca66..c96743eb3 100644 --- a/lib/src/screens/settings/widgets/settings_theme_choice.dart +++ b/lib/src/screens/settings/widgets/settings_theme_choice.dart @@ -12,9 +12,9 @@ class SettingsThemeChoicesCell extends StatelessWidget { final DisplaySettingsViewModel _displaySettingsViewModel; - final double cellHeight = 25; + final double cellHeight = 12; final double cellWidth = 12; - final double cellRadius = 8; + final double cellRadius = 18; @override Widget build(BuildContext context) { @@ -28,14 +28,17 @@ class SettingsThemeChoicesCell extends StatelessWidget { final previewHeight = _getResponsivePreviewHeight(screenHeight); final previewWidth = previewHeight * 0.6; - return Container( + return AnimatedContainer( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, height: getHeight(context, currentTheme, currentTheme.hasAccentColors), - padding: EdgeInsets.all(12), + padding: EdgeInsets.all(14), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( + SizedBox( + height: previewHeight, child: ListView.builder( itemCount: availableThemes.length, scrollDirection: Axis.horizontal, @@ -50,16 +53,16 @@ class SettingsThemeChoicesCell extends StatelessWidget { onTap: () { _displaySettingsViewModel.onThemeSelected(theme); }, - child: Container( + child: AnimatedContainer( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, margin: EdgeInsets.only(right: 24), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(cellRadius), - border: isSelected - ? Border.all( - color: Theme.of(context).colorScheme.primary, + decoration: ShapeDecoration( + shape: RoundedSuperellipseBorder(borderRadius: BorderRadius.circular(cellRadius), + side: BorderSide( + color: isSelected ? Theme.of(context).colorScheme.primary : Colors.transparent, strokeAlign: BorderSide.strokeAlignOutside) - : null, - ), + )), child: ClipRRect( borderRadius: BorderRadius.circular(cellRadius), child: CakeImageWidget( @@ -75,56 +78,94 @@ class SettingsThemeChoicesCell extends StatelessWidget { }, ), ), - if (_displaySettingsViewModel.currentTheme.hasAccentColors) ...[ - SizedBox(height: cellHeight), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - S.of(context).accent_color, - style: Theme.of(context).textTheme.bodyMedium, - ), - Container( - child: Row( - children: availableAccentColors.map((accentColor) { - final isSelected = _displaySettingsViewModel - .isAccentColorSelected(accentColor.name.toLowerCase()); - return GestureDetector( - onTap: () { - _displaySettingsViewModel - .onAccentColorSelected(accentColor.name.toLowerCase()); - }, - child: Container( - width: 26, - height: 26, - margin: EdgeInsets.only(right: 11), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - border: isSelected - ? Border.all( - color: Theme.of(context).colorScheme.onSurfaceVariant, - width: 3) - : null, - color: accentColor.color, + AnimatedSwitcher( + duration: const Duration(milliseconds: 350), + switchInCurve: Curves.easeOut, + switchOutCurve: Curves.easeIn, + transitionBuilder: (child, animation) => FadeTransition( + opacity: animation, + child: SizeTransition( + sizeFactor: animation, + axisAlignment: -1, + child: child, + ), + ), + child: _displaySettingsViewModel.currentTheme.hasAccentColors + ? Column( + key: const ValueKey('accent'), + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.only(top: 14), + child: Container(height: 1, color: Theme.of(context).colorScheme.outlineVariant) + ), + SizedBox(height: cellHeight), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + S.of(context).accent_color, + style: Theme.of(context).textTheme.bodyMedium, ), - ), - ); - }).toList(), - ), - ), - ], - ), - ], + Row( + spacing: 4, + children: availableAccentColors.map((accentColor) { + final isSelected = _displaySettingsViewModel + .isAccentColorSelected(accentColor.name.toLowerCase()); + return GestureDetector( + onTap: () { + _displaySettingsViewModel + .onAccentColorSelected(accentColor.name.toLowerCase()); + }, + child: Stack( + children: [ + AnimatedOpacity( + duration: Duration(milliseconds: 350), + opacity: isSelected ? 1 : 0, + child: Container( + width:28,height:28,decoration: BoxDecoration(borderRadius: BorderRadius.circular(99999999),border: Border.all(color:Theme.of(context) + .colorScheme + .onSurface)) + ), + ), + AnimatedScale( + duration: Duration(milliseconds: 350), + scale: isSelected ? 0.8 : 1, + child: Container( + width: 28, + height: 28, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(99999999), + color: accentColor.color), + ), + ), + ], + ), + ); + }).toList(), + ), + ], + ), + ], + ) + : const SizedBox.shrink(key: ValueKey('no-accent')), + ), if (_displaySettingsViewModel.currentTheme is BlackTheme) - SettingsSwitcherCell( - title: S.current.oled_mode, - value: _displaySettingsViewModel.isBlackThemeOledEnabled, - onValueChange: (_, bool value) { - _displaySettingsViewModel.setBlackThemeOled(value); - }, - padding: EdgeInsets.zero, - switchBackgroundColor: currentTheme.colorScheme.secondaryContainer, + Padding( + padding: EdgeInsets.only(top: 12, bottom: 4), + child: Container(height: 1, color: Theme.of(context).colorScheme.outlineVariant) ), + if (_displaySettingsViewModel.currentTheme is BlackTheme) + SettingsSwitcherCell( + height: 40, + title: S.current.oled_mode, + value: _displaySettingsViewModel.isBlackThemeOledEnabled, + onValueChange: (_, bool value) { + _displaySettingsViewModel.setBlackThemeOled(value); + }, + padding: EdgeInsets.zero, + switchBackgroundColor: currentTheme.colorScheme.secondaryContainer, + ), ], ), ); @@ -135,14 +176,14 @@ class SettingsThemeChoicesCell extends StatelessWidget { double getHeight(BuildContext context, MaterialThemeBase theme, bool hasAccentColors) { final screenHeight = MediaQuery.of(context).size.height; - double baseHeight = (screenHeight * 0.25).clamp(150.0, screenHeight * 0.5); + double baseHeight = (screenHeight * 0.253).clamp(150.0, screenHeight * 0.5); if (hasAccentColors) { - baseHeight += (screenHeight * 0.05).clamp(35.0, 60.0); + baseHeight += (screenHeight * 0.60).clamp(35.0, 60.0); } if (theme is BlackTheme) { - baseHeight += (screenHeight * 0.08).clamp(48.0, 96.0); + baseHeight += (screenHeight * 0.059).clamp(48.0, 96.0); } return baseHeight; diff --git a/lib/src/widgets/new_list_row/list_Item_style_wrapper.dart b/lib/src/widgets/new_list_row/list_Item_style_wrapper.dart index a56137568..1e4d5e70f 100644 --- a/lib/src/widgets/new_list_row/list_Item_style_wrapper.dart +++ b/lib/src/widgets/new_list_row/list_Item_style_wrapper.dart @@ -6,20 +6,21 @@ class ListItemStyleWrapper extends StatelessWidget { required this.isFirstInSection, required this.isLastInSection, required this.builder, - this.hasImage, this.onTap, this.height = 50, + this.iconPath, }); + final String? iconPath; final bool isFirstInSection; final bool isLastInSection; - final bool ?hasImage; final double height; final VoidCallback? onTap; final Widget Function(BuildContext context, TextStyle textStyle, TextStyle labelStyle) builder; @override Widget build(BuildContext context) { + final theme = Theme.of(context); final textStyle = TextStyle( @@ -60,17 +61,17 @@ class ListItemStyleWrapper extends StatelessWidget { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: builder(context, textStyle, labelStyle))))), - if(hasImage == true && isLastInSection == false) Container( + if(iconPath != null && isLastInSection == false) Container( color: theme.colorScheme.surfaceContainer, child: Padding( - padding: const EdgeInsets.only(left: 48, right: 13), + padding: const EdgeInsets.only(left: 50, right: 13), child: Container(height: 1, color: theme.colorScheme.outlineVariant), ), ) else if(!isLastInSection) Container( color: theme.colorScheme.surfaceContainer, child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 13), + padding: const EdgeInsets.symmetric(horizontal: 12), child: Container(height: 1, color: theme.colorScheme.outlineVariant), ), ) diff --git a/lib/src/widgets/new_list_row/list_item_checkbox_widget.dart b/lib/src/widgets/new_list_row/list_item_checkbox_widget.dart index 0d2422182..823328723 100644 --- a/lib/src/widgets/new_list_row/list_item_checkbox_widget.dart +++ b/lib/src/widgets/new_list_row/list_item_checkbox_widget.dart @@ -37,6 +37,7 @@ class _ListItemCheckboxWidgetState extends State { @override Widget build(BuildContext context) { return ListItemStyleWrapper( + iconPath: widget.iconPath, onTap: widget.onTap ?? () { widget.onChanged(!widget.value); }, @@ -53,11 +54,11 @@ class _ListItemCheckboxWidgetState extends State { children: [ if (widget.iconPath != null) widget.iconPath!.toLowerCase().endsWith("svg") - ? CakeImageWidget(imageUrl:widget.iconPath!, height: 24, width: 24) + ? CakeImageWidget(imageUrl:widget.iconPath!, height: 26, width: 26) : Image.asset( widget.iconPath!, - width: 24, - height: 24, + width: 26, + height: 26, ), Expanded( child: Column( diff --git a/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart b/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart index 36e509229..7705cdcac 100644 --- a/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart +++ b/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart @@ -12,7 +12,6 @@ class ListItemRegularRowWidget extends StatelessWidget { this.trailingText, this.iconPath, this.onTap, - this.hasImage, this.isFirstInSection = false, this.isLastInSection = false, this.showArrow = true, @@ -28,7 +27,6 @@ class ListItemRegularRowWidget extends StatelessWidget { final String? trailingText; final String? iconPath; final VoidCallback? onTap; - final bool? hasImage; final bool isFirstInSection; final bool isLastInSection; final bool showArrow; @@ -46,7 +44,7 @@ class ListItemRegularRowWidget extends StatelessWidget { return ListItemStyleWrapper( onTap: onTap, - hasImage: iconPath != null ? true : false, + iconPath: iconPath, isFirstInSection: isFirstInSection, isLastInSection: isLastInSection, height: subtitle != null ? 64 : 50, diff --git a/lib/src/widgets/new_list_row/list_item_selector_widget.dart b/lib/src/widgets/new_list_row/list_item_selector_widget.dart index b3e0790cf..cb138906f 100644 --- a/lib/src/widgets/new_list_row/list_item_selector_widget.dart +++ b/lib/src/widgets/new_list_row/list_item_selector_widget.dart @@ -33,25 +33,25 @@ class ListItemSelectorWidget extends StatelessWidget { isLastInSection: isLastInSection, builder: (context, textStyle, labelStyle) { return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible(child: Text(label, style: textStyle)), - Row( - children: [ - Text( - options[selectedIndex], - style: labelStyle, - ), - CakeImageWidget(imageUrl: - "assets/new-ui/chooser.svg", - colorFilter: - ColorFilter.mode(theme.colorScheme.onSurfaceVariant, BlendMode.srcIn), - ), - SizedBox(width: 8) - ], - ), - ], + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible(child: Text(label, style: textStyle)), + Row( + spacing: 8, + children: [ + Text( + options[selectedIndex], + style: labelStyle, + ), + CakeImageWidget(imageUrl: + "assets/new-ui/chooser.svg", + colorFilter: + ColorFilter.mode(theme.colorScheme.onSurfaceVariant, BlendMode.srcIn), + ), + ], + ), + ], ); }); } -} +} \ No newline at end of file diff --git a/lib/src/widgets/standard_list.dart b/lib/src/widgets/standard_list.dart index 3e5fd1bd9..f0afdcde5 100644 --- a/lib/src/widgets/standard_list.dart +++ b/lib/src/widgets/standard_list.dart @@ -6,12 +6,14 @@ class StandardListRow extends StatelessWidget { StandardListRow({ required this.title, required this.isSelected, + this.subtitle, this.onTap, this.decoration, super.key, }); final String title; + final String? subtitle; final bool isSelected; final void Function(BuildContext context)? onTap; final Decoration? decoration; @@ -48,18 +50,52 @@ class StandardListRow extends StatelessWidget { Widget? buildLeading(BuildContext context) => null; Widget buildCenter(BuildContext context, {required bool hasLeftOffset}) { + return Expanded( child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ if (hasLeftOffset) SizedBox(width: 10), Expanded( - child: Text( - title, - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: titleColor(context), - fontWeight: isSelected ? FontWeight.w800 : FontWeight.w400, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (subtitle != null && subtitle!.isNotEmpty) + Align( + alignment: Alignment.centerLeft, + child: Text( + textAlign: TextAlign.left, + subtitle!, + style: Theme.of(context).textTheme.labelMedium?.copyWith( + color: titleColor(context), + fontWeight: isSelected ? FontWeight.w800 : FontWeight.w400, + ), + ), ), + if (subtitle != null && subtitle!.isNotEmpty) + Align( + alignment: Alignment.centerLeft, + child: Text( + textAlign: TextAlign.left, + title, + style: Theme.of(context).textTheme.labelSmall?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + fontWeight: isSelected ? FontWeight.w800 : FontWeight.w400, + ), + ), + ) + else + Align( + alignment: Alignment.centerLeft, + child: Text( + title, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: titleColor(context), + fontWeight: isSelected ? FontWeight.w800 : FontWeight.w400, + ), + ), + ), + ], ), ) ], @@ -138,6 +174,7 @@ class SectionStandardList extends StatelessWidget { this.hasTopSeparator = false, this.scrollController, this.physics, + this.shrinkWrap = false, }) : totalRows = []; final int sectionCount; @@ -150,6 +187,7 @@ class SectionStandardList extends StatelessWidget { final EdgeInsets dividerPadding; final ScrollController? scrollController; final ScrollPhysics? physics; + final bool shrinkWrap; List transform( bool hasTopSeparator, @@ -208,6 +246,7 @@ class SectionStandardList extends StatelessWidget { return ListView.separated( controller: scrollController, physics: physics, + shrinkWrap: shrinkWrap, separatorBuilder: (_, index) { final row = totalRows[index]; diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart index 4fd628bb0..b92fb5d2c 100644 --- a/lib/view_model/dashboard/dashboard_view_model.dart +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -671,6 +671,10 @@ abstract class DashboardViewModelBase with Store { bool get hasLightning => wallet.type == WalletType.bitcoin && wallet.isSoftwareWallet && bitcoin!.useLightning(wallet); + @computed + bool get hasWalletConnect => + isWalletConnectCompatibleChain(wallet.type) && !wallet.isHardwareWallet; + @computed bool get isTestnet => wallet.type == WalletType.bitcoin && bitcoin!.isTestnet(wallet); diff --git a/lib/view_model/settings/connection_sync_view_model.dart b/lib/view_model/settings/connection_sync_view_model.dart new file mode 100644 index 000000000..b48ae3230 --- /dev/null +++ b/lib/view_model/settings/connection_sync_view_model.dart @@ -0,0 +1,236 @@ +import 'dart:async'; + +import 'package:cake_wallet/entities/exchange_api_mode.dart'; +import 'package:cake_wallet/entities/fiat_api_mode.dart'; +import 'package:cake_wallet/evm/evm.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/reactions/wallet_connect.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; +import 'package:cake_wallet/store/app_store.dart'; +import 'package:cake_wallet/store/settings_store.dart'; +import 'package:cake_wallet/tron/tron.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cake_wallet/utils/tor.dart'; +import 'package:cw_core/balance.dart'; +import 'package:cw_core/transaction_history.dart'; +import 'package:cw_core/transaction_info.dart'; +import 'package:cw_core/wallet_base.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:flutter/material.dart'; +import 'package:mobx/mobx.dart'; + +part 'connection_sync_view_model.g.dart'; + +class ConnectionSyncViewModel = ConnectionSyncViewModelBase with _$ConnectionSyncViewModel; + +abstract class ConnectionSyncViewModelBase with Store { + ConnectionSyncViewModelBase(this._settingsStore, this._wallet); + + final SettingsStore _settingsStore; + final WalletBase, TransactionInfo> _wallet; + + @computed + bool get lookupTwitter => _settingsStore.lookupsTwitter; + + @computed + bool get lookupsZanoAlias => _settingsStore.lookupsZanoAlias; + + @computed + bool get looksUpMastodon => _settingsStore.lookupsMastodon; + + @computed + bool get looksUpYatService => _settingsStore.lookupsYatService; + + @computed + bool get looksUpUnstoppableDomains => _settingsStore.lookupsUnstoppableDomains; + + @computed + bool get looksUpOpenAlias => _settingsStore.lookupsOpenAlias; + + @computed + bool get looksUpENS => _settingsStore.lookupsENS; + + @computed + bool get looksUpWellKnown => _settingsStore.lookupsWellKnown; + + @computed + ExchangeApiMode get exchangeStatus => _settingsStore.exchangeStatus; + + @computed + FiatApiMode get fiatApiMode => _settingsStore.fiatApiMode; + + @computed + bool get disableAutomaticExchangeStatusUpdates => + _settingsStore.disableAutomaticExchangeStatusUpdates; + + @computed + bool get builtinTor => _settingsStore.currentBuiltinTor; + + + @computed + bool get hasPowNodes => [WalletType.nano, WalletType.banano].contains(_wallet.type); + + @computed + bool get useMempoolFeeAPI => _settingsStore.useMempoolFeeAPI; + + @computed + bool get canUseMempoolFeeAPI => _wallet.type == WalletType.bitcoin; + + @computed + bool get useBlinkProtection => _settingsStore.useBlinkProtection; + + bool get canUseBlinkProtection => canSupportBlinkProtection(_wallet.chainId); + + @computed + bool get useEtherscan => _settingsStore.useEtherscan; + + @computed + bool get usePolygonScan => _settingsStore.usePolygonScan; + + @computed + bool get useBaseScan => _settingsStore.useBaseScan; + + @computed + bool get useArbiScan => _settingsStore.useArbiScan; + + @computed + bool get useBscScan => _settingsStore.useBscScan; + + @computed + bool get useTronGrid => _settingsStore.useTronGrid; + + @computed + bool get canUseEtherscan => _wallet.chainId == 1; + + @computed + bool get canUsePolygonScan => _wallet.chainId == 137; + + @computed + bool get canUseBaseScan => _wallet.chainId == 8453; + + @computed + bool get canUseArbiScan => _wallet.chainId == 42161; + + @computed + bool get canUseBscScan => _wallet.chainId == 56; + + @computed + bool get canUseTronGrid => _wallet.type == WalletType.tron; + + @action + void setLookupsTwitter(bool value) => _settingsStore.lookupsTwitter = value; + + @action + void setLookupsZanoAlias(bool value) => _settingsStore.lookupsZanoAlias = value; + + @action + void setLookupsMastodon(bool value) => _settingsStore.lookupsMastodon = value; + + @action + void setLookupsENS(bool value) => _settingsStore.lookupsENS = value; + + @action + void setLookupsWellKnown(bool value) => _settingsStore.lookupsWellKnown = value; + + @action + void setLookupsYatService(bool value) => _settingsStore.lookupsYatService = value; + + @action + void setLookupsUnstoppableDomains(bool value) => _settingsStore.lookupsUnstoppableDomains = value; + + @action + void setLookupsOpenAlias(bool value) => _settingsStore.lookupsOpenAlias = value; + + @action + void setUseMempoolFeeAPI(bool value) => _settingsStore.useMempoolFeeAPI = value; + + @action + void setDisableAutomaticExchangeStatusUpdates(bool value) => + _settingsStore.disableAutomaticExchangeStatusUpdates = value; + + @action + void setFiatMode(FiatApiMode fiatApiMode) => _settingsStore.fiatApiMode = fiatApiMode; + + @action + void setExchangeApiMode(ExchangeApiMode value) => _settingsStore.exchangeStatus = value; + + @action + void setUseBlinkProtection(bool value) => _settingsStore.useBlinkProtection = value; + + @action + void setUseEtherscan(bool value) { + _settingsStore.useEtherscan = value; + evm!.updateScanProviderUsageState(_wallet, value); + } + + @action + void setUsePolygonScan(bool value) { + _settingsStore.usePolygonScan = value; + evm!.updateScanProviderUsageState(_wallet, value); + } + + @action + void setUseBaseScan(bool value) { + _settingsStore.useBaseScan = value; + evm!.updateScanProviderUsageState(_wallet, value); + } + + @action + void setUseTronGrid(bool value) { + _settingsStore.useTronGrid = value; + tron!.updateTronGridUsageState(_wallet, value); + } + + @action + void setUseArbiScan(bool value) { + _settingsStore.useArbiScan = value; + evm!.updateScanProviderUsageState(_wallet, value); + } + + @action + void setUseBscScan(bool value) { + _settingsStore.useBscScan = value; + evm!.updateScanProviderUsageState(_wallet, value); + } + + @action + void setBuiltinTor(bool value, BuildContext context) { + if (value) { + unawaited( + showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: S.of(context).tor_connection, + alertContent: S.of(context).tor_experimental, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop(true), + ); + }, + ), + ); + } + _settingsStore.currentBuiltinTor = value; + if (value) { + unawaited(ensureTorStarted(context: context).then((_) async { + if (_settingsStore.currentBuiltinTor == false) return; + int? chainId; + if (isEVMCompatibleChain(_wallet.type)) { + chainId = evm!.getSelectedChainId(_wallet); + } + await _wallet.connectToNode( + node: _settingsStore.getCurrentNode(_wallet.type, chainId: chainId)); + })); + } else { + unawaited(ensureTorStopped(context: context).then((_) async { + if (_settingsStore.currentBuiltinTor == true) return; + int? chainId; + if (isEVMCompatibleChain(_wallet.type)) { + chainId = evm!.getSelectedChainId(_wallet); + } + await _wallet.connectToNode( + node: _settingsStore.getCurrentNode(_wallet.type, chainId: chainId)); + })); + } + } +} diff --git a/lib/view_model/settings/display_settings_view_model.dart b/lib/view_model/settings/display_settings_view_model.dart index 7bc2cc4f0..ab6c8f9c9 100644 --- a/lib/view_model/settings/display_settings_view_model.dart +++ b/lib/view_model/settings/display_settings_view_model.dart @@ -24,6 +24,9 @@ abstract class DisplaySettingsViewModelBase with Store { SettingsStore get _settingsStore => _appStore.settingsStore; final ThemeStore _themeStore; + @computed + bool get disableTradeOption => _settingsStore.disableTradeOption; + @computed FiatCurrency get fiatCurrency => _settingsStore.fiatCurrency; @@ -110,6 +113,9 @@ abstract class DisplaySettingsViewModelBase with Store { return []; } + @action + void setDisableTradeOption(bool value) => _settingsStore.disableTradeOption = value; + @action void setBalanceDisplayMode(BalanceDisplayMode value) => _settingsStore.balanceDisplayMode = value; @@ -246,18 +252,18 @@ abstract class DisplaySettingsViewModelBase with Store { String getImageForTheme(MaterialThemeBase theme) { switch (theme.title) { case 'Dark Theme': - return 'assets/images/dark.svg'; + return 'assets/new-ui/dark.svg'; case 'Light Theme': - return 'assets/images/light.svg'; + return 'assets/new-ui/light.svg'; case 'Black Theme (Cake Primary)': case 'Black Theme (BCH Green)': case 'Black Theme (Bitcoin Yellow)': case 'Black Theme (Monero Orange)': case 'Black Theme (Tron Red)': case 'Black Theme (Frosting Purple)': - return 'assets/images/black_accent.svg'; + return 'assets/new-ui/black_accent.svg'; default: - return 'assets/images/dark.svg'; + return 'assets/new-ui/dark.svg'; } } } diff --git a/lib/view_model/settings/other_settings_view_model.dart b/lib/view_model/settings/other_settings_view_model.dart index b94e7f2c8..8741c265d 100644 --- a/lib/view_model/settings/other_settings_view_model.dart +++ b/lib/view_model/settings/other_settings_view_model.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart'; import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/utils/package_info.dart'; @@ -57,6 +58,33 @@ abstract class OtherSettingsViewModelBase with Store { return priority; } + @computed + bool get isAutoGenerateSubaddressesEnabled => + _settingsStore.autoGenerateSubaddressStatus != AutoGenerateSubaddressStatus.disabled; + + @action + void setAutoGenerateSubaddresses(bool value) { + _wallet.isEnabledAutoGenerateSubaddress = value; + _settingsStore.autoGenerateSubaddressStatus = + value ? AutoGenerateSubaddressStatus.enabled : AutoGenerateSubaddressStatus.disabled; + } + + bool get isAutoGenerateSubaddressesVisible => [ + WalletType.monero, + WalletType.wownero, + WalletType.bitcoin, + WalletType.litecoin, + WalletType.bitcoinCash, + WalletType.dogecoin, + WalletType.decred + ].contains(_wallet.type); + + @computed + bool get isMoneroWallet => _wallet.type == WalletType.monero; + + @computed + bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress; + @computed bool get changeRepresentativeEnabled => [WalletType.nano, WalletType.banano].contains(_wallet.type); @@ -127,6 +155,10 @@ abstract class OtherSettingsViewModelBase with Store { @computed double get customBitcoinFeeRate => _settingsStore.customBitcoinFeeRate.toDouble(); + @action + void setShouldSaveRecipientAddress(bool value) => + _settingsStore.shouldSaveRecipientAddress = value; + int? get customPriorityItemIndex { final priorities = priorityForWalletType(walletType); final customItem = priorities diff --git a/lib/view_model/settings/privacy_settings_view_model.dart b/lib/view_model/settings/privacy_settings_view_model.dart index 1b99d6644..d77eb6682 100644 --- a/lib/view_model/settings/privacy_settings_view_model.dart +++ b/lib/view_model/settings/privacy_settings_view_model.dart @@ -1,10 +1,6 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart'; -import 'package:cake_wallet/entities/exchange_api_mode.dart'; -import 'package:cake_wallet/evm/evm.dart'; import 'package:cake_wallet/store/settings_store.dart'; -import 'package:cake_wallet/tron/tron.dart'; -import 'package:cake_wallet/reactions/wallet_connect.dart'; import 'package:cake_wallet/utils/device_info.dart'; import 'package:cw_core/balance.dart'; import 'package:cw_core/transaction_history.dart'; @@ -12,7 +8,6 @@ import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/entities/fiat_api_mode.dart'; part 'privacy_settings_view_model.g.dart'; @@ -25,7 +20,10 @@ abstract class PrivacySettingsViewModelBase with Store { final WalletBase, TransactionInfo> _wallet; @computed - ExchangeApiMode get exchangeStatus => _settingsStore.exchangeStatus; + bool get isBitcoin => _wallet.type == WalletType.bitcoin; + + @computed + bool get isLitecoin => _wallet.type == WalletType.litecoin; @computed bool get isAutoGenerateSubaddressesEnabled => @@ -65,9 +63,6 @@ abstract class PrivacySettingsViewModelBase with Store { @computed bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress; - @computed - FiatApiMode get fiatApiMode => _settingsStore.fiatApiMode; - @computed bool get isAppSecure => _settingsStore.isAppSecure; @@ -81,32 +76,6 @@ abstract class PrivacySettingsViewModelBase with Store { @computed bool get disableBulletin => _settingsStore.disableBulletin; - @computed - bool get useEtherscan => _settingsStore.useEtherscan; - - @computed - bool get usePolygonScan => _settingsStore.usePolygonScan; - - @computed - bool get useBaseScan => _settingsStore.useBaseScan; - - @computed - bool get useArbiScan => _settingsStore.useArbiScan; - - @computed - bool get useBscScan => _settingsStore.useBscScan; - - @computed - bool get useTronGrid => _settingsStore.useTronGrid; - - @computed - bool get useMempoolFeeAPI => _settingsStore.useMempoolFeeAPI; - - @computed - bool get useBlinkProtection => _settingsStore.useBlinkProtection; - - bool get canUseBlinkProtection => canSupportBlinkProtection(_wallet.chainId); - @computed bool get lookupTwitter => _settingsStore.lookupsTwitter; @@ -135,36 +104,18 @@ abstract class PrivacySettingsViewModelBase with Store { bool get usePayjoin => _settingsStore.usePayjoin; @computed - bool get useLightning => _wallet.type == WalletType.bitcoin && bitcoin!.useLightning(_wallet); - - bool get canUseEtherscan => _wallet.chainId == 1; - - bool get canUsePolygonScan => _wallet.chainId == 137; - - bool get canUseBaseScan => _wallet.chainId == 8453; - - bool get canUseArbiScan => _wallet.chainId == 42161; - - bool get canUseBscScan => _wallet.chainId == 56; - - bool get canUseTronGrid => _wallet.type == WalletType.tron; - - bool get canUseMempoolFeeAPI => _wallet.type == WalletType.bitcoin; - bool get canUsePayjoin => _wallet.type == WalletType.bitcoin && DeviceInfo.instance.isMobile; + @computed bool get canUseLightning => _wallet.type == WalletType.bitcoin; + @computed + bool get useLightning => _wallet.type == WalletType.bitcoin && bitcoin!.useLightning(_wallet); + @action void setShouldSaveRecipientAddress(bool value) => _settingsStore.shouldSaveRecipientAddress = value; - @action - void setExchangeApiMode(ExchangeApiMode value) => _settingsStore.exchangeStatus = value; - - @action - void setFiatMode(FiatApiMode fiatApiMode) => _settingsStore.fiatApiMode = fiatApiMode; - @action void setIsAppSecure(bool value) => _settingsStore.isAppSecure = value; @@ -178,66 +129,6 @@ abstract class PrivacySettingsViewModelBase with Store { @action void setDisableBulletin(bool value) => _settingsStore.disableBulletin = value; - @action - void setLookupsTwitter(bool value) => _settingsStore.lookupsTwitter = value; - - @action - void setLookupsZanoAlias(bool value) => _settingsStore.lookupsZanoAlias = value; - - @action - void setLookupsMastodon(bool value) => _settingsStore.lookupsMastodon = value; - - @action - void setLookupsENS(bool value) => _settingsStore.lookupsENS = value; - - @action - void setLookupsWellKnown(bool value) => _settingsStore.lookupsWellKnown = value; - - @action - void setLookupsYatService(bool value) => _settingsStore.lookupsYatService = value; - - @action - void setLookupsUnstoppableDomains(bool value) => _settingsStore.lookupsUnstoppableDomains = value; - - @action - void setLookupsOpenAlias(bool value) => _settingsStore.lookupsOpenAlias = value; - - @action - void setUseEtherscan(bool value) { - _settingsStore.useEtherscan = value; - evm!.updateScanProviderUsageState(_wallet, value); - } - - @action - void setUsePolygonScan(bool value) { - _settingsStore.usePolygonScan = value; - evm!.updateScanProviderUsageState(_wallet, value); - } - - @action - void setUseBaseScan(bool value) { - _settingsStore.useBaseScan = value; - evm!.updateScanProviderUsageState(_wallet, value); - } - - @action - void setUseTronGrid(bool value) { - _settingsStore.useTronGrid = value; - tron!.updateTronGridUsageState(_wallet, value); - } - - @action - void setUseArbiScan(bool value) { - _settingsStore.useArbiScan = value; - evm!.updateScanProviderUsageState(_wallet, value); - } - - @action - void setUseBscScan(bool value) { - _settingsStore.useBscScan = value; - evm!.updateScanProviderUsageState(_wallet, value); - } - @action void setUseMempoolFeeAPI(bool value) => _settingsStore.useMempoolFeeAPI = value; diff --git a/lib/view_model/settings/security_settings_view_model.dart b/lib/view_model/settings/security_settings_view_model.dart index c7ea6107c..2c4175876 100644 --- a/lib/view_model/settings/security_settings_view_model.dart +++ b/lib/view_model/settings/security_settings_view_model.dart @@ -15,6 +15,9 @@ abstract class SecuritySettingsViewModelBase with Store { final SettingsStore _settingsStore; final AuthService _authService; + @computed + bool get isAppSecure => _settingsStore.isAppSecure; + @computed bool get allowBiometricalAuthentication => _settingsStore.allowBiometricalAuthentication; @@ -36,6 +39,9 @@ abstract class SecuritySettingsViewModelBase with Store { return await _biometricAuth.canCheckBiometrics() && await _biometricAuth.isAuthenticated(); } + @action + void setIsAppSecure(bool value) => _settingsStore.isAppSecure = value; + @action void setAllowBiometricalAuthentication(bool value) => _settingsStore.allowBiometricalAuthentication = value; diff --git a/assets/images/black_accent.svg b/res/pictures/black_accent.svg similarity index 100% rename from assets/images/black_accent.svg rename to res/pictures/black_accent.svg diff --git a/res/pictures/chooser.svg b/res/pictures/chooser.svg index ca5c07d48..8e7c24bf4 100644 --- a/res/pictures/chooser.svg +++ b/res/pictures/chooser.svg @@ -1,10 +1,3 @@ - - - - - - - - - + + diff --git a/assets/images/dark.svg b/res/pictures/dark.svg similarity index 100% rename from assets/images/dark.svg rename to res/pictures/dark.svg diff --git a/assets/images/light.svg b/res/pictures/light.svg similarity index 100% rename from assets/images/light.svg rename to res/pictures/light.svg diff --git a/res/pictures/settings_row_icons/privacy.svg b/res/pictures/settings_row_icons/privacy.svg index 763bfbaf3..3a8a8503f 100644 --- a/res/pictures/settings_row_icons/privacy.svg +++ b/res/pictures/settings_row_icons/privacy.svg @@ -1,40 +1,35 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/pictures/settings_row_icons/security.svg b/res/pictures/settings_row_icons/security.svg index 994f17f25..6663c091c 100644 --- a/res/pictures/settings_row_icons/security.svg +++ b/res/pictures/settings_row_icons/security.svg @@ -1,47 +1,42 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/pictures/settings_row_icons/wc.svg b/res/pictures/settings_row_icons/wc.svg new file mode 100644 index 000000000..5f334128a --- /dev/null +++ b/res/pictures/settings_row_icons/wc.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index 204e12ee5..ab480a489 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -242,6 +242,7 @@ "connected": "متصل", "connection_sync": "الاتصال والمزامنة", "connections": "الاتصالات", + "connections_desc": "إدارة الاتصالات بالخدمات وواجهات برمجة التطبيقات التابعة لجهات خارجية.", "connectWalletPrompt": "قم بتوصيل محفظتك عبر WalletConnect لإجراء المعاملات", "contact": "جهة اتصال", "contact_list_contacts": "جهات الاتصال", @@ -756,6 +757,7 @@ "privacy": "الخصوصية", "privacy_and_security": "الخصوصية والأمان", "privacy_and_security_desc": "قم بتكوين إعدادات المصادقة والأمان وإعداد المصادقة الثنائية (2FA) في Cake.", + "privacy_desc": "تغيير إعدادات الخصوصية وتبديل ميزات الخصوصية الخاصة.", "privacy_features": "ميزات الخصوصية", "privacy_policy": "سياسة الخصوصية", "privacy_settings": "إعدادات الخصوصية", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index 84524d0ee..d50474f43 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -242,6 +242,7 @@ "connected": "Свързан", "connection_sync": "Връзка и синхронизация", "connections": "Връзки", + "connections_desc": "Управлявайте връзки към услуги и API на трети страни.", "connectWalletPrompt": "Свържете портфейла си с WalletConnect, за да извършвате транзакции", "contact": "Контакт", "contact_list_contacts": "Контакти", @@ -756,6 +757,7 @@ "privacy": "Поверителност", "privacy_and_security": "Поверителност и сигурност", "privacy_and_security_desc": "Конфигурирайте настройките за удостоверяване и сигурност и настройте Cake 2FA.", + "privacy_desc": "Променете настройките за поверителност и превключете специални функции за поверителност.", "privacy_features": "Функции за поверителност", "privacy_policy": "Политика за поверителност", "privacy_settings": "Настройки за поверителност", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 4a62c699f..aebca6a93 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -242,6 +242,7 @@ "connected": "Připojeno", "connection_sync": "Připojení a synchronizace", "connections": "Připojení", + "connections_desc": "Správa připojení ke službám a rozhraním API třetích stran.", "connectWalletPrompt": "Připojte svou peněženku přes WalletConnect a provádějte transakce", "contact": "Kontakt", "contact_list_contacts": "Kontakty", @@ -756,6 +757,7 @@ "privacy": "Soukromí", "privacy_and_security": "Soukromí a zabezpečení", "privacy_and_security_desc": "Nakonfigurujte nastavení ověřování a zabezpečení a nastavte Cake 2FA.", + "privacy_desc": "Změňte nastavení ochrany osobních údajů a přepínejte speciální funkce ochrany osobních údajů.", "privacy_features": "Funkce soukromí", "privacy_policy": "Zásady ochrany osobních údajů", "privacy_settings": "Nastavení soukromí", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 8183db3e4..f3b379170 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -242,6 +242,7 @@ "connected": "Verbunden", "connection_sync": "Verbindung und Synchronisierung", "connections": "Verbindungen", + "connections_desc": "Verwalten Sie Verbindungen zu Diensten und APIs von Drittanbietern.", "connectWalletPrompt": "Verbinden Sie Ihr Wallet mit WalletConnect, um Transaktionen durchzuführen", "contact": "Kontakt", "contact_list_contacts": "Kontakte", @@ -757,6 +758,7 @@ "privacy": "Privatsphäre", "privacy_and_security": "Datenschutz & Sicherheit", "privacy_and_security_desc": "Konfigurieren Sie Authentifizierungs- und Sicherheitseinstellungen und richten Sie Cake 2FA ein.", + "privacy_desc": "Ändern Sie die Datenschutzeinstellungen und schalten Sie spezielle Datenschutzfunktionen ein.", "privacy_features": "Datenschutzfunktionen", "privacy_policy": "Datenschutzerklärung", "privacy_settings": "Datenschutzeinstellungen", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 1697827b6..f55ddf0fa 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -242,6 +242,7 @@ "connected": "Connected", "connection_sync": "Connection and sync", "connections": "Connections", + "connections_desc": "Manage connections to services and third party APIs.", "connectWalletPrompt": "Connect your wallet with WalletConnect to make transactions", "contact": "Contact", "contact_list_contacts": "Contacts", @@ -757,6 +758,7 @@ "privacy": "Privacy", "privacy_and_security": "Privacy & Security", "privacy_and_security_desc": "Configure authentication and security settings and setup Cake 2FA.", + "privacy_desc": "Change privacy settings and toggle special privacy features.", "privacy_features": "Privacy features", "privacy_policy": "Privacy Policy", "privacy_settings": "Privacy settings", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 0ba2235a7..49ce3fc0c 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -242,6 +242,7 @@ "connected": "Conectado", "connection_sync": "Conexión y sincronización", "connections": "Conexiones", + "connections_desc": "Administrar conexiones a servicios y API de terceros.", "connectWalletPrompt": "Conecta tu billetera con WalletConnect para realizar transacciones", "contact": "Contacto", "contact_list_contacts": "Contactos", @@ -757,6 +758,7 @@ "privacy": "Privacidad", "privacy_and_security": "Privacidad y seguridad", "privacy_and_security_desc": "Configure los ajustes de autenticación y seguridad y configure Cake 2FA.", + "privacy_desc": "Cambie la configuración de privacidad y alterne funciones de privacidad especiales.", "privacy_features": "Funciones de privacidad", "privacy_policy": "Política de privacidad", "privacy_settings": "Configuración de privacidad", diff --git a/res/values/strings_fa.arb b/res/values/strings_fa.arb index cad8e117f..5e1edfa7d 100644 --- a/res/values/strings_fa.arb +++ b/res/values/strings_fa.arb @@ -240,6 +240,7 @@ "connected": "متصل", "connection_sync": "اتصال و همگام‌سازی", "connections": "اتصالات", + "connections_desc": "اتصالات به سرویس ها و API های شخص ثالث را مدیریت کنید.", "connectWalletPrompt": "برای انجام تراکنش‌ها، کیف پول خود را از طریق WalletConnect متصل کنید", "contact": "مخاطب", "contact_list_contacts": "مخاطبین", @@ -755,6 +756,7 @@ "privacy": "حریم خصوصی", "privacy_and_security": "حریم خصوصی و امنیت", "privacy_and_security_desc": "تنظیمات احراز هویت و امنیت را پیکربندی کنید و Cake 2FA را راه‌اندازی کنید.", + "privacy_desc": "تنظیمات حریم خصوصی را تغییر دهید و ویژگی های حریم خصوصی را تغییر دهید.", "privacy_features": "ویژگی‌های حریم خصوصی", "privacy_policy": "سیاست حفظ حریم خصوصی", "privacy_settings": "تنظیمات حریم خصوصی", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index fc21a4dd1..625bbde3e 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -242,6 +242,7 @@ "connected": "Connecté", "connection_sync": "Connexion et synchronisation", "connections": "Connexions", + "connections_desc": "Gérez les connexions aux services et aux API tierces.", "connectWalletPrompt": "Connectez votre portefeuille avec WalletConnect pour effectuer des transactions", "contact": "Contact", "contact_list_contacts": "Contacts", @@ -756,6 +757,7 @@ "privacy": "Confidentialité", "privacy_and_security": "Confidentialité et sécurité", "privacy_and_security_desc": "Configurez les paramètres d'authentification et de sécurité, et configurez Cake 2FA.", + "privacy_desc": "Modifiez les paramètres de confidentialité et activez les fonctionnalités de confidentialité spéciales.", "privacy_features": "Fonctionnalités de confidentialité", "privacy_policy": "Politique de confidentialité", "privacy_settings": "Paramètres de confidentialité", diff --git a/res/values/strings_gn.arb b/res/values/strings_gn.arb index 1e03da9d8..7c535a745 100644 --- a/res/values/strings_gn.arb +++ b/res/values/strings_gn.arb @@ -192,6 +192,7 @@ "connect_your_hardware_wallet_ios": "Embojoaju nde billetera hardware Bluetooth ndive", "connection_sync": "Joaju ha ñembojuehe", "connections": "Jeikeha", + "connections_desc": "Emohenda joaju umi servicio ha API mbohapýha rehegua.", "connectWalletPrompt": "Embojoaju nde billetera WalletConnect ndive hag̃ua rejapo transacción", "contact": "Contacto", "contact_list_contacts": "Ñe'ẽngára", @@ -589,6 +590,7 @@ "privacy": "Ñemigua", "privacy_and_security": "Privasida ha Tekorosã", "privacy_and_security_desc": "Emohenda ñemboheko hag̃ua jehechajey hag̃ua hag̃ua hag̃ua hag̃ua seguridad ha emboheko Cake 2FA.", + "privacy_desc": "Emoambue ñemigua ñemboheko ha embohasa ñemigua mba’ekuaarã especial.", "privacy_features": "Tembiapoite ñemigua", "privacy_policy": "Purureko ñemi rehegua", "privacy_settings": "Ñemohenda ñemigua", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index 7ace34151..4d57e1b17 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -242,6 +242,7 @@ "connected": "An haɗa", "connection_sync": "Haɗi da aiki tare", "connections": "Haɗe-haɗe", + "connections_desc": "Sarrafa haɗin kai zuwa ayyuka da APIs na ɓangare na uku.", "connectWalletPrompt": "Haɗa walat ɗinka da WalletConnect don yin ma'amaloli", "contact": "Tuntuɓa", "contact_list_contacts": "Lambobin sadarwa", @@ -758,6 +759,7 @@ "privacy": "Sirri", "privacy_and_security": "Sirri & Tsaro", "privacy_and_security_desc": "Saita tabbatarwa da saitunan tsaro, sannan ka saita Cake 2FA.", + "privacy_desc": "Canja saitunan keɓantawa kuma kunna fasalolin keɓantawa na musamman.", "privacy_features": "Siffofin keɓantawa", "privacy_policy": "Manufar Sirri", "privacy_settings": "Saitunan keɓantawa", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 71aab4dae..dc7790521 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -242,6 +242,7 @@ "connected": "कनेक्टेड", "connection_sync": "कनेक्शन और सिंक", "connections": "कनेक्शन", + "connections_desc": "सेवाओं और तृतीय पक्ष एपीआई से कनेक्शन प्रबंधित करें।", "connectWalletPrompt": "लेन-देन करने के लिए अपने वॉलेट को WalletConnect से कनेक्ट करें", "contact": "संपर्क", "contact_list_contacts": "संपर्क", @@ -757,6 +758,7 @@ "privacy": "गोपनीयता", "privacy_and_security": "निजता और सुरक्षा", "privacy_and_security_desc": "प्रमाणीकरण और सुरक्षा सेटिंग्स कॉन्फ़िगर करें और Cake 2FA सेट अप करें।", + "privacy_desc": "गोपनीयता सेटिंग्स बदलें और विशेष गोपनीयता सुविधाओं को टॉगल करें।", "privacy_features": "गोपनीयता सुविधाएँ", "privacy_policy": "गोपनीयता नीति", "privacy_settings": "गोपनीयता सेटिंग्स", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index d5854b3cf..4ca1ae54a 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -242,6 +242,7 @@ "connected": "Povezano", "connection_sync": "Povezivanje i sinkronizacija", "connections": "Veze", + "connections_desc": "Upravljajte vezama s uslugama i API-jima trećih strana.", "connectWalletPrompt": "Povežite svoj novčanik s WalletConnectom za izvršavanje transakcija", "contact": "Kontakt", "contact_list_contacts": "Kontakti", @@ -756,6 +757,7 @@ "privacy": "Privatnost", "privacy_and_security": "Privatnost i sigurnost", "privacy_and_security_desc": "Konfigurirajte postavke provjere autentičnosti i sigurnosti te postavite Cake 2FA.", + "privacy_desc": "Promijenite postavke privatnosti i uključite/isključite posebne značajke privatnosti.", "privacy_features": "Značajke privatnosti", "privacy_policy": "Pravila privatnosti", "privacy_settings": "Postavke privatnosti", diff --git a/res/values/strings_hy.arb b/res/values/strings_hy.arb index 470fc1660..f884ebddb 100644 --- a/res/values/strings_hy.arb +++ b/res/values/strings_hy.arb @@ -242,6 +242,7 @@ "connected": "Միացված", "connection_sync": "Կապ և համաժամեցում", "connections": "Միացումներ", + "connections_desc": "Կառավարեք կապերը ծառայությունների և երրորդ կողմի API-ների հետ:", "connectWalletPrompt": "Միացրեք ձեր դրամապանակը WalletConnect-ի միջոցով՝ գործարքներ կատարելու համար", "contact": "Կոնտակտ", "contact_list_contacts": "Կոնտակտներ", @@ -755,6 +756,7 @@ "privacy": "Գաղտնիություն", "privacy_and_security": "Գաղտնիություն և անվտանգություն", "privacy_and_security_desc": "Կազմաձևեք նույնականացման և անվտանգության կարգավորումները և կարգավորեք Cake 2FA-ն։", + "privacy_desc": "Փոխեք գաղտնիության կարգավորումները և միացրեք գաղտնիության հատուկ գործառույթները:", "privacy_features": "Գաղտնիության գործառույթներ", "privacy_policy": "Գաղտնիության քաղաքականություն", "privacy_settings": "Գաղտնիության կարգավորումներ", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index d1bb7b41e..99a587392 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -242,6 +242,7 @@ "connected": "Terhubung", "connection_sync": "Koneksi dan sinkronisasi", "connections": "Koneksi", + "connections_desc": "Kelola koneksi ke layanan dan API pihak ketiga.", "connectWalletPrompt": "Hubungkan dompet Anda dengan WalletConnect untuk melakukan transaksi", "contact": "Kontak", "contact_list_contacts": "Kontak", @@ -758,6 +759,7 @@ "privacy": "Privasi", "privacy_and_security": "Privasi & Keamanan", "privacy_and_security_desc": "Konfigurasikan pengaturan autentikasi dan keamanan serta siapkan Cake 2FA.", + "privacy_desc": "Ubah pengaturan privasi dan aktifkan fitur privasi khusus.", "privacy_features": "Fitur privasi", "privacy_policy": "Kebijakan Privasi", "privacy_settings": "Pengaturan Privasi", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index bb97d1a3d..72ed9288e 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -242,6 +242,7 @@ "connected": "Connesso", "connection_sync": "Connessione e sincronizzazione", "connections": "Connessioni", + "connections_desc": "Gestisci le connessioni a servizi e API di terze parti.", "connectWalletPrompt": "Collega il tuo wallet con WalletConnect per effettuare transazioni", "contact": "Contatto", "contact_list_contacts": "Contatti", @@ -757,6 +758,7 @@ "privacy": "Privacy", "privacy_and_security": "Privacy e sicurezza", "privacy_and_security_desc": "Configura le impostazioni di autenticazione e sicurezza e imposta Cake 2FA.", + "privacy_desc": "Modifica le impostazioni sulla privacy e attiva le funzionalità speciali sulla privacy.", "privacy_features": "Funzionalità per la privacy", "privacy_policy": "Informativa sulla privacy", "privacy_settings": "Impostazioni sulla privacy", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index 8f83c67a2..1597fb304 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -242,6 +242,7 @@ "connected": "接続済み", "connection_sync": "接続と同期", "connections": "接続", + "connections_desc": "サービスおよびサードパーティ API への接続を管理します。", "connectWalletPrompt": "WalletConnect でウォレットを接続して取引を行う", "contact": "連絡先", "contact_list_contacts": "連絡先", @@ -757,6 +758,7 @@ "privacy": "プライバシー", "privacy_and_security": "プライバシーとセキュリティ", "privacy_and_security_desc": "認証とセキュリティの設定を構成し、Cake 2FA をセットアップします。", + "privacy_desc": "プライバシー設定を変更し、特別なプライバシー機能を切り替えます。", "privacy_features": "プライバシー機能", "privacy_policy": "プライバシーポリシー", "privacy_settings": "プライバシー設定", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 8fa44e7ee..6df7fd1ba 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -242,6 +242,7 @@ "connected": "연결됨", "connection_sync": "연결 및 동기화", "connections": "연결", + "connections_desc": "서비스 및 타사 API에 대한 연결을 관리합니다.", "connectWalletPrompt": "거래를 하려면 WalletConnect로 지갑을 연결하세요", "contact": "연락처", "contact_list_contacts": "연락처", @@ -757,6 +758,7 @@ "privacy": "개인정보 보호", "privacy_and_security": "개인정보 보호 및 보안", "privacy_and_security_desc": "인증 및 보안 설정을 구성하고 Cake 2FA를 설정합니다.", + "privacy_desc": "개인정보 보호 설정을 변경하고 특별 개인정보 보호 기능을 전환하세요.", "privacy_features": "개인정보 보호 기능", "privacy_policy": "개인정보처리방침", "privacy_settings": "개인정보 보호 설정", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index d75350ccb..a9785f5be 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -242,6 +242,7 @@ "connected": "ချိတ်ဆက်ပြီး", "connection_sync": "ချိတ်ဆက်မှုနှင့် ထပ်တူညီစေခြင်း", "connections": "ချိတ်ဆက်မှုများ", + "connections_desc": "ဝန်ဆောင်မှုများနှင့် ပြင်ပကုမ္ပဏီ API များသို့ ချိတ်ဆက်မှုများကို စီမံပါ။", "connectWalletPrompt": "ငွေလွှဲပြောင်းမှုများ ပြုလုပ်ရန် WalletConnect ဖြင့် သင့်ပိုက်ဆံအိတ်ကို ချိတ်ဆက်ပါ", "contact": "ဆက်သွယ်ရန်", "contact_list_contacts": "အဆက်အသွယ်များ", @@ -756,6 +757,7 @@ "privacy": "ကိုယ်ရေးလုံခြုံမှု", "privacy_and_security": "ကိုယ်ရေးကိုယ်တာနှင့် လုံခြုံရေး", "privacy_and_security_desc": "အထောက်အထားစိစစ်ခြင်းနှင့် လုံခြုံရေးဆက်တင်များကို ပြင်ဆင်သတ်မှတ်ပြီး Cake 2FA ကို စနစ်ထည့်သွင်းပါ။", + "privacy_desc": "ကိုယ်ရေးကိုယ်တာဆက်တင်များကိုပြောင်းလဲပြီး အထူးကိုယ်ရေးကိုယ်တာအင်္ဂါရပ်များကို ပြောင်းပါ။", "privacy_features": "ကိုယ်ရေးလုံခြုံရေး အင်္ဂါရပ်များ", "privacy_policy": "ကိုယ်ရေးအချက်အလက်မူဝါဒ", "privacy_settings": "ကိုယ်ရေးကိုယ်တာ ဆက်တင်များ", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index d4d7348cc..3d85f18fd 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -240,6 +240,7 @@ "connected": "Verbonden", "connection_sync": "Verbinding en synchronisatie", "connections": "Verbindingen", + "connections_desc": "Beheer verbindingen met services en API's van derden.", "connectWalletPrompt": "Verbind je wallet met WalletConnect om transacties uit te voeren", "contact": "Contact", "contact_list_contacts": "Contacten", @@ -753,6 +754,7 @@ "privacy": "Privacy", "privacy_and_security": "Privacy en beveiliging", "privacy_and_security_desc": "Configureer de authenticatie- en beveiligingsinstellingen en stel Cake 2FA in.", + "privacy_desc": "Wijzig privacy-instellingen en schakel speciale privacyfuncties in.", "privacy_features": "Privacyfuncties", "privacy_policy": "Privacybeleid", "privacy_settings": "Privacy-instellingen", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 8238356ec..e80a7d3b3 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -242,6 +242,7 @@ "connected": "Połączono", "connection_sync": "Połączenie i synchronizacja", "connections": "Połączenia", + "connections_desc": "Zarządzaj połączeniami z usługami i interfejsami API stron trzecich.", "connectWalletPrompt": "Połącz swój portfel z WalletConnect, aby wykonywać transakcje", "contact": "Kontakt", "contact_list_contacts": "Kontakty", @@ -755,6 +756,7 @@ "privacy": "Prywatność", "privacy_and_security": "Prywatność i bezpieczeństwo", "privacy_and_security_desc": "Skonfiguruj ustawienia uwierzytelniania i zabezpieczeń oraz skonfiguruj Cake 2FA.", + "privacy_desc": "Zmień ustawienia prywatności i przełącz specjalne funkcje prywatności.", "privacy_features": "Funkcje prywatności", "privacy_policy": "Polityka prywatności", "privacy_settings": "Ustawienia prywatności", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index b807bbc75..d2823434f 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -242,6 +242,7 @@ "connected": "Conectado", "connection_sync": "Conexão e sincronização", "connections": "Conexões", + "connections_desc": "Gerencie conexões com serviços e APIs de terceiros.", "connectWalletPrompt": "Conecte sua carteira ao WalletConnect para realizar transações", "contact": "Contato", "contact_list_contacts": "Contatos", @@ -758,6 +759,7 @@ "privacy": "Privacidade", "privacy_and_security": "Privacidade e Segurança", "privacy_and_security_desc": "Configure as definições de autenticação e segurança e configure o Cake 2FA.", + "privacy_desc": "Altere as configurações de privacidade e ative recursos especiais de privacidade.", "privacy_features": "Recursos de privacidade", "privacy_policy": "Política de Privacidade", "privacy_settings": "Configurações de privacidade", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 9e888ab76..416377e8f 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -242,6 +242,7 @@ "connected": "Подключено", "connection_sync": "Подключение и синхронизация", "connections": "Подключения", + "connections_desc": "Управляйте подключениями к сервисам и сторонним API.", "connectWalletPrompt": "Подключите свой кошелек к WalletConnect, чтобы совершать транзакции", "contact": "Контакт", "contact_list_contacts": "Контакты", @@ -757,6 +758,7 @@ "privacy": "Конфиденциальность", "privacy_and_security": "Конфиденциальность и безопасность", "privacy_and_security_desc": "Настройте параметры аутентификации и безопасности, а также настройте Cake 2FA.", + "privacy_desc": "Измените настройки конфиденциальности и включите специальные функции конфиденциальности.", "privacy_features": "Функции конфиденциальности", "privacy_policy": "Политика конфиденциальности", "privacy_settings": "Настройки конфиденциальности", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index faae414b6..fc986ff8b 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -242,6 +242,7 @@ "connected": "เชื่อมต่อแล้ว", "connection_sync": "การเชื่อมต่อและซิงค์", "connections": "การเชื่อมต่อ", + "connections_desc": "จัดการการเชื่อมต่อกับบริการและ API ของบุคคลที่สาม", "connectWalletPrompt": "เชื่อมต่อกระเป๋าเงินของคุณกับ WalletConnect เพื่อทำธุรกรรม", "contact": "ผู้ติดต่อ", "contact_list_contacts": "รายชื่อผู้ติดต่อ", @@ -756,6 +757,7 @@ "privacy": "ความเป็นส่วนตัว", "privacy_and_security": "ความเป็นส่วนตัวและความปลอดภัย", "privacy_and_security_desc": "กำหนดค่าการยืนยันตัวตนและการตั้งค่าความปลอดภัย และตั้งค่า Cake 2FA", + "privacy_desc": "เปลี่ยนการตั้งค่าความเป็นส่วนตัวและสลับคุณสมบัติความเป็นส่วนตัวพิเศษ", "privacy_features": "ฟีเจอร์ความเป็นส่วนตัว", "privacy_policy": "นโยบายความเป็นส่วนตัว", "privacy_settings": "การตั้งค่าความเป็นส่วนตัว", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index ee61e64e0..2893fdc42 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -242,6 +242,7 @@ "connected": "Nakakonekta", "connection_sync": "Koneksyon at pag-sync", "connections": "Mga koneksyon", + "connections_desc": "Pamahalaan ang mga koneksyon sa mga serbisyo at mga third party na API.", "connectWalletPrompt": "Ikonekta ang iyong wallet sa WalletConnect para makapag-transact", "contact": "Kontak", "contact_list_contacts": "Mga Contact", @@ -756,6 +757,7 @@ "privacy": "Pagkapribado", "privacy_and_security": "Pagkapribado at Seguridad", "privacy_and_security_desc": "I-configure ang mga setting ng pagpapatotoo at seguridad at i-set up ang Cake 2FA.", + "privacy_desc": "Baguhin ang mga setting ng privacy at i-toggle ang mga espesyal na feature sa privacy.", "privacy_features": "Mga tampok sa privacy", "privacy_policy": "Patakaran sa Privacy", "privacy_settings": "Mga setting sa privacy", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index 5975b61d8..f2753f940 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -242,6 +242,7 @@ "connected": "Bağlı", "connection_sync": "Bağlantı ve senkronizasyon", "connections": "Bağlantılar", + "connections_desc": "Hizmetlere ve üçüncü taraf API'lere olan bağlantıları yönetin.", "connectWalletPrompt": "İşlem yapmak için cüzdanınızı WalletConnect ile bağlayın", "contact": "Kişi", "contact_list_contacts": "Kişiler", @@ -756,6 +757,7 @@ "privacy": "Gizlilik", "privacy_and_security": "Gizlilik ve Güvenlik", "privacy_and_security_desc": "Kimlik doğrulama ve güvenlik ayarlarını yapılandırın ve Cake 2FA'yı ayarlayın.", + "privacy_desc": "Gizlilik ayarlarını değiştirin ve özel gizlilik özelliklerini değiştirin.", "privacy_features": "Gizlilik özellikleri", "privacy_policy": "Gizlilik Politikası", "privacy_settings": "Gizlilik ayarları", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 06dc6ff98..fc280695c 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -242,6 +242,7 @@ "connected": "Підключено", "connection_sync": "Підключення та синхронізація", "connections": "Підключення", + "connections_desc": "Керуйте підключеннями до служб і сторонніх API.", "connectWalletPrompt": "Підключіть свій гаманець через WalletConnect, щоб здійснювати транзакції", "contact": "Контакт", "contact_list_contacts": "Контакти", @@ -756,6 +757,7 @@ "privacy": "Конфіденційність", "privacy_and_security": "Конфіденційність і безпека", "privacy_and_security_desc": "Налаштуйте параметри автентифікації та безпеки й налаштуйте Cake 2FA.", + "privacy_desc": "Змініть налаштування конфіденційності та ввімкніть спеціальні функції конфіденційності.", "privacy_features": "Функції приватності", "privacy_policy": "Політика конфіденційності", "privacy_settings": "Налаштування конфіденційності", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 058ea4429..e8de667ac 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -242,6 +242,7 @@ "connected": "منسلک", "connection_sync": "کنکشن اور ہم آہنگی", "connections": "کنکشنز", + "connections_desc": "سروسز اور تھرڈ پارٹی APIs کے کنکشنز کا نظم کریں۔", "connectWalletPrompt": "لین دین کرنے کے لیے WalletConnect کے ذریعے اپنا والیٹ کنیکٹ کریں", "contact": "رابطہ", "contact_list_contacts": "رابطے", @@ -758,6 +759,7 @@ "privacy": "رازداری", "privacy_and_security": "رازداری اور سیکیورٹی", "privacy_and_security_desc": "تصدیق اور سیکیورٹی کی ترتیبات کو کنفیگر کریں اور Cake 2FA سیٹ اپ کریں۔", + "privacy_desc": "رازداری کی ترتیبات کو تبدیل کریں اور خصوصی رازداری کی خصوصیات کو ٹوگل کریں۔", "privacy_features": "رازداری کی خصوصیات", "privacy_policy": "رازداری کی پالیسی", "privacy_settings": "پرائیویسی کی ترتیبات", diff --git a/res/values/strings_vi.arb b/res/values/strings_vi.arb index 4bc63830c..63efd82e7 100644 --- a/res/values/strings_vi.arb +++ b/res/values/strings_vi.arb @@ -241,6 +241,7 @@ "connected": "Đã kết nối", "connection_sync": "Kết nối và đồng bộ", "connections": "Kết nối", + "connections_desc": "Quản lý kết nối với các dịch vụ và API của bên thứ ba.", "connectWalletPrompt": "Kết nối ví của bạn với WalletConnect để thực hiện các giao dịch", "contact": "Liên hệ", "contact_list_contacts": "Liên hệ", @@ -754,6 +755,7 @@ "privacy": "Quyền riêng tư", "privacy_and_security": "Quyền riêng tư & Bảo mật", "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.", + "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.", "privacy_features": "Tính năng quyền riêng tư", "privacy_policy": "Chính sách bảo mật", "privacy_settings": "Cài đặt quyền riêng tư", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 485a54150..177a2422c 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -242,6 +242,7 @@ "connected": "Ti sopọ", "connection_sync": "Ìsopọ̀ àti ìbámu", "connections": "Awọn asopọ", + "connections_desc": "Ṣakoso awọn asopọ si awọn iṣẹ ati awọn API ẹnikẹta.", "connectWalletPrompt": "So apamọwọ rẹ pọ̀ mọ́ WalletConnect láti ṣe àwọn ìdúnàdúrà", "contact": "Olùbáṣepọ̀", "contact_list_contacts": "Àwọn olùbásọ̀rọ̀", @@ -757,6 +758,7 @@ "privacy": "Àṣírí", "privacy_and_security": "Ìpamọ́ & Ààbò", "privacy_and_security_desc": "Ṣètò ìfàṣẹsí àti àwọn àtúnṣe aabo, kí o sì ṣètò Cake 2FA.", + "privacy_desc": "Yi eto ipamọ pada ki o yi awọn ẹya aṣiri pataki pada.", "privacy_features": "Awọn ẹya ìpamọ́", "privacy_policy": "Ilana Aṣírí", "privacy_settings": "Àwọn ààtò ìpamọ́", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index aacc64cbb..e8fc8f72e 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -242,6 +242,7 @@ "connected": "已连接", "connection_sync": "连接与同步", "connections": "连接", + "connections_desc": "管理与服务和第三方 API 的连接。", "connectWalletPrompt": "通过 WalletConnect 连接您的钱包以进行交易", "contact": "联系人", "contact_list_contacts": "联系人", @@ -756,6 +757,7 @@ "privacy": "隐私", "privacy_and_security": "隐私与安全", "privacy_and_security_desc": "配置身份验证与安全设置,并设置 Cake 2FA。", + "privacy_desc": "更改隐私设置并切换特殊隐私功能。", "privacy_features": "隐私功能", "privacy_policy": "隐私政策", "privacy_settings": "隐私设置",