diff --git a/lib/db/isar/main_db.dart b/lib/db/isar/main_db.dart index be46edf02..9e7e0da95 100644 --- a/lib/db/isar/main_db.dart +++ b/lib/db/isar/main_db.dart @@ -8,6 +8,8 @@ * */ +import 'dart:io'; + import 'package:decimal/decimal.dart'; import 'package:isar_community/isar.dart'; import 'package:tuple/tuple.dart'; @@ -76,7 +78,7 @@ class MainDB { // inspector: kDebugMode, inspector: false, name: "wallet_data", - maxSizeMiB: 512, + maxSizeMiB: Platform.isWindows ? 1024 : 512, ); return true; } @@ -445,18 +447,16 @@ class MainDB { // Future deleteWalletBlockchainData(String walletId) async { - final transactionCount = await getTransactions(walletId).count(); - final transactionCountV2 = await isar.transactionV2s - .where() - .walletIdEqualTo(walletId) - .count(); - final addressCount = await getAddresses(walletId).count(); - final utxoCount = await getUTXOs(walletId).count(); - // final lelantusCoinCount = - // await isar.lelantusCoins.where().walletIdEqualTo(walletId).count(); - await isar.writeTxn(() async { - const paginateLimit = 50; + final transactionCount = await getTransactions(walletId).count(); + final transactionCountV2 = await isar.transactionV2s + .where() + .walletIdEqualTo(walletId) + .count(); + final addressCount = await getAddresses(walletId).count(); + final utxoCount = await getUTXOs(walletId).count(); + + const paginateLimit = 100; // transactions for (int i = 0; i < transactionCount; i += paginateLimit) { diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart index fc4269f08..74e83cf88 100644 --- a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart +++ b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_list.dart @@ -131,9 +131,11 @@ class _TransactionsV2ListState extends ConsumerState { _subscription = _query.watch().listen((event) { WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - _transactions = event; - }); + if (mounted) { + setState(() { + _transactions = event; + }); + } }); }); diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/delete_wallet_keys_popup.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/delete_wallet_keys_popup.dart index bd6dac13f..c9a0c5074 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/delete_wallet_keys_popup.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/delete_wallet_keys_popup.dart @@ -13,6 +13,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; + import '../../../../notifications/show_flush_bar.dart'; import '../../../../pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart'; import '../../../../providers/global/secure_store_provider.dart'; @@ -21,6 +22,7 @@ import '../../../../route_generator.dart'; import '../../../../themes/stack_colors.dart'; import '../../../../utilities/assets.dart'; import '../../../../utilities/clipboard_interface.dart'; +import '../../../../utilities/logger.dart'; import '../../../../utilities/text_styles.dart'; import '../../../../wallets/isar/providers/wallet_info_provider.dart'; import '../../../../widgets/desktop/desktop_dialog.dart'; @@ -52,6 +54,11 @@ class _DeleteWalletKeysPopup extends ConsumerState { late final List _words; late final ClipboardInterface _clipboardInterface; + static const _recoveryPhraseInfo = + "Please write down your recovery phrase in the correct order and save it " + "to keep your funds secure. " + "You will be shown your recovery phrase on the next screen."; + @override void initState() { _walletId = widget.walletId; @@ -72,9 +79,7 @@ class _DeleteWalletKeysPopup extends ConsumerState { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( - padding: const EdgeInsets.only( - left: 32, - ), + padding: const EdgeInsets.only(left: 32), child: Text( "Wallet keys", style: STextStyles.desktopH3(context), @@ -82,51 +87,37 @@ class _DeleteWalletKeysPopup extends ConsumerState { ), DesktopDialogCloseButton( onPressedOverride: () { - Navigator.of( - context, - rootNavigator: true, - ).pop(); + Navigator.of(context, rootNavigator: true).pop(); }, ), ], ), - const SizedBox( - height: 28, - ), + const SizedBox(height: 28), Text( "Recovery phrase", style: STextStyles.desktopTextMedium(context), ), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), Center( child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 32, - ), + padding: const EdgeInsets.symmetric(horizontal: 32), child: Text( - "Please write down your recovery phrase in the correct order and " - "save it to keep your funds secure. You will be shown your recovery phrase on the next screen.", + _recoveryPhraseInfo, style: STextStyles.desktopTextExtraExtraSmall(context), textAlign: TextAlign.center, ), ), ), - const SizedBox( - height: 24, - ), + const SizedBox(height: 24), Padding( - padding: const EdgeInsets.symmetric( - horizontal: 32, - ), + padding: const EdgeInsets.symmetric(horizontal: 32), child: RawMaterialButton( hoverColor: Colors.transparent, onPressed: () async { await _clipboardInterface.setData( ClipboardData(text: _words.join(" ")), ); - if (mounted) { + if (context.mounted) { unawaited( showFloatingFlushBar( type: FlushBarType.info, @@ -140,19 +131,15 @@ class _DeleteWalletKeysPopup extends ConsumerState { child: MnemonicTable( words: widget.words, isDesktop: true, - itemBorderColor: Theme.of(context) - .extension()! - .buttonBackSecondary, + itemBorderColor: Theme.of( + context, + ).extension()!.buttonBackSecondary, ), ), ), - const SizedBox( - height: 24, - ), + const SizedBox(height: 24), Padding( - padding: const EdgeInsets.symmetric( - horizontal: 32, - ), + padding: const EdgeInsets.symmetric(horizontal: 32), child: Row( children: [ Expanded( @@ -162,9 +149,7 @@ class _DeleteWalletKeysPopup extends ConsumerState { await Navigator.of(context).push( RouteGenerator.getRoute( builder: (context) { - return ConfirmDelete( - walletId: _walletId, - ); + return ConfirmDelete(walletId: _walletId); }, settings: const RouteSettings( name: "/desktopConfirmDelete", @@ -177,9 +162,7 @@ class _DeleteWalletKeysPopup extends ConsumerState { ], ), ), - const SizedBox( - height: 32, - ), + const SizedBox(height: 32), ], ), ); @@ -187,10 +170,7 @@ class _DeleteWalletKeysPopup extends ConsumerState { } class ConfirmDelete extends ConsumerStatefulWidget { - const ConfirmDelete({ - super.key, - required this.walletId, - }); + const ConfirmDelete({super.key, required this.walletId}); final String walletId; @@ -207,9 +187,7 @@ class _ConfirmDeleteState extends ConsumerState { children: [ const Row( mainAxisAlignment: MainAxisAlignment.end, - children: [ - DesktopDialogCloseButton(), - ], + children: [DesktopDialogCloseButton()], ), Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -238,12 +216,22 @@ class _ConfirmDeleteState extends ConsumerState { buttonHeight: ButtonHeight.xl, label: "Continue", onPressed: () async { - await ref.read(pWallets).deleteWallet( - ref.read(pWalletInfo(widget.walletId)), - ref.read(secureStoreProvider), - ); + try { + await ref + .read(pWallets) + .deleteWallet( + ref.read(pWalletInfo(widget.walletId)), + ref.read(secureStoreProvider), + ); + } catch (e, s) { + Logging.instance.f( + "Wallet deletion errors", + error: e, + stackTrace: s, + ); + } - if (mounted) { + if (context.mounted) { Navigator.of(context, rootNavigator: true).pop(true); } }, diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart index 032a61bf4..17de7cd21 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart @@ -44,6 +44,12 @@ class DesktopAttentionDeleteWallet extends ConsumerStatefulWidget { class _DesktopAttentionDeleteWallet extends ConsumerState { + static const _deleteWarning = + "You are going to permanently delete your wallet.\n\nIf you delete your" + " wallet, the only way you can have access to your funds is by using your" + " backup key.\n\n${AppConfig.appName} does not keep nor is able to " + "restore your backup key or your wallet.\n\nPLEASE SAVE YOUR BACKUP KEY."; + @override Widget build(BuildContext context) { return DesktopDialog( @@ -68,25 +74,19 @@ class _DesktopAttentionDeleteWallet Text("Attention!", style: STextStyles.desktopH2(context)), const SizedBox(height: 16), RoundedContainer( - color: - Theme.of( - context, - ).extension()!.snackBarBackError, + color: Theme.of( + context, + ).extension()!.snackBarBackError, child: Padding( padding: const EdgeInsets.all(10.0), child: Text( - "You are going to permanently delete your wallet.\n\nIf you delete your wallet, " - "the only way you can have access to your funds is by using your backup key." - "\n\n${AppConfig.appName} does not keep nor is able to restore your backup key or your wallet." - "\n\nPLEASE SAVE YOUR BACKUP KEY.", - style: STextStyles.desktopTextExtraExtraSmall( - context, - ).copyWith( - color: - Theme.of( + _deleteWarning, + style: STextStyles.desktopTextExtraExtraSmall(context) + .copyWith( + color: Theme.of( context, ).extension()!.snackBarTextError, - ), + ), ), ), ), @@ -119,51 +119,46 @@ class _DesktopAttentionDeleteWallet if (context.mounted) { await Navigator.of(context).push( MaterialPageRoute( - builder: - (builder) => DesktopDialog( - maxWidth: 614, - maxHeight: double.infinity, - child: Column( + builder: (builder) => DesktopDialog( + maxWidth: 614, + maxHeight: double.infinity, + child: Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Padding( - padding: - const EdgeInsets.only( - left: 32, - ), - child: Text( - "Wallet keys", - style: - STextStyles.desktopH3( - context, - ), - ), - ), - DesktopDialogCloseButton( - onPressedOverride: () { - Navigator.of( - context, - rootNavigator: true, - ).pop(); - }, + Padding( + padding: const EdgeInsets.only( + left: 32, + ), + child: Text( + "Wallet keys", + style: STextStyles.desktopH3( + context, ), - ], + ), ), - Padding( - padding: const EdgeInsets.all(32), - child: - DeleteViewOnlyWalletKeysView( - walletId: widget.walletId, - data: data, - ), + DesktopDialogCloseButton( + onPressedOverride: () { + Navigator.of( + context, + rootNavigator: true, + ).pop(); + }, ), ], ), - ), + Padding( + padding: const EdgeInsets.all(32), + child: DeleteViewOnlyWalletKeysView( + walletId: widget.walletId, + data: data, + ), + ), + ], + ), + ), ), ); } @@ -182,7 +177,8 @@ class _DesktopAttentionDeleteWallet } } on BadDecryption catch (e, s) { Logging.instance.f( - "Desktop wallet delete error. Showing decryption error continue dialog.", + "Desktop wallet delete error. " + "Showing decryption error continue dialog.", error: e, stackTrace: s, ); @@ -220,6 +216,10 @@ class ErrorLoadingKeysDialog extends StatelessWidget { final String walletId; + static const _errorInfoExtra = + "Could not retrieve wallet keys/mnemonic phrase/seed.\n\n" + "Are you certain you would like to continue with wallet deletion?"; + @override Widget build(BuildContext context) { return DesktopDialog( @@ -251,8 +251,7 @@ class ErrorLoadingKeysDialog extends StatelessWidget { children: [ RoundedWhiteContainer( child: Text( - "Could not retrieve wallet keys/mnemonic phrase/seed.\n\n" - "Are you certain you would like to continue with wallet deletion?", + _errorInfoExtra, style: STextStyles.label(context).copyWith(fontSize: 16), ), ), diff --git a/lib/services/price.dart b/lib/services/price.dart index 537ea3a04..7af1ec2ba 100644 --- a/lib/services/price.dart +++ b/lib/services/price.dart @@ -202,7 +202,7 @@ class PriceAPI { static Future?> availableBaseCurrencies() async { final externalCalls = Prefs.instance.externalCalls; - final HTTP client = HTTP(); + const client = HTTP(); if ((!Util.isTestEnv && !externalCalls) || !(await Prefs.instance.isExternalCallsSet())) { diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart index f3729b2ae..0dec8aab2 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart @@ -557,6 +557,10 @@ mixin SparkInterface .valueIntStringEqualTo("0") .findAll(); + if (coins.isEmpty) { + throw Exception("No spendable Spark coins found"); + } + final available = info.cachedBalanceTertiary.spendable; if (txAmount > available) { @@ -577,10 +581,11 @@ mixin SparkInterface ) .toList(); - final currentId = await electrumXClient.getSparkLatestCoinId(); + final myCoinGroupIds = coins.map((e) => e.groupId).toSet(); + final List> setMaps = []; final List<({int groupId, String blockHash})> idAndBlockHashes = []; - for (int i = 1; i <= currentId; i++) { + for (final i in myCoinGroupIds) { final resultSet = await FiroCacheCoordinator.getSetCoinsForGroupId( i, network: cryptoCurrency.network,