From 6879df4917bde04d70a328e35fc9bcadb55c7e2d Mon Sep 17 00:00:00 2001 From: zarzet <42882290+zarzet@users.noreply.github.com> Date: Sun, 18 Oct 2026 22:05:33 +0700 Subject: [PATCH] refactor(services): clarify misleading names and drop a no-op rethrow Remove the try/catch that only rethrew in the library scan helper, rename the history loader that schedules a microtask, and fix two comments. --- lib/providers/download_history_provider.dart | 4 +- lib/services/history_database.dart | 5 +- lib/services/platform_bridge.dart | 118 +++++++++---------- 3 files changed, 63 insertions(+), 64 deletions(-) diff --git a/lib/providers/download_history_provider.dart b/lib/providers/download_history_provider.dart index 6528a755..9e25dfbb 100644 --- a/lib/providers/download_history_provider.dart +++ b/lib/providers/download_history_provider.dart @@ -118,11 +118,11 @@ class DownloadHistoryNotifier extends Notifier { @override DownloadHistoryState build() { ref.onDispose(() => _indexBumpTimer?.cancel()); - _loadFromDatabaseSync(); + _scheduleLoadFromDatabase(); return DownloadHistoryState(); } - void _loadFromDatabaseSync() { + void _scheduleLoadFromDatabase() { if (_isLoaded) return; _isLoaded = true; Future.microtask(() async { diff --git a/lib/services/history_database.dart b/lib/services/history_database.dart index 138b5106..99f65ed8 100644 --- a/lib/services/history_database.dart +++ b/lib/services/history_database.dart @@ -52,7 +52,8 @@ class HistoryBatchLookupRequest { const HistoryBatchLookupRequest(this.tracks); /// An immutable request whose hash is computed only once. Use for lists - /// retained across widget builds; the legacy constructor remains available. + /// retained across widget builds; the const constructor recomputes the hash + /// on every use. factory HistoryBatchLookupRequest.snapshot( Iterable tracks, ) = _HistoryBatchLookupSnapshot; @@ -339,6 +340,8 @@ class HistoryDatabase { return (value ?? '').trim().toLowerCase(); } + /// Returns '' for an empty track name, unlike [LibraryDatabase.matchKeyFor], + /// which returns '|artist' in that case. static String matchKeyFor(String? trackName, String? artistName) { final track = normalizeLookupText(trackName); if (track.isEmpty) return ''; diff --git a/lib/services/platform_bridge.dart b/lib/services/platform_bridge.dart index e533c93a..3ec423a3 100644 --- a/lib/services/platform_bridge.dart +++ b/lib/services/platform_bridge.dart @@ -2479,68 +2479,64 @@ class PlatformBridge { '${scanDir.path}${Platform.pathSeparator}' 'library_scan_${hash.toRadixString(16).padLeft(8, '0')}.ndjson', ); - try { - if (isCancelled?.call() == true) { - throw StateError('Library scan cancelled before native scan'); - } - if (forceFullScan) { - // An explicit rescan must not resume metadata from an earlier attempt. - for (final file in [output, File('${output.path}.state')]) { - if (await file.exists()) await file.delete(); - } - // Preserve covers referenced by the current DB until ingestion succeeds. - // Fresh paths bypass native disk and Flutter image caches together. - final covers = Directory('${scanDir.path}/library_covers'); - await covers.create(recursive: true); - final freshCovers = await covers.createTemp('full_scan_'); - await setLibraryCoverCacheDir(freshCovers.path); - } - if (isCancelled?.call() == true) { - throw StateError('Library scan cancelled before native scan'); - } - final result = await _channel.invokeMethod(method, { - ...arguments, - 'output_path': output.path, - }); - if (result is! Map) { - throw FormatException('$method returned ${result.runtimeType}'); - } - if (result['cancelled'] == true) { - throw FormatException('$method returned a cancelled partial scan'); - } - final errors = result['error_count']; - if (errors is! num || - !errors.isFinite || - errors < 0 || - errors != errors.toInt()) { - throw FormatException('$method returned an invalid error count'); - } - final pathValue = result['path']; - final countValue = result['count']; - if (pathValue is! String || pathValue.trim().isEmpty) { - throw FormatException('$method returned an invalid output path'); - } - if (countValue is! num || - !countValue.isFinite || - countValue < 0 || - countValue != countValue.toInt()) { - throw FormatException('$method returned an invalid row count'); - } - final path = pathValue; - final count = countValue.toInt(); - final file = File(path); - if (!await file.exists()) { - throw FormatException('$method did not create its output file'); - } - return LibraryScanNDJSONFile( - file: file, - expectedCount: count, - errorCount: errors.toInt(), - ); - } catch (_) { - // Keep partial output; native SAF scan resumes from its sidecar. - rethrow; + // Partial output is kept on failure; native SAF scan resumes from its sidecar. + if (isCancelled?.call() == true) { + throw StateError('Library scan cancelled before native scan'); } + if (forceFullScan) { + // An explicit rescan must not resume metadata from an earlier attempt. + for (final file in [output, File('${output.path}.state')]) { + if (await file.exists()) await file.delete(); + } + // Preserve covers referenced by the current DB until ingestion succeeds. + // Fresh paths bypass native disk and Flutter image caches together. + final covers = Directory('${scanDir.path}/library_covers'); + await covers.create(recursive: true); + final freshCovers = await covers.createTemp('full_scan_'); + await setLibraryCoverCacheDir(freshCovers.path); + } + if (isCancelled?.call() == true) { + throw StateError('Library scan cancelled before native scan'); + } + final result = await _channel.invokeMethod(method, { + ...arguments, + 'output_path': output.path, + }); + if (result is! Map) { + throw FormatException('$method returned ${result.runtimeType}'); + } + if (result['cancelled'] == true) { + throw FormatException('$method returned a cancelled partial scan'); + } + final errors = result['error_count']; + if (errors is! num || + !errors.isFinite || + errors < 0 || + errors != errors.toInt()) { + throw FormatException('$method returned an invalid error count'); + } + final pathValue = result['path']; + final countValue = result['count']; + if (pathValue is! String || pathValue.trim().isEmpty) { + throw FormatException('$method returned an invalid output path'); + } + if (countValue is! num || + !countValue.isFinite || + countValue < 0 || + countValue != countValue.toInt()) { + throw FormatException('$method returned an invalid row count'); + } + final path = pathValue; + final count = countValue.toInt(); + final file = File(path); + if (!await file.exists()) { + throw FormatException('$method did not create its output file'); + } + return LibraryScanNDJSONFile( + file: file, + expectedCount: count, + errorCount: errors.toInt(), + ); } static Future> scanSafTreeIncremental(