diff --git a/Sources/SstData/AppSettings.swift b/Sources/SstData/AppSettings.swift new file mode 100644 index 0000000..9747790 --- /dev/null +++ b/Sources/SstData/AppSettings.swift @@ -0,0 +1,45 @@ +import Combine +import Foundation + +/// User preferences, persisted in UserDefaults as soon as a value changes. +public final class AppSettings: ObservableObject { + public static let defaultModelVariant = "large-v3-v20240930_turbo" + + enum Key { + static let hotkey = "hotkeyID" + static let model = "modelVariant" + static let keepHistory = "keepHistory" + static let usePriming = "usePriming" + static let useCorrection = "useCorrection" + } + + private let defaults: UserDefaults + + /// `HotkeyBinding.id` of the key that has to be held. + @Published public var hotkeyID: String { + didSet { defaults.set(hotkeyID, forKey: Key.hotkey) } + } + @Published public var modelVariant: String { + didSet { defaults.set(modelVariant, forKey: Key.model) } + } + @Published public var keepHistory: Bool { + didSet { defaults.set(keepHistory, forKey: Key.keepHistory) } + } + /// Give the speech engine the dictionary words as context. + @Published public var usePriming: Bool { + didSet { defaults.set(usePriming, forKey: Key.usePriming) } + } + /// Apply the dictionary corrections after transcription. + @Published public var useCorrection: Bool { + didSet { defaults.set(useCorrection, forKey: Key.useCorrection) } + } + + public init(defaults: UserDefaults = .standard) { + self.defaults = defaults + hotkeyID = defaults.string(forKey: Key.hotkey) ?? "fn" + modelVariant = defaults.string(forKey: Key.model) ?? Self.defaultModelVariant + keepHistory = defaults.object(forKey: Key.keepHistory) as? Bool ?? true + usePriming = defaults.object(forKey: Key.usePriming) as? Bool ?? true + useCorrection = defaults.object(forKey: Key.useCorrection) as? Bool ?? true + } +} diff --git a/Tests/SstDataTests/AppSettingsTests.swift b/Tests/SstDataTests/AppSettingsTests.swift new file mode 100644 index 0000000..e384f41 --- /dev/null +++ b/Tests/SstDataTests/AppSettingsTests.swift @@ -0,0 +1,38 @@ +import Foundation +import Testing +@testable import SstData + +struct AppSettingsTests { + func freshDefaults() -> UserDefaults { + let name = "sst-tests-\(UUID().uuidString)" + let defaults = UserDefaults(suiteName: name)! + defaults.removePersistentDomain(forName: name) + return defaults + } + + @Test func defaultsMatchTheSpec() { + let settings = AppSettings(defaults: freshDefaults()) + #expect(settings.hotkeyID == "fn") + #expect(settings.modelVariant == "large-v3-v20240930_turbo") + #expect(settings.keepHistory) + #expect(settings.usePriming) + #expect(settings.useCorrection) + } + + @Test func changesArePersisted() { + let defaults = freshDefaults() + let settings = AppSettings(defaults: defaults) + settings.hotkeyID = "rightOption" + settings.modelVariant = "small" + settings.keepHistory = false + settings.usePriming = false + settings.useCorrection = false + + let reloaded = AppSettings(defaults: defaults) + #expect(reloaded.hotkeyID == "rightOption") + #expect(reloaded.modelVariant == "small") + #expect(!reloaded.keepHistory) + #expect(!reloaded.usePriming) + #expect(!reloaded.useCorrection) + } +}