This commit is contained in:
Matthew Fosse 2024-09-11 12:33:11 -07:00
parent 9f1b9548c3
commit 180b967c18
5 changed files with 107 additions and 38 deletions

View file

@ -456,7 +456,8 @@ abstract class ElectrumWalletBase
await updateBalance(); await updateBalance();
await updateFeeRates(); await updateFeeRates();
_updateFeeRateTimer ??= _updateFeeRateTimer?.cancel();
_updateFeeRateTimer =
Timer.periodic(const Duration(minutes: 1), (timer) async => await updateFeeRates()); Timer.periodic(const Duration(minutes: 1), (timer) async => await updateFeeRates());
if (alwaysScan == true) { if (alwaysScan == true) {
@ -471,6 +472,13 @@ abstract class ElectrumWalletBase
} }
} }
@action
@override
Future<void> stopSync() async {
syncStatus = StoppedSyncingSyncStatus();
_updateFeeRateTimer?.cancel();
}
@action @action
Future<void> updateFeeRates() async { Future<void> updateFeeRates() async {
if (await checkIfMempoolAPIIsEnabled()) { if (await checkIfMempoolAPIIsEnabled()) {
@ -1113,7 +1121,8 @@ abstract class ElectrumWalletBase
}); });
} }
unspentCoins.removeWhere((utxo) => estimatedTx.utxos.any((e) => e.utxo.txHash == utxo.hash)); unspentCoins
.removeWhere((utxo) => estimatedTx.utxos.any((e) => e.utxo.txHash == utxo.hash));
await updateBalance(); await updateBalance();
}); });
@ -2069,7 +2078,8 @@ abstract class ElectrumWalletBase
_isTryingToConnect = true; _isTryingToConnect = true;
Timer(Duration(seconds: 5), () { Timer(Duration(seconds: 5), () {
if (this.syncStatus is NotConnectedSyncStatus || this.syncStatus is LostConnectionSyncStatus) { if (this.syncStatus is NotConnectedSyncStatus ||
this.syncStatus is LostConnectionSyncStatus) {
this.electrumClient.connectToUri( this.electrumClient.connectToUri(
node!.uri, node!.uri,
useSSL: node!.useSSL ?? false, useSSL: node!.useSSL ?? false,

View file

@ -32,6 +32,7 @@ const notificationChannelDescription = 'Cake Wallet Background Service';
const DELAY_SECONDS_BEFORE_SYNC_START = 15; const DELAY_SECONDS_BEFORE_SYNC_START = 15;
void setNotificationStandby(FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin) async { void setNotificationStandby(FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin) async {
flutterLocalNotificationsPlugin.cancelAll();
flutterLocalNotificationsPlugin.show( flutterLocalNotificationsPlugin.show(
notificationId, notificationId,
initialNotificationTitle, initialNotificationTitle,
@ -181,22 +182,37 @@ Future<void> onStart(ServiceInstance service) async {
for (int i = 0; i < syncingWallets.length; i++) { for (int i = 0; i < syncingWallets.length; i++) {
final wallet = syncingWallets[i]; final wallet = syncingWallets[i];
final syncProgress = ((wallet!.syncStatus.progress()) * 100).toStringAsPrecision(5); final syncProgress = ((wallet!.syncStatus.progress()) * 100).toStringAsPrecision(5);
title += "${wallet.name}-${syncProgress}% "; // title += "${wallet.name}-${syncProgress}% ";
String title = "${wallet.type} - ${wallet.name} - ${syncProgress}% Synced";
flutterLocalNotificationsPlugin.show(
notificationId,
title,
'Background sync - ${DateTime.now()}',
NotificationDetails(
android: AndroidNotificationDetails(
"${notificationChannelId}_$i",
"${notificationChannelName}_$i",
icon: 'ic_bg_service_small',
ongoing: true,
),
),
);
} }
flutterLocalNotificationsPlugin.show( // flutterLocalNotificationsPlugin.show(
notificationId, // notificationId,
title, // title,
'Background sync - ${DateTime.now()}', // 'Background sync - ${DateTime.now()}',
const NotificationDetails( // const NotificationDetails(
android: AndroidNotificationDetails( // android: AndroidNotificationDetails(
notificationChannelId, // notificationChannelId,
notificationChannelName, // notificationChannelName,
icon: 'ic_bg_service_small', // icon: 'ic_bg_service_small',
ongoing: true, // ongoing: true,
), // ),
), // ),
); // );
}); });
}); });
} }
@ -211,14 +227,7 @@ Future<bool> onIosBackground(ServiceInstance service) async {
Future<void> initializeService(FlutterBackgroundService bgService, bool useNotifications) async { Future<void> initializeService(FlutterBackgroundService bgService, bool useNotifications) async {
if (useNotifications) { if (useNotifications) {
const AndroidNotificationChannel channel = AndroidNotificationChannel( FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
notificationChannelId,
notificationChannelName,
description: notificationChannelDescription,
importance: Importance.low,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin(); FlutterLocalNotificationsPlugin();
if (Platform.isIOS || Platform.isAndroid) { if (Platform.isIOS || Platform.isAndroid) {
@ -230,13 +239,17 @@ Future<void> initializeService(FlutterBackgroundService bgService, bool useNotif
); );
} }
await flutterLocalNotificationsPlugin for (int i = 0; i < 10; i++) {
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>() AndroidNotificationChannel channel = AndroidNotificationChannel(
?.createNotificationChannel(channel); "${notificationChannelId}_$i",
"${notificationChannelName}_$i",
flutterLocalNotificationsPlugin description: notificationChannelDescription,
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>() importance: Importance.low,
?.requestNotificationsPermission(); );
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
}
setNotificationStandby(flutterLocalNotificationsPlugin); setNotificationStandby(flutterLocalNotificationsPlugin);
} }
@ -273,10 +286,13 @@ Future<void> initializeService(FlutterBackgroundService bgService, bool useNotif
class BackgroundTasks { class BackgroundTasks {
FlutterBackgroundService bgService = FlutterBackgroundService(); FlutterBackgroundService bgService = FlutterBackgroundService();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
void updateServiceState(bool foreground, bool useNotifications) async { void updateServiceState(bool foreground, bool useNotifications) async {
if (foreground) { if (foreground) {
bgService.invoke('stopService'); bgService.invoke('stopService');
await Future.delayed(const Duration(seconds: 2));
initializeService(bgService, useNotifications); initializeService(bgService, useNotifications);
} else { } else {
bgService.invoke("setBackground"); bgService.invoke("setBackground");
@ -313,10 +329,15 @@ class BackgroundTasks {
return; return;
} }
final SyncMode syncMode = settingsStore.currentSyncMode; final SyncMode syncMode = settingsStore.currentSyncMode;
final bool syncAll = settingsStore.currentSyncAll; final bool syncAll = settingsStore.currentSyncAll;
if (settingsStore.showSyncNotification) {
flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission();
}
if (syncMode.type == SyncType.disabled || !FeatureFlag.isBackgroundSyncEnabled) { if (syncMode.type == SyncType.disabled || !FeatureFlag.isBackgroundSyncEnabled) {
bgService.invoke('stopService'); bgService.invoke('stopService');
return; return;

View file

@ -132,6 +132,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
@override @override
void didChangeAppLifecycleState(AppLifecycleState state) { void didChangeAppLifecycleState(AppLifecycleState state) {
final syncingWalletTypes = [WalletType.litecoin, WalletType.monero, WalletType.bitcoin];
switch (state) { switch (state) {
case AppLifecycleState.paused: case AppLifecycleState.paused:
if (isQrScannerShown) { if (isQrScannerShown) {
@ -142,7 +143,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
setState(() => _setInactive(true)); setState(() => _setInactive(true));
} }
if (widget.appStore.wallet?.type == WalletType.litecoin) { if (syncingWalletTypes.contains(widget.appStore.wallet?.type)) {
widget.appStore.wallet?.stopSync(); widget.appStore.wallet?.stopSync();
} }
@ -172,7 +173,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
return; return;
} }
wasInBackground = false; wasInBackground = false;
if (widget.appStore.wallet?.type == WalletType.litecoin) { if (syncingWalletTypes.contains(widget.appStore.wallet?.type)) {
// wait a few seconds before starting the sync make sure the background service is fully exited: // wait a few seconds before starting the sync make sure the background service is fully exited:
Future.delayed(const Duration(seconds: 3), () { Future.delayed(const Duration(seconds: 3), () {
widget.appStore.wallet?.startSync(); widget.appStore.wallet?.startSync();
@ -180,13 +181,15 @@ class RootState extends State<Root> with WidgetsBindingObserver {
} }
break; break;
case AppLifecycleState.paused: case AppLifecycleState.paused:
getIt.get<BackgroundTasks>().updateServiceState(false, showNotifications); // TODO: experimental: maybe should uncomment this:
// getIt.get<BackgroundTasks>().updateServiceState(false, showNotifications);
case AppLifecycleState.inactive: case AppLifecycleState.inactive:
case AppLifecycleState.detached: case AppLifecycleState.detached:
default: default:
// if we enter any state other than resumed start a timer for 30 seconds // 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 // after which we'll consider the app to be in the background
_stateTimer?.cancel(); _stateTimer?.cancel();
// TODO: bump this to > 30 seconds when testing is done:
_stateTimer = Timer(const Duration(seconds: 10), () async { _stateTimer = Timer(const Duration(seconds: 10), () async {
wasInBackground = true; wasInBackground = true;
getIt.get<BackgroundTasks>().updateServiceState(false, showNotifications); getIt.get<BackgroundTasks>().updateServiceState(false, showNotifications);

View file

@ -78,6 +78,34 @@ class ConnectionSyncPage extends BasePage {
// } // }
}); });
}), }),
Observer(builder: (context) {
return SettingsSwitcherCell(
title: "T: show sync% in notification",
value: dashboardViewModel.showSyncNotification,
onValueChange: (BuildContext _, bool isEnabled) async {
dashboardViewModel.setShowSyncNotification(isEnabled);
// if (!isEnabled) {
// final bool confirmation = await showPopUp<bool>(
// context: context,
// builder: (BuildContext context) {
// return AlertWithTwoActions(
// alertTitle: S.of(context).warning,
// alertContent: S.of(context).disable_fee_api_warning,
// rightButtonText: S.of(context).confirm,
// leftButtonText: S.of(context).cancel,
// actionRightButton: () => Navigator.of(context).pop(true),
// actionLeftButton: () => Navigator.of(context).pop(false));
// }) ??
// false;
// if (confirmation) {
// _privacySettingsViewModel.setUseMempoolFeeAPI(isEnabled);
// }
// return;
// }
},
);
}),
Observer(builder: (context) { Observer(builder: (context) {
return SettingsSwitcherCell( return SettingsSwitcherCell(
title: S.current.sync_all_wallets, title: S.current.sync_all_wallets,
@ -106,7 +134,8 @@ class ConnectionSyncPage extends BasePage {
}, },
), ),
if (isWalletConnectCompatibleChain(dashboardViewModel.wallet.type) && if (isWalletConnectCompatibleChain(dashboardViewModel.wallet.type) &&
!dashboardViewModel.wallet.isHardwareWallet) ...[ // ToDo: Remove this line once WalletConnect is implemented !dashboardViewModel.wallet.isHardwareWallet) ...[
// ToDo: Remove this line once WalletConnect is implemented
WalletConnectTile( WalletConnectTile(
onTap: () => Navigator.of(context).pushNamed(Routes.walletConnectConnectionsListing), onTap: () => Navigator.of(context).pushNamed(Routes.walletConnectConnectionsListing),
), ),
@ -138,4 +167,4 @@ class ConnectionSyncPage extends BasePage {
}, },
); );
} }
} }

View file

@ -714,6 +714,12 @@ abstract class DashboardViewModelBase with Store {
@computed @computed
bool get syncAll => settingsStore.currentSyncAll; bool get syncAll => settingsStore.currentSyncAll;
@action
void setShowSyncNotification(bool value) => settingsStore.showSyncNotification = value;
@computed
bool get showSyncNotification => settingsStore.showSyncNotification;
@action @action
void setSyncAll(bool value) => settingsStore.currentSyncAll = value; void setSyncAll(bool value) => settingsStore.currentSyncAll = value;