From 60bf871945a06651808b2613131254a2996d62bf Mon Sep 17 00:00:00 2001 From: zarzet Date: Thu, 9 Jul 2026 19:47:11 +0700 Subject: [PATCH] fix(downloads): flush queue persistence when app is backgrounded Queue writes are debounced by 350 ms and the only guaranteed flush ran in the provider's onDispose, which never fires when the OS kills the backgrounded process - the most recent queue mutations were silently lost, so items could vanish after the app sat minimised for a while. Expose flushQueuePersistence() on the queue notifier and call it from the app lifecycle observer on AppLifecycleState.paused, the last reliable callback before a potential process kill. --- lib/main.dart | 8 ++++++++ lib/providers/download_queue_provider.dart | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/main.dart b/lib/main.dart index e00ebd1b..b47da80c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -149,6 +149,14 @@ class _EagerInitializationState extends ConsumerState<_EagerInitialization> void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { _maybeAutoScanLocalLibrary(); + } else if (state == AppLifecycleState.paused) { + // Last reliable moment before the OS may kill the process: make sure + // any debounced download-queue persistence reaches disk. + if (ref.exists(downloadQueueProvider)) { + unawaited( + ref.read(downloadQueueProvider.notifier).flushQueuePersistence(), + ); + } } } diff --git a/lib/providers/download_queue_provider.dart b/lib/providers/download_queue_provider.dart index f247827a..69fe5de7 100644 --- a/lib/providers/download_queue_provider.dart +++ b/lib/providers/download_queue_provider.dart @@ -2039,6 +2039,16 @@ class DownloadQueueNotifier extends Notifier { return const DownloadQueueState(); } + /// Flush any debounced queue persistence to disk immediately. Called when + /// the app is backgrounded: the OS may kill the process without a graceful + /// teardown, and a pending debounce timer would silently drop the most + /// recent queue mutations. + Future flushQueuePersistence() async { + if (_queuePersistDebounce?.isActive != true) return; + _queuePersistDebounce?.cancel(); + await _flushQueueToStorage(); + } + Future _loadQueueFromStorage() async { if (_isLoaded) return; _isLoaded = true;