New Settings (#3065)

* Update display_settings_page.dart

* Update settings_choices_cell.dart

* Update settings_theme_choice.dart

* Convert display_settings_page.dart to NewListSection

* Cleanup [skip ci]

* Minor

* Minor [skip ci]

* Add SizedBox to scroll view

* Upgrade receive_top_bar.dart with gradient and optional child content

* Adjust animations

* Add modal_page_wrapper.dart

* Add option to hide AppBar for BasePage [skip ci]

* New settings all final (#3067)

* Conflict

* ModalPageWrapper improved abstraction

* display_settings_page.dart minor update

* connection_sync_page.dart redesign

* Conflict

* manage_nodes_page.dart initial redesign

* other settings initial

* Conflict

* add optional subtitle to standard_list.dart

* add connection_sync_view_model.dart

* Add missing images

* Conflict

* Update list item widgets

* Conflict

* Conflict

* Conflict

* minor updates

* Conflict

* Fixes + move Mweb to privacy page

* Conflict

* Remove observer from modal_page_wrapper.dart

* Conflict

* Conflict

* Refactor settings_page.dart with suggestions

* Suggestion fixes

* Conflicts + fix About page

* Fix sync bar conflict

* Update Connections page title [skip ci]

* Trigger CI

* Fix Lightning and Payjoin log export

* Update MWEB node page

* Add FeatureFlag to AutomaticNodeSwitching

* Fix address text on privacy_page.dart

* Move WalletConnect from connection_sync_page.dart to settings_page.dart

* Add WalletConnect icon

* Fix settings icons

* Make text strings use S.of(context) and fix About string in settings_page.dart

* Display settings page fixes

* modal_page_wrapper.dart minor suggestions

* Missingimage

* Add spacing to list_item_selector_widget.dart

* Fix error on manage_nodes_page.dart
This commit is contained in:
tuxsudo
2026-03-14 14:15:42 +01:00
committed by GitHub
parent aa18ea3960
commit 3815fc30c6
80 changed files with 1957 additions and 1339 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+7 -4
View File
@@ -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<void> setup({
return PowNodeListViewModel(_powNodeSource, appStore);
});
getIt.registerFactory(() => ConnectionSyncPage(getIt.get<DashboardViewModel>()));
getIt.registerFactory(() => ConnectionSyncViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!));
getIt.registerFactory(() => ConnectionSyncPage(getIt.get<ConnectionSyncViewModel>()));
getIt.registerFactory(() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(),
getIt.get<AuthService>(), getIt.get<AppStore>().wallet!.isHardwareWallet));
@@ -1140,7 +1143,7 @@ Future<void> setup({
getIt.registerFactory(() => TrocadorProvidersPage(getIt.get<TrocadorProvidersViewModel>()));
getIt.registerFactory(() => DomainLookupsPage(getIt.get<PrivacySettingsViewModel>()));
getIt.registerFactory(() => DomainLookupsPage(getIt.get<ConnectionSyncViewModel>()));
getIt.registerFactory(() => DisplaySettingsPage(getIt.get<DisplaySettingsViewModel>()));
@@ -1691,9 +1694,9 @@ Future<void> setup({
getIt.registerFactoryParam<ManageNodesPage, bool, void>((bool isPow, _) {
if (isPow) {
return ManageNodesPage(isPow, powNodeListViewModel: getIt.get<PowNodeListViewModel>());
return ManageNodesPage(isPow, powNodeListViewModel: getIt.get<PowNodeListViewModel>(), dashboardViewModel: getIt.get<DashboardViewModel>());
}
return ManageNodesPage(isPow, nodeListViewModel: getIt.get<NodeListViewModel>());
return ManageNodesPage(isPow, nodeListViewModel: getIt.get<NodeListViewModel>(), dashboardViewModel: getIt.get<DashboardViewModel>());
});
getIt.registerFactory(
+54 -55
View File
@@ -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<AboutPage> {
@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<AboutPage> {
foregroundColor: Theme.of(context).colorScheme.primary,
trailingIconSize: 10)
]
}),
)
],
)
]));
})
],
)
])),
);
}
}
+56 -35
View File
@@ -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<String, List<ListItem>> 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<ListItem>()
.toList())));
List<ListItem> 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<ListItem>()
.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(),
),
),]
),
@@ -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<ManageNodesPage>(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);
}
}
}
@@ -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: <Color>[
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,
],
),
),
);
}
}
@@ -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 {
),
);
}
}
}
+16 -17
View File
@@ -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<ThemeStore>().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),
),
);
},
@@ -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<NodeForm> {
initialValue: vm.socksProxyAddress,
validator: SocksProxyNodeAddressValidator(),
),
if(FeatureFlag.isAutomaticNodeSwitchingEnabled)
ListItemCheckbox(
keyValue: vm.autoSwitchingUIKey,
label: S.current.enable_for_auto_switching,
@@ -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;
@@ -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<bool>(
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<void>(
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<void>(
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<void> _presentReconnectAlert(BuildContext context) async {
await showPopUp<void>(
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());
},
);
}
}
@@ -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<SyncStatusDisplayMode>(
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<BitcoinAmountDisplayMode>(
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<FiatCurrency>(
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<String>(
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<ThemeMode>(
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<ThemeMode>(
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<void>(
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<void>(
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<void>(
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<void>(
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
@@ -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
],
+81 -42
View File
@@ -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<void>(
context: context,
@@ -110,11 +133,10 @@ class ManageNodesPage extends BasePage {
);
},
);
return nodeListRow;
},
);
},
),
return nodeListRow;
},
);
},
);
},
),
@@ -122,4 +144,21 @@ class ManageNodesPage extends BasePage {
),
);
}
Future<void> _presentReconnectAlert(BuildContext context) async {
await showPopUp<void>(
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());
},
);
}
}
+46 -38
View File
@@ -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<MwebNodePage> createState() => _MwebNodePageState();
}
class _MwebNodePageState extends State<MwebNodePage> {
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: <Widget>[
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);
}
}
+199 -154
View File
@@ -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<void>(
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<void>(
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<void> onExportLNLog(BuildContext context) async {
final file = await _otherSettingsViewModel.getLightningLog();
+88 -192
View File
@@ -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<FiatApiMode>(
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<ExchangeApiMode>(
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<bool>(
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),
// ),
],
);
}),
],
);
}),
),
),
);
}
+151 -156
View File
@@ -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<PinCodeWidget> pinCtx, String _) async {
pinCtx.close();
_securitySettingsViewModel.setEnableDuressPin(true);
},
);
}
if (confirmation) {
Navigator.of(context).pushNamed(
Routes.setupDuressPin,
arguments:
(PinCodeState<PinCodeWidget> 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<void>(
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<PinCodeWidget> setupPinContext, String _) {
setupPinContext.close();
await showPopUp<void>(
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<PinCodeWidget> 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,
);
})
]
}),
),
],
),
);
}
@@ -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 {
),
);
}
}
}
@@ -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: () {
@@ -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;
@@ -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),
),
)
@@ -37,6 +37,7 @@ class _ListItemCheckboxWidgetState extends State<ListItemCheckboxWidget> {
@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<ListItemCheckboxWidget> {
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(
@@ -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,
@@ -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),
),
],
),
],
);
});
}
}
}
+44 -5
View File
@@ -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<Widget> 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];
@@ -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);
@@ -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<Balance, TransactionHistoryBase<TransactionInfo>, 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<bool>(
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));
}));
}
}
}
@@ -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';
}
}
}
@@ -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
@@ -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<Balance, TransactionHistoryBase<TransactionInfo>, 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;
@@ -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;

Before

Width:  |  Height:  |  Size: 778 B

After

Width:  |  Height:  |  Size: 778 B

+2 -9
View File
@@ -1,10 +1,3 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_14441_461975)">
<path d="M8.51392 11.9985L5 8.48462L5.66456 7.82006L8.51392 10.6576L11.3633 7.82006L12.0278 8.48462L8.51392 11.9985ZM5.67404 4.16738L5 3.51245L8.51392 -0.00146484L12.0278 3.51245L11.3538 4.16738L8.51392 1.33947L5.67404 4.16738Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_14441_461975">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
<svg width="8" height="13" viewBox="0 0 8 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.76917 12.8717L0 9.1025L0.712833 8.38967L3.76917 11.4333L6.8255 8.38967L7.53833 9.1025L3.76917 12.8717ZM0.723 4.47167L0 3.76917L3.76917 0L7.53833 3.76917L6.81533 4.47167L3.76917 1.43833L0.723 4.47167Z" fill="#8C9FBB"/>
</svg>

Before

Width:  |  Height:  |  Size: 551 B

After

Width:  |  Height:  |  Size: 331 B

Before

Width:  |  Height:  |  Size: 778 B

After

Width:  |  Height:  |  Size: 778 B

Before

Width:  |  Height:  |  Size: 778 B

