Files
QueueCube/ios/QueueCube/Backend/Settings.swift
2025-10-10 23:13:50 -07:00

118 lines
2.9 KiB
Swift

//
// Settings.swift
// QueueCube
//
// Created by James Magahern on 6/10/25.
//
import Foundation
struct Settings
{
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
}
// 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<T: Settings.Key>(_ 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
{
static let settingsChanged = Notification.Name("settingsChanged")
}