From de142abae6803892fc143cd23475365e17320c2f Mon Sep 17 00:00:00 2001 From: zarzet <42882290+zarzet@users.noreply.github.com> Date: Mon, 19 Oct 2026 01:02:57 +0700 Subject: [PATCH] refactor(library): share the scan completion tail as _finishScan The full-scan and incremental branches of _runScan ended with the same sequence: source state update, last-scanned prefs, summary refresh, the mounted check, the final state, log and completion notification. Move that sequence into _finishScan. The only differences, the cover cache prune after a full scan and the summary text, become parameters; the summary stays a closure so it still reads the state after the final update. Each call is the last statement of its branch, so the early return on unmount keeps the same effect. --- lib/providers/local_library_provider.dart | 164 ++++++++++------------ 1 file changed, 72 insertions(+), 92 deletions(-) diff --git a/lib/providers/local_library_provider.dart b/lib/providers/local_library_provider.dart index 27c66836..88402fcc 100644 --- a/lib/providers/local_library_provider.dart +++ b/lib/providers/local_library_provider.dart @@ -1017,52 +1017,14 @@ class LocalLibraryNotifier extends Notifier { _log.i('Skipped $skippedDownloads files already in download history'); } - final now = DateTime.now(); - _sourceVersion++; - await _db.updateSourceState( - activeSourceId, - available: true, - lastSeenAt: now, - lastScannedAt: now, - clearLastScanError: true, - ); - try { - final prefs = await SharedPreferences.getInstance(); - await writeLocalLibraryLastScannedAt(prefs, now); - await prefs.setInt(_excludedDownloadedCountKey, skippedDownloads); - _log.d('Saved lastScannedAt: $now'); - } catch (e) { - _log.w('Failed to save lastScannedAt: $e'); - } - - await _refreshSummaryFromStorage( - lastScannedAt: now, - excludedDownloadedCount: skippedDownloads, - ); - if (!ref.mounted) return; - state = state.copyWith( - isScanning: false, - scanIsFinalizing: false, - scanProgress: 100, - lastScannedAt: now, - scanWasCancelled: false, - excludedDownloadedCount: skippedDownloads, - ); - await _pruneLibraryCoverCache(); - - final summary = - 'Full scan complete: ${state.totalCount} tracks found, ' - '$skippedDownloads already in downloads, ' - '${state.scanErrorCount} errors'; - if (state.scanErrorCount > 0) { - _log.e(summary); - } else { - _log.i(summary); - } - await _showScanCompleteNotification( - totalTracks: state.totalCount, - excludedDownloadedCount: skippedDownloads, - errorCount: state.scanErrorCount, + await _finishScan( + sourceId: activeSourceId, + skippedDownloads: skippedDownloads, + pruneCoverCache: true, + summary: () => + 'Full scan complete: ${state.totalCount} tracks found, ' + '$skippedDownloads already in downloads, ' + '${state.scanErrorCount} errors', ); } else { final nativeIngestion = PlatformBridge.supportsCoreBackend; @@ -1220,52 +1182,15 @@ class LocalLibraryNotifier extends Notifier { _log.i('Deleted $deleteCount items from database'); } - final now = DateTime.now(); - _sourceVersion++; - await _db.updateSourceState( - activeSourceId, - available: true, - lastSeenAt: now, - lastScannedAt: now, - clearLastScanError: true, - ); - try { - final prefs = await SharedPreferences.getInstance(); - await writeLocalLibraryLastScannedAt(prefs, now); - await prefs.setInt(_excludedDownloadedCountKey, skippedDownloads); - _log.d('Saved lastScannedAt: $now'); - } catch (e) { - _log.w('Failed to save lastScannedAt: $e'); - } - - await _refreshSummaryFromStorage( - lastScannedAt: now, - excludedDownloadedCount: skippedDownloads, - ); - if (!ref.mounted) return; - state = state.copyWith( - isScanning: false, - scanIsFinalizing: false, - scanProgress: 100, - lastScannedAt: now, - scanWasCancelled: false, - excludedDownloadedCount: skippedDownloads, - ); - - final summary = - 'Incremental scan complete: ${state.totalCount} total tracks ' - '($scannedCount new/updated, $skippedCount unchanged, ' - '$deletedCount removed, $skippedDownloads already in downloads, ' - '${state.scanErrorCount} errors)'; - if (state.scanErrorCount > 0) { - _log.e(summary); - } else { - _log.i(summary); - } - await _showScanCompleteNotification( - totalTracks: state.totalCount, - excludedDownloadedCount: skippedDownloads, - errorCount: state.scanErrorCount, + await _finishScan( + sourceId: activeSourceId, + skippedDownloads: skippedDownloads, + pruneCoverCache: false, + summary: () => + 'Incremental scan complete: ${state.totalCount} total tracks ' + '($scannedCount new/updated, $skippedCount unchanged, ' + '$deletedCount removed, $skippedDownloads already in downloads, ' + '${state.scanErrorCount} errors)', ); } } catch (e, stack) { @@ -1320,6 +1245,61 @@ class LocalLibraryNotifier extends Notifier { } } + /// Shared completion tail of a successful full or incremental scan. + /// [summary] is evaluated after the final state update so it reads the + /// refreshed totals. + Future _finishScan({ + required String sourceId, + required int skippedDownloads, + required bool pruneCoverCache, + required String Function() summary, + }) async { + final now = DateTime.now(); + _sourceVersion++; + await _db.updateSourceState( + sourceId, + available: true, + lastSeenAt: now, + lastScannedAt: now, + clearLastScanError: true, + ); + try { + final prefs = await SharedPreferences.getInstance(); + await writeLocalLibraryLastScannedAt(prefs, now); + await prefs.setInt(_excludedDownloadedCountKey, skippedDownloads); + _log.d('Saved lastScannedAt: $now'); + } catch (e) { + _log.w('Failed to save lastScannedAt: $e'); + } + + await _refreshSummaryFromStorage( + lastScannedAt: now, + excludedDownloadedCount: skippedDownloads, + ); + if (!ref.mounted) return; + state = state.copyWith( + isScanning: false, + scanIsFinalizing: false, + scanProgress: 100, + lastScannedAt: now, + scanWasCancelled: false, + excludedDownloadedCount: skippedDownloads, + ); + if (pruneCoverCache) await _pruneLibraryCoverCache(); + + final message = summary(); + if (state.scanErrorCount > 0) { + _log.e(message); + } else { + _log.i(message); + } + await _showScanCompleteNotification( + totalTracks: state.totalCount, + excludedDownloadedCount: skippedDownloads, + errorCount: state.scanErrorCount, + ); + } + void _startProgressPolling() { final useStream = Platform.isAndroid || Platform.isIOS; _progressPoller.start(useStream: useStream);