Merge-Entscheidungen als reine Funktionen (sync_merge.dart)
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
/// Die reinen Entscheidungsfunktionen des Abgleichs — ohne Netz, ohne
|
||||
/// Datenbank, ohne Plattform-Kanäle.
|
||||
///
|
||||
/// Sie liegen bewusst außerhalb von `SyncService`: was hier steht, lässt sich
|
||||
/// mit einer Handvoll Mengen prüfen statt mit einem halben Server.
|
||||
library;
|
||||
|
||||
/// Wie viele Favoriten je Lauf höchstens gepusht werden.
|
||||
///
|
||||
/// Der Rest kommt im nächsten Lauf dran. Die Pushes sind idempotent, ein
|
||||
/// Teilausfall heilt sich dadurch von selbst.
|
||||
const int maxFavoritenPushes = 200;
|
||||
|
||||
/// Die cloudIds, die zum Server gepusht werden müssen: `lokal \ server`.
|
||||
///
|
||||
/// [lokaleFavoriten] sind lokale Song-IDs, [cloudIdVon] bildet sie auf ihre
|
||||
/// cloudId ab. Titel ohne cloudId kennt der Server nicht — sie tauchen in
|
||||
/// keiner Richtung im Abgleich auf.
|
||||
List<String> zuPushendeFavoriten({
|
||||
required Set<String> lokaleFavoriten,
|
||||
required Map<String, String> cloudIdVon,
|
||||
required Set<String> amServer,
|
||||
int deckel = maxFavoritenPushes,
|
||||
}) {
|
||||
final offen = <String>[];
|
||||
for (final songId in lokaleFavoriten) {
|
||||
final cloudId = cloudIdVon[songId];
|
||||
if (cloudId == null) continue;
|
||||
if (amServer.contains(cloudId)) continue;
|
||||
offen.add(cloudId);
|
||||
if (offen.length >= deckel) break;
|
||||
}
|
||||
return offen;
|
||||
}
|
||||
|
||||
/// Die lokalen Song-IDs, die aus dem Server-Stand als Favorit dazukommen:
|
||||
/// `server \ lokal`.
|
||||
///
|
||||
/// Eine cloudId ohne lokalen Titel (Download fehlgeschlagen, noch nicht
|
||||
/// geladen) wird **übersprungen, nicht gelöscht**: ein Favorit ohne Song wäre
|
||||
/// über den Join unsichtbar, würde aber weiter mitgeschleppt.
|
||||
List<String> lokalZuSetzendeFavoriten({
|
||||
required Set<String> amServer,
|
||||
required Map<String, String> songIdVonCloudId,
|
||||
required Set<String> lokaleFavoriten,
|
||||
}) {
|
||||
final offen = <String>[];
|
||||
for (final cloudId in amServer) {
|
||||
final songId = songIdVonCloudId[cloudId];
|
||||
if (songId == null) continue;
|
||||
if (lokaleFavoriten.contains(songId)) continue;
|
||||
offen.add(songId);
|
||||
}
|
||||
return offen;
|
||||
}
|
||||
|
||||
/// Ob der „Was ist neu"-Bericht fällig ist.
|
||||
///
|
||||
/// `null` heißt Neuinstallation, Abmeldung oder gelöschte App-Daten — dann ist
|
||||
/// er **nicht** fällig, sonst begrüßt ein frisch eingerichtetes Gerät den
|
||||
/// Nutzer mit „Willkommen zurück! 325 neue Songs". `sollAutoSync` entscheidet
|
||||
/// bei `null` bewusst umgekehrt und ist hier **kein** Vorbild.
|
||||
bool berichtFaellig(DateTime? letzterErfolg, DateTime jetzt) =>
|
||||
letzterErfolg != null &&
|
||||
jetzt.difference(letzterErfolg) >= const Duration(hours: 24);
|
||||
Reference in New Issue
Block a user