diff --git a/QueueCube/Backend/Server.swift b/QueueCube/Backend/Server.swift index acefade..6260524 100644 --- a/QueueCube/Backend/Server.swift +++ b/QueueCube/Backend/Server.swift @@ -7,7 +7,7 @@ import Foundation -struct Server: Identifiable, Codable +struct Server: Identifiable, Codable, Equatable { let serviceName: String? let baseURL: URL diff --git a/QueueCube/Backend/Settings.swift b/QueueCube/Backend/Settings.swift index a011233..2e31a8b 100644 --- a/QueueCube/Backend/Settings.swift +++ b/QueueCube/Backend/Settings.swift @@ -9,44 +9,106 @@ import Foundation struct Settings { - var configuredServers: [Server] + var selectedServer: Server? + + var configuredServers: [Server] { + willSet { + // Set selected server to whatever the first server is, if we're adding the first one. + if configuredServers.isEmpty && !newValue.isEmpty && selectedServer == nil { + selectedServer = newValue.first + } + + // If the selected server is being removed, set it to something else + if !newValue.contains(where: { $0 == selectedServer }) { + selectedServer = newValue.first // nil if empty + } + } + } + + var isConfigured: Bool { !configuredServers.isEmpty } + + static func fromDefaults() -> Settings { + let defaults = UserDefaults.standard + return Settings( + selectedServer: defaults[SelectedServerKey.self], + configuredServers: defaults[ConfiguredServersKey.self] + ) + } + + func save() { + let defaults = UserDefaults.standard + defaults[ConfiguredServersKey.self] = configuredServers + defaults[SelectedServerKey.self] = selectedServer + + postSettingsChanged() + } + + func postSettingsChanged() { + NotificationCenter.default.post(name: .settingsChanged, object: nil) + } + + // MARK: - Modifiers + + func selectedServer(_ server: Server?) -> Self { + var copy = self + copy.selectedServer = server + return copy + } func configuredServers(_ servers: [Server]) -> Self { var copy = self copy.configuredServers = servers - return copy - } - - var isConfigured: Bool { - !configuredServers.isEmpty - } - - static func fromDefaults() -> Settings { - let configuredServers: [Server] = { - guard let configuredServersData = UserDefaults.standard.data(forKey: Keys.configuredServers.rawValue) - else { return [] } - - guard let configuredServers = try? PropertyListDecoder().decode([Server].self, from: configuredServersData) - else { return [] } - - return configuredServers - }() - - return Settings(configuredServers: configuredServers) - } - - func save() { - let configuredServersData = try! PropertyListEncoder().encode(configuredServers) - UserDefaults.standard.set(configuredServersData, forKey: Keys.configuredServers.rawValue) - NotificationCenter.default.post(name: .settingsChanged, object: nil) + return copy } // MARK: - Types enum Keys: String { + case selectedServer case configuredServers } + + fileprivate protocol Key + { + associatedtype Value: Codable + + static var defaultValue: Value { get } + static var key: String { get } + } + + private struct ConfiguredServersKey: Key { + static var defaultValue: [Server] { [] } + } + + private struct SelectedServerKey: Key { + static var defaultValue: Server? { nil } + } +} + +extension UserDefaults +{ + fileprivate subscript(_ type: T.Type) -> T.Value { + get { + guard let data = data(forKey: type.key) + else { return type.defaultValue } + + guard let value = try? PropertyListDecoder().decode(type.Value, from: data) + else { return type.defaultValue } + + return value + } + + set { + let data = try? PropertyListEncoder().encode(newValue) + set(data, forKey: type.key) + } + } +} + +extension Settings.Key +{ + static var key: String { Mirror(reflecting: Self.self).description } } extension Notification.Name