import Foundation /// Ein hinterlegter Server. Die App kann beliebig viele davon kennen und /// zwischen ihnen umschalten, ohne sich jedes Mal neu anzumelden. /// /// Das Token liegt **nicht** hier, sondern im Keychain unter einem Konto, das /// aus der `id` gebildet wird (siehe `Session.keychainAccount`). Diese Struktur /// landet als JSON in den UserDefaults und darf deshalb nichts Geheimes /// enthalten. struct ServerProfile: Codable, Identifiable, Equatable { let id: UUID var name: String var urlString: String /// Zuletzt angemeldeter Benutzer - nur fuer die Anzeige und damit das /// Anmeldefeld beim Wechsel schon ausgefuellt ist. var username: String /// Zuletzt bekannte Rolle. Entscheidet, ob der Verwaltungs-Tab erscheint, /// bevor `me()` den Wert frisch bestaetigt hat. var isAdmin: Bool init(id: UUID = UUID(), name: String, urlString: String, username: String = "", isAdmin: Bool = false) { self.id = id self.name = name self.urlString = urlString self.username = username self.isAdmin = isAdmin } var url: URL? { Session.normalize(urlString) } /// Ohne eigenen Namen ist der Rechnername die brauchbarste Bezeichnung: /// aus "http://192.168.1.50:8080/" wird "192.168.1.50". static func suggestedName(for raw: String) -> String { guard let url = Session.normalize(raw), let host = url.host, !host.isEmpty else { return "Server" } return host } } /// Liest und schreibt die Profilliste. Bewusst getrennt von `Session`, damit /// die Ablage fuer sich verstaendlich bleibt. enum ProfileStore { static let profilesKey = "server_profiles" static let activeKey = "active_profile_id" static func load() -> [ServerProfile] { guard let data = UserDefaults.standard.data(forKey: profilesKey), let profiles = try? JSONDecoder().decode([ServerProfile].self, from: data) else { return [] } return profiles } static func save(_ profiles: [ServerProfile]) { guard let data = try? JSONEncoder().encode(profiles) else { return } UserDefaults.standard.set(data, forKey: profilesKey) } static func loadActiveID() -> UUID? { guard let raw = UserDefaults.standard.string(forKey: activeKey) else { return nil } return UUID(uuidString: raw) } static func saveActiveID(_ id: UUID?) { if let id { UserDefaults.standard.set(id.uuidString, forKey: activeKey) } else { UserDefaults.standard.removeObject(forKey: activeKey) } } }