works but is still buggy

This commit is contained in:
Matthew Fosse 2024-08-29 17:53:10 -04:00
parent 879c29fe7c
commit 9b96bde7f2
6 changed files with 97 additions and 214 deletions

View file

@ -300,10 +300,11 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
@action
@override
Future<void> stopSync() async {
print("STOPPING SYNC");
_syncTimer?.cancel();
_utxoStream?.cancel();
await CwMweb.stop();
syncStatus = NotSyncingSyncStatus();
syncStatus = StoppedSyncingSyncStatus();
}
Future<void> initMwebUtxosBox() async {
@ -888,7 +889,6 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
// generate inital mweb addresses:
(walletAddresses as LitecoinWalletAddresses).topUpMweb(0);
}
stopSync();
startSync();
}

View file

@ -83,10 +83,11 @@ class LostConnectionSyncStatus extends NotConnectedSyncStatus {
String toString() => 'Reconnecting';
}
class NotSyncingSyncStatus extends SyncStatus {
// when the application has been paused by the OS:
class StoppedSyncingSyncStatus extends SyncStatus {
@override
double progress() => 0.0;
@override
String toString() => 'stopped';
}

View file

@ -187,77 +187,32 @@ void callbackDispatcher() {
Future<void> onStart(ServiceInstance service) async {
print("BACKGROUND SERVICE STARTED!");
// Only available for flutter 3.0.0 and later
DartPluginRegistrant.ensureInitialized();
// commented because the behavior appears to be bugged:
// DartPluginRegistrant.ensureInitialized();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
// this will be used as notification channel id
// this will be used as notification channel id
// this will be used for notification id, So you can update your custom notification with this id.
const notificationChannelId = 'my_foreground';
// this will be used for notification id, So you can update your custom notification with this id.
const notificationChannelName = 'MY FOREGROUND SERVICE';
const notificationId = 888;
if (service is AndroidServiceInstance) {
service.on('setAsForeground').listen((event) {
service.setAsForegroundService();
});
service.on('setAsBackground').listen((event) {
service.setAsBackgroundService();
});
}
service.on('stopService').listen((event) {
service.stopSelf();
});
// // bring to foreground
// Timer.periodic(const Duration(seconds: 1), (timer) async {
// if (service is AndroidServiceInstance) {
// if (await service.isForegroundService()) {
// flutterLocalNotificationsPlugin.show(
// notificationId,
// 'COOL SERVICE',
// 'Awesome ${DateTime.now()}',
// const NotificationDetails(
// android: AndroidNotificationDetails(
// notificationChannelId,
// 'MY FOREGROUND SERVICE',
// icon: 'ic_bg_service_small',
// ongoing: true,
// ),
// ),
// );
// } else {
// flutterLocalNotificationsPlugin.show(
// notificationId,
// 'BACKGROUND SERVICE?',
// 'Awesome ${DateTime.now()}',
// const NotificationDetails(
// android: AndroidNotificationDetails(
// notificationChannelId,
// 'MY FOREGROUND SERVICE',
// icon: 'ic_bg_service_small',
// ongoing: true,
// ),
// ),
// );
// }
// }
// });
// /// The work manager runs on a separate isolate from the main flutter isolate.
// /// thus we initialize app configs first; hive, getIt, etc...
// await initializeAppConfigs();
service.on('status').listen((event) async {
print(event);
});
bool bgSyncStarted = false;
service.on('foreground').listen((event) async {
bgSyncStarted = false;
});
service.on('startBgSync').listen((event) async {
if (bgSyncStarted) {
return;
@ -271,22 +226,29 @@ Future<void> onStart(ServiceInstance service) async {
Timer.periodic(const Duration(milliseconds: 1500), (timer) {
final wallet = getIt.get<AppStore>().wallet;
final syncProgress = wallet?.syncStatus.progress();
final syncProgress = ((wallet?.syncStatus.progress() ?? 0) * 100).toStringAsPrecision(3);
flutterLocalNotificationsPlugin.show(
notificationId,
"${syncProgress}",
'Awesome ${DateTime.now()}',
"${syncProgress}% Synced",
'Mweb background sync - ${DateTime.now()}',
const NotificationDetails(
android: AndroidNotificationDetails(
notificationChannelId,
'MY FOREGROUND SERVICE',
notificationChannelName,
icon: 'ic_bg_service_small',
ongoing: true,
),
),
);
});
// print("stopping in ten seconds!");
// Timer(const Duration(seconds: 10), () {
// // stop the service after 10 seconds
// print("stopping now!");
// service.stopSelf();
// });
});
// final List<WalletListItem> ltcWallets = getIt
@ -385,23 +347,6 @@ Future<bool> onIosBackground(ServiceInstance service) async {
}
Future<void> initializeService(FlutterBackgroundService bgService) async {
// final service = FlutterBackgroundService();
// await service.configure(
// iosConfiguration: IosConfiguration(
// autoStart: true,
// onForeground: onStart,
// onBackground: onIosBackground,
// ),
// androidConfiguration: AndroidConfiguration(
// autoStart: true,
// onStart: onStart,
// isForegroundMode: false,
// autoStartOnBoot: true,
// ),
// );
/// OPTIONAL, using custom notification channel id
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'my_foreground', // id
'MY FOREGROUND SERVICE', // title
@ -429,40 +374,52 @@ Future<void> initializeService(FlutterBackgroundService bgService) async {
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission();
const initialNotificationTitle = 'Cake Background Sync';
const initialNotificationContent = 'On standby - app is in the foreground';
const notificationId = 888;
const notificationChannelId = 'my_foreground';
const notificationChannelName = 'MY FOREGROUND SERVICE';
flutterLocalNotificationsPlugin.show(
notificationId,
initialNotificationTitle,
initialNotificationContent,
const NotificationDetails(
android: AndroidNotificationDetails(
notificationChannelId,
notificationChannelName,
icon: 'ic_bg_service_small',
ongoing: true,
),
),
);
await bgService.configure(
androidConfiguration: AndroidConfiguration(
// this will be executed when app is in foreground or background in separated isolate
onStart: onStart,
// auto start service
autoStart: true,
isForegroundMode: true,
notificationChannelId: 'my_foreground',
initialNotificationTitle: 'AWESOME SERVICE',
initialNotificationContent: 'Initializing',
foregroundServiceNotificationId: 888,
notificationChannelId: notificationChannelId,
initialNotificationTitle: initialNotificationTitle,
initialNotificationContent: initialNotificationContent,
foregroundServiceNotificationId: notificationId,
foregroundServiceTypes: [AndroidForegroundType.dataSync],
),
iosConfiguration: IosConfiguration(
// auto start service
autoStart: true,
// this will be executed when app is in foreground in separated isolate
onForeground: onStart,
// you have to enable background fetch capability on xcode project
onBackground: onIosBackground,
),
);
var wallet = getIt.get<AppStore>().wallet;
bgService.invoke("foreground");
Timer.periodic(const Duration(milliseconds: 1000), (timer) {
var wallet = getIt.get<AppStore>().wallet;
if (wallet?.syncStatus.toString() == "stopped") {
bgService.invoke("startBgSync");
timer.cancel();
}
// bgService.invoke("status", {"status": wallet?.syncStatus.toString()});
});
}
@ -496,93 +453,19 @@ class BackgroundTasks {
return;
}
// try {
// bool isServiceRunning = await bgService.isRunning();
// if (isServiceRunning) {
// return;
// // print("Service is ALREADY running!");
// // bgService.invoke('stopService');
// }
// } catch (_) {}
await initializeService(bgService);
// await service.configure(
// androidConfiguration: AndroidConfiguration(
// // this will be executed when app is in foreground or background in separated isolate
// onStart: onStart,
// // auto start service
// autoStart: true,
// isForegroundMode: true,
// notificationChannelId: notificationChannelId, // this must match with notification channel you created above.
// initialNotificationTitle: 'AWESOME SERVICE',
// initialNotificationContent: 'Initializing',
// foregroundServiceNotificationId: notificationId,
// );
// await Workmanager().initialize(
// callbackDispatcher,
// isInDebugMode: true,
// );
// final inputData = <String, dynamic>{"sync_all": syncAll};
// final constraints = Constraints(
// networkType:
// syncMode.type == SyncType.unobtrusive ? NetworkType.unmetered : NetworkType.connected,
// requiresBatteryNotLow: syncMode.type == SyncType.unobtrusive,
// requiresCharging: syncMode.type == SyncType.unobtrusive,
// requiresDeviceIdle: syncMode.type == SyncType.unobtrusive,
// );
// if (Platform.isIOS && syncMode.type == SyncType.unobtrusive) {
// // await Workmanager().registerOneOffTask(
// // moneroSyncTaskKey,
// // moneroSyncTaskKey,
// // initialDelay: syncMode.frequency,
// // existingWorkPolicy: ExistingWorkPolicy.replace,
// // inputData: inputData,
// // constraints: constraints,
// // );
// await Workmanager().registerOneOffTask(
// mwebSyncTaskKey,
// mwebSyncTaskKey,
// initialDelay: Duration(seconds: 30),
// existingWorkPolicy: ExistingWorkPolicy.replace,
// inputData: inputData,
// constraints: constraints,
// );
// return;
// }
// await Workmanager().registerPeriodicTask(
// moneroSyncTaskKey,
// moneroSyncTaskKey,
// initialDelay: syncMode.frequency,
// frequency: syncMode.frequency,
// existingWorkPolicy: changeExisting ? ExistingWorkPolicy.replace : ExistingWorkPolicy.keep,
// inputData: inputData,
// constraints: constraints,
// );
// await Workmanager().registerPeriodicTask(
// mwebSyncTaskKey,
// mwebSyncTaskKey,
// initialDelay: syncMode.frequency,
// frequency: syncMode.frequency,
// existingWorkPolicy: changeExisting ? ExistingWorkPolicy.replace : ExistingWorkPolicy.keep,
// inputData: inputData,
// constraints: constraints,
// );
} catch (error, stackTrace) {
print(error);
print(stackTrace);
}
}
void cancelSyncTask() {
// try {
// Workmanager().cancelByUniqueName(moneroSyncTaskKey);
// } catch (error, stackTrace) {
// print(error);
// print(stackTrace);
// }
// try {
// Workmanager().cancelByUniqueName(mwebSyncTaskKey);
// } catch (error, stackTrace) {
// print(error);
// print(stackTrace);
// }
}
}

View file

@ -1,3 +1,5 @@
import 'dart:isolate';
import 'package:cake_wallet/di.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/store/app_store.dart';
@ -8,12 +10,8 @@ import 'package:cake_wallet/core/wallet_loading_service.dart';
Future<void> loadCurrentWallet({String? password}) async {
final appStore = getIt.get<AppStore>();
final name = getIt
.get<SharedPreferences>()
.getString(PreferencesKey.currentWalletName);
final typeRaw =
getIt.get<SharedPreferences>().getInt(PreferencesKey.currentWalletType) ??
0;
final name = getIt.get<SharedPreferences>().getString(PreferencesKey.currentWalletName);
final typeRaw = getIt.get<SharedPreferences>().getInt(PreferencesKey.currentWalletType) ?? 0;
if (name == null) {
throw Exception('Incorrect current wallet name: $name');
@ -21,12 +19,9 @@ Future<void> loadCurrentWallet({String? password}) async {
final type = deserializeFromInt(typeRaw);
final walletLoadingService = getIt.get<WalletLoadingService>();
final wallet = await walletLoadingService.load(
type,
name,
password: password);
final wallet = await walletLoadingService.load(type, name, password: password);
await appStore.changeCurrentWallet(wallet);
// TODO: potential for infinite loop here since this is run when the wallet is loaded for syncing from the bg:
// getIt.get<BackgroundTasks>().registerSyncTask();
getIt.get<BackgroundTasks>().registerSyncTask();
}

View file

@ -43,13 +43,15 @@ class RootState extends State<Root> with WidgetsBindingObserver {
: _isInactiveController = StreamController<bool>.broadcast(),
_isInactive = false,
_requestAuth = true,
_postFrameCallback = false;
_postFrameCallback = false,
_previousState = AppLifecycleState.resumed;
Stream<bool> get isInactive => _isInactiveController.stream;
StreamController<bool> _isInactiveController;
bool _isInactive;
bool _postFrameCallback;
bool _requestAuth;
AppLifecycleState _previousState;
StreamSubscription<Uri?>? stream;
ReactionDisposer? _walletReactionDisposer;
@ -148,13 +150,18 @@ class RootState extends State<Root> with WidgetsBindingObserver {
});
}
});
if (widget.appStore.wallet?.type == WalletType.litecoin) {
widget.appStore.wallet?.startSync();
// prevent triggering startSync from the notifications menu on android / other non-paused states:
if (_previousState == AppLifecycleState.paused) {
if (widget.appStore.wallet?.type == WalletType.litecoin) {
widget.appStore.wallet?.startSync();
}
}
break;
default:
break;
}
_previousState = state;
}
@override

View file

@ -56,29 +56,26 @@ class ConnectionSyncPage extends BasePage {
if (Platform.isIOS) return;
if (syncMode.type != SyncType.disabled) {
final isDisabled = await isBatteryOptimizationDisabled();
if (isDisabled) return;
await showPopUp<void>(
context: context,
builder: (BuildContext dialogContext) {
return AlertWithTwoActions(
alertTitle: S.current.disableBatteryOptimization,
alertContent: S.current.disableBatteryOptimizationDescription,
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).ok,
actionLeftButton: () => Navigator.of(dialogContext).pop(),
actionRightButton: () async {
await requestDisableBatteryOptimization();
Navigator.of(dialogContext).pop();
},
);
},
);
}
// if (syncMode.type != SyncType.disabled) {
// final isDisabled = await isBatteryOptimizationDisabled();
// if (isDisabled) return;
// await showPopUp<void>(
// context: context,
// builder: (BuildContext dialogContext) {
// return AlertWithTwoActions(
// alertTitle: S.current.disableBatteryOptimization,
// alertContent: S.current.disableBatteryOptimizationDescription,
// leftButtonText: S.of(context).cancel,
// rightButtonText: S.of(context).ok,
// actionLeftButton: () => Navigator.of(dialogContext).pop(),
// actionRightButton: () async {
// await requestDisableBatteryOptimization();
// Navigator.of(dialogContext).pop();
// },
// );
// },
// );
// }
});
}),
Observer(builder: (context) {