import Foundation import Observation struct WebDAVConfig: Equatable { var url: String var username: String var password: String var notesPath: String var isConfigured: Bool { !url.trimmingCharacters(in: .whitespaces).isEmpty && !username.trimmingCharacters(in: .whitespaces).isEmpty && !password.trimmingCharacters(in: .whitespaces).isEmpty } var authHeader: String { let encoded = Data("\(username):\(password)".utf8).base64EncodedString() return "Basic \(encoded)" } } @Observable final class WebDAVSettings { private static let urlKey = "webdav.url" private static let usernameKey = "webdav.username" private static let pathKey = "webdav.notesPath" private static let passwordKey = "webdav.password" var url: String { didSet { UserDefaults.standard.set(url, forKey: Self.urlKey) } } var username: String { didSet { UserDefaults.standard.set(username, forKey: Self.usernameKey) } } var notesPath: String { didSet { UserDefaults.standard.set(notesPath, forKey: Self.pathKey) } } var password: String { didSet { KeychainStore.set(password.isEmpty ? nil : password, for: Self.passwordKey) } } init() { let d = UserDefaults.standard url = d.string(forKey: Self.urlKey) ?? "" username = d.string(forKey: Self.usernameKey) ?? "" notesPath = d.string(forKey: Self.pathKey) ?? "/notes/" #if DEBUG password = d.string(forKey: "debug.password") ?? KeychainStore.get(Self.passwordKey) ?? "" #else password = KeychainStore.get(Self.passwordKey) ?? "" #endif } var isConfigured: Bool { config.isConfigured } var config: WebDAVConfig { WebDAVConfig(url: url, username: username, password: password, notesPath: notesPath) } }