import Foundation import Observation /// Holt eine Liste, legt sie in den Zwischenspeicher und weiss, was bei einem /// Fehlschlag noch da ist. /// /// Jede Listenansicht braucht dasselbe: laden, Fehler zeigen, zum Aktualisieren /// herunterziehen, offline den letzten Stand behalten. Einmal hier, statt in /// jeder Ansicht neu. @MainActor @Observable final class Lader { private(set) var zustand: Ladezustand = .laedt private let schluessel: String private let holen: () async throws -> A /// - Parameter schluessel: Name im Zwischenspeicher. Der Endpunktpfad ist /// eine gute Wahl – er ist eindeutig und beim Suchen lesbar. init(schluessel: String, holen: @escaping () async throws -> A) { self.schluessel = schluessel self.holen = holen } /// Lädt. Beim ersten Mal wird ein vorhandener Stand sofort angezeigt, /// damit die Liste nicht leer aufblitzt, während der Abruf läuft. func lade(zeigeGemerktesSofort: Bool = true) async { if zeigeGemerktesSofort, zustand.inhalt == nil, let gemerkt = Zwischenspeicher.hole(A.self, unter: schluessel) { zustand = .ausSpeicher(gemerkt.wert, geholtAm: gemerkt.geholtAm, fehler: .keineVerbindung("")) } else if zustand.inhalt == nil { zustand = .laedt } do { let frisch = try await holen() Zwischenspeicher.lege(frisch, unter: schluessel) zustand = .da(frisch) } catch let fehler as APIFehler { if let gemerkt = Zwischenspeicher.hole(A.self, unter: schluessel) { zustand = .ausSpeicher(gemerkt.wert, geholtAm: gemerkt.geholtAm, fehler: fehler) } else { zustand = .fehler(fehler) } } catch { zustand = .fehler(.keineVerbindung(error.localizedDescription)) } } /// Fürs Herunterziehen: kein Zwischenzustand, die alte Liste bleibt /// stehen, bis die neue da ist. func aktualisiere() async { await lade(zeigeGemerktesSofort: false) } }