v2.53.1 — LOW-1: Willkommen-zurück-Dialog nur bei >24h Offline (24h-Check)

This commit is contained in:
Dustin
2026-08-05 11:26:00 +02:00
parent f14b658566
commit 83bb86a1fa
3 changed files with 50 additions and 0 deletions
+4
View File
@@ -267,6 +267,10 @@ class _CloudScreenState extends State<CloudScreen>
/// „Willkommen zurück! Seit letztem Sync: +8 neue · 3 gelöscht · ⭐5“ /// „Willkommen zurück! Seit letztem Sync: +8 neue · 3 gelöscht · ⭐5“
void _zeigeKonfliktReport(SyncBericht bericht) { void _zeigeKonfliktReport(SyncBericht bericht) {
if (!mounted) return; if (!mounted) return;
// LOW-1: „Willkommen zurück!“ nur zeigen, wenn der letzte Sync mehr als
// 24h zurückliegt (oder noch nie gesynct) — sonst Dialog-Flut bei jedem
// Sync mit Änderungen. Basis ist der letzterSync-Stand VOR diesem Lauf.
if (!bericht.nachLangerPause()) return;
final titel = 'Willkommen zurück!'; final titel = 'Willkommen zurück!';
final zeilen = <String>[ final zeilen = <String>[
'Seit deinem letzten Sync:', 'Seit deinem letzten Sync:',
+20
View File
@@ -35,11 +35,17 @@ class SyncBericht {
/// Menschlich lesbare Änderungszeilen („+ Neuer Song: …“, „− Gelöscht: …“). /// Menschlich lesbare Änderungszeilen („+ Neuer Song: …“, „− Gelöscht: …“).
final List<String> details; final List<String> details;
/// Letzter Sync-ZEITPUNKT VOR diesem Lauf (Snapshot vor listSongs,
/// MED-1) — Basis für den 24h-Check des „Willkommen zurück!“-Dialogs
/// (LOW-1). null = noch nie gesynct (Erst-Sync) → Dialog zeigen.
final DateTime? letzterSyncVorher;
const SyncBericht({ const SyncBericht({
required this.neueSongs, required this.neueSongs,
required this.geloeschteSongs, required this.geloeschteSongs,
required this.favoritenGeaendert, required this.favoritenGeaendert,
this.details = const [], this.details = const [],
this.letzterSyncVorher,
}); });
bool get hatAenderungen => bool get hatAenderungen =>
@@ -54,6 +60,16 @@ class SyncBericht {
]; ];
return teile.join(' · '); return teile.join(' · ');
} }
/// LOW-1: „Willkommen zurück!“-Dialog nur nach längerer Pause zeigen —
/// letzter Sync mehr als 24h zurück (oder noch nie gesynct). [jetzt]
/// injizierbar für Tests.
bool nachLangerPause({DateTime? jetzt}) {
final vorher = letzterSyncVorher;
if (vorher == null) return true;
final j = jetzt ?? DateTime.now();
return j.difference(vorher) > const Duration(hours: 24);
}
} }
/// Zentraler Cloud-Sync (Sprint D, v2.52.2). /// Zentraler Cloud-Sync (Sprint D, v2.52.2).
@@ -487,6 +503,10 @@ class SyncService {
geloeschteSongs: geloeschteSongs, geloeschteSongs: geloeschteSongs,
favoritenGeaendert: favoritenGeaendert, favoritenGeaendert: favoritenGeaendert,
details: [...neueDetails, ...loeschDetails, ...favoritenDetails], details: [...neueDetails, ...loeschDetails, ...favoritenDetails],
// LOW-1: 24h-Check des „Willkommen zurück!“-Dialogs gegen den
// letzterSync-Stand VOR diesem Sync (MED-1-Snapshot) — nicht gegen
// den frisch persistierten, sonst wäre die Pause immer 0.
letzterSyncVorher: letzterSync,
); );
if (bericht.hatAenderungen) { if (bericht.hatAenderungen) {
onBericht?.call(bericht); onBericht?.call(bericht);
+26
View File
@@ -103,6 +103,32 @@ void main() {
expect(bericht.details, hasLength(2)); expect(bericht.details, hasLength(2));
expect(bericht.details.first, '+ Neuer Song: A'); expect(bericht.details.first, '+ Neuer Song: A');
}); });
test('nachLangerPause: letzterSyncVorher null (Erst-Sync) → true', () {
const bericht = SyncBericht(
neueSongs: 1, geloeschteSongs: 0, favoritenGeaendert: 0);
expect(bericht.nachLangerPause(jetzt: DateTime(2026, 8, 5, 12)), isTrue);
});
test('nachLangerPause: < 24h seit letztem Sync → false', () {
final bericht = SyncBericht(
neueSongs: 1,
geloeschteSongs: 0,
favoritenGeaendert: 0,
letzterSyncVorher: DateTime(2026, 8, 5, 11, 0),
);
expect(bericht.nachLangerPause(jetzt: DateTime(2026, 8, 5, 12)), isFalse);
});
test('nachLangerPause: > 24h seit letztem Sync → true', () {
final bericht = SyncBericht(
neueSongs: 1,
geloeschteSongs: 0,
favoritenGeaendert: 0,
letzterSyncVorher: DateTime(2026, 8, 3, 10, 0),
);
expect(bericht.nachLangerPause(jetzt: DateTime(2026, 8, 5, 12)), isTrue);
});
}); });
group('songAusServerMap (MED-2: Server-Listeneintrag → lokaler Song)', () { group('songAusServerMap (MED-2: Server-Listeneintrag → lokaler Song)', () {