After

Width:  |  Height:  |  Size: 778 B

+33 -38
View File
@@ -1,40 +1,35 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_16845_60754)">
<g clip-path="url(#clip1_16845_60754)">
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint0_linear_16845_60754)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint1_linear_16845_60754)"/>
<path d="M11.8691 3.35876C14.2163 3.35876 16.1192 5.26162 16.1192 7.60881V9.85891H17.4943C18.1155 9.85897 18.6191 10.3625 18.6191 10.9838V18.2337C18.6191 18.855 18.1155 19.3586 17.4943 19.3586H6.24403C5.62276 19.3586 5.11914 18.855 5.11914 18.2337V10.9838C5.11916 10.3625 5.62278 9.85897 6.24403 9.85891H7.61908V7.60881C7.6191 5.26165 9.52197 3.3588 11.8691 3.35876ZM11.8691 13.0787C11.049 13.0787 10.384 13.7436 10.384 14.5638C10.384 15.3839 11.049 16.0489 11.8691 16.0489C12.6893 16.0489 13.3543 15.3839 13.3543 14.5638C13.3543 13.7436 12.6893 13.0787 11.8691 13.0787ZM11.8691 5.35871C10.6265 5.35875 9.61938 6.36621 9.61936 7.60881V9.85891H14.1193V7.60881C14.1192 6.36619 13.1118 5.35871 11.8691 5.35871Z" fill="white"/>
<path d="M11.8691 3.35876C14.2163 3.35876 16.1192 5.26162 16.1192 7.60881V9.85891H17.4943C18.1155 9.85897 18.6191 10.3625 18.6191 10.9838V18.2337C18.6191 18.855 18.1155 19.3586 17.4943 19.3586H6.24403C5.62276 19.3586 5.11914 18.855 5.11914 18.2337V10.9838C5.11916 10.3625 5.62278 9.85897 6.24403 9.85891H7.61908V7.60881C7.6191 5.26165 9.52197 3.3588 11.8691 3.35876ZM11.8691 13.0787C11.049 13.0787 10.384 13.7436 10.384 14.5638C10.384 15.3839 11.049 16.0489 11.8691 16.0489C12.6893 16.0489 13.3543 15.3839 13.3543 14.5638C13.3543 13.7436 12.6893 13.0787 11.8691 13.0787ZM11.8691 5.35871C10.6265 5.35875 9.61938 6.36621 9.61936 7.60881V9.85891H14.1193V7.60881C14.1192 6.36619 13.1118 5.35871 11.8691 5.35871Z" fill="url(#paint2_linear_16845_60754)"/>
<path d="M11.8691 3.35876C14.2163 3.35876 16.1192 5.26162 16.1192 7.60881V9.85891H17.4943C18.1155 9.85897 18.6191 10.3625 18.6191 10.9838V18.2337C18.6191 18.855 18.1155 19.3586 17.4943 19.3586H6.24403C5.62276 19.3586 5.11914 18.855 5.11914 18.2337V10.9838C5.11916 10.3625 5.62278 9.85897 6.24403 9.85891H7.61908V7.60881C7.6191 5.26165 9.52197 3.3588 11.8691 3.35876ZM11.8691 13.0787C11.049 13.0787 10.384 13.7436 10.384 14.5638C10.384 15.3839 11.049 16.0489 11.8691 16.0489C12.6893 16.0489 13.3543 15.3839 13.3543 14.5638C13.3543 13.7436 12.6893 13.0787 11.8691 13.0787ZM11.8691 5.35871C10.6265 5.35875 9.61938 6.36621 9.61936 7.60881V9.85891H14.1193V7.60881C14.1192 6.36619 13.1118 5.35871 11.8691 5.35871Z" fill="url(#paint3_linear_16845_60754)"/>
<path d="M11.8691 3.35876C14.2163 3.35876 16.1192 5.26162 16.1192 7.60881V9.85891H17.4943C18.1155 9.85897 18.6191 10.3625 18.6191 10.9838V18.2337C18.6191 18.855 18.1155 19.3586 17.4943 19.3586H6.24403C5.62276 19.3586 5.11914 18.855 5.11914 18.2337V10.9838C5.11916 10.3625 5.62278 9.85897 6.24403 9.85891H7.61908V7.60881C7.6191 5.26165 9.52197 3.3588 11.8691 3.35876ZM11.8691 13.0787C11.049 13.0787 10.384 13.7436 10.384 14.5638C10.384 15.3839 11.049 16.0489 11.8691 16.0489C12.6893 16.0489 13.3543 15.3839 13.3543 14.5638C13.3543 13.7436 12.6893 13.0787 11.8691 13.0787ZM11.8691 5.35871C10.6265 5.35875 9.61938 6.36621 9.61936 7.60881V9.85891H14.1193V7.60881C14.1192 6.36619 13.1118 5.35871 11.8691 5.35871Z" fill="url(#paint4_linear_16845_60754)"/>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_16845_60754" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#8F8F8F"/>
<stop offset="1" stop-color="#6D6D6D"/>
</linearGradient>
<linearGradient id="paint1_linear_16845_60754" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#F7931A"/>
<stop offset="1" stop-color="#F67300"/>
</linearGradient>
<linearGradient id="paint2_linear_16845_60754" x1="11.8691" y1="3.35876" x2="11.8691" y2="19.3586" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#A4B8FF"/>
</linearGradient>
<linearGradient id="paint3_linear_16845_60754" x1="11.8691" y1="3.35876" x2="11.8691" y2="19.3586" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#A4CEFF"/>
</linearGradient>
<linearGradient id="paint4_linear_16845_60754" x1="11.8691" y1="3.35876" x2="11.8691" y2="19.3586" gradientUnits="userSpaceOnUse">
<stop stop-color="#5F330B"/>
<stop offset="1" stop-color="#462100"/>
</linearGradient>
<clipPath id="clip0_16845_60754">
<rect width="24" height="24" fill="white"/>
</clipPath>
<clipPath id="clip1_16845_60754">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
<g clip-path="url(#clip0_16529_391320)">
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint0_linear_16529_391320)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint1_linear_16529_391320)"/>
<path d="M11.8711 3.3584C14.2183 3.3584 16.1211 5.26126 16.1212 7.60844V9.85854H17.4962C18.1175 9.8586 18.6211 10.3622 18.6211 10.9834V18.2334C18.6211 18.8547 18.1175 19.3582 17.4962 19.3583H6.24598C5.62471 19.3582 5.12109 18.8547 5.12109 18.2334V10.9834C5.12112 10.3622 5.62473 9.8586 6.24598 9.85854H7.62103V7.60844C7.62105 5.26128 9.52393 3.35844 11.8711 3.3584ZM11.8711 13.0783C11.051 13.0783 10.386 13.7433 10.386 14.5634C10.386 15.3835 11.051 16.0485 11.8711 16.0485C12.6912 16.0485 13.3562 15.3835 13.3562 14.5634C13.3562 13.7433 12.6912 13.0783 11.8711 13.0783ZM11.8711 5.35834C10.6285 5.35838 9.62133 6.36584 9.62131 7.60844V9.85854H14.1212V7.60844C14.1212 6.36582 13.1137 5.35834 11.8711 5.35834Z" fill="white"/>
<path d="M11.8711 3.3584C14.2183 3.3584 16.1211 5.26126 16.1212 7.60844V9.85854H17.4962C18.1175 9.8586 18.6211 10.3622 18.6211 10.9834V18.2334C18.6211 18.8547 18.1175 19.3582 17.4962 19.3583H6.24598C5.62471 19.3582 5.12109 18.8547 5.12109 18.2334V10.9834C5.12112 10.3622 5.62473 9.8586 6.24598 9.85854H7.62103V7.60844C7.62105 5.26128 9.52393 3.35844 11.8711 3.3584ZM11.8711 13.0783C11.051 13.0783 10.386 13.7433 10.386 14.5634C10.386 15.3835 11.051 16.0485 11.8711 16.0485C12.6912 16.0485 13.3562 15.3835 13.3562 14.5634C13.3562 13.7433 12.6912 13.0783 11.8711 13.0783ZM11.8711 5.35834C10.6285 5.35838 9.62133 6.36584 9.62131 7.60844V9.85854H14.1212V7.60844C14.1212 6.36582 13.1137 5.35834 11.8711 5.35834Z" fill="url(#paint2_linear_16529_391320)"/>
<path d="M11.8711 3.3584C14.2183 3.3584 16.1211 5.26126 16.1212 7.60844V9.85854H17.4962C18.1175 9.8586 18.6211 10.3622 18.6211 10.9834V18.2334C18.6211 18.8547 18.1175 19.3582 17.4962 19.3583H6.24598C5.62471 19.3582 5.12109 18.8547 5.12109 18.2334V10.9834C5.12112 10.3622 5.62473 9.8586 6.24598 9.85854H7.62103V7.60844C7.62105 5.26128 9.52393 3.35844 11.8711 3.3584ZM11.8711 13.0783C11.051 13.0783 10.386 13.7433 10.386 14.5634C10.386 15.3835 11.051 16.0485 11.8711 16.0485C12.6912 16.0485 13.3562 15.3835 13.3562 14.5634C13.3562 13.7433 12.6912 13.0783 11.8711 13.0783ZM11.8711 5.35834C10.6285 5.35838 9.62133 6.36584 9.62131 7.60844V9.85854H14.1212V7.60844C14.1212 6.36582 13.1137 5.35834 11.8711 5.35834Z" fill="url(#paint3_linear_16529_391320)"/>
<path d="M11.8711 3.3584C14.2183 3.3584 16.1211 5.26126 16.1212 7.60844V9.85854H17.4962C18.1175 9.8586 18.6211 10.3622 18.6211 10.9834V18.2334C18.6211 18.8547 18.1175 19.3582 17.4962 19.3583H6.24598C5.62471 19.3582 5.12109 18.8547 5.12109 18.2334V10.9834C5.12112 10.3622 5.62473 9.8586 6.24598 9.85854H7.62103V7.60844C7.62105 5.26128 9.52393 3.35844 11.8711 3.3584ZM11.8711 13.0783C11.051 13.0783 10.386 13.7433 10.386 14.5634C10.386 15.3835 11.051 16.0485 11.8711 16.0485C12.6912 16.0485 13.3562 15.3835 13.3562 14.5634C13.3562 13.7433 12.6912 13.0783 11.8711 13.0783ZM11.8711 5.35834C10.6285 5.35838 9.62133 6.36584 9.62131 7.60844V9.85854H14.1212V7.60844C14.1212 6.36582 13.1137 5.35834 11.8711 5.35834Z" fill="url(#paint4_linear_16529_391320)"/>
</g>
<defs>
<linearGradient id="paint0_linear_16529_391320" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#8F8F8F"/>
<stop offset="1" stop-color="#6D6D6D"/>
</linearGradient>
<linearGradient id="paint1_linear_16529_391320" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#F7931A"/>
<stop offset="1" stop-color="#F67300"/>
</linearGradient>
<linearGradient id="paint2_linear_16529_391320" x1="11.8711" y1="3.3584" x2="11.8711" y2="19.3583" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#A4B8FF"/>
</linearGradient>
<linearGradient id="paint3_linear_16529_391320" x1="11.8711" y1="3.3584" x2="11.8711" y2="19.3583" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#A4CEFF"/>
</linearGradient>
<linearGradient id="paint4_linear_16529_391320" x1="11.8711" y1="3.3584" x2="11.8711" y2="19.3583" gradientUnits="userSpaceOnUse">
<stop stop-color="#5F330B"/>
<stop offset="1" stop-color="#462100"/>
</linearGradient>
<clipPath id="clip0_16529_391320">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

