import Foundation /// Datei-Format für die WidgetKit-Extension. Wird vom Haupt-Target nach /// jedem erfolgreichen `DeckListStore.refresh()` in den shared App-Group- /// Container geschrieben; das Widget liest es im TimelineProvider. /// /// Wire ist bewusst stabil + schmal — nur was das Widget rendert. /// Neue Felder dürfen additiv dazukommen, alte Felder bleiben. struct WidgetSnapshot: Codable { let updatedAt: Date let totalDueCount: Int let topDecks: [Entry] struct Entry: Codable, Identifiable { let id: String // deck-id let name: String let dueCount: Int let colorHex: String? } } /// Liest und schreibt WidgetSnapshot in den shared App-Group-Container. enum WidgetSnapshotStore { /// App-Group-ID — muss exakt mit dem Entitlement-Eintrag matchen. static let appGroupID = "group.ev.mana.cardecky" static let snapshotFilename = "widget-snapshot.json" static var snapshotURL: URL? { FileManager.default .containerURL(forSecurityApplicationGroupIdentifier: appGroupID)? .appendingPathComponent(snapshotFilename) } static func write(_ snapshot: WidgetSnapshot) { guard let url = snapshotURL else { return } let encoder = JSONEncoder() encoder.dateEncodingStrategy = .iso8601 guard let data = try? encoder.encode(snapshot) else { return } try? data.write(to: url, options: .atomic) } static func read() -> WidgetSnapshot? { guard let url = snapshotURL, let data = try? Data(contentsOf: url) else { return nil } let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 return try? decoder.decode(WidgetSnapshot.self, from: data) } }