From 032a507e72e03cd8602848740b03bf88c6eda986 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 13 May 2024 08:10:53 -0600 Subject: [PATCH 1/4] frost db tx fix and some lint clean up --- .../wallet/impl/bitcoin_frost_wallet.dart | 63 +++++++++++-------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart index 1798fd79f..5d0bb3ffc 100644 --- a/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart +++ b/lib/wallets/wallet/impl/bitcoin_frost_wallet.dart @@ -180,10 +180,12 @@ class BitcoinFrostWallet extends Wallet { final config = Frost.createSignConfig( network: network, inputs: utxosToUse - .map((e) => ( - utxo: e, - scriptPubKey: publicKey, - )) + .map( + (e) => ( + utxo: e, + scriptPubKey: publicKey, + ), + ) .toList(), outputs: txData.recipients!, changeAddress: (await getCurrentReceivingAddress())!.value, @@ -278,8 +280,9 @@ class BitcoinFrostWallet extends Wallet { Amount _roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) { return Amount( rawValue: BigInt.from( - ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() * - (feeRatePerKB / 1000).ceil()), + ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() * + (feeRatePerKB / 1000).ceil(), + ), fractionDigits: cryptoCurrency.fractionDigits, ); } @@ -333,7 +336,7 @@ class BitcoinFrostWallet extends Wallet { final currentHeight = await chainHeight; final coin = info.coin; - List> allTransactions = []; + final List> allTransactions = []; for (final txHash in allTxHashes) { final storedTx = await mainDB.isar.transactionV2s @@ -390,8 +393,8 @@ class BitcoinFrostWallet extends Wallet { ); final prevOutJson = Map.from( - (inputTx["vout"] as List).firstWhere((e) => e["n"] == vout) - as Map); + (inputTx["vout"] as List).firstWhere((e) => e["n"] == vout) as Map, + ); final prevOut = OutputV2.fromElectrumXJson( prevOutJson, @@ -456,7 +459,8 @@ class BitcoinFrostWallet extends Wallet { TransactionSubType subType = TransactionSubType.none; if (outputs.length > 1 && inputs.isNotEmpty) { for (int i = 0; i < outputs.length; i++) { - List? scriptChunks = outputs[i].scriptPubKeyAsm?.split(" "); + final List? scriptChunks = + outputs[i].scriptPubKeyAsm?.split(" "); if (scriptChunks?.length == 2 && scriptChunks?[0] == "OP_RETURN") { final blindedPaymentCode = scriptChunks![1]; final bytes = blindedPaymentCode.toUint8ListFromHex; @@ -575,8 +579,10 @@ class BitcoinFrostWallet extends Wallet { return txData; } catch (e, s) { - Logging.instance.log("Exception rethrown from confirmSend(): $e\n$s", - level: LogLevel.Error); + Logging.instance.log( + "Exception rethrown from confirmSend(): $e\n$s", + level: LogLevel.Error, + ); rethrow; } } @@ -685,7 +691,7 @@ class BitcoinFrostWallet extends Wallet { multisigConfig = await getMultisigConfig(); } if (serializedKeys == null || multisigConfig == null) { - String err = "${info.coinName} wallet ${info.walletId} had null keys/cfg"; + final err = "${info.coinName} wallet ${info.walletId} had null keys/cfg"; Logging.instance.log(err, level: LogLevel.Fatal); throw Exception(err); // TODO [prio=low]: handle null keys or config. This should not happen. @@ -713,7 +719,7 @@ class BitcoinFrostWallet extends Wallet { if (knownSalts.contains(salt)) { throw Exception("Known frost multisig salt found!"); } - List updatedKnownSalts = List.from(knownSalts); + final List updatedKnownSalts = List.from(knownSalts); updatedKnownSalts.add(salt); await _updateKnownSalts(updatedKnownSalts); } else { @@ -1015,8 +1021,9 @@ class BitcoinFrostWallet extends Wallet { .findFirstSync()!; Future _updateParticipants(List participants) async { + final info = frostInfo; + await mainDB.isar.writeTxn(() async { - final info = frostInfo; await mainDB.isar.frostWalletInfo.delete(info.id); await mainDB.isar.frostWalletInfo.put( info.copyWith(participants: participants), @@ -1031,8 +1038,9 @@ class BitcoinFrostWallet extends Wallet { .findFirstSync()!; Future _updateThreshold(int threshold) async { + final info = frostInfo; + await mainDB.isar.writeTxn(() async { - final info = frostInfo; await mainDB.isar.frostWalletInfo.delete(info.id); await mainDB.isar.frostWalletInfo.put( info.copyWith(threshold: threshold), @@ -1047,8 +1055,9 @@ class BitcoinFrostWallet extends Wallet { .findFirstSync()!; Future _updateMyName(String myName) async { + final info = frostInfo; + await mainDB.isar.writeTxn(() async { - final info = frostInfo; await mainDB.isar.frostWalletInfo.delete(info.id); await mainDB.isar.frostWalletInfo.put( info.copyWith(myName: myName), @@ -1074,13 +1083,15 @@ class BitcoinFrostWallet extends Wallet { Future _updateElectrumX() async { final failovers = nodeService .failoverNodesFor(coin: cryptoCurrency.coin) - .map((e) => ElectrumXNode( - address: e.host, - port: e.port, - name: e.name, - id: e.id, - useSSL: e.useSSL, - )) + .map( + (e) => ElectrumXNode( + address: e.host, + port: e.port, + name: e.name, + id: e.id, + useSSL: e.useSSL, + ), + ) .toList(); final newNode = await _getCurrentElectrumXNode(); @@ -1109,7 +1120,9 @@ class BitcoinFrostWallet extends Wallet { } bool _duplicateTxCheck( - List> allTransactions, String txid) { + List> allTransactions, + String txid, + ) { for (int i = 0; i < allTransactions.length; i++) { if (allTransactions[i]["txid"] == txid) { return true; From 441faf4d3ab53f04db6a022f34e80a4e0e9a289b Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 13 May 2024 08:11:12 -0600 Subject: [PATCH 2/4] fix frost coin assets --- lib/themes/coin_card_provider.dart | 14 -------------- lib/themes/coin_icon_provider.dart | 7 ------- lib/themes/coin_image_provider.dart | 14 -------------- 3 files changed, 35 deletions(-) diff --git a/lib/themes/coin_card_provider.dart b/lib/themes/coin_card_provider.dart index ce5e71038..b34e9e6f1 100644 --- a/lib/themes/coin_card_provider.dart +++ b/lib/themes/coin_card_provider.dart @@ -16,13 +16,6 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart'; final coinCardProvider = Provider.family((ref, coin) { final assets = ref.watch(themeAssetsProvider); - // TODO: handle this differently by adding proper frost assets to themes - if (coin == Coin.bitcoinFrost) { - coin = Coin.bitcoin; - } else if (coin == Coin.bitcoinFrostTestNet) { - coin = Coin.bitcoinTestNet; - } - if (assets is ThemeAssetsV3) { return assets.coinCardImages?[coin.mainNetVersion]; } else { @@ -33,13 +26,6 @@ final coinCardProvider = Provider.family((ref, coin) { final coinCardFavoritesProvider = Provider.family((ref, coin) { final assets = ref.watch(themeAssetsProvider); - // TODO: handle this differently by adding proper frost assets to themes - if (coin == Coin.bitcoinFrost) { - coin = Coin.bitcoin; - } else if (coin == Coin.bitcoinFrostTestNet) { - coin = Coin.bitcoinTestNet; - } - if (assets is ThemeAssetsV3) { return assets.coinCardFavoritesImages?[coin.mainNetVersion] ?? assets.coinCardImages?[coin.mainNetVersion]; diff --git a/lib/themes/coin_icon_provider.dart b/lib/themes/coin_icon_provider.dart index f0c0df842..9bd3990bb 100644 --- a/lib/themes/coin_icon_provider.dart +++ b/lib/themes/coin_icon_provider.dart @@ -16,13 +16,6 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart'; final coinIconProvider = Provider.family((ref, coin) { final assets = ref.watch(themeAssetsProvider); - // TODO: handle this differently by adding proper frost assets to themes - if (coin == Coin.bitcoinFrost) { - coin = Coin.bitcoin; - } else if (coin == Coin.bitcoinFrostTestNet) { - coin = Coin.bitcoinTestNet; - } - if (assets is ThemeAssets) { switch (coin) { case Coin.bitcoin: diff --git a/lib/themes/coin_image_provider.dart b/lib/themes/coin_image_provider.dart index fa1fdde4c..6ca839fb9 100644 --- a/lib/themes/coin_image_provider.dart +++ b/lib/themes/coin_image_provider.dart @@ -16,13 +16,6 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart'; final coinImageProvider = Provider.family((ref, coin) { final assets = ref.watch(themeAssetsProvider); - // TODO: handle this differently by adding proper frost assets to themes - if (coin == Coin.bitcoinFrost) { - coin = Coin.bitcoin; - } else if (coin == Coin.bitcoinFrostTestNet) { - coin = Coin.bitcoinTestNet; - } - if (assets is ThemeAssets) { switch (coin) { case Coin.bitcoin: @@ -71,13 +64,6 @@ final coinImageProvider = Provider.family((ref, coin) { final coinImageSecondaryProvider = Provider.family((ref, coin) { final assets = ref.watch(themeAssetsProvider); - // TODO: handle this differently by adding proper frost assets to themes - if (coin == Coin.bitcoinFrost) { - coin = Coin.bitcoin; - } else if (coin == Coin.bitcoinFrostTestNet) { - coin = Coin.bitcoinTestNet; - } - if (assets is ThemeAssets) { switch (coin) { case Coin.bitcoin: From 3f4ebe022945bea4224648e1a8acd64893a652ab Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 13 May 2024 08:55:27 -0600 Subject: [PATCH 3/4] specific error dialog when an unrecoverable frost error has occurred --- lib/frost_route_generator.dart | 1 + .../new/create_new_frost_ms_wallet_view.dart | 1 + .../select_new_frost_import_type_view.dart | 3 +- .../new/steps/frost_create_step_2.dart | 4 +- .../new/steps/frost_create_step_3.dart | 4 +- .../reshare/frost_reshare_step_1a.dart | 5 +- .../reshare/frost_reshare_step_1b.dart | 5 +- .../reshare/frost_reshare_step_1c.dart | 1 + .../reshare/frost_reshare_step_2abd.dart | 5 +- .../reshare/frost_reshare_step_2c.dart | 19 +-- .../reshare/frost_reshare_step_3abd.dart | 20 +-- .../reshare/frost_reshare_step_4.dart | 5 +- .../reshare/frost_reshare_step_5.dart | 5 +- .../send_view/frost_ms/frost_send_view.dart | 1 + .../send_steps/frost_send_step_1b.dart | 18 ++- .../send_steps/frost_send_step_2.dart | 17 +- .../send_steps/frost_send_step_3.dart | 5 +- .../frost_ms/frost_ms_options_view.dart | 1 + .../complete_reshare_config_view.dart | 26 +-- lib/pages/wallet_view/wallet_view.dart | 151 ++++++++++-------- .../wallet_view/sub_widgets/my_wallet.dart | 4 +- .../dialogs/frost/frost_error_dialog.dart | 92 +++++++++++ 22 files changed, 259 insertions(+), 134 deletions(-) create mode 100644 lib/widgets/dialogs/frost/frost_error_dialog.dart diff --git a/lib/frost_route_generator.dart b/lib/frost_route_generator.dart index a6905a243..d401c7030 100644 --- a/lib/frost_route_generator.dart +++ b/lib/frost_route_generator.dart @@ -41,6 +41,7 @@ final pFrostScaffoldArgs = StateProvider< List stepRoutes, FrostInterruptionDialogType frostInterruptionDialogType, NavigatorState parentNav, + String callerRouteName, })?>((ref) => null); abstract class FrostRouteGenerator { diff --git a/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart b/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart index c8bf16e26..5ce23eaad 100644 --- a/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart +++ b/lib/pages/add_wallet_views/frost_ms/new/create_new_frost_ms_wallet_view.dart @@ -431,6 +431,7 @@ class _NewFrostMsWalletViewState frostInterruptionDialogType: FrostInterruptionDialogType.walletCreation, parentNav: Navigator.of(context), + callerRouteName: CreateNewFrostMsWalletView.routeName, ); await Navigator.of(context).pushNamed( diff --git a/lib/pages/add_wallet_views/frost_ms/new/select_new_frost_import_type_view.dart b/lib/pages/add_wallet_views/frost_ms/new/select_new_frost_import_type_view.dart index b438baac5..1a7378bc6 100644 --- a/lib/pages/add_wallet_views/frost_ms/new/select_new_frost_import_type_view.dart +++ b/lib/pages/add_wallet_views/frost_ms/new/select_new_frost_import_type_view.dart @@ -131,7 +131,6 @@ class _SelectNewFrostImportTypeViewState PrimaryButton( label: "Continue", onPressed: () async { - final String route; switch (_selectedOption) { case _ImportOption.multisigNew: ref.read(pFrostScaffoldArgs.state).state = ( @@ -144,6 +143,7 @@ class _SelectNewFrostImportTypeViewState parentNav: Navigator.of(context), frostInterruptionDialogType: FrostInterruptionDialogType.walletCreation, + callerRouteName: SelectNewFrostImportTypeView.routeName, ); break; @@ -158,6 +158,7 @@ class _SelectNewFrostImportTypeViewState parentNav: Navigator.of(context), frostInterruptionDialogType: FrostInterruptionDialogType.resharing, + callerRouteName: SelectNewFrostImportTypeView.routeName, ); break; } diff --git a/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_2.dart b/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_2.dart index 181a7c3d6..f993d6783 100644 --- a/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_2.dart +++ b/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_2.dart @@ -11,6 +11,7 @@ import 'package:stackwallet/widgets/custom_buttons/frost_qr_dialog_button.dart'; import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/detail_item.dart'; +import 'package:stackwallet/widgets/dialogs/frost/frost_error_dialog.dart'; import 'package:stackwallet/widgets/frost_step_user_steps.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; @@ -183,10 +184,9 @@ class _FrostCreateStep2State extends ConsumerState { if (context.mounted) { return await showDialog( context: context, - builder: (_) => StackOkDialog( + builder: (_) => FrostErrorDialog( title: "Failed to generate shares", message: e.toString(), - desktopPopRootNavigator: Util.isDesktop, ), ); } diff --git a/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_3.dart b/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_3.dart index 782d86135..54cabcec0 100644 --- a/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_3.dart +++ b/lib/pages/add_wallet_views/frost_ms/new/steps/frost_create_step_3.dart @@ -11,6 +11,7 @@ import 'package:stackwallet/widgets/custom_buttons/frost_qr_dialog_button.dart'; import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/detail_item.dart'; +import 'package:stackwallet/widgets/dialogs/frost/frost_error_dialog.dart'; import 'package:stackwallet/widgets/frost_step_user_steps.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; @@ -184,9 +185,8 @@ class _FrostCreateStep3State extends ConsumerState { if (context.mounted) { return await showDialog( context: context, - builder: (_) => StackOkDialog( + builder: (_) => const FrostErrorDialog( title: "Failed to complete key generation", - desktopPopRootNavigator: Util.isDesktop, ), ); } diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1a.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1a.dart index 46f272daf..3b20a8820 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1a.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1a.dart @@ -20,9 +20,9 @@ import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/detail_item.dart'; +import 'package:stackwallet/widgets/dialogs/frost/frost_error_dialog.dart'; import 'package:stackwallet/widgets/dialogs/simple_mobile_dialog.dart'; import 'package:stackwallet/widgets/frost_step_user_steps.dart'; -import 'package:stackwallet/widgets/stack_dialog.dart'; class FrostReshareStep1a extends ConsumerStatefulWidget { const FrostReshareStep1a({super.key}); @@ -88,9 +88,8 @@ class _FrostReshareStep1aState extends ConsumerState { if (mounted) { await showDialog( context: context, - builder: (_) => StackOkDialog( + builder: (_) => FrostErrorDialog( title: e.toString(), - desktopPopRootNavigator: Util.isDesktop, ), ); } diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1b.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1b.dart index 71fe0e737..0df4c4b09 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1b.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1b.dart @@ -12,8 +12,8 @@ import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart'; import 'package:stackwallet/widgets/custom_buttons/checkbox_text_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; +import 'package:stackwallet/widgets/dialogs/frost/frost_error_dialog.dart'; import 'package:stackwallet/widgets/frost_step_user_steps.dart'; -import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; class FrostReshareStep1b extends ConsumerStatefulWidget { @@ -124,9 +124,8 @@ class _FrostReshareStep1bState extends ConsumerState { if (mounted) { await showDialog( context: context, - builder: (_) => StackOkDialog( + builder: (_) => FrostErrorDialog( title: e.toString(), - desktopPopRootNavigator: Util.isDesktop, ), ); } diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart index adc1c7f5e..2bbfef1de 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart @@ -190,6 +190,7 @@ class _FrostReshareStep1cState extends ConsumerState { parentNav: data.parentNav, frostInterruptionDialogType: FrostInterruptionDialogType.resharing, + callerRouteName: data.callerRouteName, ); ref.read(pFrostMyName.state).state = ref.read(pFrostResharingData).myName!; diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2abd.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2abd.dart index 63edc03cf..1a688bb03 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2abd.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2abd.dart @@ -15,7 +15,7 @@ import 'package:stackwallet/widgets/custom_buttons/frost_qr_dialog_button.dart'; import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/detail_item.dart'; -import 'package:stackwallet/widgets/stack_dialog.dart'; +import 'package:stackwallet/widgets/dialogs/frost/frost_error_dialog.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; class FrostReshareStep2abd extends ConsumerStatefulWidget { @@ -86,10 +86,9 @@ class _FrostReshareStep2abdState extends ConsumerState { if (mounted) { await showDialog( context: context, - builder: (_) => StackOkDialog( + builder: (_) => FrostErrorDialog( title: "Error", message: e.toString(), - desktopPopRootNavigator: Util.isDesktop, ), ); } diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2c.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2c.dart index 0c811c635..798c503e5 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2c.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2c.dart @@ -8,7 +8,7 @@ import 'package:stackwallet/services/frost.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; -import 'package:stackwallet/widgets/stack_dialog.dart'; +import 'package:stackwallet/widgets/dialogs/frost/frost_error_dialog.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; class FrostReshareStep2c extends ConsumerStatefulWidget { @@ -63,14 +63,15 @@ class _FrostReshareStep2cState extends ConsumerState { level: LogLevel.Fatal, ); - await showDialog( - context: context, - builder: (_) => StackOkDialog( - title: "Error", - message: e.toString(), - desktopPopRootNavigator: Util.isDesktop, - ), - ); + if (mounted) { + await showDialog( + context: context, + builder: (_) => FrostErrorDialog( + title: "Error", + message: e.toString(), + ), + ); + } } finally { _buttonLock = false; } diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_3abd.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_3abd.dart index 5bccf7756..d49df3cc7 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_3abd.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_3abd.dart @@ -13,7 +13,7 @@ import 'package:stackwallet/widgets/custom_buttons/frost_qr_dialog_button.dart'; import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/detail_item.dart'; -import 'package:stackwallet/widgets/stack_dialog.dart'; +import 'package:stackwallet/widgets/dialogs/frost/frost_error_dialog.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; class FrostReshareStep3abd extends ConsumerStatefulWidget { @@ -73,15 +73,15 @@ class _FrostReshareStep3abdState extends ConsumerState { "$e\n$s", level: LogLevel.Fatal, ); - - await showDialog( - context: context, - builder: (_) => StackOkDialog( - title: "Error", - message: e.toString(), - desktopPopRootNavigator: Util.isDesktop, - ), - ); + if (mounted) { + await showDialog( + context: context, + builder: (_) => FrostErrorDialog( + title: "Error", + message: e.toString(), + ), + ); + } } finally { _buttonLock = false; } diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_4.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_4.dart index 2eb7c8f65..12de74573 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_4.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_4.dart @@ -17,7 +17,7 @@ import 'package:stackwallet/widgets/custom_buttons/frost_qr_dialog_button.dart'; import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/detail_item.dart'; -import 'package:stackwallet/widgets/stack_dialog.dart'; +import 'package:stackwallet/widgets/dialogs/frost/frost_error_dialog.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; // was FinishResharingView @@ -94,10 +94,9 @@ class _FrostReshareStep4State extends ConsumerState { if (mounted) { await showDialog( context: context, - builder: (_) => StackOkDialog( + builder: (_) => FrostErrorDialog( title: "Error", message: e.toString(), - desktopPopRootNavigator: Util.isDesktop, ), ); } diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_5.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_5.dart index 2171f5ad8..fe0875747 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_5.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_5.dart @@ -20,7 +20,7 @@ import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart'; import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/detail_item.dart'; -import 'package:stackwallet/widgets/stack_dialog.dart'; +import 'package:stackwallet/widgets/dialogs/frost/frost_error_dialog.dart'; // was VerifyUpdatedWalletView class FrostReshareStep5 extends ConsumerStatefulWidget { @@ -110,10 +110,9 @@ class _FrostReshareStep5State extends ConsumerState { if (mounted) { await showDialog( context: context, - builder: (_) => StackOkDialog( + builder: (_) => FrostErrorDialog( title: "Error", message: e.toString(), - desktopPopRootNavigator: Util.isDesktop, ), ); } diff --git a/lib/pages/send_view/frost_ms/frost_send_view.dart b/lib/pages/send_view/frost_ms/frost_send_view.dart index 133d0afd4..ccaf5452e 100644 --- a/lib/pages/send_view/frost_ms/frost_send_view.dart +++ b/lib/pages/send_view/frost_ms/frost_send_view.dart @@ -139,6 +139,7 @@ class _FrostSendViewState extends ConsumerState { parentNav: Navigator.of(context), frostInterruptionDialogType: FrostInterruptionDialogType.transactionCreation, + callerRouteName: FrostSendView.routeName, ); await Navigator.of(context).pushNamed( diff --git a/lib/pages/send_view/frost_ms/send_steps/frost_send_step_1b.dart b/lib/pages/send_view/frost_ms/send_steps/frost_send_step_1b.dart index 197d72e63..5015110aa 100644 --- a/lib/pages/send_view/frost_ms/send_steps/frost_send_step_1b.dart +++ b/lib/pages/send_view/frost_ms/send_steps/frost_send_step_1b.dart @@ -109,14 +109,16 @@ class _FrostSendStep1bState extends ConsumerState { "$e\n$s", level: LogLevel.Error, ); - await showDialog( - context: context, - builder: (_) => StackOkDialog( - title: "Import and attempt sign config failed", - message: e.toString(), - desktopPopRootNavigator: Util.isDesktop, - ), - ); + if (mounted) { + await showDialog( + context: context, + builder: (_) => StackOkDialog( + title: "Import and attempt sign config failed", + message: e.toString(), + desktopPopRootNavigator: Util.isDesktop, + ), + ); + } } finally { _attemptSignLock = false; } diff --git a/lib/pages/send_view/frost_ms/send_steps/frost_send_step_2.dart b/lib/pages/send_view/frost_ms/send_steps/frost_send_step_2.dart index 66f088b39..7fbea39da 100644 --- a/lib/pages/send_view/frost_ms/send_steps/frost_send_step_2.dart +++ b/lib/pages/send_view/frost_ms/send_steps/frost_send_step_2.dart @@ -14,8 +14,8 @@ import 'package:stackwallet/widgets/custom_buttons/frost_qr_dialog_button.dart'; import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/detail_item.dart'; +import 'package:stackwallet/widgets/dialogs/frost/frost_error_dialog.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; -import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; class FrostSendStep2 extends ConsumerStatefulWidget { @@ -293,13 +293,14 @@ class _FrostSendStep2State extends ConsumerState { level: LogLevel.Fatal, ); - return await showDialog( - context: context, - builder: (_) => StackOkDialog( - title: "Failed to continue signing", - desktopPopRootNavigator: Util.isDesktop, - ), - ); + if (context.mounted) { + return await showDialog( + context: context, + builder: (_) => const FrostErrorDialog( + title: "Failed to continue signing", + ), + ); + } } }, ), diff --git a/lib/pages/send_view/frost_ms/send_steps/frost_send_step_3.dart b/lib/pages/send_view/frost_ms/send_steps/frost_send_step_3.dart index bb7e462b9..46bb5cdb0 100644 --- a/lib/pages/send_view/frost_ms/send_steps/frost_send_step_3.dart +++ b/lib/pages/send_view/frost_ms/send_steps/frost_send_step_3.dart @@ -15,8 +15,8 @@ import 'package:stackwallet/widgets/custom_buttons/frost_qr_dialog_button.dart'; import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/detail_item.dart'; +import 'package:stackwallet/widgets/dialogs/frost/frost_error_dialog.dart'; import 'package:stackwallet/widgets/frost_step_user_steps.dart'; -import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; class FrostSendStep3 extends ConsumerStatefulWidget { @@ -238,9 +238,8 @@ class _FrostSendStep3State extends ConsumerState { if (context.mounted) { return await showDialog( context: context, - builder: (_) => StackOkDialog( + builder: (_) => const FrostErrorDialog( title: "Failed to complete signing process", - desktopPopRootNavigator: Util.isDesktop, ), ); } diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart index c18d78477..491f96c93 100644 --- a/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart @@ -162,6 +162,7 @@ class FrostMSWalletOptionsView extends ConsumerWidget { parentNav: Navigator.of(context), frostInterruptionDialogType: FrostInterruptionDialogType.resharing, + callerRouteName: FrostMSWalletOptionsView.routeName, ); Navigator.of(context).pushNamed( diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/complete_reshare_config_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/complete_reshare_config_view.dart index 7d8a61bcf..5ac986a6c 100644 --- a/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/complete_reshare_config_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/complete_reshare_config_view.dart @@ -129,18 +129,19 @@ class _CompleteReshareConfigViewState final wallet = ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet; - ref.read(pFrostScaffoldArgs.state).state = ( - info: ( - walletName: wallet.info.name, - frostCurrency: wallet.cryptoCurrency, - ), - walletId: wallet.walletId, - stepRoutes: FrostRouteGenerator.initiateReshareStepRoutes, - parentNav: Navigator.of(context), - frostInterruptionDialogType: FrostInterruptionDialogType.resharing, - ); - if (mounted) { + ref.read(pFrostScaffoldArgs.state).state = ( + info: ( + walletName: wallet.info.name, + frostCurrency: wallet.cryptoCurrency, + ), + walletId: wallet.walletId, + stepRoutes: FrostRouteGenerator.initiateReshareStepRoutes, + parentNav: Navigator.of(context), + frostInterruptionDialogType: FrostInterruptionDialogType.resharing, + callerRouteName: CompleteReshareConfigView.routeName, + ); + await Navigator.of(context).pushNamed( FrostStepScaffold.routeName, ); @@ -345,7 +346,8 @@ class _CompleteReshareConfigViewState () => _includeMeInReshare = value == true, ); _participantsCountChanged( - _newParticipantsCountController.text); + _newParticipantsCountController.text, + ); }, ), ), diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart index 20bd28575..57d404c0a 100644 --- a/lib/pages/wallet_view/wallet_view.dart +++ b/lib/pages/wallet_view/wallet_view.dart @@ -277,25 +277,27 @@ class _WalletViewState extends ConsumerState { const timeout = Duration(milliseconds: 1500); if (_cachedTime == null || now.difference(_cachedTime!) > timeout) { _cachedTime = now; - unawaited(showDialog( - context: context, - barrierDismissible: false, - builder: (_) => WillPopScope( - onWillPop: () async { - Navigator.of(context).popUntil( - ModalRoute.withName(HomeView.routeName), - ); - _logout(); - return false; - }, - child: const StackDialog(title: "Tap back again to exit wallet"), + unawaited( + showDialog( + context: context, + barrierDismissible: false, + builder: (_) => WillPopScope( + onWillPop: () async { + Navigator.of(context).popUntil( + ModalRoute.withName(HomeView.routeName), + ); + _logout(); + return false; + }, + child: const StackDialog(title: "Tap back again to exit wallet"), + ), + ).timeout( + timeout, + onTimeout: () => Navigator.of(context).popUntil( + ModalRoute.withName(WalletView.routeName), + ), ), - ).timeout( - timeout, - onTimeout: () => Navigator.of(context).popUntil( - ModalRoute.withName(WalletView.routeName), - ), - )); + ); } return false; } @@ -373,6 +375,7 @@ class _WalletViewState extends ConsumerState { parentNav: Navigator.of(context), frostInterruptionDialogType: FrostInterruptionDialogType.transactionCreation, + callerRouteName: WalletView.routeName, ); await Navigator.of(context).pushNamed( @@ -398,11 +401,12 @@ class _WalletViewState extends ConsumerState { .tickerEqualToAnyExchangeNameName(coin.ticker) .findFirst(); } catch (_) { - _future = ExchangeDataLoadingService.instance.loadAll().then((_) => - ExchangeDataLoadingService.instance.isar.currencies - .where() - .tickerEqualToAnyExchangeNameName(coin.ticker) - .findFirst()); + _future = ExchangeDataLoadingService.instance.loadAll().then( + (_) => ExchangeDataLoadingService.instance.isar.currencies + .where() + .tickerEqualToAnyExchangeNameName(coin.ticker) + .findFirst(), + ); } final currency = await showLoading( @@ -411,7 +415,7 @@ class _WalletViewState extends ConsumerState { message: "Loading...", ); - if (mounted) { + if (context.mounted) { unawaited( Navigator.of(context).pushNamed( WalletInitiatedExchangeView.routeName, @@ -568,7 +572,7 @@ class _WalletViewState extends ConsumerState { }, ), ), - ) + ), ], ), ); @@ -607,7 +611,7 @@ class _WalletViewState extends ConsumerState { style: STextStyles.navBarTitle(context), overflow: TextOverflow.ellipsis, ), - ) + ), ], ), actions: [ @@ -670,9 +674,12 @@ class _WalletViewState extends ConsumerState { color: Theme.of(context) .extension()! .background, - icon: ref.watch(notificationsProvider.select( - (value) => value - .hasUnreadNotificationsFor(walletId))) + icon: ref.watch( + notificationsProvider.select( + (value) => + value.hasUnreadNotificationsFor(walletId), + ), + ) ? SvgPicture.file( File( ref.watch( @@ -683,10 +690,14 @@ class _WalletViewState extends ConsumerState { ), width: 20, height: 20, - color: ref.watch(notificationsProvider.select( - (value) => - value.hasUnreadNotificationsFor( - walletId))) + color: ref.watch( + notificationsProvider.select( + (value) => + value.hasUnreadNotificationsFor( + walletId, + ), + ), + ) ? null : Theme.of(context) .extension()! @@ -696,10 +707,14 @@ class _WalletViewState extends ConsumerState { Assets.svg.bell, width: 20, height: 20, - color: ref.watch(notificationsProvider.select( - (value) => - value.hasUnreadNotificationsFor( - walletId))) + color: ref.watch( + notificationsProvider.select( + (value) => + value.hasUnreadNotificationsFor( + walletId, + ), + ), + ) ? null : Theme.of(context) .extension()! @@ -720,22 +735,25 @@ class _WalletViewState extends ConsumerState { .state; if (unreadNotificationIds.isEmpty) return; - List> futures = []; + final List> futures = []; for (int i = 0; i < unreadNotificationIds.length - 1; i++) { - futures.add(ref - .read(notificationsProvider) - .markAsRead( + futures.add( + ref.read(notificationsProvider).markAsRead( unreadNotificationIds.elementAt(i), - false)); + false, + ), + ); } // wait for multiple to update if any Future.wait(futures).then((_) { // only notify listeners once ref.read(notificationsProvider).markAsRead( - unreadNotificationIds.last, true); + unreadNotificationIds.last, + true, + ); }); }); }, @@ -824,7 +842,8 @@ class _WalletViewState extends ConsumerState { style: Theme.of(context) .extension()! .getSecondaryEnabledButtonStyle( - context), + context, + ), onPressed: () async { await showDialog( context: context, @@ -855,7 +874,8 @@ class _WalletViewState extends ConsumerState { style: Theme.of(context) .extension()! .getPrimaryEnabledButtonStyle( - context), + context, + ), child: Text( "Continue", style: @@ -1073,21 +1093,22 @@ class _WalletViewState extends ConsumerState { ), if (coin == Coin.banano) WalletNavigationBarItemData( - icon: SvgPicture.asset( - Assets.svg.monkey, - height: 20, - width: 20, - color: Theme.of(context) - .extension()! - .bottomNavIconIcon, - ), - label: "MonKey", - onTap: () { - Navigator.of(context).pushNamed( - MonkeyView.routeName, - arguments: widget.walletId, - ); - }), + icon: SvgPicture.asset( + Assets.svg.monkey, + height: 20, + width: 20, + color: Theme.of(context) + .extension()! + .bottomNavIconIcon, + ), + label: "MonKey", + onTap: () { + Navigator.of(context).pushNamed( + MonkeyView.routeName, + arguments: widget.walletId, + ); + }, + ), if (ref.watch( pWallets.select( (value) => value.getWallet(widget.walletId) @@ -1112,8 +1133,12 @@ class _WalletViewState extends ConsumerState { ); }, ), - if (ref.watch(pWallets.select((value) => - value.getWallet(widget.walletId) is PaynymInterface))) + if (ref.watch( + pWallets.select( + (value) => + value.getWallet(widget.walletId) is PaynymInterface, + ), + )) WalletNavigationBarItemData( label: "PayNym", icon: const PaynymNavIcon(), @@ -1145,7 +1170,7 @@ class _WalletViewState extends ConsumerState { level: LogLevel.Info, ); - if (mounted) { + if (context.mounted) { Navigator.of(context).pop(); // check if account exists and for matching code to see if claimed diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart index da7cd15e9..63974518b 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart @@ -13,6 +13,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/frost_route_generator.dart'; import 'package:stackwallet/pages/send_view/frost_ms/frost_send_view.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart'; +import 'package:stackwallet/pages_desktop_specific/my_stack_view/my_stack_view.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_receive.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_token_send.dart'; @@ -104,6 +105,7 @@ class _MyWalletState extends ConsumerState { frostInterruptionDialogType: FrostInterruptionDialogType .transactionCreation, + callerRouteName: MyStackView.routeName, ); await Navigator.of(context).pushNamed( @@ -111,7 +113,7 @@ class _MyWalletState extends ConsumerState { ); }, ), - ) + ), ], ), FrostSendView( diff --git a/lib/widgets/dialogs/frost/frost_error_dialog.dart b/lib/widgets/dialogs/frost/frost_error_dialog.dart new file mode 100644 index 000000000..8b1e56e15 --- /dev/null +++ b/lib/widgets/dialogs/frost/frost_error_dialog.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/frost_route_generator.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/widgets/desktop/primary_button.dart'; +import 'package:stackwallet/widgets/stack_dialog.dart'; + +class FrostErrorDialog extends ConsumerWidget { + const FrostErrorDialog({ + super.key, + required this.title, + this.icon, + this.message, + }); + + final String title; + final Widget? icon; + final String? message; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return SafeArea( + child: StackDialogBase( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Text( + title, + style: STextStyles.pageTitleH2(context), + ), + ), + icon != null ? icon! : Container(), + ], + ), + if (message != null) + const SizedBox( + height: 8, + ), + if (message != null) + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + message!, + style: STextStyles.smallMed14(context), + ), + ], + ), + const SizedBox( + height: 8, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Process must be restarted", + style: STextStyles.smallMed14(context), + ), + ], + ), + const SizedBox( + height: 20, + ), + Row( + children: [ + const Spacer(), + const SizedBox( + width: 8, + ), + PrimaryButton( + label: "Ok", + onPressed: () { + ref.read(pFrostScaffoldCanPopDesktop.notifier).state = true; + ref.read(pFrostScaffoldArgs)!.parentNav.popUntil( + ModalRoute.withName( + ref.read(pFrostScaffoldArgs)!.callerRouteName, + ), + ); + }, + ), + ], + ), + ], + ), + ), + ); + } +} From 20438da655e694fdb92de6d391c25ee0a8d893fc Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 13 May 2024 10:10:34 -0600 Subject: [PATCH 4/4] all wallets sync changes for better ui performance --- .../syncing_options_view.dart | 37 ++-- .../wallet_syncing_options_view.dart | 46 +++-- lib/pages/wallet_view/wallet_view.dart | 16 +- .../wallet_view/desktop_wallet_view.dart | 18 +- lib/services/wallets.dart | 166 +++++++++++++++++- 5 files changed, 218 insertions(+), 65 deletions(-) diff --git a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart index 4ff5da679..58144b681 100644 --- a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart +++ b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart @@ -11,7 +11,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart'; -import 'package:stackwallet/providers/global/active_wallet_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/constants.dart'; @@ -95,12 +94,12 @@ class SyncingOptionsView extends ConsumerWidget { ref.read(prefsChangeNotifierProvider).syncType = SyncingType.currentWalletOnly; - // disable auto sync on all wallets that aren't active/current - ref.read(pWallets).wallets.forEach((e) { - if (e.walletId != ref.read(currentWalletIdProvider)) { - e.shouldAutoSync = false; - } - }); + // // disable auto sync on all wallets that aren't active/current + // ref.read(pWallets).wallets.forEach((e) { + // if (e.walletId != ref.read(currentWalletIdProvider)) { + // e.shouldAutoSync = false; + // } + // }); } }, child: Container( @@ -174,11 +173,11 @@ class SyncingOptionsView extends ConsumerWidget { ref.read(prefsChangeNotifierProvider).syncType = SyncingType.allWalletsOnStartup; - // enable auto sync on all wallets - ref - .read(pWallets) - .wallets - .forEach((e) => e.shouldAutoSync = true); + // // enable auto sync on all wallets + // ref + // .read(pWallets) + // .wallets + // .forEach((e) => e.shouldAutoSync = true); } }, child: Container( @@ -252,13 +251,13 @@ class SyncingOptionsView extends ConsumerWidget { ref.read(prefsChangeNotifierProvider).syncType = SyncingType.selectedWalletsAtStartup; - final ids = ref - .read(prefsChangeNotifierProvider) - .walletIdsSyncOnStartup; - - // enable auto sync on selected wallets only - ref.read(pWallets).wallets.forEach( - (e) => e.shouldAutoSync = ids.contains(e.walletId)); + // final ids = ref + // .read(prefsChangeNotifierProvider) + // .walletIdsSyncOnStartup; + // + // // enable auto sync on selected wallets only + // ref.read(pWallets).wallets.forEach( + // (e) => e.shouldAutoSync = ids.contains(e.walletId)); } }, child: Container( diff --git a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart index 824656496..8ded05dd6 100644 --- a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart +++ b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart @@ -13,13 +13,11 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:stackwallet/providers/global/active_wallet_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/sync_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; @@ -181,9 +179,9 @@ class WalletSyncingOptionsView extends ConsumerWidget { .walletIdsSyncOnStartup)) .contains(info.walletId), onValueChanged: (value) { - final syncType = ref - .read(prefsChangeNotifierProvider) - .syncType; + // final syncType = ref + // .read(prefsChangeNotifierProvider) + // .syncType; final ids = ref .read(prefsChangeNotifierProvider) .walletIdsSyncOnStartup @@ -194,25 +192,25 @@ class WalletSyncingOptionsView extends ConsumerWidget { ids.remove(info.walletId); } - final wallet = ref - .read(pWallets) - .getWallet(info.walletId); - - switch (syncType) { - case SyncingType.currentWalletOnly: - if (info.walletId == - ref.read( - currentWalletIdProvider)) { - wallet.shouldAutoSync = value; - } - break; - case SyncingType - .selectedWalletsAtStartup: - case SyncingType - .allWalletsOnStartup: - wallet.shouldAutoSync = value; - break; - } + // final wallet = ref + // .read(pWallets) + // .getWallet(info.walletId); + // + // switch (syncType) { + // case SyncingType.currentWalletOnly: + // if (info.walletId == + // ref.read( + // currentWalletIdProvider)) { + // wallet.shouldAutoSync = value; + // } + // break; + // case SyncingType + // .selectedWalletsAtStartup: + // case SyncingType + // .allWalletsOnStartup: + // wallet.shouldAutoSync = value; + // break; + // } ref .read(prefsChangeNotifierProvider) diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart index 57d404c0a..f00751425 100644 --- a/lib/pages/wallet_view/wallet_view.dart +++ b/lib/pages/wallet_view/wallet_view.dart @@ -124,7 +124,7 @@ class _WalletViewState extends ConsumerState { late final bool isSparkWallet; - late final bool _shouldDisableAutoSyncOnLogOut; + // late final bool _shouldDisableAutoSyncOnLogOut; late WalletSyncStatus _currentSyncStatus; late NodeConnectionStatus _currentNodeStatus; @@ -177,9 +177,9 @@ class _WalletViewState extends ConsumerState { if (!wallet.shouldAutoSync) { // enable auto sync if it wasn't enabled when loading wallet wallet.shouldAutoSync = true; - _shouldDisableAutoSyncOnLogOut = true; - } else { - _shouldDisableAutoSyncOnLogOut = false; + // _shouldDisableAutoSyncOnLogOut = true; + // } else { + // _shouldDisableAutoSyncOnLogOut = false; } isSparkWallet = wallet is SparkInterface; @@ -303,10 +303,10 @@ class _WalletViewState extends ConsumerState { } void _logout() async { - if (_shouldDisableAutoSyncOnLogOut) { - // disable auto sync if it was enabled only when loading wallet - ref.read(pWallets).getWallet(walletId).shouldAutoSync = false; - } + // if (_shouldDisableAutoSyncOnLogOut) { + // // disable auto sync if it was enabled only when loading wallet + ref.read(pWallets).getWallet(walletId).shouldAutoSync = false; + // } ref.read(currentWalletIdProvider.notifier).state = null; ref.read(transactionFilterProvider.state).state = null; diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart index 70766661b..146f596d7 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart @@ -72,7 +72,7 @@ class _DesktopWalletViewState extends ConsumerState { late final TextEditingController controller; late final EventBus eventBus; - late final bool _shouldDisableAutoSyncOnLogOut; + // late final bool _shouldDisableAutoSyncOnLogOut; Future onBackPressed() async { await _logout(); @@ -83,10 +83,10 @@ class _DesktopWalletViewState extends ConsumerState { Future _logout() async { final wallet = ref.read(pWallets).getWallet(widget.walletId); - if (_shouldDisableAutoSyncOnLogOut) { - // disable auto sync if it was enabled only when loading wallet - wallet.shouldAutoSync = false; - } + // if (_shouldDisableAutoSyncOnLogOut) { + // // disable auto sync if it was enabled only when loading wallet + wallet.shouldAutoSync = false; + // } ref.read(transactionFilterProvider.state).state = null; if (ref.read(prefsChangeNotifierProvider).isAutoBackupEnabled && ref.read(prefsChangeNotifierProvider).backupFrequencyType == @@ -131,11 +131,11 @@ class _DesktopWalletViewState extends ConsumerState { ref.read(currentWalletIdProvider.notifier).state = wallet.walletId); if (!wallet.shouldAutoSync) { - // enable auto sync if it wasn't enabled when loading wallet + // // enable auto sync if it wasn't enabled when loading wallet wallet.shouldAutoSync = true; - _shouldDisableAutoSyncOnLogOut = true; - } else { - _shouldDisableAutoSyncOnLogOut = false; + // _shouldDisableAutoSyncOnLogOut = true; + // } else { + // _shouldDisableAutoSyncOnLogOut = false; } wallet.refresh(); diff --git a/lib/services/wallets.dart b/lib/services/wallets.dart index 7dab60dbd..bba7bfe90 100644 --- a/lib/services/wallets.dart +++ b/lib/services/wallets.dart @@ -136,7 +136,8 @@ class Wallets { Future load(Prefs prefs, MainDB mainDB) async { // return await _loadV1(prefs, mainDB); - return await _loadV2(prefs, mainDB); + // return await _loadV2(prefs, mainDB); + return await _loadV3(prefs, mainDB); } Future _loadV1(Prefs prefs, MainDB mainDB) async { @@ -240,6 +241,7 @@ class Wallets { } } + /// should be fastest but big ui performance hit Future _loadV2(Prefs prefs, MainDB mainDB) async { if (hasLoaded) { return; @@ -358,6 +360,160 @@ class Wallets { await Future.wait(deleteFutures); } + /// should be best performance + Future _loadV3(Prefs prefs, MainDB mainDB) async { + if (hasLoaded) { + return; + } + hasLoaded = true; + + // clear out any wallet hive boxes where the wallet was deleted in previous app run + for (final walletId in DB.instance + .values(boxName: DB.boxNameWalletsToDeleteOnStart)) { + await mainDB.isar.writeTxn(() async => await mainDB.isar.walletInfo + .where() + .walletIdEqualTo(walletId) + .deleteAll()); + } + // clear list + await DB.instance + .deleteAll(boxName: DB.boxNameWalletsToDeleteOnStart); + + final walletInfoList = await mainDB.isar.walletInfo.where().findAll(); + if (walletInfoList.isEmpty) { + return; + } + + final List> walletIDInitFutures = []; + final List> deleteFutures = []; + final List<({Wallet wallet, bool shouldAutoSync})> walletsToInitLinearly = + []; + + final List walletIdsToSyncOnceOnStartup = []; + bool shouldSyncAllOnceOnStartup = false; + switch (prefs.syncType) { + case SyncingType.currentWalletOnly: + // do nothing as this will be set when going into a wallet from the main screen + break; + case SyncingType.selectedWalletsAtStartup: + walletIdsToSyncOnceOnStartup.addAll(prefs.walletIdsSyncOnStartup); + break; + case SyncingType.allWalletsOnStartup: + shouldSyncAllOnceOnStartup = true; + break; + } + + for (final walletInfo in walletInfoList) { + try { + final isVerified = await walletInfo.isMnemonicVerified(mainDB.isar); + Logging.instance.log( + "LOADING WALLET: ${walletInfo.name}:${walletInfo.walletId} " + "IS VERIFIED: $isVerified", + level: LogLevel.Info, + ); + + if (isVerified) { + // TODO: integrate this into the new wallets somehow? + // requires some thinking + // final txTracker = + // TransactionNotificationTracker(walletId: walletInfo.walletId); + + final walletIdCompleter = Completer(); + + walletIDInitFutures.add(walletIdCompleter.future); + + await Wallet.load( + walletId: walletInfo.walletId, + mainDB: mainDB, + secureStorageInterface: nodeService.secureStorageInterface, + nodeService: nodeService, + prefs: prefs, + ).then((wallet) { + if (wallet is CwBasedInterface) { + // walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync)); + + walletIdCompleter.complete("dummy_ignore"); + } else { + walletIdCompleter.complete(wallet.walletId); + } + + _wallets[wallet.walletId] = wallet; + }); + } else { + // wallet creation was not completed by user so we remove it completely + deleteFutures.add(_deleteWallet(walletInfo.walletId)); + } + } catch (e, s) { + Logging.instance.log("$e $s", level: LogLevel.Fatal); + continue; + } + } + + final asyncWalletIds = await Future.wait(walletIDInitFutures); + asyncWalletIds.removeWhere((e) => e == "dummy_ignore"); + + final List idsToRefresh = []; + final List> walletInitFutures = asyncWalletIds + .map( + (id) => _wallets[id]!.init().then( + (_) { + if (shouldSyncAllOnceOnStartup || + walletIdsToSyncOnceOnStartup.contains(id)) { + idsToRefresh.add(id); + } + }, + ), + ) + .toList(); + + Future _refreshFutures(List idsToRefresh) async { + final start = DateTime.now(); + Logging.instance.log( + "Initial refresh start: ${start.toUtc()}", + level: LogLevel.Warning, + ); + const groupCount = 3; + for (int i = 0; i < idsToRefresh.length; i += groupCount) { + final List> futures = []; + for (int j = 0; j < groupCount; j++) { + if (i + j >= idsToRefresh.length) { + break; + } + futures.add( + _wallets[idsToRefresh[i + j]]!.refresh(), + ); + } + await Future.wait(futures); + } + Logging.instance.log( + "Initial refresh duration: ${DateTime.now().difference(start)}", + level: LogLevel.Warning, + ); + } + + if (walletInitFutures.isNotEmpty && walletsToInitLinearly.isNotEmpty) { + unawaited( + Future.wait([ + _initLinearly(walletsToInitLinearly), + ...walletInitFutures, + ]).then( + (value) => _refreshFutures(idsToRefresh), + ), + ); + } else if (walletInitFutures.isNotEmpty) { + unawaited( + Future.wait(walletInitFutures).then( + (value) => _refreshFutures(idsToRefresh), + ), + ); + } else if (walletsToInitLinearly.isNotEmpty) { + unawaited(_initLinearly(walletsToInitLinearly)); + } + + // finally await any deletions that haven't completed yet + await Future.wait(deleteFutures); + } + Future loadAfterStackRestore( Prefs prefs, List wallets, @@ -396,10 +552,10 @@ class Wallets { if (wallet is CwBasedInterface) { // walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync)); } else { - walletInitFutures.add(wallet.init().then((value) { - if (shouldSetAutoSync) { - wallet.shouldAutoSync = true; - } + walletInitFutures.add(wallet.init().then((_) { + // if (shouldSetAutoSync) { + // wallet.shouldAutoSync = true; + // } })); } }