From 2e170ca2985b638fe46e69c019b98cddf782b29b Mon Sep 17 00:00:00 2001 From: zarzet <42882290+zarzet@users.noreply.github.com> Date: Sun, 11 Oct 2026 15:38:20 +0700 Subject: [PATCH] fix(notifications): show indeterminate scans without false zero percent --- lib/l10n/arb/app_ar.arb | 5 +- lib/l10n/arb/app_de.arb | 5 +- lib/l10n/arb/app_en.arb | 5 +- lib/l10n/arb/app_es.arb | 5 +- lib/l10n/arb/app_es_ES.arb | 5 +- lib/l10n/arb/app_fr.arb | 5 +- lib/l10n/arb/app_hi.arb | 5 +- lib/l10n/arb/app_id.arb | 5 +- lib/l10n/arb/app_it.arb | 5 +- lib/l10n/arb/app_ja.arb | 5 +- lib/l10n/arb/app_ko.arb | 5 +- lib/l10n/arb/app_nl.arb | 5 +- lib/l10n/arb/app_pt.arb | 5 +- lib/l10n/arb/app_pt_PT.arb | 5 +- lib/l10n/arb/app_ru.arb | 5 +- lib/l10n/arb/app_tr.arb | 5 +- lib/l10n/arb/app_uk.arb | 5 +- lib/l10n/arb/app_zh.arb | 5 +- lib/l10n/arb/app_zh_CN.arb | 5 +- lib/l10n/arb/app_zh_TW.arb | 5 +- lib/services/notification_service.dart | 19 ++++-- test/notification_service_test.dart | 90 +++++++++++++++++++++++++- 22 files changed, 121 insertions(+), 88 deletions(-) diff --git a/lib/l10n/arb/app_ar.arb b/lib/l10n/arb/app_ar.arb index 545cbbe1..b7a2dc2b 100644 --- a/lib/l10n/arb/app_ar.arb +++ b/lib/l10n/arb/app_ar.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index a017e6cd..d6a1581f 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} gescannte Dateien • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} gescannte Dateien", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index bab25f67..f8a01b24 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -5400,15 +5400,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_es.arb b/lib/l10n/arb/app_es.arb index 745597ab..7247a48c 100644 --- a/lib/l10n/arb/app_es.arb +++ b/lib/l10n/arb/app_es.arb @@ -4096,15 +4096,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_es_ES.arb b/lib/l10n/arb/app_es_ES.arb index 3049e319..8906efc6 100644 --- a/lib/l10n/arb/app_es_ES.arb +++ b/lib/l10n/arb/app_es_ES.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} archivos escaneados • {percentage} %", + "notifLibraryScanProgressNoTotal": "{scanned} archivos escaneados", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb index b493dfce..b130167f 100644 --- a/lib/l10n/arb/app_fr.arb +++ b/lib/l10n/arb/app_fr.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} fichiers analysés • {percentage} %", + "notifLibraryScanProgressNoTotal": "{scanned} fichiers analysés", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_hi.arb b/lib/l10n/arb/app_hi.arb index 7888bbe1..70e299fd 100644 --- a/lib/l10n/arb/app_hi.arb +++ b/lib/l10n/arb/app_hi.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_id.arb b/lib/l10n/arb/app_id.arb index f611399f..982bca69 100644 --- a/lib/l10n/arb/app_id.arb +++ b/lib/l10n/arb/app_id.arb @@ -5484,15 +5484,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} file terpindai • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} file terpindai", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_it.arb b/lib/l10n/arb/app_it.arb index af065e32..4b006414 100644 --- a/lib/l10n/arb/app_it.arb +++ b/lib/l10n/arb/app_it.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_ja.arb b/lib/l10n/arb/app_ja.arb index 9e2080d9..4646374f 100644 --- a/lib/l10n/arb/app_ja.arb +++ b/lib/l10n/arb/app_ja.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_ko.arb b/lib/l10n/arb/app_ko.arb index 739d9570..426a7706 100644 --- a/lib/l10n/arb/app_ko.arb +++ b/lib/l10n/arb/app_ko.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} 게의 파일이 스캔됨 • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} 게의 파일이 스캔됨", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_nl.arb b/lib/l10n/arb/app_nl.arb index 73227d0d..a99cb48a 100644 --- a/lib/l10n/arb/app_nl.arb +++ b/lib/l10n/arb/app_nl.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_pt.arb b/lib/l10n/arb/app_pt.arb index 54393ebe..0e2a4ef1 100644 --- a/lib/l10n/arb/app_pt.arb +++ b/lib/l10n/arb/app_pt.arb @@ -4096,15 +4096,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_pt_PT.arb b/lib/l10n/arb/app_pt_PT.arb index 16186c65..fc94f0ff 100644 --- a/lib/l10n/arb/app_pt_PT.arb +++ b/lib/l10n/arb/app_pt_PT.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_ru.arb b/lib/l10n/arb/app_ru.arb index c34eb9b8..ae71bb82 100644 --- a/lib/l10n/arb/app_ru.arb +++ b/lib/l10n/arb/app_ru.arb @@ -5354,15 +5354,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} файлов отсканировано • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} файлов отсканировано", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_tr.arb b/lib/l10n/arb/app_tr.arb index af594290..c4a88256 100644 --- a/lib/l10n/arb/app_tr.arb +++ b/lib/l10n/arb/app_tr.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_uk.arb b/lib/l10n/arb/app_uk.arb index fa39289a..418191a1 100644 --- a/lib/l10n/arb/app_uk.arb +++ b/lib/l10n/arb/app_uk.arb @@ -5342,15 +5342,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} Файлів скановано • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} Файлів скановано", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_zh.arb b/lib/l10n/arb/app_zh.arb index a732d66a..2b3e18e5 100644 --- a/lib/l10n/arb/app_zh.arb +++ b/lib/l10n/arb/app_zh.arb @@ -4946,15 +4946,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_zh_CN.arb b/lib/l10n/arb/app_zh_CN.arb index a3ed9e32..31e490c2 100644 --- a/lib/l10n/arb/app_zh_CN.arb +++ b/lib/l10n/arb/app_zh_CN.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/l10n/arb/app_zh_TW.arb b/lib/l10n/arb/app_zh_TW.arb index 93697026..a95c8fbc 100644 --- a/lib/l10n/arb/app_zh_TW.arb +++ b/lib/l10n/arb/app_zh_TW.arb @@ -5355,15 +5355,12 @@ } } }, - "notifLibraryScanProgressNoTotal": "{scanned} files scanned • {percentage}%", + "notifLibraryScanProgressNoTotal": "{scanned} files scanned", "@notifLibraryScanProgressNoTotal": { "description": "Notification body for library scan progress when total is unknown", "placeholders": { "scanned": { "type": "int" - }, - "percentage": { - "type": "int" } } }, diff --git a/lib/services/notification_service.dart b/lib/services/notification_service.dart index b13bb6ba..aa1f2498 100644 --- a/lib/services/notification_service.dart +++ b/lib/services/notification_service.dart @@ -240,7 +240,8 @@ class NotificationService { } /// Builds [NotificationDetails]. A non-null [progress] switches to the - /// low-importance ongoing progress style; otherwise a dismissible alert. + /// low-importance ongoing progress style; a negative value is indeterminate. + /// Otherwise builds a dismissible alert. NotificationDetails _details({ bool library = false, int? progress, @@ -276,7 +277,8 @@ class NotificationService { priority: inProgress ? Priority.low : Priority.defaultPriority, showProgress: inProgress, maxProgress: inProgress ? 100 : 0, - progress: progress ?? 0, + progress: progress?.clamp(0, 100) ?? 0, + indeterminate: (progress ?? 0) < 0, ongoing: inProgress, autoCancel: !inProgress, playSound: playSound, @@ -455,17 +457,20 @@ class NotificationService { }) async { if (!_isInitialized) await initialize(); - final clampedProgress = progress.clamp(0.0, 100.0); - final percentage = clampedProgress.round(); - final progressBody = totalFiles > 0 + // Network scans read tags while discovering folders, so their total is + // unknown. Zero percent would falsely imply that no files were processed. + // Use the same indeterminate value for the foreground service and plugin. + final hasTotal = totalFiles > 0; + final percentage = hasTotal ? progress.clamp(0.0, 100.0).round() : -1; + final progressBody = hasTotal ? (_l10n?.notifLibraryScanProgressWithTotal( scannedFiles, totalFiles, percentage, ) ?? '$scannedFiles/$totalFiles files • $percentage%') - : (_l10n?.notifLibraryScanProgressNoTotal(scannedFiles, percentage) ?? - '$scannedFiles files scanned • $percentage%'); + : (_l10n?.notifLibraryScanProgressNoTotal(scannedFiles) ?? + '$scannedFiles files scanned'); final body = (currentFile != null && currentFile.isNotEmpty) ? '$progressBody\n$currentFile' : progressBody; diff --git a/test/notification_service_test.dart b/test/notification_service_test.dart index 8a2ab745..6999f263 100644 --- a/test/notification_service_test.dart +++ b/test/notification_service_test.dart @@ -1,7 +1,9 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:spotiflac_android/l10n/app_localizations.dart'; import 'package:spotiflac_android/services/notification_service.dart'; import 'package:spotiflac_android/services/verification_notification.dart'; @@ -17,8 +19,11 @@ void main() { tapId: 'dart:cold-tap', ); - setUp(() { + setUp(() async { debugDefaultTargetPlatformOverride = TargetPlatform.android; + NotificationService().updateStrings( + await AppLocalizations.delegate.load(const Locale('en')), + ); TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (call) async { methodCalls.add(call); @@ -117,4 +122,87 @@ void main() { ), ); }); + + test( + 'scan with unknown total shows count and indeterminate progress', + () async { + final service = NotificationService(); + for (final count in [0, 1566]) { + await service.showLibraryScanProgress( + progress: 0, + scannedFiles: count, + totalFiles: 0, + currentFile: 'track.flac', + ); + + final arguments = + methodCalls.lastWhere((call) => call.method == 'show').arguments + as Map; + final details = arguments['platformSpecifics'] as Map; + + expect(arguments['id'], NotificationService.libraryScanId); + expect(arguments['body'], '$count files scanned\ntrack.flac'); + expect(details['showProgress'], isTrue); + expect(details['indeterminate'], isTrue); + expect(details['progress'], 0); + expect(details['ongoing'], isTrue); + expect(details['autoCancel'], isFalse); + expect(details['playSound'], isFalse); + } + }, + ); + + test('scan switches to percentage when total becomes known', () async { + final service = NotificationService(); + await service.showLibraryScanProgress( + progress: 0, + scannedFiles: 1566, + totalFiles: 0, + ); + await service.showLibraryScanProgress( + progress: 78.3, + scannedFiles: 1566, + totalFiles: 2000, + currentFile: 'track.flac', + ); + + final progressArguments = + methodCalls.lastWhere((call) => call.method == 'show').arguments + as Map; + final progressDetails = + progressArguments['platformSpecifics'] as Map; + expect(progressArguments['body'], '1566/2000 files • 78%\ntrack.flac'); + expect(progressDetails['showProgress'], isTrue); + expect(progressDetails['indeterminate'], isFalse); + expect(progressDetails['progress'], 78); + + await service.showLibraryScanComplete(totalTracks: 2000); + final completeArguments = + methodCalls.lastWhere((call) => call.method == 'show').arguments + as Map; + final completeDetails = + completeArguments['platformSpecifics'] as Map; + expect(completeArguments['body'], '2000 tracks indexed'); + expect(completeDetails['showProgress'], isFalse); + expect(completeDetails['ongoing'], isFalse); + expect(completeDetails['autoCancel'], isTrue); + }); + + test('unknown-total scan never displays percentage in any locale', () async { + final service = NotificationService(); + for (final locale in AppLocalizations.supportedLocales) { + service.updateStrings(await AppLocalizations.delegate.load(locale)); + await service.showLibraryScanProgress( + progress: 0, + scannedFiles: 1566, + totalFiles: 0, + ); + final arguments = + methodCalls.lastWhere((call) => call.method == 'show').arguments + as Map; + final body = arguments['body'] as String; + expect(body, contains('1566'), reason: '$locale'); + expect(body, isNot(contains('%')), reason: '$locale'); + } + }); }