diff --git a/Hex/Models/HexSettings.swift b/Hex/Models/HexSettings.swift index 35e018c..2eaa2af 100644 --- a/Hex/Models/HexSettings.swift +++ b/Hex/Models/HexSettings.swift @@ -3,79 +3,111 @@ import Dependencies import Foundation // To add a new setting, add a new property to the struct, the CodingKeys enum, and the custom decoder -struct HexSettings: Codable, Equatable { +struct TranscriptionSettings: Codable, Equatable, Identifiable { var soundEffectsEnabled: Bool = true - var hotkey: HotKey = .init(key: nil, modifiers: [.option]) - var openOnLogin: Bool = false - var showDockIcon: Bool = true var selectedModel: String = "openai_whisper-large-v3-v20240930" var useClipboardPaste: Bool = true var preventSystemSleep: Bool = true var pauseMediaOnRecord: Bool = true var outputLanguage: String? = nil + var hotkey: HotKey = .init(key: nil, modifiers: [.option]) // Define coding keys to match struct properties enum CodingKeys: String, CodingKey { case soundEffectsEnabled - case hotkey - case openOnLogin - case showDockIcon case selectedModel case useClipboardPaste case preventSystemSleep case pauseMediaOnRecord case outputLanguage + case hotkey + } + + var id: HotKey { + return hotkey } init( soundEffectsEnabled: Bool = true, - hotkey: HotKey = .init(key: nil, modifiers: [.option]), - openOnLogin: Bool = false, - showDockIcon: Bool = true, selectedModel: String = "openai_whisper-large-v3-v20240930", useClipboardPaste: Bool = true, preventSystemSleep: Bool = true, pauseMediaOnRecord: Bool = true, - on outputLanguage: String? = nil + outputLanguage: String? = nil, + hotkey: HotKey = .init(key: nil, modifiers: [.option]) ) { self.soundEffectsEnabled = soundEffectsEnabled - self.hotkey = hotkey - self.openOnLogin = openOnLogin - self.showDockIcon = showDockIcon self.selectedModel = selectedModel self.useClipboardPaste = useClipboardPaste self.preventSystemSleep = preventSystemSleep self.pauseMediaOnRecord = pauseMediaOnRecord self.outputLanguage = outputLanguage + self.hotkey = hotkey } // Custom decoder that handles missing fields init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - // Decode each property, using decodeIfPresent with default fallbacks - soundEffectsEnabled = - try container.decodeIfPresent(Bool.self, forKey: .soundEffectsEnabled) ?? true hotkey = try container.decodeIfPresent(HotKey.self, forKey: .hotkey) ?? .init(key: nil, modifiers: [.option]) - openOnLogin = try container.decodeIfPresent(Bool.self, forKey: .openOnLogin) ?? false - showDockIcon = try container.decodeIfPresent(Bool.self, forKey: .showDockIcon) ?? true selectedModel = try container.decodeIfPresent(String.self, forKey: .selectedModel) ?? "openai_whisper-large-v3-v20240930" - useClipboardPaste = try container.decodeIfPresent(Bool.self, forKey: .useClipboardPaste) ?? true + useClipboardPaste = + try container.decodeIfPresent(Bool.self, forKey: .useClipboardPaste) ?? true preventSystemSleep = try container.decodeIfPresent(Bool.self, forKey: .preventSystemSleep) ?? true pauseMediaOnRecord = try container.decodeIfPresent(Bool.self, forKey: .pauseMediaOnRecord) ?? true outputLanguage = try container.decodeIfPresent(String.self, forKey: .outputLanguage) + hotkey = + try container.decodeIfPresent(HotKey.self, forKey: .hotkey) + ?? .init(key: nil, modifiers: [.option]) + } +} + +// To add a new setting, add a new property to the struct, the CodingKeys enum, and the custom decoder +struct HexSettings: Codable, Equatable { + var hotKeyOptions: IdentifiedArrayOf = [.init()] + var openOnLogin: Bool = false + var showDockIcon: Bool = true + + // Define coding keys to match struct properties + enum CodingKeys: String, CodingKey { + case openOnLogin + case showDockIcon + case hotKeyOptions + } + + init( + openOnLogin: Bool = false, + showDockIcon: Bool = true, + hotKeyOptions: IdentifiedArrayOf = [.init()] + ) { + self.openOnLogin = openOnLogin + self.showDockIcon = showDockIcon + self.hotKeyOptions = hotKeyOptions + } + + // Custom decoder that handles missing fields + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + // Decode each property, using decodeIfPresent with default fallbacks + openOnLogin = try container.decodeIfPresent(Bool.self, forKey: .openOnLogin) ?? false + showDockIcon = try container.decodeIfPresent(Bool.self, forKey: .showDockIcon) ?? true + /// TODO: Write code to upgrade settings from previous versions where transcriptionSettings was not present + hotKeyOptions = + try container.decodeIfPresent( + IdentifiedArrayOf.self, forKey: .hotKeyOptions) + ?? [.init()] } } extension SharedReaderKey - where Self == FileStorageKey.Default -{ +where Self == FileStorageKey.Default { static var hexSettings: Self { Self[ .fileStorage(URL.documentsDirectory.appending(component: "hex_settings.json")), diff --git a/Hex/Models/HotKey.swift b/Hex/Models/HotKey.swift index 1f55d6b..d4dbd50 100644 --- a/Hex/Models/HotKey.swift +++ b/Hex/Models/HotKey.swift @@ -32,7 +32,7 @@ public enum Modifier: Identifiable, Codable, Equatable, Hashable, Comparable { } } -public struct Modifiers: Codable, Equatable, ExpressibleByArrayLiteral { +public struct Modifiers: Codable, Equatable, ExpressibleByArrayLiteral, Hashable { var modifiers: Set var sorted: [Modifier] { @@ -102,7 +102,7 @@ public struct Modifiers: Codable, Equatable, ExpressibleByArrayLiteral { } } -public struct HotKey: Codable, Equatable { +public struct HotKey: Codable, Equatable, Hashable { public var key: Key? public var modifiers: Modifiers }