Prompt on app close when local node is running
build / Build Linux wallet (push) Failing after 1m48s
build / Build Windows wallet (push) Has been cancelled

This commit is contained in:
Codex Bot
2026-04-19 21:08:25 +02:00
parent 1e6df7f3c9
commit 9aaec9b387
3 changed files with 67 additions and 5 deletions
+61 -1
View File
@@ -89,6 +89,7 @@ class _PeyaAppState extends ConsumerState<PeyaApp> {
_didInit = true;
final tray = ref.read(trayServiceProvider);
final windowLifecycle = ref.read(windowLifecycleServiceProvider);
windowLifecycle.onBeforeClose = _handleAppCloseRequest;
await tray.init();
await windowLifecycle.init();
ref.read(syncSchedulerProvider);
@@ -233,7 +234,10 @@ class _PeyaAppState extends ConsumerState<PeyaApp> {
},
onSyncNow: () => ref.read(walletControllerProvider.notifier).syncNow(),
onQuit: () async {
await ref.read(walletRepositoryProvider).closeWallet();
final shouldClose = await _handleAppCloseRequest();
if (!shouldClose) {
return;
}
await tray.dispose();
await windowManager.setPreventClose(false);
await windowManager.close();
@@ -241,6 +245,62 @@ class _PeyaAppState extends ConsumerState<PeyaApp> {
);
}
Future<bool> _handleAppCloseRequest() async {
final config = ref.read(appConfigControllerProvider);
final localNodeService = ref.read(localNodeServiceProvider);
final shouldPromptForLocalNode = config.nodeConfig.mode == NodeMode.local &&
await localNodeService.isRunning(
config: LocalNodeConfig(extraArgs: config.localNodeArgs),
);
var shouldStopLocalNode = false;
if (shouldPromptForLocalNode) {
final l10n = AppLocalizations.of(context);
if (l10n == null || !mounted) {
return false;
}
final decision = await showDialog<bool?>(
context: context,
builder: (dialogContext) {
return AlertDialog(
title: Text(l10n.closeWalletNodeDialogTitle),
content: Text(l10n.closeWalletNodeDialogBody),
actions: [
TextButton(
onPressed: () => Navigator.of(dialogContext).pop(null),
child: Text(l10n.cancelAction),
),
TextButton(
onPressed: () => Navigator.of(dialogContext).pop(false),
child: Text(l10n.closeWalletKeepNodeAction),
),
ElevatedButton(
onPressed: () => Navigator.of(dialogContext).pop(true),
child: Text(l10n.closeWalletStopNodeAction),
),
],
);
},
);
if (decision == null) {
return false;
}
shouldStopLocalNode = decision;
}
if (shouldStopLocalNode) {
final stopped = await localNodeService.stop();
if (!stopped) {
if (mounted) {
_scaffoldMessengerKey.currentState?.showSnackBar(
SnackBar(content: Text(context.l10n.localNodeStopFailure)),
);
}
return false;
}
}
await ref.read(walletRepositoryProvider).closeWallet();
return true;
}
void _showErrorSnackBar(String message) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) {
+6 -3
View File
@@ -10,12 +10,11 @@ class WindowLifecycleService with WindowListener {
WindowLifecycleService({
required this.trayService,
required this.readConfig,
required this.onBeforeClose,
});
final TrayService trayService;
final AppConfig Function() readConfig;
final Future<void> Function()? onBeforeClose;
Future<bool> Function()? onBeforeClose;
bool _initialized = false;
bool _isClosing = false;
@@ -42,7 +41,11 @@ class WindowLifecycleService with WindowListener {
}
_isClosing = true;
if (onBeforeClose != null) {
await onBeforeClose!();
final shouldContinue = await onBeforeClose!();
if (!shouldContinue) {
_isClosing = false;
return;
}
}
await windowManager.setPreventClose(false);
await windowManager.close();
-1
View File
@@ -80,7 +80,6 @@ final windowLifecycleServiceProvider = Provider<WindowLifecycleService>((ref) {
return WindowLifecycleService(
trayService: tray,
readConfig: () => ref.read(appConfigControllerProvider),
onBeforeClose: () => ref.read(walletRepositoryProvider).closeWallet(),
);
});