import Foundation enum NativePage: String, CaseIterable, Identifiable, Sendable { case home, tasks, shopping, notes, more var id: String { rawValue } var title: String { switch self { case .home: "Übersicht" case .tasks: "Aufgaben" case .shopping: "Einkauf" case .notes: "Notizen" case .more: "Mehr" } } var symbol: String { switch self { case .home: "house" case .tasks: "checkmark.square" case .shopping: "cart" case .notes: "note.text" case .more: "ellipsis" } } } struct NativeBootstrap: Decodable, Sendable { let appName: String let setupRequired: Bool let passwordResetEnabled: Bool } struct NativeAuthentication: Decodable, Sendable { let enabled: Bool let passwordLoginEnabled: Bool let guestPasswordLoginEnabled: Bool? } struct NativeUser: Decodable, Sendable { let id: Int let username: String let displayName: String } struct NativePermissions: Decodable, Sendable { let admin: Bool let modules: [String: String] let widgets: [String: String] func access(_ module: String) -> String { admin ? "write" : modules[module] ?? "write" } func showsWidget(_ widget: String) -> Bool { admin || widgets[widget] != "none" } } struct NativeIdentity: Decodable, Sendable { let user: NativeUser? let permissions: NativePermissions? let csrfToken: String? let twoFactorRequired: Bool? } struct NativeEnvelope: Decodable, Sendable { let data: Value } struct NativeEmpty: Decodable, Sendable {} struct NativeTask: Decodable, Identifiable, Sendable { let id: Int let title: String let description: String? let status: String let priority: String let dueDate: String? let category: String? } struct NativeNote: Decodable, Identifiable, Sendable { let id: Int let title: String? let content: String let pinned: Int } struct NativeShoppingList: Decodable, Identifiable, Sendable { let id: Int let name: String let itemTotal: Int? let itemChecked: Int? let openCount: Int? } struct NativeShoppingItem: Decodable, Identifiable, Sendable { let id: Int let name: String let quantity: String? let category: String? let isChecked: Int } struct NativeEventPreview: Decodable, Identifiable, Sendable { let id: Int let title: String let startDatetime: String } struct NativeTaskPreview: Decodable, Identifiable, Sendable { let id: Int let title: String let dueDate: String? } struct NativeDashboard: Decodable, Sendable { let openTaskCount: Int? let shoppingOpenCount: Int? let urgentTasks: [NativeTaskPreview] let upcomingEvents: [NativeEventPreview] let shoppingLists: [NativeShoppingList] let pinnedNotes: [NativeNote] } enum NativeValue: Encodable, Sendable { case string(String) case number(Int) case bool(Bool) case null func encode(to encoder: Encoder) throws { var value = encoder.singleValueContainer() switch self { case .string(let text): try value.encode(text) case .number(let number): try value.encode(number) case .bool(let flag): try value.encode(flag) case .null: try value.encodeNil() } } } enum NativeAPIError: LocalizedError { case response(Int) case invalidResponse, invalidPath, unavailable, closed var errorDescription: String? { switch self { case .response(401): "Anmeldung oder Sitzung ist nicht mehr gültig." case .response(403): "Diese Aktion ist nicht erlaubt. Bitte prüfe deine Berechtigungen." case .response(409): "Der Eintrag wurde inzwischen geändert. Bitte neu laden." case .response(429): "Zu viele Versuche. Bitte warte einen Moment." case .response(let status): "Die Anfrage konnte nicht abgeschlossen werden (HTTP \(status))." case .invalidPath, .invalidResponse: "Der Server hat keine gültige API-Antwort geliefert." case .unavailable: "Verbindung fehlgeschlagen. Bitte Server, Zertifikat und Netzwerk prüfen." case .closed: "Diese Sitzung wurde geschlossen." } } }