import Foundation
|
|
public enum PreferenceKey: String, CaseIterable, Equatable, Sendable {
|
case schemaVersion = "schemaVersion"
|
case showMinimizedWindows = "quickSwitch.showMinimizedWindows"
|
case showFullscreenWindows = "quickSwitch.showFullscreenWindows"
|
case quickSwitchWaterfallViewMode = "quickSwitch.waterfallViewMode"
|
case theme = "appearance.theme"
|
case language = "appearance.language"
|
case spaceDisplayStrategy = "spaces.displayStrategy"
|
|
public var storageKey: String {
|
"com.ar.Aligner.preferences.\(rawValue)"
|
}
|
}
|
|
public enum ThemePreference: String, CaseIterable, Equatable, Sendable {
|
case system
|
case light
|
case dark
|
}
|
|
public enum LanguagePreference: String, CaseIterable, Equatable, Sendable {
|
case system
|
case english
|
case simplifiedChinese
|
}
|
|
public enum SpaceDisplayStrategy: String, CaseIterable, Equatable, Sendable {
|
case includeVisibleAndFullscreen
|
case currentSpaceOnly
|
}
|
|
public enum QuickSwitchWaterfallViewMode: String, CaseIterable, Equatable, Sendable {
|
case verticalColumns
|
case horizontalMasonry
|
}
|
|
public struct AlignerPreferences: Equatable, Sendable {
|
public let showMinimizedWindows: Bool
|
public let showFullscreenWindows: Bool
|
public let quickSwitchWaterfallViewMode: QuickSwitchWaterfallViewMode
|
public let theme: ThemePreference
|
public let language: LanguagePreference
|
public let spaceDisplayStrategy: SpaceDisplayStrategy
|
|
public init(
|
showMinimizedWindows: Bool,
|
showFullscreenWindows: Bool,
|
quickSwitchWaterfallViewMode: QuickSwitchWaterfallViewMode,
|
theme: ThemePreference,
|
language: LanguagePreference,
|
spaceDisplayStrategy: SpaceDisplayStrategy
|
) {
|
self.showMinimizedWindows = showMinimizedWindows
|
self.showFullscreenWindows = showFullscreenWindows
|
self.quickSwitchWaterfallViewMode = quickSwitchWaterfallViewMode
|
self.theme = theme
|
self.language = language
|
self.spaceDisplayStrategy = spaceDisplayStrategy
|
}
|
}
|
|
public enum PreferenceSchema {
|
public static let version = 2
|
|
public static let defaults = AlignerPreferences(
|
showMinimizedWindows: true,
|
showFullscreenWindows: true,
|
quickSwitchWaterfallViewMode: .verticalColumns,
|
theme: .system,
|
language: .system,
|
spaceDisplayStrategy: .includeVisibleAndFullscreen
|
)
|
|
public static var registrationDictionary: [String: Any] {
|
[
|
PreferenceKey.schemaVersion.storageKey: version,
|
PreferenceKey.showMinimizedWindows.storageKey: defaults.showMinimizedWindows,
|
PreferenceKey.showFullscreenWindows.storageKey: defaults.showFullscreenWindows,
|
PreferenceKey.quickSwitchWaterfallViewMode.storageKey: defaults.quickSwitchWaterfallViewMode.rawValue,
|
PreferenceKey.theme.storageKey: defaults.theme.rawValue,
|
PreferenceKey.language.storageKey: defaults.language.rawValue,
|
PreferenceKey.spaceDisplayStrategy.storageKey: defaults.spaceDisplayStrategy.rawValue
|
]
|
}
|
}
|
|
public protocol PreferenceStoreProtocol {
|
func registerDefaults()
|
func storedSchemaVersion() -> Int
|
func needsMigration() -> Bool
|
func read() -> AlignerPreferences
|
func write(_ preferences: AlignerPreferences)
|
func reset()
|
}
|
|
public final class UserDefaultsPreferenceStore: PreferenceStoreProtocol {
|
private let userDefaults: UserDefaults
|
|
public init(userDefaults: UserDefaults = .standard) {
|
self.userDefaults = userDefaults
|
}
|
|
public func registerDefaults() {
|
userDefaults.register(defaults: PreferenceSchema.registrationDictionary)
|
}
|
|
public func storedSchemaVersion() -> Int {
|
registerDefaults()
|
return userDefaults.integer(forKey: PreferenceKey.schemaVersion.storageKey)
|
}
|
|
public func needsMigration() -> Bool {
|
storedSchemaVersion() < PreferenceSchema.version
|
}
|
|
public func read() -> AlignerPreferences {
|
registerDefaults()
|
|
return AlignerPreferences(
|
showMinimizedWindows: userDefaults.bool(forKey: PreferenceKey.showMinimizedWindows.storageKey),
|
showFullscreenWindows: userDefaults.bool(forKey: PreferenceKey.showFullscreenWindows.storageKey),
|
quickSwitchWaterfallViewMode: rawValue(
|
for: .quickSwitchWaterfallViewMode,
|
default: PreferenceSchema.defaults.quickSwitchWaterfallViewMode
|
),
|
theme: rawValue(for: .theme, default: PreferenceSchema.defaults.theme),
|
language: rawValue(for: .language, default: PreferenceSchema.defaults.language),
|
spaceDisplayStrategy: rawValue(
|
for: .spaceDisplayStrategy,
|
default: PreferenceSchema.defaults.spaceDisplayStrategy
|
)
|
)
|
}
|
|
public func write(_ preferences: AlignerPreferences) {
|
userDefaults.set(PreferenceSchema.version, forKey: PreferenceKey.schemaVersion.storageKey)
|
userDefaults.set(preferences.showMinimizedWindows, forKey: PreferenceKey.showMinimizedWindows.storageKey)
|
userDefaults.set(preferences.showFullscreenWindows, forKey: PreferenceKey.showFullscreenWindows.storageKey)
|
userDefaults.set(
|
preferences.quickSwitchWaterfallViewMode.rawValue,
|
forKey: PreferenceKey.quickSwitchWaterfallViewMode.storageKey
|
)
|
userDefaults.set(preferences.theme.rawValue, forKey: PreferenceKey.theme.storageKey)
|
userDefaults.set(preferences.language.rawValue, forKey: PreferenceKey.language.storageKey)
|
userDefaults.set(preferences.spaceDisplayStrategy.rawValue, forKey: PreferenceKey.spaceDisplayStrategy.storageKey)
|
}
|
|
public func reset() {
|
for key in PreferenceKey.allCases {
|
userDefaults.removeObject(forKey: key.storageKey)
|
}
|
registerDefaults()
|
}
|
|
private func rawValue<T: RawRepresentable>(for key: PreferenceKey, default defaultValue: T) -> T where T.RawValue == String {
|
guard let value = userDefaults.string(forKey: key.storageKey) else {
|
return defaultValue
|
}
|
|
return T(rawValue: value) ?? defaultValue
|
}
|
}
|