import Foundation import Combine private func ud(_ type: T.Type, key: String) -> T? { guard let data = UserDefaults.standard.data(forKey: key) else { return nil } return try? JSONDecoder().decode(type, from: data) } private func saveUD(_ value: T?, key: String) { guard let value else { UserDefaults.standard.removeObject(forKey: key); return } if let data = try? JSONEncoder().encode(value) { UserDefaults.standard.set(data, forKey: key) } } final class ConnectionStore: ObservableObject { static let shared = ConnectionStore() @Published var savedConnection: NASConnection? { didSet { saveUD(savedConnection, key: "savedConnection") } } @Published var backupFilter: BackupFilter { didSet { saveUD(backupFilter, key: "backupFilter") } } @Published var trustedSSIDs: [String] { didSet { UserDefaults.standard.set(trustedSSIDs, forKey: "trustedSSIDs") } } @Published var lanTriggerEnabled: Bool { didSet { UserDefaults.standard.set(lanTriggerEnabled, forKey: "lanTriggerEnabled") } } @Published var startDelaySeconds: Int { didSet { UserDefaults.standard.set(startDelaySeconds, forKey: "startDelaySeconds") } } @Published var chargingOnlyMode: Bool { didSet { UserDefaults.standard.set(chargingOnlyMode, forKey: "chargingOnlyMode") } } @Published var quietHoursEnabled: Bool { didSet { UserDefaults.standard.set(quietHoursEnabled, forKey: "quietHoursEnabled") } } @Published var quietHoursStart: Int { didSet { UserDefaults.standard.set(quietHoursStart, forKey: "quietHoursStart") } } @Published var quietHoursEnd: Int { didSet { UserDefaults.standard.set(quietHoursEnd, forKey: "quietHoursEnd") } } // Cellular & remote access @Published var allowCellularBackup: Bool { didSet { UserDefaults.standard.set(allowCellularBackup, forKey: "allowCellularBackup") } } @Published var useTailscaleWhenRemote: Bool { didSet { UserDefaults.standard.set(useTailscaleWhenRemote, forKey: "useTailscaleWhenRemote") } } @Published var tailscaleHost: String { didSet { UserDefaults.standard.set(tailscaleHost, forKey: "tailscaleHost") } } @Published private(set) var historyEntries: [BackupHistoryEntry] = [] private init() { savedConnection = ud(NASConnection.self, key: "savedConnection") backupFilter = ud(BackupFilter.self, key: "backupFilter") ?? BackupFilter() trustedSSIDs = UserDefaults.standard.stringArray(forKey: "trustedSSIDs") ?? [] lanTriggerEnabled = UserDefaults.standard.object(forKey: "lanTriggerEnabled") as? Bool ?? true startDelaySeconds = UserDefaults.standard.object(forKey: "startDelaySeconds") as? Int ?? 30 chargingOnlyMode = UserDefaults.standard.object(forKey: "chargingOnlyMode") as? Bool ?? true quietHoursEnabled = UserDefaults.standard.object(forKey: "quietHoursEnabled") as? Bool ?? false quietHoursStart = UserDefaults.standard.object(forKey: "quietHoursStart") as? Int ?? 23 quietHoursEnd = UserDefaults.standard.object(forKey: "quietHoursEnd") as? Int ?? 7 allowCellularBackup = UserDefaults.standard.object(forKey: "allowCellularBackup") as? Bool ?? false useTailscaleWhenRemote = UserDefaults.standard.object(forKey: "useTailscaleWhenRemote") as? Bool ?? false tailscaleHost = UserDefaults.standard.string(forKey: "tailscaleHost") ?? "" historyEntries = ud([BackupHistoryEntry].self, key: "historyEntries") ?? [] } func appendHistoryEntry(_ entry: BackupHistoryEntry) { historyEntries.insert(entry, at: 0) saveUD(historyEntries, key: "historyEntries") } func removeHistoryEntries(at offsets: IndexSet) { historyEntries.remove(atOffsets: offsets) saveUD(historyEntries, key: "historyEntries") } func clearHistory() { historyEntries = [] UserDefaults.standard.removeObject(forKey: "historyEntries") } var isInQuietHours: Bool { guard quietHoursEnabled else { return false } let hour = Calendar.current.component(.hour, from: Date()) if quietHoursStart > quietHoursEnd { return hour >= quietHoursStart || hour < quietHoursEnd } return hour >= quietHoursStart && hour < quietHoursEnd } }