From ef96f3b76c3fc1e7a42b835879142e7dde4a0f2f Mon Sep 17 00:00:00 2001 From: sneurlax Date: Wed, 29 May 2024 17:45:42 -0500 Subject: [PATCH 1/7] Add enableLelantusScanning bool and restore/rescan logic Squashed commit msgs: add (currently unused) bool enableLelantusScanning to WalletInfo only do Lelantus things if Lelantus is enabled 6ac468 --- lib/wallets/isar/models/wallet_info.dart | 1 + lib/wallets/wallet/impl/firo_wallet.dart | 89 +++++++++++++++--------- 2 files changed, 58 insertions(+), 32 deletions(-) diff --git a/lib/wallets/isar/models/wallet_info.dart b/lib/wallets/isar/models/wallet_info.dart index a84fe4348..351229c29 100644 --- a/lib/wallets/isar/models/wallet_info.dart +++ b/lib/wallets/isar/models/wallet_info.dart @@ -507,4 +507,5 @@ abstract class WalletInfoKeys { static const String tezosDerivationPath = "tezosDerivationPathKey"; static const String lelantusCoinIsarRescanRequired = "lelantusCoinIsarRescanRequired"; + static const String enableLelantusScanning = "enableLelantusScanning"; } diff --git a/lib/wallets/wallet/impl/firo_wallet.dart b/lib/wallets/wallet/impl/firo_wallet.dart index dce8cd9fa..510d08cfb 100644 --- a/lib/wallets/wallet/impl/firo_wallet.dart +++ b/lib/wallets/wallet/impl/firo_wallet.dart @@ -610,13 +610,25 @@ class FiroWallet extends Bip39HDWallet await mainDB.deleteWalletBlockchainData(walletId); } + // Parse otherDataJsonString to get the enableLelantusScanning value. + bool? enableLelantusScanning = false; + if (info.otherDataJsonString != null) { + final otherDataJson = json.decode(info.otherDataJsonString!); + enableLelantusScanning = + otherDataJson["enableLelantusScanning"] as bool? ?? false; + } + // lelantus - final latestSetId = await electrumXClient.getLelantusLatestCoinId(); - final setDataMapFuture = getSetDataMap(latestSetId); - final usedSerialNumbersFuture = - electrumXCachedClient.getUsedCoinSerials( - cryptoCurrency: info.coin, - ); + int? latestSetId; + Future>? setDataMapFuture; + Future>? usedSerialNumbersFuture; + if (enableLelantusScanning) { + latestSetId = await electrumXClient.getLelantusLatestCoinId(); + setDataMapFuture = getSetDataMap(latestSetId); + usedSerialNumbersFuture = electrumXCachedClient.getUsedCoinSerials( + cryptoCurrency: info.coin, + ); + } // spark final latestSparkCoinId = await electrumXClient.getSparkLatestCoinId(); @@ -736,39 +748,52 @@ class FiroWallet extends Bip39HDWallet updateUTXOs(), ]); - final futureResults = await Future.wait([ - usedSerialNumbersFuture, - setDataMapFuture, - sparkAnonSetFuture, - sparkUsedCoinTagsFuture, - ]); + List> futures = []; + + futures.add(sparkAnonSetFuture); + futures.add(sparkUsedCoinTagsFuture); + if (enableLelantusScanning) { + futures.add(usedSerialNumbersFuture!); + futures.add(setDataMapFuture!); + } + + final futureResults = await Future.wait(futures); // lelantus - final usedSerialsSet = (futureResults[0] as List).toSet(); - final setDataMap = futureResults[1] as Map; + Set? usedSerialsSet; + Map? setDataMap; + if (enableLelantusScanning) { + usedSerialsSet = (futureResults[2] as List).toSet(); + setDataMap = futureResults[3] as Map; + } // spark - final sparkAnonymitySet = futureResults[2] as Map; - final sparkSpentCoinTags = futureResults[3] as Set; + final sparkAnonymitySet = futureResults[0] as Map; + final sparkSpentCoinTags = futureResults[1] as Set; if (Util.isDesktop) { - await Future.wait([ - recoverLelantusWallet( - latestSetId: latestSetId, - usedSerialNumbers: usedSerialsSet, - setDataMap: setDataMap, - ), - recoverSparkWallet( - anonymitySet: sparkAnonymitySet, - spentCoinTags: sparkSpentCoinTags, - ), - ]); + List> futures = []; + if (enableLelantusScanning) { + futures.add(recoverLelantusWallet( + latestSetId: latestSetId!, + usedSerialNumbers: usedSerialsSet!, + setDataMap: setDataMap!, + )); + } + futures.add(recoverSparkWallet( + anonymitySet: sparkAnonymitySet, + spentCoinTags: sparkSpentCoinTags, + )); + + await Future.wait(futures); } else { - await recoverLelantusWallet( - latestSetId: latestSetId, - usedSerialNumbers: usedSerialsSet, - setDataMap: setDataMap, - ); + if (enableLelantusScanning) { + await recoverLelantusWallet( + latestSetId: latestSetId!, + usedSerialNumbers: usedSerialsSet!, + setDataMap: setDataMap!, + ); + } await recoverSparkWallet( anonymitySet: sparkAnonymitySet, spentCoinTags: sparkSpentCoinTags, From 32561b56943c5060053838387086df003a25e812 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Wed, 29 May 2024 17:46:21 -0500 Subject: [PATCH 2/7] Scan for Lelantus transactions desktop UI Squashed commit msgs: WIP add lelantus checkmark to restore options view, pass to restore view make bool optional, pass it style restore option text --- .../restore_options_view.dart | 32 ++++++++- .../restore_wallet_view.dart | 25 ++++--- .../more_features/more_features_dialog.dart | 67 +++++++++++++++++++ lib/route_generator.dart | 7 +- 4 files changed, 119 insertions(+), 12 deletions(-) diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart index e04ed9959..8e6459649 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart @@ -72,6 +72,9 @@ class _RestoreOptionsViewState extends ConsumerState { bool get supportsMnemonicPassphrase => coin.hasMnemonicPassphraseSupport; + bool enableLelantusScanning = false; + bool get supportsLelantus => coin is Firo; + @override void initState() { walletName = widget.walletName; @@ -107,12 +110,13 @@ class _RestoreOptionsViewState extends ConsumerState { if (mounted) { await Navigator.of(context).pushNamed( RestoreWalletView.routeName, - arguments: Tuple5( + arguments: Tuple6( walletName, coin, ref.read(mnemonicWordCountStateProvider.state).state, _restoreFromDate, passwordController.text, + enableLelantusScanning, ), ); } @@ -437,6 +441,32 @@ class _RestoreOptionsViewState extends ConsumerState { color: Colors.transparent, child: Column( children: [ + Row( + children: [ + Checkbox( + value: enableLelantusScanning, + onChanged: (bool? newValue) { + setState(() { + enableLelantusScanning = newValue ?? true; + }); + }, + ), + Text( + 'Scan for Lelantus transactions', + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ) + : STextStyles.itemSubtitle(context), + ), + ], + ), + const SizedBox( + height: 8, + ), ClipRRect( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart index 9daf9d300..d7fcd7264 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart @@ -22,15 +22,9 @@ import 'package:flutter_libmonero/monero/monero.dart' as libxmr; import 'package:flutter_libmonero/wownero/wownero.dart' as libwow; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:wakelock/wakelock.dart'; + import '../../../notifications/show_flush_bar.dart'; -import '../add_token_view/edit_wallet_tokens_view.dart'; -import 'confirm_recovery_dialog.dart'; -import 'sub_widgets/restore_failed_dialog.dart'; -import 'sub_widgets/restore_succeeded_dialog.dart'; -import 'sub_widgets/restoring_dialog.dart'; -import '../select_wallet_for_token_view.dart'; -import '../verify_recovery_phrase_view/verify_recovery_phrase_view.dart'; -import '../../home_view/home_view.dart'; import '../../../pages_desktop_specific/desktop_home_view.dart'; import '../../../pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart'; import '../../../providers/db/main_db_provider.dart'; @@ -64,7 +58,14 @@ import '../../../widgets/icon_widgets/qrcode_icon.dart'; import '../../../widgets/table_view/table_view.dart'; import '../../../widgets/table_view/table_view_cell.dart'; import '../../../widgets/table_view/table_view_row.dart'; -import 'package:wakelock/wakelock.dart'; +import '../../home_view/home_view.dart'; +import '../add_token_view/edit_wallet_tokens_view.dart'; +import '../select_wallet_for_token_view.dart'; +import '../verify_recovery_phrase_view/verify_recovery_phrase_view.dart'; +import 'confirm_recovery_dialog.dart'; +import 'sub_widgets/restore_failed_dialog.dart'; +import 'sub_widgets/restore_succeeded_dialog.dart'; +import 'sub_widgets/restoring_dialog.dart'; class RestoreWalletView extends ConsumerStatefulWidget { const RestoreWalletView({ @@ -74,6 +75,7 @@ class RestoreWalletView extends ConsumerStatefulWidget { required this.seedWordsLength, required this.mnemonicPassphrase, required this.restoreFromDate, + this.enableLelantusScanning = false, this.barcodeScanner = const BarcodeScannerWrapper(), this.clipboard = const ClipboardWrapper(), }); @@ -85,6 +87,7 @@ class RestoreWalletView extends ConsumerStatefulWidget { final String mnemonicPassphrase; final int seedWordsLength; final DateTime restoreFromDate; + final bool enableLelantusScanning; final BarcodeScannerInterface barcodeScanner; final ClipboardInterface clipboard; @@ -256,6 +259,8 @@ class _RestoreWalletViewState extends ConsumerState { otherDataJsonString = jsonEncode( { WalletInfoKeys.lelantusCoinIsarRescanRequired: false, + WalletInfoKeys.enableLelantusScanning: + widget.enableLelantusScanning, }, ); } @@ -331,6 +336,8 @@ class _RestoreWalletViewState extends ConsumerState { mnemonic: mnemonic, ); + // TODO [prio=high]: Update wallet with widget.enableLelantusScanning. + // TODO: extract interface with isRestore param switch (wallet.runtimeType) { case const (EpiccashWallet): diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart index 10366c646..03f4db1c7 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart @@ -8,9 +8,13 @@ * */ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; + +import '../../../../../providers/db/main_db_provider.dart'; import '../../../../../providers/global/prefs_provider.dart'; import '../../../../../providers/global/wallets_provider.dart'; import '../../../../../themes/stack_colors.dart'; @@ -18,10 +22,12 @@ import '../../../../../utilities/assets.dart'; import '../../../../../utilities/text_styles.dart'; import '../../../../../wallets/crypto_currency/coins/banano.dart'; import '../../../../../wallets/crypto_currency/coins/firo.dart'; +import '../../../../../wallets/isar/models/wallet_info.dart'; import '../../../../../wallets/wallet/wallet_mixin_interfaces/cash_fusion_interface.dart'; import '../../../../../wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; import '../../../../../wallets/wallet/wallet_mixin_interfaces/ordinals_interface.dart'; import '../../../../../wallets/wallet/wallet_mixin_interfaces/paynym_interface.dart'; +import '../../../../../widgets/custom_buttons/draggable_switch_button.dart'; import '../../../../../widgets/desktop/desktop_dialog.dart'; import '../../../../../widgets/desktop/desktop_dialog_close_button.dart'; import '../../../../../widgets/rounded_container.dart'; @@ -53,6 +59,8 @@ class MoreFeaturesDialog extends ConsumerStatefulWidget { } class _MoreFeaturesDialogState extends ConsumerState { + bool? enableLelantusScanning = false; + @override Widget build(BuildContext context) { final wallet = ref.watch( @@ -61,6 +69,13 @@ class _MoreFeaturesDialogState extends ConsumerState { ), ); + // Parse otherDataJsonString to get the enableLelantusScanning value. + if (wallet.info.otherDataJsonString != null) { + final otherDataJson = json.decode(wallet.info.otherDataJsonString!); + enableLelantusScanning = + otherDataJson["enableLelantusScanning"] as bool? ?? false; + } + final coinControlPrefEnabled = ref.watch( prefsChangeNotifierProvider.select( (value) => value.enableCoinControl, @@ -136,6 +151,58 @@ class _MoreFeaturesDialogState extends ConsumerState { iconAsset: Assets.svg.cashFusion, onPressed: () => widget.onFusionPressed?.call(), ), + if (wallet.info.coin is Firo) + Padding( + padding: const EdgeInsets.symmetric( + vertical: 6, + horizontal: 32, + ), + child: RoundedContainer( + color: Colors.transparent, + borderColor: Theme.of(context) + .extension()! + .textFieldDefaultBG, + child: Row( + children: [ + SizedBox(width: 3), + SizedBox( + height: 20, + width: 40, + child: DraggableSwitchButton( + isOn: enableLelantusScanning ?? false, + onValueChanged: (newValue) { + // Toggle enableLelantusScanning in wallet info. + wallet.info.updateOtherData(newEntries: { + WalletInfoKeys.enableLelantusScanning: + !(enableLelantusScanning ?? false) + }, isar: ref.read(mainDBProvider).isar).then((value) { + // Should setState be used here? + enableLelantusScanning = + !(enableLelantusScanning ?? false); + }); + }, + ), + ), + const SizedBox( + width: 16, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Scan for Lelantus transactions", + style: STextStyles.w600_20(context), + ), + // Text( + // detail, + // style: STextStyles.desktopTextExtraExtraSmall(context), + // ), + ], + ), + ], + ), + ), + ), const SizedBox( height: 28, ), diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 735b8681e..516c1ddb8 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -11,6 +11,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:isar/isar.dart'; +import 'package:tuple/tuple.dart'; + import 'models/add_wallet_list_entity/add_wallet_list_entity.dart'; import 'models/add_wallet_list_entity/sub_classes/eth_token_entity.dart'; import 'models/buy/response_objects/quote.dart'; @@ -194,7 +196,6 @@ import 'wallets/models/tx_data.dart'; import 'wallets/wallet/wallet.dart'; import 'widgets/choose_coin_view.dart'; import 'widgets/frost_scaffold.dart'; -import 'package:tuple/tuple.dart'; /* * This file contains all the routes for the app. @@ -1390,7 +1391,8 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case RestoreWalletView.routeName: - if (args is Tuple5) { + if (args + is Tuple6) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => RestoreWalletView( @@ -1399,6 +1401,7 @@ class RouteGenerator { seedWordsLength: args.item3, restoreFromDate: args.item4, mnemonicPassphrase: args.item5, + enableLelantusScanning: args.item6 ?? false, ), settings: RouteSettings( name: settings.name, From 8374d300358057943a3af316d3171b29d16a8f10 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Wed, 29 May 2024 19:42:14 -0500 Subject: [PATCH 3/7] Lelantus settings mobile UI and cleanup --- .../restore_wallet_view.dart | 2 - .../lelantus_settings_view.dart | 146 ++++++++++++++++++ .../wallet_settings_wallet_settings_view.dart | 42 ++++- lib/route_generator.dart | 13 ++ pubspec.lock | 2 +- 5 files changed, 199 insertions(+), 6 deletions(-) create mode 100644 lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart index d7fcd7264..a7768b061 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart @@ -336,8 +336,6 @@ class _RestoreWalletViewState extends ConsumerState { mnemonic: mnemonic, ); - // TODO [prio=high]: Update wallet with widget.enableLelantusScanning. - // TODO: extract interface with isRestore param switch (wallet.runtimeType) { case const (EpiccashWallet): diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart new file mode 100644 index 000000000..58632c1cd --- /dev/null +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart @@ -0,0 +1,146 @@ +/* + * This file is part of Stack Wallet. + * + * Copyright (c) 2023 Cypher Stack + * All Rights Reserved. + * The code is distributed under GPLv3 license, see LICENSE file for details. + * Generated by Cypher Stack on 2023-05-26 + * + */ + +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../../../providers/db/main_db_provider.dart'; +import '../../../../providers/global/wallets_provider.dart'; +import '../../../../themes/stack_colors.dart'; +import '../../../../utilities/text_styles.dart'; +import '../../../../wallets/crypto_currency/crypto_currency.dart'; +import '../../../../wallets/isar/models/wallet_info.dart'; +import '../../../../wallets/wallet/wallet.dart'; +import '../../../../widgets/background.dart'; +import '../../../../widgets/custom_buttons/app_bar_icon_button.dart'; +import '../../../../widgets/custom_buttons/draggable_switch_button.dart'; + +class LelantusSettingsView extends ConsumerStatefulWidget { + const LelantusSettingsView({ + super.key, + required this.walletId, + }); + + static const String routeName = "/lelantusSettings"; + + final String walletId; + + @override + ConsumerState createState() => + _LelantusSettingsViewState(); +} + +class _LelantusSettingsViewState extends ConsumerState { + late final TextEditingController _controller; + late final String walletId; + + final _focusNode = FocusNode(); + + bool _isInitialized = false; + Wallet? wallet; + bool? enableLelantusScanning = false; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + if (!_isInitialized) { + // Get the wallet. + wallet = ref.watch( + pWallets.select( + (value) => value.getWallet(widget.walletId), + ), + ); + + // Parse otherDataJsonString to get the enableLelantusScanning value. + if (wallet?.info.otherDataJsonString != null) { + final otherDataJson = json.decode(wallet!.info.otherDataJsonString!); + enableLelantusScanning = + otherDataJson["enableLelantusScanning"] as bool? ?? false; + } + + _isInitialized = true; // Ensure this logic runs only once + } + } + + @override + void dispose() { + _controller.dispose(); + _focusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Background( + child: Scaffold( + backgroundColor: Theme.of(context).extension()!.background, + appBar: AppBar( + leading: AppBarBackButton( + onPressed: () { + Navigator.of(context).pop(); + }, + ), + title: Text( + "Lelantus settings", + style: STextStyles.navBarTitle(context), + ), + ), + body: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + SizedBox( + height: 20, + width: 40, + child: DraggableSwitchButton( + isOn: enableLelantusScanning ?? false, + onValueChanged: (newValue) { + // Toggle enableLelantusScanning in wallet info. + wallet?.info.updateOtherData(newEntries: { + WalletInfoKeys.enableLelantusScanning: + !(enableLelantusScanning ?? false) + }, isar: ref.read(mainDBProvider).isar).then((value) { + // Should setState be used here? + enableLelantusScanning = + !(enableLelantusScanning ?? false); + }); + }, + ), + ), + const SizedBox( + width: 16, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Scan for Lelantus transactions", + style: STextStyles.smallMed12(context), + ), + // Text( + // detail, + // style: STextStyles.desktopTextExtraExtraSmall(context), + // ), + ], + ), + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart index a3c3a2969..7c2884258 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart @@ -10,9 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import '../../../pinpad_views/lock_screen_view.dart'; -import 'delete_wallet_warning_view.dart'; -import 'rename_wallet_view.dart'; + import '../../../../route_generator.dart'; import '../../../../themes/stack_colors.dart'; import '../../../../utilities/constants.dart'; @@ -22,6 +20,10 @@ import '../../../../widgets/background.dart'; import '../../../../widgets/custom_buttons/app_bar_icon_button.dart'; import '../../../../widgets/rounded_white_container.dart'; import '../../../../widgets/stack_dialog.dart'; +import '../../../pinpad_views/lock_screen_view.dart'; +import 'delete_wallet_warning_view.dart'; +import 'lelantus_settings_view.dart'; +import 'rename_wallet_view.dart'; class WalletSettingsWalletSettingsView extends ConsumerWidget { const WalletSettingsWalletSettingsView({ @@ -180,6 +182,40 @@ class WalletSettingsWalletSettingsView extends ConsumerWidget { ), ), ), + const SizedBox( + height: 8, + ), + RoundedWhiteContainer( + padding: const EdgeInsets.all(0), + child: RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + onPressed: () { + Navigator.of(context).pushNamed( + LelantusSettingsView.routeName, + arguments: walletId, + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 20, + ), + child: Row( + children: [ + Text( + "Lelantus settings", + style: STextStyles.titleBold12(context), + ), + ], + ), + ), + ), + ), ], ), ), diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 516c1ddb8..27d1eb4f7 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -129,6 +129,7 @@ import 'pages/settings_views/wallet_settings_view/wallet_settings_view.dart'; import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/change_representative_view.dart'; import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_recovery_phrase_view.dart'; import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_warning_view.dart'; +import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart'; import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart'; import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart'; import 'pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/xpub_view.dart'; @@ -1953,6 +1954,18 @@ class RouteGenerator { } return _routeError("${settings.name} invalid args: ${args.toString()}"); + case LelantusSettingsView.routeName: + if (args is String) { + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => LelantusSettingsView(walletId: args), + settings: RouteSettings( + name: settings.name, + ), + ); + } + return _routeError("${settings.name} invalid args: ${args.toString()}"); + // == Desktop specific routes ============================================ case CreatePasswordView.routeName: if (args is bool) { diff --git a/pubspec.lock b/pubspec.lock index a9cfa08cf..e8c94e9a2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1194,7 +1194,7 @@ packages: source: hosted version: "0.2.0" monero: - dependency: "direct main" + dependency: transitive description: path: "." ref: "6a17a405a1a260fa228b2f4fc94044088a4335ac" From cbe9919e67b3f80b7568b26245d397379f640cae Mon Sep 17 00:00:00 2001 From: sneurlax Date: Wed, 29 May 2024 19:44:24 -0500 Subject: [PATCH 4/7] Refresh Lelantus data appropriately according to the enableLelantusScanning WalletInfo setting (stored in otherDataJsonString) --- lib/wallets/wallet/wallet.dart | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart index 8fa0b9ddf..83698a819 100644 --- a/lib/wallets/wallet/wallet.dart +++ b/lib/wallets/wallet/wallet.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:isar/isar.dart'; import 'package:meta/meta.dart'; @@ -558,7 +559,16 @@ abstract class Wallet { // TODO: [prio=low] handle this differently. Extra modification of this file for coin specific functionality should be avoided. if (this is LelantusInterface) { - await (this as LelantusInterface).refreshLelantusData(); + // Parse otherDataJsonString to get the enableLelantusScanning value. + bool enableLelantusScanning = false; + if (this.info.otherDataJsonString != null) { + final otherDataJson = json.decode(this.info.otherDataJsonString!); + enableLelantusScanning = + otherDataJson["enableLelantusScanning"] as bool? ?? false; + } + if (enableLelantusScanning) { + await (this as LelantusInterface).refreshLelantusData(); + } } GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.90, walletId)); From 0f98c0be2c55a1831683c0b02eb1b161ef48bde0 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 30 May 2024 17:50:09 -0500 Subject: [PATCH 5/7] Use WalletInfoKeys (plus standardize Lelantus') and make UI var private --- .../lelantus_settings_view.dart | 3 ++- .../more_features/more_features_dialog.dart | 15 ++++++++------- lib/wallets/isar/models/wallet_info.dart | 2 +- lib/wallets/wallet/impl/firo_wallet.dart | 3 ++- lib/wallets/wallet/wallet.dart | 3 ++- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart index 58632c1cd..ad53ccacf 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart @@ -64,7 +64,8 @@ class _LelantusSettingsViewState extends ConsumerState { if (wallet?.info.otherDataJsonString != null) { final otherDataJson = json.decode(wallet!.info.otherDataJsonString!); enableLelantusScanning = - otherDataJson["enableLelantusScanning"] as bool? ?? false; + otherDataJson[WalletInfoKeys.enableLelantusScanning] as bool? ?? + false; } _isInitialized = true; // Ensure this logic runs only once diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart index 03f4db1c7..f1a9815c4 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart @@ -59,7 +59,7 @@ class MoreFeaturesDialog extends ConsumerStatefulWidget { } class _MoreFeaturesDialogState extends ConsumerState { - bool? enableLelantusScanning = false; + bool _enableLelantusScanning = false; @override Widget build(BuildContext context) { @@ -72,8 +72,9 @@ class _MoreFeaturesDialogState extends ConsumerState { // Parse otherDataJsonString to get the enableLelantusScanning value. if (wallet.info.otherDataJsonString != null) { final otherDataJson = json.decode(wallet.info.otherDataJsonString!); - enableLelantusScanning = - otherDataJson["enableLelantusScanning"] as bool? ?? false; + _enableLelantusScanning = + otherDataJson[WalletInfoKeys.enableLelantusScanning] as bool? ?? + false; } final coinControlPrefEnabled = ref.watch( @@ -169,16 +170,16 @@ class _MoreFeaturesDialogState extends ConsumerState { height: 20, width: 40, child: DraggableSwitchButton( - isOn: enableLelantusScanning ?? false, + isOn: _enableLelantusScanning, onValueChanged: (newValue) { // Toggle enableLelantusScanning in wallet info. wallet.info.updateOtherData(newEntries: { WalletInfoKeys.enableLelantusScanning: - !(enableLelantusScanning ?? false) + !(_enableLelantusScanning) }, isar: ref.read(mainDBProvider).isar).then((value) { // Should setState be used here? - enableLelantusScanning = - !(enableLelantusScanning ?? false); + _enableLelantusScanning = + !(_enableLelantusScanning); }); }, ), diff --git a/lib/wallets/isar/models/wallet_info.dart b/lib/wallets/isar/models/wallet_info.dart index 351229c29..a2b7ae126 100644 --- a/lib/wallets/isar/models/wallet_info.dart +++ b/lib/wallets/isar/models/wallet_info.dart @@ -507,5 +507,5 @@ abstract class WalletInfoKeys { static const String tezosDerivationPath = "tezosDerivationPathKey"; static const String lelantusCoinIsarRescanRequired = "lelantusCoinIsarRescanRequired"; - static const String enableLelantusScanning = "enableLelantusScanning"; + static const String enableLelantusScanning = "enableLelantusScanningKey"; } diff --git a/lib/wallets/wallet/impl/firo_wallet.dart b/lib/wallets/wallet/impl/firo_wallet.dart index 510d08cfb..3da17a3ff 100644 --- a/lib/wallets/wallet/impl/firo_wallet.dart +++ b/lib/wallets/wallet/impl/firo_wallet.dart @@ -615,7 +615,8 @@ class FiroWallet extends Bip39HDWallet if (info.otherDataJsonString != null) { final otherDataJson = json.decode(info.otherDataJsonString!); enableLelantusScanning = - otherDataJson["enableLelantusScanning"] as bool? ?? false; + otherDataJson[WalletInfoKeys.enableLelantusScanning] as bool? ?? + false; } // lelantus diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart index 83698a819..56469071c 100644 --- a/lib/wallets/wallet/wallet.dart +++ b/lib/wallets/wallet/wallet.dart @@ -564,7 +564,8 @@ abstract class Wallet { if (this.info.otherDataJsonString != null) { final otherDataJson = json.decode(this.info.otherDataJsonString!); enableLelantusScanning = - otherDataJson["enableLelantusScanning"] as bool? ?? false; + otherDataJson[WalletInfoKeys.enableLelantusScanning] as bool? ?? + false; } if (enableLelantusScanning) { await (this as LelantusInterface).refreshLelantusData(); From d37d86759d73afbdf1a8455ba7ac71d7e390663c Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 30 May 2024 18:17:26 -0500 Subject: [PATCH 6/7] Lock toggling lelantus scanning behind a mutex --- .../lelantus_settings_view.dart | 30 ++++++++++++------- .../more_features/more_features_dialog.dart | 24 ++++++++++----- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart index ad53ccacf..1f8c342b0 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/lelantus_settings_view.dart @@ -47,7 +47,8 @@ class _LelantusSettingsViewState extends ConsumerState { bool _isInitialized = false; Wallet? wallet; - bool? enableLelantusScanning = false; + bool _enableLelantusScanning = false; + bool _isUpdatingLelantusScanning = false; @override void didChangeDependencies() { @@ -63,7 +64,7 @@ class _LelantusSettingsViewState extends ConsumerState { // Parse otherDataJsonString to get the enableLelantusScanning value. if (wallet?.info.otherDataJsonString != null) { final otherDataJson = json.decode(wallet!.info.otherDataJsonString!); - enableLelantusScanning = + _enableLelantusScanning = otherDataJson[WalletInfoKeys.enableLelantusScanning] as bool? ?? false; } @@ -106,16 +107,23 @@ class _LelantusSettingsViewState extends ConsumerState { height: 20, width: 40, child: DraggableSwitchButton( - isOn: enableLelantusScanning ?? false, - onValueChanged: (newValue) { + isOn: _enableLelantusScanning, + onValueChanged: (newValue) async { + if (_isUpdatingLelantusScanning) return; + _isUpdatingLelantusScanning = true; // Lock mutex. + // Toggle enableLelantusScanning in wallet info. - wallet?.info.updateOtherData(newEntries: { - WalletInfoKeys.enableLelantusScanning: - !(enableLelantusScanning ?? false) - }, isar: ref.read(mainDBProvider).isar).then((value) { - // Should setState be used here? - enableLelantusScanning = - !(enableLelantusScanning ?? false); + await wallet?.info.updateOtherData( + newEntries: { + WalletInfoKeys.enableLelantusScanning: + !_enableLelantusScanning, + }, + isar: ref.read(mainDBProvider).isar, + ); + + setState(() { + _enableLelantusScanning = !_enableLelantusScanning; + _isUpdatingLelantusScanning = false; // Free mutex. }); }, ), diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart index f1a9815c4..1ab2a6781 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart @@ -60,6 +60,7 @@ class MoreFeaturesDialog extends ConsumerStatefulWidget { class _MoreFeaturesDialogState extends ConsumerState { bool _enableLelantusScanning = false; + bool _isUpdatingLelantusScanning = false; // Mutex. @override Widget build(BuildContext context) { @@ -171,15 +172,22 @@ class _MoreFeaturesDialogState extends ConsumerState { width: 40, child: DraggableSwitchButton( isOn: _enableLelantusScanning, - onValueChanged: (newValue) { + onValueChanged: (newValue) async { + if (_isUpdatingLelantusScanning) return; + _isUpdatingLelantusScanning = true; // Lock mutex. + // Toggle enableLelantusScanning in wallet info. - wallet.info.updateOtherData(newEntries: { - WalletInfoKeys.enableLelantusScanning: - !(_enableLelantusScanning) - }, isar: ref.read(mainDBProvider).isar).then((value) { - // Should setState be used here? - _enableLelantusScanning = - !(_enableLelantusScanning); + await wallet.info.updateOtherData( + newEntries: { + WalletInfoKeys.enableLelantusScanning: + !_enableLelantusScanning, + }, + isar: ref.read(mainDBProvider).isar, + ); + + setState(() { + _enableLelantusScanning = !_enableLelantusScanning; + _isUpdatingLelantusScanning = false; // Free mutex. }); }, ), From 1e425e7848ae98850f7d0d52a980520d59ef4835 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 30 May 2024 21:58:03 -0500 Subject: [PATCH 7/7] use CheckboxTextButton *eye twitches* --- .../restore_options_view.dart | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart index 8e6459649..1ba3cef79 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart @@ -25,6 +25,7 @@ import '../../../../utilities/util.dart'; import '../../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../../widgets/conditional_parent.dart'; import '../../../../widgets/custom_buttons/app_bar_icon_button.dart'; +import '../../../../widgets/custom_buttons/checkbox_text_button.dart'; import '../../../../widgets/date_picker/date_picker.dart'; import '../../../../widgets/desktop/desktop_app_bar.dart'; import '../../../../widgets/desktop/desktop_scaffold.dart'; @@ -441,28 +442,13 @@ class _RestoreOptionsViewState extends ConsumerState { color: Colors.transparent, child: Column( children: [ - Row( - children: [ - Checkbox( - value: enableLelantusScanning, - onChanged: (bool? newValue) { - setState(() { - enableLelantusScanning = newValue ?? true; - }); - }, - ), - Text( - 'Scan for Lelantus transactions', - style: isDesktop - ? STextStyles.desktopTextExtraSmall(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ) - : STextStyles.itemSubtitle(context), - ), - ], + CheckboxTextButton( + label: "Scan for Lelantus transactions", + onChanged: (newValue) { + setState(() { + enableLelantusScanning = newValue ?? true; + }); + }, ), const SizedBox( height: 8,