mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-24 06:48:38 +02:00
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:
@@ -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
|
||||
],
|
||||
|
||||
@@ -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());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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),
|
||||
// ),
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user