Skip to content

Gemerkte Reisen geraten zwischen lokaler Merkliste und DB-Konto auseinander; Swipe kann „halb löschen“ und Duplikate erzeugen #15

Description

@grosserknallkopf

Beschreibung

Bei einer einzelnen gemerkten Reise ist bei mir ein inkonsistenter Zustand entstanden:

  • Die Reise ist weiterhin im Tab „Reisen“ sichtbar.
  • Beim Öffnen der Reise zeigt das Lesezeichen oben rechts aber an, dass sie nicht gemerkt sei.
  • Dadurch kann ich sie nicht normal „entmerken“.
  • Wenn ich sie erneut merke und danach wieder entmerke, verschwindet der ursprüngliche Eintrag nicht.
  • Inzwischen wird die Reise sogar mehrfach im Reisen-Tab angezeigt.

Möglicherweise hängt das mit folgendem vorherigen Ereignis zusammen:

Ich habe einmal versehentlich eine Reise im Reisen-Tab per Swipe gelöscht. In der Schnelle konnte ich nicht erkennen, welche Reise das war. Als ich danach nach einer fehlenden Reise gesucht habe, schien keine zu fehlen.

Daher mein Verdacht: Durch den Swipe wurde eine Reise möglicherweise nur lokal gelöscht, blieb aber DB-seitig weiterhin als „Gemerkte Reise“ bestehen.

Das Problem tritt bei mir derzeit nur bei einer Reise auf, was zu diesem Ablauf passen würde.

Beobachtetes Verhalten

Sinngemäß:

  1. Reise wird im Reisen-Tab angezeigt.
  2. Reise öffnen.
  3. Lesezeichen oben rechts ist leer.
  4. Erneut auf Lesezeichen tippen.
  5. Reise wird erneut gemerkt.
  6. Wieder entmerken.
  7. Ursprünglicher Eintrag bleibt bestehen.
  8. Nach mehreren Versuchen existiert die Reise mehrfach im Reisen-Tab.

Erwartetes Verhalten

Eine im Reisen-Tab als „gemerkt“ angezeigte Reise sollte:

  • beim Öffnen auch ein aktives Lesezeichen zeigen
  • sich über das Lesezeichen zuverlässig entmerken lassen
  • beim Swipe vollständig entfernt werden
  • nicht mehrfach angelegt werden können

Lokaler Zustand und DB-seitige „Meine Reisen“ sollten konsistent bleiben.

Mögliche Ursache im aktuellen Code

Soweit ich den Code richtig verstehe, zeigt der Reisen-Tab zeigt bei eingeloggtem DB-Konto zwei unabhängige Quellen gleichzeitig:

  1. DB-seitige „Gemerkte Reisen“ aus savedReisenProvider
  2. lokal gespeicherte Reisen aus libraryProvider

Das sieht man direkt im Reisen-Screen: erst werden die serverseitigen „Gemerkten Reisen“ gerendert, danach separat die lokalen „Anstehenden Reisen“.

Der Swipe löscht aber nur lokal

Beim Wegwischen einer lokalen Reise passiert ausschließlich:

onDismissed: (_) {
  ref.read(libraryProvider.notifier).removeJourney(saved.key);
}

Und removeJourney() entfernt nur aus state.journeys und speichert die lokale Liste neu:

void removeJourney(String key) {
  state = state.copyWith(
      journeys: state.journeys.where((j) => j.key != key).toList());
  _saveJourneys();
}

Es gibt dort keinerlei Löschung der DB-seitigen gemerkten Reise.

Das heißt: Ein Lösch-Swipe kann tatsächlich exakt Folgendes erzeugt haben:

lokal gelöscht
aber auf dem DB-Konto weiterhin gemerkt

Also "halb gelöscht".

Warum das Lesezeichen danach leer ist

Ob das Lesezeichen oben rechts gefüllt erscheint, wird ausschließlich anhand der lokalen Library geprüft:

final key =
    SavedJourney(journey: journey, savedAtMs: 0).key;
final saved = ref.watch(libraryProvider).hasJourney(key);

hasJourney() schaut wiederum nur in:

journeys.any((j) => j.key == key)

Die App fragt an dieser Stelle nicht, ob dieselbe Reise noch DB-seitig als „gemerkt“ existiert.

Damit ergibt das Verhalten vollkommen Sinn:

  1. Reise ursprünglich gemerkt
  2. lokal und DB-seitig vorhanden
  3. Swipe im Reisen-Tab
  4. lokale Reise gelöscht
  5. DB-Reise bleibt bestehen
  6. sie erscheint weiterhin unter „Gemerkte Reisen“
  7. beim Öffnen ist das Lesezeichen leer, weil lokal nichts mehr existiert

Und warum Duplikate kommen

Das ist der nächste kritische Teil.

Wenn man bei leerem Lesezeichen erneut auf „merken“ tippt:

toggleJourney(journey);

wird wieder ein lokaler Eintrag angelegt.

Wenn man eingeloggt bist, wird anschließend zusätzlich _syncDbReise(..., saved: true) aufgerufen. Diese Funktion legt über saveReise() eine neue DB-seitige gemerkte Reise an:

final rkUuid = await service.saveReise(...);
if (rkUuid != null) ids.put(key, rkUuid);

Wenn die alte DB-Reise noch existiert, entsteht also:

alte serverseitige Reise

  • neu angelegte serverseitige Reise

Genau dadurch können doppelte Einträge im Reisen-Tab entstehen.

Noch ein zusätzliches Problem

Die Zuordnung:

lokaler Journey-Key → DB-rkUuid

wird nur im Arbeitsspeicher der laufenden Sitzung gehalten:

class DbSavedReiseIds extends Notifier<Map<String, String>> {
  Map<String, String> build() => {};
}

Der Kommentar behauptet zwar:

cross-session removal reconciles via the trip overview

aber im von mir geprüften Code sehe ich für diese Zuordnung keine tatsächliche persistente Speicherung und auch keine erkennbare Rekonstruktion aus der Übersicht. Die Map startet leer.

Beim Entmerken wird die DB-Reise aber nur gelöscht, wenn für den lokalen Key eine rkUuid in genau dieser Map gefunden wird:

final rkUuid = ids.take(key);
if (rkUuid != null) await service.deleteReise(rkUuid);

Das heißt: Nach App-Neustart oder bei einer serverseitigen Reise, die nicht in dieser Sitzung über genau diesen Bookmark-Flow angelegt wurde, kann das Entmerken lokal funktionieren, ohne die passende DB-Reise zu löschen.

Das ist meines Erachtens ein ziemlich klarer Synchronisationsbug.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions