// // Constants.swift // DynamicIsland // // Created by Richard Kunkli on 2024. 10. 17.. // Modified by Hariharan Mudaliar import SwiftUI import Defaults private let availableDirectories = FileManager .default .urls(for: .documentDirectory, in: .userDomainMask) let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let bundleIdentifier = Bundle.main.bundleIdentifier! let appVersion = "\(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "") (\(Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? ""))" let temporaryDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! let spacing: CGFloat = 16 struct CustomVisualizer: Codable, Hashable, Equatable, Defaults.Serializable { let UUID: UUID var name: String var url: URL var speed: CGFloat = 1.0 } enum CalendarSelectionState: Codable, Defaults.Serializable { case all case selected(Set) } enum ClipboardDisplayMode: String, CaseIterable, Codable, Defaults.Serializable { case popover = "popover" // Traditional popover attached to button case panel = "panel" // Floating panel near notch var displayName: String { switch self { case .popover: return "Popover" case .panel: return "Panel" } } var description: String { switch self { case .popover: return "Shows clipboard as a dropdown attached to the clipboard button" case .panel: return "Shows clipboard in a floating panel near the notch" } } } enum ScreenAssistantDisplayMode: String, CaseIterable, Codable, Defaults.Serializable { case popover = "popover" // Traditional popover attached to button case panel = "panel" // Floating panel near notch var displayName: String { switch self { case .popover: return "Popover" case .panel: return "Panel" } } var description: String { switch self { case .popover: return "Shows screen assistant as a dropdown attached to the AI button" case .panel: return "Shows screen assistant in a floating panel near the notch" } } } enum ColorPickerDisplayMode: String, CaseIterable, Codable, Defaults.Serializable { case popover = "popover" // Traditional popover attached to button case panel = "panel" // Floating panel near notch var displayName: String { switch self { case .popover: return "Popover" case .panel: return "Panel" } } var description: String { switch self { case .popover: return "Shows color picker as a dropdown attached to the color picker button" case .panel: return "Shows color picker in a floating panel near the notch" } } } enum HideNotchOption: String, Defaults.Serializable { case always case nowPlayingOnly case never } // Define notification names at file scope extension Notification.Name { static let mediaControllerChanged = Notification.Name("mediaControllerChanged") } // Media controller types for selection in settings enum MediaControllerType: String, CaseIterable, Identifiable, Defaults.Serializable { case nowPlaying = "Now Playing" case appleMusic = "Apple Music" case spotify = "Spotify" case youtubeMusic = "Youtube Music" var id: String { self.rawValue } } // Sneak peek styles for selection in settings enum SneakPeekStyle: String, CaseIterable, Identifiable, Defaults.Serializable { case standard = "Default" case inline = "Inline" var id: String { self.rawValue } } enum ProgressBarStyle: String, CaseIterable, Identifiable, Defaults.Serializable { case hierarchical = "Hierarchical" case gradient = "Gradient" case segmented = "Segmented" var id: String { self.rawValue } } // AI Model types for screen assistant enum AIModelProvider: String, CaseIterable, Identifiable, Defaults.Serializable { case gemini = "Gemini" case openai = "OpenAI GPT" case claude = "Claude" case local = "Local Model" var id: String { self.rawValue } var displayName: String { return self.rawValue } var description: String { switch self { case .gemini: return "Google's Gemini AI with multimodal capabilities" case .openai: return "OpenAI's GPT models with advanced reasoning" case .claude: return "Anthropic's Claude with strong analytical skills" case .local: return "Local AI model (Ollama or similar)" } } var supportedModels: [AIModel] { switch self { case .gemini: return [ // Gemini 2.5 Models (Latest) AIModel(id: "gemini-2.5-pro", name: "Gemini 2.5 Pro", supportsThinking: true), AIModel(id: "gemini-2.5-flash", name: "Gemini 2.5 Flash", supportsThinking: true), AIModel(id: "gemini-2.5-flash-lite", name: "Gemini 2.5 Flash-Lite", supportsThinking: false), AIModel(id: "gemini-2.5-flash-live", name: "Gemini 2.5 Flash Live", supportsThinking: false), AIModel(id: "gemini-2.5-flash-native-audio", name: "Gemini 2.5 Flash Native Audio", supportsThinking: true), // Gemini 2.0 Models AIModel(id: "gemini-2.0-flash", name: "Gemini 2.0 Flash", supportsThinking: false), AIModel(id: "gemini-2.0-flash-lite", name: "Gemini 2.0 Flash-Lite", supportsThinking: false), AIModel(id: "gemini-2.0-flash-live", name: "Gemini 2.0 Flash Live", supportsThinking: false), // Legacy 1.5 Models (for compatibility) AIModel(id: "gemini-1.5-pro", name: "Gemini 1.5 Pro", supportsThinking: false), AIModel(id: "gemini-1.5-flash", name: "Gemini 1.5 Flash", supportsThinking: false) ] case .openai: return [ AIModel(id: "gpt-4o", name: "GPT-4o", supportsThinking: false), AIModel(id: "gpt-4o-mini", name: "GPT-4o Mini", supportsThinking: false), AIModel(id: "o1-preview", name: "o1 Preview", supportsThinking: true), AIModel(id: "o1-mini", name: "o1 Mini", supportsThinking: true) ] case .claude: return [ AIModel(id: "claude-3-5-sonnet", name: "Claude 3.5 Sonnet", supportsThinking: false), AIModel(id: "claude-3-haiku", name: "Claude 3 Haiku", supportsThinking: false) ] case .local: return [ AIModel(id: "llama3.2", name: "Llama 3.2", supportsThinking: false), AIModel(id: "qwen2.5", name: "Qwen 2.5", supportsThinking: false) ] } } } struct AIModel: Codable, Identifiable, Defaults.Serializable { let id: String let name: String let supportsThinking: Bool var displayName: String { return name + (supportsThinking ? " (Thinking)" : "") } } extension Defaults.Keys { // MARK: General static let menubarIcon = Key("menubarIcon", default: true) static let showOnAllDisplays = Key("showOnAllDisplays", default: false) static let automaticallySwitchDisplay = Key("automaticallySwitchDisplay", default: true) static let releaseName = Key("releaseName", default: "alpha 0.0.1") static let hidePanelsFromScreenCapture = Key("hideFromScreenCapture", default: false) // MARK: Behavior static let minimumHoverDuration = Key("minimumHoverDuration", default: 0.3) static let enableHaptics = Key("enableHaptics", default: true) static let openNotchOnHover = Key("openNotchOnHover", default: true) static let extendHoverArea = Key("extendHoverArea", default: false) static let notchHeightMode = Key( "notchHeightMode", default: WindowHeightMode.matchRealNotchSize ) static let nonNotchHeightMode = Key( "nonNotchHeightMode", default: WindowHeightMode.matchMenuBar ) static let nonNotchHeight = Key("nonNotchHeight", default: 32) static let notchHeight = Key("notchHeight", default: 32) //static let openLastTabByDefault = Key("openLastTabByDefault", default: false) // MARK: Appearance static let showEmojis = Key("showEmojis", default: false) //static let alwaysShowTabs = Key("alwaysShowTabs", default: true) static let showMirror = Key("showMirror", default: false) static let mirrorShape = Key("mirrorShape", default: MirrorShapeEnum.rectangle) static let settingsIconInNotch = Key("settingsIconInNotch", default: true) static let lightingEffect = Key("lightingEffect", default: true) static let accentColor = Key("accentColor", default: Color.blue) static let enableShadow = Key("enableShadow", default: true) static let cornerRadiusScaling = Key("cornerRadiusScaling", default: true) static let useModernCloseAnimation = Key("useModernCloseAnimation", default: true) static let showNotHumanFace = Key("showNotHumanFace", default: false) static let tileShowLabels = Key("tileShowLabels", default: false) static let showCalendar = Key("showCalendar", default: false) static let sliderColor = Key( "sliderUseAlbumArtColor", default: SliderColorEnum.white ) static let playerColorTinting = Key("playerColorTinting", default: true) static let useMusicVisualizer = Key("useMusicVisualizer", default: true) static let customVisualizers = Key<[CustomVisualizer]>("customVisualizers", default: []) static let selectedVisualizer = Key("selectedVisualizer", default: nil) // MARK: Gestures static let enableGestures = Key("enableGestures", default: true) static let closeGestureEnabled = Key("closeGestureEnabled", default: true) static let gestureSensitivity = Key("gestureSensitivity", default: 200.0) // MARK: Media playback static let coloredSpectrogram = Key("coloredSpectrogram", default: true) static let enableSneakPeek = Key("enableSneakPeek", default: false) static let sneakPeekStyles = Key("sneakPeekStyles", default: .standard) static let enableFullscreenMediaDetection = Key("enableFullscreenMediaDetection", default: true) static let waitInterval = Key("waitInterval", default: 3) static let showShuffleAndRepeat = Key("showShuffleAndRepeat", default: false) // MARK: Battery static let showPowerStatusNotifications = Key("showPowerStatusNotifications", default: true) static let showBatteryIndicator = Key("showBatteryIndicator", default: true) static let showBatteryPercentage = Key("showBatteryPercentage", default: true) static let showPowerStatusIcons = Key("showPowerStatusIcons", default: true) // MARK: Downloads static let enableDownloadListener = Key("enableDownloadListener", default: true) static let enableSafariDownloads = Key("enableSafariDownloads", default: true) static let selectedDownloadIndicatorStyle = Key("selectedDownloadIndicatorStyle", default: DownloadIndicatorStyle.progress) static let selectedDownloadIconStyle = Key("selectedDownloadIconStyle", default: DownloadIconStyle.onlyAppIcon) // MARK: HUD static let inlineHUD = Key("inlineHUD", default: false) static let progressBarStyle = Key("progressBarStyle", default: .hierarchical) // Legacy support - keeping for backward compatibility static let enableGradient = Key("enableGradient", default: false) static let systemEventIndicatorShadow = Key("systemEventIndicatorShadow", default: false) static let systemEventIndicatorUseAccent = Key("systemEventIndicatorUseAccent", default: false) // MARK: Shelf static let dynamicShelf = Key("dynamicShelf", default: true) static let openShelfByDefault = Key("openShelfByDefault", default: true) // MARK: Calendar static let calendarSelectionState = Key("calendarSelectionState", default: .all) // MARK: Fullscreen Media Detection static let alwaysHideInFullscreen = Key("alwaysHideInFullscreen", default: false) static let hideNotchOption = Key("hideNotchOption", default: .nowPlayingOnly) // MARK: Wobble Animation static let enableWobbleAnimation = Key("enableWobbleAnimation", default: false) // MARK: Media Controller static let mediaController = Key("mediaController", default: defaultMediaController) // MARK: Stats Feature static let enableStatsFeature = Key("enableStatsFeature", default: false) static let autoStartStatsMonitoring = Key("autoStartStatsMonitoring", default: true) static let showCpuGraph = Key("showCpuGraph", default: true) static let showMemoryGraph = Key("showMemoryGraph", default: true) static let showGpuGraph = Key("showGpuGraph", default: true) static let showNetworkGraph = Key("showNetworkGraph", default: false) static let showDiskGraph = Key("showDiskGraph", default: false) static let showStatsPanel = Key("showStatsPanel", default: true) // MARK: Timer Feature static let enableTimerFeature = Key("enableTimerFeature", default: true) // MARK: ColorPicker Feature static let enableColorPickerFeature = Key("enableColorPickerFeature", default: true) static let showColorFormats = Key("showColorFormats", default: true) static let colorPickerDisplayMode = Key("colorPickerDisplayMode", default: .panel) static let colorHistorySize = Key("colorHistorySize", default: 10) static let showColorPickerIcon = Key("showColorPickerIcon", default: true) // MARK: Clipboard Feature static let enableClipboardManager = Key("enableClipboardManager", default: true) static let clipboardHistorySize = Key("clipboardHistorySize", default: 3) static let showClipboardIcon = Key("showClipboardIcon", default: true) static let clipboardDisplayMode = Key("clipboardDisplayMode", default: .panel) // MARK: Screen Assistant Feature static let enableScreenAssistant = Key("enableScreenAssistant", default: true) static let screenAssistantDisplayMode = Key("screenAssistantDisplayMode", default: .panel) static let geminiApiKey = Key("geminiApiKey", default: "") static let openaiApiKey = Key("openaiApiKey", default: "") static let claudeApiKey = Key("claudeApiKey", default: "") static let selectedAIProvider = Key("selectedAIProvider", default: .gemini) static let selectedAIModel = Key("selectedAIModel", default: nil) static let enableThinkingMode = Key("enableThinkingMode", default: false) static let localModelEndpoint = Key("localModelEndpoint", default: "http://localhost:11434") // MARK: Keyboard Shortcuts static let enableShortcuts = Key("enableShortcuts", default: true) // MARK: System HUD Feature static let enableSystemHUD = Key("enableSystemHUD", default: false) static let enableVolumeHUD = Key("enableVolumeHUD", default: true) static let enableBrightnessHUD = Key("enableBrightnessHUD", default: true) static let enableKeyboardBacklightHUD = Key("enableKeyboardBacklightHUD", default: true) static let systemHUDSensitivity = Key("systemHUDSensitivity", default: 5) // Helper to determine the default media controller based on macOS version static var defaultMediaController: MediaControllerType { if #available(macOS 15.4, *) { return .appleMusic } else { return .nowPlaying } } // Migration helper to convert from legacy enableGradient Boolean to new ProgressBarStyle enum static func migrateProgressBarStyle() { // Check if migration is needed by seeing if the old Boolean was set to gradient let wasGradientEnabled = Defaults[.enableGradient] // Only migrate if we're still using the default hierarchical value but gradient was enabled if wasGradientEnabled && Defaults[.progressBarStyle] == .hierarchical { Defaults[.progressBarStyle] = .gradient } } }