+40 -45
View File
@@ -1,47 +1,42 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_16845_60955)">
<g clip-path="url(#clip1_16845_60955)">
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="black"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint0_linear_16845_60955)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint1_linear_16845_60955)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint2_linear_16845_60955)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="#2C5CF6"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint3_linear_16845_60955)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint4_linear_16845_60955)"/>
<path d="M12 20.8489C9.98136 20.2984 8.31007 19.1102 6.98613 17.2843C5.66204 15.4584 5 13.417 5 11.1602V5.79006L12 3.16949L19 5.79006V11.1602C19 13.417 18.338 15.4584 17.0139 17.2843C15.6899 19.1102 14.0186 20.2984 12 20.8489ZM12 19.3736C13.5089 18.9069 14.7689 17.9852 15.78 16.6086C16.7911 15.2319 17.3822 13.6958 17.5533 12.0002H12V4.6591L6.4 6.75023V11.5714C6.4 11.6862 6.41556 11.8291 6.44667 12.0002H12V19.3736Z" fill="#E3E3E3"/>
<path d="M12 20.8489C9.98136 20.2984 8.31007 19.1102 6.98613 17.2843C5.66204 15.4584 5 13.417 5 11.1602V5.79006L12 3.16949L19 5.79006V11.1602C19 13.417 18.338 15.4584 17.0139 17.2843C15.6899 19.1102 14.0186 20.2984 12 20.8489ZM12 19.3736C13.5089 18.9069 14.7689 17.9852 15.78 16.6086C16.7911 15.2319 17.3822 13.6958 17.5533 12.0002H12V4.6591L6.4 6.75023V11.5714C6.4 11.6862 6.41556 11.8291 6.44667 12.0002H12V19.3736Z" fill="url(#paint5_linear_16845_60955)"/>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_16845_60955" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#2C2C2C"/>
<stop offset="1" stop-color="#191919"/>
</linearGradient>
<linearGradient id="paint1_linear_16845_60955" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#351C83"/>
<stop offset="1" stop-color="#0C0033"/>
</linearGradient>
<linearGradient id="paint2_linear_16845_60955" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF6200"/>
<stop offset="1" stop-color="#E20F0F"/>
</linearGradient>
<linearGradient id="paint3_linear_16845_60955" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#2C5CF6"/>
<stop offset="1" stop-color="#0F37FF"/>
</linearGradient>
<linearGradient id="paint4_linear_16845_60955" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#3B96FF"/>
<stop offset="1" stop-color="#0044F0"/>
</linearGradient>
<linearGradient id="paint5_linear_16845_60955" x1="12" y1="3.16949" x2="12" y2="20.8489" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#A4CEFF"/>
</linearGradient>
<clipPath id="clip0_16845_60955">
<rect width="24" height="24" fill="white"/>
</clipPath>
<clipPath id="clip1_16845_60955">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
<g clip-path="url(#clip0_16529_391334)">
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="black"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint0_linear_16529_391334)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint1_linear_16529_391334)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint2_linear_16529_391334)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="#2C5CF6"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint3_linear_16529_391334)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint4_linear_16529_391334)"/>
<path d="M12 20.8494C9.98136 20.2988 8.31007 19.1106 6.98613 17.2847C5.66204 15.4588 5 13.4175 5 11.1607V5.79049L12 3.16992L19 5.79049V11.1607C19 13.4175 18.338 15.4588 17.0139 17.2847C15.6899 19.1106 14.0186 20.2988 12 20.8494ZM12 19.374C13.5089 18.9073 14.7689 17.9857 15.78 16.609C16.7911 15.2323 17.3822 13.6962 17.5533 12.0007H12V4.65952L6.4 6.75066V11.5718C6.4 11.6866 6.41556 11.8295 6.44667 12.0007H12V19.374Z" fill="#E3E3E3"/>
<path d="M12 20.8494C9.98136 20.2988 8.31007 19.1106 6.98613 17.2847C5.66204 15.4588 5 13.4175 5 11.1607V5.79049L12 3.16992L19 5.79049V11.1607C19 13.4175 18.338 15.4588 17.0139 17.2847C15.6899 19.1106 14.0186 20.2988 12 20.8494ZM12 19.374C13.5089 18.9073 14.7689 17.9857 15.78 16.609C16.7911 15.2323 17.3822 13.6962 17.5533 12.0007H12V4.65952L6.4 6.75066V11.5718C6.4 11.6866 6.41556 11.8295 6.44667 12.0007H12V19.374Z" fill="url(#paint5_linear_16529_391334)"/>
</g>
<defs>
<linearGradient id="paint0_linear_16529_391334" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#2C2C2C"/>
<stop offset="1" stop-color="#191919"/>
</linearGradient>
<linearGradient id="paint1_linear_16529_391334" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#351C83"/>
<stop offset="1" stop-color="#0C0033"/>
</linearGradient>
<linearGradient id="paint2_linear_16529_391334" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF6200"/>
<stop offset="1" stop-color="#E20F0F"/>
</linearGradient>
<linearGradient id="paint3_linear_16529_391334" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#2C5CF6"/>
<stop offset="1" stop-color="#0F37FF"/>
</linearGradient>
<linearGradient id="paint4_linear_16529_391334" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#3B96FF"/>
<stop offset="1" stop-color="#0044F0"/>
</linearGradient>
<linearGradient id="paint5_linear_16529_391334" x1="12" y1="3.16992" x2="12" y2="20.8494" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#A4CEFF"/>
</linearGradient>
<clipPath id="clip0_16529_391334">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

