mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-02-01 07:26:01 +00:00
experimental
This commit is contained in:
parent
a9f7dec112
commit
582830de49
4 changed files with 119 additions and 69 deletions
|
@ -60,6 +60,8 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
|
|||
|
||||
bool get isHardwareWallet => walletInfo.isHardwareWallet;
|
||||
|
||||
Future<void> init();
|
||||
|
||||
Future<void> connectToNode({required Node node});
|
||||
|
||||
// there is a default definition here because only coins with a pow node (nano based) need to override this
|
||||
|
|
|
@ -158,10 +158,7 @@ abstract class MoneroWalletBase
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: this doesn't work, need to find a better way to check if we are on the main thread
|
||||
bool isMainThread = Isolate.current.debugName == "main";
|
||||
printV("isMainThread: $isMainThread");
|
||||
|
||||
_autoSaveTimer?.cancel();
|
||||
_autoSaveTimer =
|
||||
Timer.periodic(Duration(seconds: _autoSaveInterval), (_) async => await save());
|
||||
|
||||
|
@ -275,6 +272,8 @@ abstract class MoneroWalletBase
|
|||
return;
|
||||
}
|
||||
monero_wallet.stopSync();
|
||||
_autoSaveTimer?.cancel();
|
||||
monero_wallet.closeCurrentWallet();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -737,13 +736,17 @@ abstract class MoneroWalletBase
|
|||
if (walletInfo.isRecovery) {
|
||||
await _askForUpdateTransactionHistory();
|
||||
_askForUpdateBalance();
|
||||
walletAddresses.accountList.update();
|
||||
if (!isBackgroundSyncing) {
|
||||
walletAddresses.accountList.update();
|
||||
}
|
||||
}
|
||||
|
||||
if (blocksLeft < 100) {
|
||||
await _askForUpdateTransactionHistory();
|
||||
_askForUpdateBalance();
|
||||
walletAddresses.accountList.update();
|
||||
if (!isBackgroundSyncing) {
|
||||
walletAddresses.accountList.update();
|
||||
}
|
||||
syncStatus = SyncedSyncStatus();
|
||||
|
||||
if (!_hasSyncAfterStartup) {
|
||||
|
|
|
@ -118,6 +118,22 @@ void setWalletNotification(FlutterLocalNotificationsPlugin flutterLocalNotificat
|
|||
);
|
||||
}
|
||||
|
||||
AppLifecycleState appStateFromString(String state) {
|
||||
switch (state) {
|
||||
case "AppLifecycleState.paused":
|
||||
return AppLifecycleState.paused;
|
||||
case "AppLifecycleState.resumed":
|
||||
return AppLifecycleState.resumed;
|
||||
case "AppLifecycleState.hidden":
|
||||
return AppLifecycleState.hidden;
|
||||
case "AppLifecycleState.detached":
|
||||
return AppLifecycleState.detached;
|
||||
case "AppLifecycleState.inactive":
|
||||
return AppLifecycleState.inactive;
|
||||
}
|
||||
throw Exception("unknown app state: $state");
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
Future<void> onStart(ServiceInstance service) async {
|
||||
printV("BACKGROUND SERVICE STARTED");
|
||||
|
@ -125,10 +141,13 @@ Future<void> onStart(ServiceInstance service) async {
|
|||
Timer? _syncTimer;
|
||||
Timer? _stuckSyncTimer;
|
||||
Timer? _queueTimer;
|
||||
Timer? _appStateTimer;
|
||||
List<WalletBase> syncingWallets = [];
|
||||
List<WalletBase> standbyWallets = [];
|
||||
Timer? _bgTimer;
|
||||
int fgCount = 0;
|
||||
AppLifecycleState lastAppState = AppLifecycleState.resumed;
|
||||
final List<AppLifecycleState> lastAppStates = [];
|
||||
String serviceState = "NOT_RUNNING";
|
||||
|
||||
// commented because the behavior appears to be bugged:
|
||||
// DartPluginRegistrant.ensureInitialized();
|
||||
|
@ -136,8 +155,7 @@ Future<void> onStart(ServiceInstance service) async {
|
|||
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
||||
service.on("stopService").listen((event) async {
|
||||
printV("STOPPING BACKGROUND SERVICE");
|
||||
Future<void> stopAllSyncing() async {
|
||||
_syncTimer?.cancel();
|
||||
_stuckSyncTimer?.cancel();
|
||||
_queueTimer?.cancel();
|
||||
|
@ -157,6 +175,11 @@ Future<void> onStart(ServiceInstance service) async {
|
|||
} catch (e) {
|
||||
printV("error stopping sync: $e");
|
||||
}
|
||||
}
|
||||
|
||||
service.on("stopService").listen((event) async {
|
||||
printV("STOPPING BACKGROUND SERVICE");
|
||||
await stopAllSyncing();
|
||||
// stop the service itself:
|
||||
service.invoke("serviceState", {"state": "NOT_RUNNING"});
|
||||
await service.stopSelf();
|
||||
|
@ -166,36 +189,39 @@ Future<void> onStart(ServiceInstance service) async {
|
|||
printV(event);
|
||||
});
|
||||
|
||||
void setForeground() {
|
||||
Future<void> setForeground() async {
|
||||
serviceState = "FOREGROUND";
|
||||
bgSyncStarted = false;
|
||||
_syncTimer?.cancel();
|
||||
setNotificationStandby(flutterLocalNotificationsPlugin);
|
||||
}
|
||||
|
||||
service.on("setForeground").listen((event) async {
|
||||
setForeground();
|
||||
await setForeground();
|
||||
service.invoke("serviceState", {"state": "FOREGROUND"});
|
||||
});
|
||||
|
||||
void setReady() {
|
||||
setNotificationReady(flutterLocalNotificationsPlugin);
|
||||
if (serviceState != "READY" && serviceState != "BACKGROUND") {
|
||||
serviceState = "READY";
|
||||
setNotificationReady(flutterLocalNotificationsPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
service.on("setReady").listen((event) async {
|
||||
setReady();
|
||||
service.invoke("serviceState", {"state": "READY"});
|
||||
});
|
||||
|
||||
service.on("foregroundPing").listen((event) async {
|
||||
fgCount = 0;
|
||||
service.on("appState").listen((event) async {
|
||||
printV("APP STATE: ${event?["state"]}");
|
||||
lastAppState = appStateFromString(event?["state"] as String);
|
||||
});
|
||||
|
||||
// we have entered the background, start the sync:
|
||||
void setBackground() async {
|
||||
if (bgSyncStarted) {
|
||||
return;
|
||||
}
|
||||
// only runs once per service instance:
|
||||
if (bgSyncStarted) return;
|
||||
bgSyncStarted = true;
|
||||
serviceState = "BACKGROUND";
|
||||
|
||||
await Future.delayed(const Duration(seconds: DELAY_SECONDS_BEFORE_SYNC_START));
|
||||
printV("STARTING SYNC FROM BG");
|
||||
|
@ -482,23 +508,24 @@ Future<void> onStart(ServiceInstance service) async {
|
|||
setBackground();
|
||||
});
|
||||
|
||||
// this is a backup timer to trigger in case the user fully closes the app, so that we still
|
||||
// start the background sync process:
|
||||
// annoyingly foreground code still runs in the background on android for some time, so we still use the original method
|
||||
// to detect if we are in the background since it's much faster
|
||||
_bgTimer = Timer.periodic(const Duration(seconds: 1), (timer) async {
|
||||
fgCount++;
|
||||
// we haven't been pinged in a while, so we are likely in the background:
|
||||
if (fgCount == 4) {
|
||||
setReady();
|
||||
return;
|
||||
// if the app state changes to paused, setReady()
|
||||
// if the app state has been paused for more than 10 seconds, setBackground()
|
||||
_appStateTimer = Timer.periodic(const Duration(seconds: 1), (timer) async {
|
||||
lastAppStates.add(lastAppState);
|
||||
if (lastAppStates.length > 10) {
|
||||
lastAppStates.removeAt(0);
|
||||
}
|
||||
|
||||
if (fgCount > 10) {
|
||||
fgCount = 0;
|
||||
// printV(lastAppStates);
|
||||
// if (lastAppState == AppLifecycleState.resumed && serviceState != "FOREGROUND") {
|
||||
// setForeground();
|
||||
// }
|
||||
if (lastAppStates.length < 5) return;
|
||||
if (lastAppState == AppLifecycleState.paused && serviceState != "READY") {
|
||||
setReady();
|
||||
}
|
||||
// if all 10 states are paused, setBackground()
|
||||
if (lastAppStates.every((state) => state == AppLifecycleState.paused) && !bgSyncStarted) {
|
||||
setBackground();
|
||||
service.invoke("serviceState", {"state": "BACKGROUND"});
|
||||
_bgTimer?.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -592,16 +619,22 @@ class BackgroundTasks {
|
|||
bgService.invoke("foregroundPing");
|
||||
}
|
||||
|
||||
Future<void> serviceForeground() async {
|
||||
if (serviceState == "FOREGROUND") {
|
||||
return;
|
||||
}
|
||||
void lastAppState(AppLifecycleState state) {
|
||||
bgService.invoke("appState", {"state": state.toString()});
|
||||
}
|
||||
|
||||
Future<void> serviceForeground() async {
|
||||
printV("SERVICE FOREGROUNDED");
|
||||
final settingsStore = getIt.get<SettingsStore>();
|
||||
bool showNotifications = settingsStore.showSyncNotification;
|
||||
bgService.invoke("stopService");
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
await Future.delayed(const Duration(seconds: 3));
|
||||
initializeService(bgService, showNotifications);
|
||||
bgService.invoke("setForeground");
|
||||
}
|
||||
|
||||
Future<bool> isServiceRunning() async {
|
||||
return await bgService.isRunning();
|
||||
}
|
||||
|
||||
void serviceReady() {
|
||||
|
|
|
@ -133,7 +133,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
|||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) async {
|
||||
final syncingWalletTypes = [WalletType.litecoin, WalletType.monero, WalletType.bitcoin];
|
||||
switch (state) {
|
||||
case AppLifecycleState.paused:
|
||||
|
@ -145,10 +145,6 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
|||
setState(() => _setInactive(true));
|
||||
}
|
||||
|
||||
if (FeatureFlag.isBackgroundSyncEnabled && syncingWalletTypes.contains(widget.appStore.wallet?.type)) {
|
||||
widget.appStore.wallet?.stopSync();
|
||||
}
|
||||
|
||||
break;
|
||||
case AppLifecycleState.resumed:
|
||||
widget.authService.requireAuth().then((value) {
|
||||
|
@ -163,37 +159,53 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
|||
break;
|
||||
}
|
||||
|
||||
// _stateTimer?.cancel();
|
||||
// _stateTimer = Timer(const Duration(seconds: 1), () async {
|
||||
// getIt.get<BackgroundTasks>().lastAppState(state);
|
||||
// });
|
||||
|
||||
getIt.get<BackgroundTasks>().lastAppState(state);
|
||||
|
||||
// background service handling:
|
||||
printV("state: $state");
|
||||
switch (state) {
|
||||
case AppLifecycleState.resumed:
|
||||
// restart the background service if it was running before:
|
||||
getIt.get<BackgroundTasks>().serviceForeground();
|
||||
_stateTimer?.cancel();
|
||||
if (!wasInBackground) {
|
||||
return;
|
||||
}
|
||||
wasInBackground = false;
|
||||
if (syncingWalletTypes.contains(widget.appStore.wallet?.type)) {
|
||||
// wait a few seconds before starting the sync make sure the background service is fully exited:
|
||||
Future.delayed(const Duration(seconds: 3), () {
|
||||
widget.appStore.wallet?.startSync();
|
||||
});
|
||||
}
|
||||
// // restart the background service if it was running before:
|
||||
await getIt.get<BackgroundTasks>().serviceForeground();
|
||||
// _stateTimer?.cancel();
|
||||
// if (!wasInBackground) {
|
||||
// return;
|
||||
// }
|
||||
// wasInBackground = false;
|
||||
// final appStore = widget.appStore;
|
||||
// final wallet = appStore.wallet;
|
||||
// if (syncingWalletTypes.contains(wallet?.type)) {
|
||||
// // wait a few seconds before starting the sync to make sure the background service is fully exited:
|
||||
// Future.delayed(const Duration(seconds: 50), () async {
|
||||
// final node = appStore.settingsStore.getCurrentNode(wallet!.type);
|
||||
// await wallet.stopSync();
|
||||
// await wallet.init();
|
||||
// wallet.connectToNode(node: node);
|
||||
// wallet.startSync();
|
||||
// });
|
||||
// }
|
||||
break;
|
||||
case AppLifecycleState.paused:
|
||||
getIt.get<BackgroundTasks>().serviceReady();
|
||||
case AppLifecycleState.hidden:
|
||||
case AppLifecycleState.inactive:
|
||||
case AppLifecycleState.detached:
|
||||
default:
|
||||
// anything other than resumed update the notification to say we're in the "ready" state:
|
||||
// if we enter any state other than resumed start a timer for 30 seconds
|
||||
// after which we'll consider the app to be in the background
|
||||
_stateTimer?.cancel();
|
||||
// TODO: bump this to > 30 seconds when testing is done:
|
||||
_stateTimer = Timer(const Duration(seconds: 10), () async {
|
||||
wasInBackground = true;
|
||||
getIt.get<BackgroundTasks>().serviceBackground();
|
||||
});
|
||||
break;
|
||||
case AppLifecycleState.paused:
|
||||
widget.appStore.wallet?.stopSync();
|
||||
// getIt.get<BackgroundTasks>().serviceReady();
|
||||
// // if (FeatureFlag.isBackgroundSyncEnabled &&
|
||||
// // syncingWalletTypes.contains(widget.appStore.wallet?.type)) {
|
||||
// // widget.appStore.wallet?.stopSync();
|
||||
// // }
|
||||
// _stateTimer?.cancel();
|
||||
// _stateTimer = Timer(const Duration(seconds: 10), () async {
|
||||
// wasInBackground = true;
|
||||
// getIt.get<BackgroundTasks>().serviceBackground();
|
||||
// });
|
||||
break;
|
||||
}
|
||||
_previousState = state;
|
||||
|
|
Loading…
Reference in a new issue