From 20438da655e694fdb92de6d391c25ee0a8d893fc Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 13 May 2024 10:10:34 -0600 Subject: [PATCH] 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; + // } })); } }