all wallets sync changes for better ui performance

This commit is contained in:
julian 2024-05-13 10:10:34 -06:00
parent 3f4ebe0229
commit 20438da655
5 changed files with 218 additions and 65 deletions

View file

@ -11,7 +11,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.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/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/providers/providers.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
@ -95,12 +94,12 @@ class SyncingOptionsView extends ConsumerWidget {
ref.read(prefsChangeNotifierProvider).syncType = ref.read(prefsChangeNotifierProvider).syncType =
SyncingType.currentWalletOnly; SyncingType.currentWalletOnly;
// disable auto sync on all wallets that aren't active/current // // disable auto sync on all wallets that aren't active/current
ref.read(pWallets).wallets.forEach((e) { // ref.read(pWallets).wallets.forEach((e) {
if (e.walletId != ref.read(currentWalletIdProvider)) { // if (e.walletId != ref.read(currentWalletIdProvider)) {
e.shouldAutoSync = false; // e.shouldAutoSync = false;
} // }
}); // });
} }
}, },
child: Container( child: Container(
@ -174,11 +173,11 @@ class SyncingOptionsView extends ConsumerWidget {
ref.read(prefsChangeNotifierProvider).syncType = ref.read(prefsChangeNotifierProvider).syncType =
SyncingType.allWalletsOnStartup; SyncingType.allWalletsOnStartup;
// enable auto sync on all wallets // // enable auto sync on all wallets
ref // ref
.read(pWallets) // .read(pWallets)
.wallets // .wallets
.forEach((e) => e.shouldAutoSync = true); // .forEach((e) => e.shouldAutoSync = true);
} }
}, },
child: Container( child: Container(
@ -252,13 +251,13 @@ class SyncingOptionsView extends ConsumerWidget {
ref.read(prefsChangeNotifierProvider).syncType = ref.read(prefsChangeNotifierProvider).syncType =
SyncingType.selectedWalletsAtStartup; SyncingType.selectedWalletsAtStartup;
final ids = ref // final ids = ref
.read(prefsChangeNotifierProvider) // .read(prefsChangeNotifierProvider)
.walletIdsSyncOnStartup; // .walletIdsSyncOnStartup;
//
// enable auto sync on selected wallets only // // enable auto sync on selected wallets only
ref.read(pWallets).wallets.forEach( // ref.read(pWallets).wallets.forEach(
(e) => e.shouldAutoSync = ids.contains(e.walletId)); // (e) => e.shouldAutoSync = ids.contains(e.walletId));
} }
}, },
child: Container( child: Container(

View file

@ -13,13 +13,11 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.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/providers/providers.dart';
import 'package:stackwallet/themes/coin_icon_provider.dart'; import 'package:stackwallet/themes/coin_icon_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/amount/amount_formatter.dart';
import 'package:stackwallet/utilities/constants.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/text_styles.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
@ -181,9 +179,9 @@ class WalletSyncingOptionsView extends ConsumerWidget {
.walletIdsSyncOnStartup)) .walletIdsSyncOnStartup))
.contains(info.walletId), .contains(info.walletId),
onValueChanged: (value) { onValueChanged: (value) {
final syncType = ref // final syncType = ref
.read(prefsChangeNotifierProvider) // .read(prefsChangeNotifierProvider)
.syncType; // .syncType;
final ids = ref final ids = ref
.read(prefsChangeNotifierProvider) .read(prefsChangeNotifierProvider)
.walletIdsSyncOnStartup .walletIdsSyncOnStartup
@ -194,25 +192,25 @@ class WalletSyncingOptionsView extends ConsumerWidget {
ids.remove(info.walletId); ids.remove(info.walletId);
} }
final wallet = ref // final wallet = ref
.read(pWallets) // .read(pWallets)
.getWallet(info.walletId); // .getWallet(info.walletId);
//
switch (syncType) { // switch (syncType) {
case SyncingType.currentWalletOnly: // case SyncingType.currentWalletOnly:
if (info.walletId == // if (info.walletId ==
ref.read( // ref.read(
currentWalletIdProvider)) { // currentWalletIdProvider)) {
wallet.shouldAutoSync = value; // wallet.shouldAutoSync = value;
} // }
break; // break;
case SyncingType // case SyncingType
.selectedWalletsAtStartup: // .selectedWalletsAtStartup:
case SyncingType // case SyncingType
.allWalletsOnStartup: // .allWalletsOnStartup:
wallet.shouldAutoSync = value; // wallet.shouldAutoSync = value;
break; // break;
} // }
ref ref
.read(prefsChangeNotifierProvider) .read(prefsChangeNotifierProvider)

View file

@ -124,7 +124,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
late final bool isSparkWallet; late final bool isSparkWallet;
late final bool _shouldDisableAutoSyncOnLogOut; // late final bool _shouldDisableAutoSyncOnLogOut;
late WalletSyncStatus _currentSyncStatus; late WalletSyncStatus _currentSyncStatus;
late NodeConnectionStatus _currentNodeStatus; late NodeConnectionStatus _currentNodeStatus;
@ -177,9 +177,9 @@ class _WalletViewState extends ConsumerState<WalletView> {
if (!wallet.shouldAutoSync) { 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; wallet.shouldAutoSync = true;
_shouldDisableAutoSyncOnLogOut = true; // _shouldDisableAutoSyncOnLogOut = true;
} else { // } else {
_shouldDisableAutoSyncOnLogOut = false; // _shouldDisableAutoSyncOnLogOut = false;
} }
isSparkWallet = wallet is SparkInterface; isSparkWallet = wallet is SparkInterface;
@ -303,10 +303,10 @@ class _WalletViewState extends ConsumerState<WalletView> {
} }
void _logout() async { void _logout() async {
if (_shouldDisableAutoSyncOnLogOut) { // if (_shouldDisableAutoSyncOnLogOut) {
// disable auto sync if it was enabled only when loading wallet // // disable auto sync if it was enabled only when loading wallet
ref.read(pWallets).getWallet(walletId).shouldAutoSync = false; ref.read(pWallets).getWallet(walletId).shouldAutoSync = false;
} // }
ref.read(currentWalletIdProvider.notifier).state = null; ref.read(currentWalletIdProvider.notifier).state = null;
ref.read(transactionFilterProvider.state).state = null; ref.read(transactionFilterProvider.state).state = null;

View file

@ -72,7 +72,7 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
late final TextEditingController controller; late final TextEditingController controller;
late final EventBus eventBus; late final EventBus eventBus;
late final bool _shouldDisableAutoSyncOnLogOut; // late final bool _shouldDisableAutoSyncOnLogOut;
Future<void> onBackPressed() async { Future<void> onBackPressed() async {
await _logout(); await _logout();
@ -83,10 +83,10 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
Future<void> _logout() async { Future<void> _logout() async {
final wallet = ref.read(pWallets).getWallet(widget.walletId); final wallet = ref.read(pWallets).getWallet(widget.walletId);
if (_shouldDisableAutoSyncOnLogOut) { // if (_shouldDisableAutoSyncOnLogOut) {
// disable auto sync if it was enabled only when loading wallet // // disable auto sync if it was enabled only when loading wallet
wallet.shouldAutoSync = false; wallet.shouldAutoSync = false;
} // }
ref.read(transactionFilterProvider.state).state = null; ref.read(transactionFilterProvider.state).state = null;
if (ref.read(prefsChangeNotifierProvider).isAutoBackupEnabled && if (ref.read(prefsChangeNotifierProvider).isAutoBackupEnabled &&
ref.read(prefsChangeNotifierProvider).backupFrequencyType == ref.read(prefsChangeNotifierProvider).backupFrequencyType ==
@ -131,11 +131,11 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
ref.read(currentWalletIdProvider.notifier).state = wallet.walletId); ref.read(currentWalletIdProvider.notifier).state = wallet.walletId);
if (!wallet.shouldAutoSync) { 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; wallet.shouldAutoSync = true;
_shouldDisableAutoSyncOnLogOut = true; // _shouldDisableAutoSyncOnLogOut = true;
} else { // } else {
_shouldDisableAutoSyncOnLogOut = false; // _shouldDisableAutoSyncOnLogOut = false;
} }
wallet.refresh(); wallet.refresh();

View file

@ -136,7 +136,8 @@ class Wallets {
Future<void> load(Prefs prefs, MainDB mainDB) async { Future<void> load(Prefs prefs, MainDB mainDB) async {
// return await _loadV1(prefs, mainDB); // return await _loadV1(prefs, mainDB);
return await _loadV2(prefs, mainDB); // return await _loadV2(prefs, mainDB);
return await _loadV3(prefs, mainDB);
} }
Future<void> _loadV1(Prefs prefs, MainDB mainDB) async { Future<void> _loadV1(Prefs prefs, MainDB mainDB) async {
@ -240,6 +241,7 @@ class Wallets {
} }
} }
/// should be fastest but big ui performance hit
Future<void> _loadV2(Prefs prefs, MainDB mainDB) async { Future<void> _loadV2(Prefs prefs, MainDB mainDB) async {
if (hasLoaded) { if (hasLoaded) {
return; return;
@ -358,6 +360,160 @@ class Wallets {
await Future.wait(deleteFutures); await Future.wait(deleteFutures);
} }
/// should be best performance
Future<void> _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<String>(boxName: DB.boxNameWalletsToDeleteOnStart)) {
await mainDB.isar.writeTxn(() async => await mainDB.isar.walletInfo
.where()
.walletIdEqualTo(walletId)
.deleteAll());
}
// clear list
await DB.instance
.deleteAll<String>(boxName: DB.boxNameWalletsToDeleteOnStart);
final walletInfoList = await mainDB.isar.walletInfo.where().findAll();
if (walletInfoList.isEmpty) {
return;
}
final List<Future<String>> walletIDInitFutures = [];
final List<Future<void>> deleteFutures = [];
final List<({Wallet wallet, bool shouldAutoSync})> walletsToInitLinearly =
[];
final List<String> 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<String>();
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<String> idsToRefresh = [];
final List<Future<void>> walletInitFutures = asyncWalletIds
.map(
(id) => _wallets[id]!.init().then(
(_) {
if (shouldSyncAllOnceOnStartup ||
walletIdsToSyncOnceOnStartup.contains(id)) {
idsToRefresh.add(id);
}
},
),
)
.toList();
Future<void> _refreshFutures(List<String> 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<Future<void>> 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<void> loadAfterStackRestore( Future<void> loadAfterStackRestore(
Prefs prefs, Prefs prefs,
List<Wallet> wallets, List<Wallet> wallets,
@ -396,10 +552,10 @@ class Wallets {
if (wallet is CwBasedInterface) { if (wallet is CwBasedInterface) {
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync)); // walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
} else { } else {
walletInitFutures.add(wallet.init().then((value) { walletInitFutures.add(wallet.init().then((_) {
if (shouldSetAutoSync) { // if (shouldSetAutoSync) {
wallet.shouldAutoSync = true; // wallet.shouldAutoSync = true;
} // }
})); }));
} }
} }