+29
View File
@@ -0,0 +1,29 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_17329_949648)">
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint0_linear_17329_949648)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint1_linear_17329_949648)"/>
<path d="M0 8C0 5.19974 0 3.79961 0.544967 2.73005C1.02433 1.78924 1.78924 1.02433 2.73005 0.544967C3.79961 0 5.19974 0 8 0H16C18.8003 0 20.2004 0 21.27 0.544967C22.2108 1.02433 22.9757 1.78924 23.455 2.73005C24 3.79961 24 5.19974 24 8V16C24 18.8003 24 20.2004 23.455 21.27C22.9757 22.2108 22.2108 22.9757 21.27 23.455C20.2004 24 18.8003 24 16 24H8C5.19974 24 3.79961 24 2.73005 23.455C1.78924 22.9757 1.02433 22.2108 0.544967 21.27C0 20.2004 0 18.8003 0 16V8Z" fill="url(#paint2_linear_17329_949648)"/>
<path d="M21.6004 12.2103L15.9535 17.8165L12.0004 13.8926L8.04727 17.8165L2.40039 12.2103L4.0931 10.5301L8.04727 14.454L12.0004 10.5301L15.9535 14.454L19.9077 10.5301L21.6004 12.2103ZM5.78997 8.85195C9.62131 5.04933 14.3815 5.04937 18.2129 8.85195L16.5181 10.5332C13.6046 7.64263 10.3981 7.64269 7.48477 10.5342L5.78997 8.85195Z" fill="url(#paint3_linear_17329_949648)"/>
</g>
<defs>
<linearGradient id="paint0_linear_17329_949648" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#0082F8"/>
<stop offset="1" stop-color="#0666FF"/>
</linearGradient>
<linearGradient id="paint1_linear_17329_949648" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#2B9AFF"/>
<stop offset="1" stop-color="#0666FF"/>
</linearGradient>
<linearGradient id="paint2_linear_17329_949648" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#3396FF"/>
<stop offset="1" stop-color="#007CFF"/>
</linearGradient>
<linearGradient id="paint3_linear_17329_949648" x1="12.0004" y1="6" x2="12.0004" y2="17.8165" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#BFDEFF"/>
</linearGradient>
<clipPath id="clip0_17329_949648">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

+2
View File
@@ -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": "إعدادات الخصوصية",
+2
View File
@@ -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": "Настройки за поверителност",
+2
View File
@@ -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í",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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": "تنظیمات حریم خصوصی",
+2
View File
@@ -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é",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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": "गोपनीयता सेटिंग्स",
+2
View File
@@ -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",
+2
View File
@@ -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": "Գաղտնիության կարգավորումներ",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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": "プライバシー設定",
+2
View File
@@ -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": "개인정보 보호 설정",
+2
View File
@@ -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": "ကိုယ်ရေးကိုယ်တာ ဆက်တင်များ",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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": "Настройки конфиденциальности",
+2
View File
@@ -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": "การตั้งค่าความเป็นส่วนตัว",
+2
View File
@@ -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",
+2
View File
@@ -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ı",
+2
View File
@@ -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": "Налаштування конфіденційності",
+2
View File
@@ -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": "پرائیویسی کی ترتیبات",
+2
View File
@@ -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ư",
+2
View File
@@ -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ọ́",
+2
View File
@@ -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": "隐私设置",