v2.55.2 — Manueller Sync: Status-Popup, Hintergrund-Weiterlauf, Sperrbildschirm-Notification
- cloud_screen.dart: Sync-Popup mit Live-Fortschritt („12/325 synchronisiert"), „Im Hintergrund fortsetzen"-Button, Ergebnis-Snackbar nach Abschluss - sync_service.dart: Notification-Kanal auf HIGH + Visibility.public, Foreground-Service starten/stoppen während Sync (Display-aus-Garantie), statische syncNotificationDetails() für Tests - main.dart: Sync-Channel-Importance auf HIGH (überschreibt alte low-Einstellung) - Tests: +7 (syncNotificationDetails HIGH/public, Lifecycle-Unabhängigkeit)
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:melo_app/services/sync_service.dart';
|
||||
import 'package:melo_app/services/realtime_sync_service.dart';
|
||||
|
||||
/// SyncService-Tests (Sprint E, MED-3-Review-Fix).
|
||||
/// SyncService-Tests (Sprint E, MED-3-Review-Fix, v2.55.2).
|
||||
///
|
||||
/// Abgedeckt:
|
||||
/// - `tombstoneAnwenden`-Matrix (null-letzterSync / null-deletedAt /
|
||||
@@ -9,8 +11,10 @@ import 'package:melo_app/services/sync_service.dart';
|
||||
/// - `SyncBericht` (hatAenderungen, zusammenfassung, details)
|
||||
/// - `songAusServerMap` (MED-2: Server-Listeneintrag → lokaler Song-DB-
|
||||
/// Eintrag mit cloud_id + Titeldaten)
|
||||
///
|
||||
/// Reine, statische Funktionen — kein DB-/Plattform-Zugriff nötig.
|
||||
/// - v2.55.2: `syncNotificationDetails` (Importance.high,
|
||||
/// Priority.high, Visibility.public für Sperrbildschirm)
|
||||
/// - v2.55.2: Sync-Service von Lifecycle unabhängig
|
||||
/// (RealtimeSyncService.pausiere() ≠ SyncService stoppen)
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
@@ -174,4 +178,78 @@ void main() {
|
||||
expect(song.groesseBytes, 1024);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── v2.55.2: Notification-Konfiguration ───
|
||||
|
||||
group('syncNotificationDetails (v2.55.2: HIGH + public)', () {
|
||||
test('ongoing=true → Importance.high, Priority.high, showProgress', () {
|
||||
final details =
|
||||
SyncService.syncNotificationDetails(ongoing: true, progress: 5, maxProgress: 25);
|
||||
|
||||
expect(details.importance, Importance.high);
|
||||
expect(details.priority, Priority.high);
|
||||
expect(details.visibility, NotificationVisibility.public);
|
||||
expect(details.showProgress, isTrue);
|
||||
expect(details.ongoing, isTrue);
|
||||
expect(details.autoCancel, isFalse);
|
||||
expect(details.progress, 5);
|
||||
expect(details.maxProgress, 25);
|
||||
expect(details.onlyAlertOnce, isTrue);
|
||||
});
|
||||
|
||||
test('ongoing=false → autoCancel, kein Progress', () {
|
||||
final details = SyncService.syncNotificationDetails(ongoing: false);
|
||||
|
||||
expect(details.importance, Importance.high);
|
||||
expect(details.priority, Priority.high);
|
||||
expect(details.visibility, NotificationVisibility.public);
|
||||
expect(details.showProgress, isFalse);
|
||||
expect(details.ongoing, isFalse);
|
||||
expect(details.autoCancel, isTrue);
|
||||
expect(details.progress, 0);
|
||||
expect(details.maxProgress, 0);
|
||||
});
|
||||
|
||||
test('maxProgress=0 bei ongoing=true → default 1 (Division durch 0)', () {
|
||||
final details =
|
||||
SyncService.syncNotificationDetails(ongoing: true, progress: 0, maxProgress: 0);
|
||||
|
||||
// maxProgress muss > 0 sein, sonst crasht die Notification-API
|
||||
expect(details.maxProgress, 1);
|
||||
});
|
||||
|
||||
test('channelId ist de.baka.melo.sync', () {
|
||||
final details = SyncService.syncNotificationDetails(ongoing: false);
|
||||
expect(details.channelId, 'de.baka.melo.sync');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── v2.55.2: Lifecycle-Unabhängigkeit ───
|
||||
|
||||
group('SyncService unabhängig von RealtimeSyncService-Lifecycle', () {
|
||||
test('laeuftGlobal wird NICHT durch pausiere() zurückgesetzt', () {
|
||||
// SyncService.laeuftGlobal startet als false.
|
||||
// Der Lifecycle (RealtimeSyncService.pausiere) darf diesen Zustand
|
||||
// NICHT beeinflussen — es sind getrennte Systeme.
|
||||
expect(SyncService.laeuftGlobal, isFalse);
|
||||
|
||||
// Lifecycle: App geht in den Hintergrund
|
||||
RealtimeSyncService().pausiere();
|
||||
|
||||
// SyncService muss unabhängig bleiben
|
||||
expect(SyncService.laeuftGlobal, isFalse);
|
||||
});
|
||||
|
||||
test('laeuftNotifier wird NICHT durch pausiere() verändert', () {
|
||||
final vorher = SyncService.laeuftNotifier.value;
|
||||
RealtimeSyncService().pausiere();
|
||||
expect(SyncService.laeuftNotifier.value, vorher);
|
||||
});
|
||||
|
||||
test('syncBenachrichtigungGetippt wird NICHT durch pausiere() verändert', () {
|
||||
final vorher = SyncService.syncBenachrichtigungGetippt.value;
|
||||
RealtimeSyncService().pausiere();
|
||||
expect(SyncService.syncBenachrichtigungGetippt.value, vorher);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user