import CodexBarCoreimport Foundationimport ServiceManagement extension SettingsStore { private static let mergedOverviewSelectionEditedActiveProvidersKey = "mergedOverviewSelectionEditedActiveProviders" func noteBackgroundWorkSettingsChanged() { self.backgroundWorkSettingsRevision &+= 1 } var refreshFrequency: RefreshFrequency { get { self.defaultsState.refreshFrequency } set { let previousValue = self.defaultsState.refreshFrequency if newValue == .adaptiveAgentAware, previousValue != .adaptiveAgentAware, self.defaultsState.adaptiveActivityScanConsent == .declined { self.defaultsState.adaptiveActivityScanConsent = .undecided self.userDefaults.set( AdaptiveActivityScanConsent.undecided.rawValue, forKey: "adaptiveActivityScanConsent") } self.defaultsState.refreshFrequency = newValue self.userDefaults.set(newValue.rawValue, forKey: "refreshFrequency") self.noteBackgroundWorkSettingsChanged() } } var adaptiveActivityScanConsent: AdaptiveActivityScanConsent { get { self.defaultsState.adaptiveActivityScanConsent } set { self.defaultsState.adaptiveActivityScanConsent = newValue self.userDefaults.set(newValue.rawValue, forKey: "adaptiveActivityScanConsent") self.noteBackgroundWorkSettingsChanged() } } var adaptiveActivityScanningEnabled: Bool { self.refreshFrequency == .adaptiveAgentAware && self.adaptiveActivityScanConsent == .allowed } var shouldRequestAdaptiveActivityScanConsent: Bool { self.refreshFrequency == .adaptiveAgentAware && self.adaptiveActivityScanConsent == .undecided } /// When enabled, keeping the menu open through its short refresh delay fetches usage for every /// enabled provider. The periodic refresh clock remains unchanged. See `scheduleOpenMenuRefresh`. var refreshAllProvidersOnMenuOpen: Bool { get { self.defaultsState.refreshAllProvidersOnMenuOpen } set { self.defaultsState.refreshAllProvidersOnMenuOpen = newValue self.userDefaults.set(newValue, forKey: "refreshAllProvidersOnMenuOpen") } } var launchAtLogin: Bool { get { self.defaultsState.launchAtLogin } set { self.defaultsState.launchAtLogin = newValue self.userDefaults.set(newValue, forKey: "launchAtLogin") LaunchAtLoginManager.setEnabled(newValue) } } var debugMenuEnabled: Bool { get { self.defaultsState.debugMenuEnabled } set { self.defaultsState.debugMenuEnabled = newValue self.userDefaults.set(newValue, forKey: "debugMenuEnabled") } } var debugDisableKeychainAccess: Bool { get { self.defaultsState.debugDisableKeychainAccess } set { self.defaultsState.debugDisableKeychainAccess = newValue self.userDefaults.set(newValue, forKey: "debugDisableKeychainAccess") if Self.shouldBridgeSharedDefaults(for: self.userDefaults) { Self.sharedDefaults?.set(newValue, forKey: "debugDisableKeychainAccess") } KeychainAccessGate.isDisabled = newValue self.noteBackgroundWorkSettingsChanged() } } var debugFileLoggingEnabled: Bool { get { self.defaultsState.debugFileLoggingEnabled } set { self.defaultsState.debugFileLoggingEnabled = newValue self.userDefaults.set(newValue, forKey: "debugFileLoggingEnabled") CodexBarLog.setFileLoggingEnabled(newValue) } } var debugLogLevel: CodexBarLog.Level { get { let raw = self.defaultsState.debugLogLevelRaw return CodexBarLog.parseLevel(raw) ?? .verbose } set { self.defaultsState.debugLogLevelRaw = newValue.rawValue self.userDefaults.set(newValue.rawValue, forKey: "debugLogLevel") CodexBarLog.setLogLevel(newValue) } } var debugKeepCLISessionsAlive: Bool { get { self.defaultsState.debugKeepCLISessionsAlive } set { self.defaultsState.debugKeepCLISessionsAlive = newValue self.userDefaults.set(newValue, forKey: "debugKeepCLISessionsAlive") self.noteBackgroundWorkSettingsChanged() } } var isVerboseLoggingEnabled: Bool { self.debugLogLevel.rank <= CodexBarLog.Level.verbose.rank } private var debugLoadingPatternRaw: String? { get { self.defaultsState.debugLoadingPatternRaw } set { self.defaultsState.debugLoadingPatternRaw = newValue if let raw = newValue { self.userDefaults.set(raw, forKey: "debugLoadingPattern") } else { self.userDefaults.removeObject(forKey: "debugLoadingPattern") } } } var statusChecksEnabled: Bool { get { self.defaultsState.statusChecksEnabled } set { self.defaultsState.statusChecksEnabled = newValue self.userDefaults.set(newValue, forKey: "statusChecksEnabled") self.noteBackgroundWorkSettingsChanged() } } var sessionQuotaNotificationsEnabled: Bool { get { self.defaultsState.sessionQuotaNotificationsEnabled } set { self.defaultsState.sessionQuotaNotificationsEnabled = newValue self.userDefaults.set(newValue, forKey: "sessionQuotaNotificationsEnabled") self.noteBackgroundWorkSettingsChanged() } } var quotaWarningNotificationsEnabled: Bool { get { self.defaultsState.quotaWarningNotificationsEnabled } set { self.defaultsState.quotaWarningNotificationsEnabled = newValue self.userDefaults.set(newValue, forKey: "quotaWarningNotificationsEnabled") self.noteBackgroundWorkSettingsChanged() } } var predictivePaceWarningNotificationsEnabled: Bool { get { self.defaultsState.predictivePaceWarningNotificationsEnabled } set { guard self.defaultsState.predictivePaceWarningNotificationsEnabled != newValue else { return } self.defaultsState.predictivePaceWarningNotificationsEnabled = newValue self.userDefaults.set(newValue, forKey: "predictivePaceWarningNotificationsEnabled") self.noteBackgroundWorkSettingsChanged() } } var quotaWarningThresholds: [Int] { get { QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningThresholdsRaw) } set { let sanitized = QuotaWarningThresholds.sanitized(newValue) guard QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningThresholdsRaw) != sanitized || QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningSessionThresholdsRaw) != sanitized || QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningWeeklyThresholdsRaw) != sanitized else { return } self.defaultsState.quotaWarningThresholdsRaw = sanitized self.defaultsState.quotaWarningSessionThresholdsRaw = sanitized self.defaultsState.quotaWarningWeeklyThresholdsRaw = sanitized self.userDefaults.set(sanitized, forKey: "quotaWarningThresholds") self.userDefaults.set(sanitized, forKey: "quotaWarningSessionThresholds") self.userDefaults.set(sanitized, forKey: "quotaWarningWeeklyThresholds") self.noteBackgroundWorkSettingsChanged() } } func quotaWarningThresholds(_ window: QuotaWarningWindow) -> [Int] { switch window { case .session: QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningSessionThresholdsRaw) case .weekly: QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningWeeklyThresholdsRaw) } } func setQuotaWarningThresholds(_ window: QuotaWarningWindow, thresholds: [Int]) { let sanitized = QuotaWarningThresholds.sanitized(thresholds) guard self.quotaWarningThresholds(window) != sanitized else { return } switch window { case .session: self.defaultsState.quotaWarningSessionThresholdsRaw = sanitized self.userDefaults.set(sanitized, forKey: "quotaWarningSessionThresholds") case .weekly: self.defaultsState.quotaWarningWeeklyThresholdsRaw = sanitized self.userDefaults.set(sanitized, forKey: "quotaWarningWeeklyThresholds") } self.noteBackgroundWorkSettingsChanged() } func quotaWarningWindowEnabled(_ window: QuotaWarningWindow) -> Bool { switch window { case .session: self.defaultsState.quotaWarningSessionEnabled case .weekly: self.defaultsState.quotaWarningWeeklyEnabled } } func setQuotaWarningWindowEnabled(_ window: QuotaWarningWindow, enabled: Bool) { switch window { case .session: self.defaultsState.quotaWarningSessionEnabled = enabled self.userDefaults.set(enabled, forKey: "quotaWarningSessionEnabled") case .weekly: self.defaultsState.quotaWarningWeeklyEnabled = enabled self.userDefaults.set(enabled, forKey: "quotaWarningWeeklyEnabled") } self.noteBackgroundWorkSettingsChanged() } var quotaWarningSoundEnabled: Bool { get { self.defaultsState.quotaWarningSoundEnabled } set { self.defaultsState.quotaWarningSoundEnabled = newValue self.userDefaults.set(newValue, forKey: "quotaWarningSoundEnabled") self.noteBackgroundWorkSettingsChanged() } } var quotaWarningOnScreenAlertEnabled: Bool { get { self.defaultsState.quotaWarningOnScreenAlertEnabled } set { self.defaultsState.quotaWarningOnScreenAlertEnabled = newValue self.userDefaults.set(newValue, forKey: "quotaWarningOnScreenAlertEnabled") } } var quotaWarningMarkersVisible: Bool { get { self.defaultsState.quotaWarningMarkersVisible } set { self.defaultsState.quotaWarningMarkersVisible = newValue self.userDefaults.set(newValue, forKey: "quotaWarningMarkersVisible") } } var weeklyProgressWorkDays: Int? { get { self.defaultsState.weeklyProgressWorkDays } set { self.defaultsState.weeklyProgressWorkDays = newValue if let newValue { self.userDefaults.set(newValue, forKey: "weeklyProgressWorkDays") } else { self.userDefaults.removeObject(forKey: "weeklyProgressWorkDays") } } } var usageBarsShowUsed: Bool { get { self.defaultsState.usageBarsShowUsed } set { self.defaultsState.usageBarsShowUsed = newValue self.userDefaults.set(newValue, forKey: "usageBarsShowUsed") } } var resetTimesShowAbsolute: Bool { get { self.defaultsState.resetTimesShowAbsolute } set { self.defaultsState.resetTimesShowAbsolute = newValue self.userDefaults.set(newValue, forKey: "resetTimesShowAbsolute") } } var providerChangelogLinksEnabled: Bool { get { self.defaultsState.providerChangelogLinksEnabled } set { self.defaultsState.providerChangelogLinksEnabled = newValue self.userDefaults.set(newValue, forKey: "providerChangelogLinksEnabled") } } var menuBarShowsBrandIconWithPercent: Bool { get { self.defaultsState.menuBarShowsBrandIconWithPercent } set { self.defaultsState.menuBarShowsBrandIconWithPercent = newValue self.userDefaults.set(newValue, forKey: "menuBarShowsBrandIconWithPercent") } } var menuBarHidesCritters: Bool { get { self.defaultsState.menuBarHidesCritters } set { self.defaultsState.menuBarHidesCritters = newValue self.userDefaults.set(newValue, forKey: "menuBarHidesCritters") } } var menuBarHighContrastOnInactiveDisplays: Bool { get { self.defaultsState.menuBarHighContrastOnInactiveDisplays } set { self.defaultsState.menuBarHighContrastOnInactiveDisplays = newValue self.userDefaults.set(newValue, forKey: "menuBarHighContrastOnInactiveDisplays") } } private var menuBarDisplayModeRaw: String? { get { self.defaultsState.menuBarDisplayModeRaw } set { self.defaultsState.menuBarDisplayModeRaw = newValue if let raw = newValue { self.userDefaults.set(raw, forKey: "menuBarDisplayMode") } else { self.userDefaults.removeObject(forKey: "menuBarDisplayMode") } } } var menuBarDisplayMode: MenuBarDisplayMode { get { MenuBarDisplayMode(rawValue: self.menuBarDisplayModeRaw ?? "") ?? .percent } set { self.menuBarDisplayModeRaw = newValue.rawValue } } var menuBarShowsResetTimeWhenExhausted: Bool { get { self.defaultsState.menuBarShowsResetTimeWhenExhausted } set { self.defaultsState.menuBarShowsResetTimeWhenExhausted = newValue self.userDefaults.set(newValue, forKey: "menuBarShowsResetTimeWhenExhausted") } } private var kiroMenuBarDisplayModeRaw: String? { get { self.defaultsState.kiroMenuBarDisplayModeRaw } set { self.defaultsState.kiroMenuBarDisplayModeRaw = newValue if let raw = newValue { self.userDefaults.set(raw, forKey: "kiroMenuBarDisplayMode") } else { self.userDefaults.removeObject(forKey: "kiroMenuBarDisplayMode") } } } var kiroMenuBarDisplayMode: KiroMenuBarDisplayMode { get { KiroMenuBarDisplayMode(rawValue: self.kiroMenuBarDisplayModeRaw ?? "") ?? .automatic } set { self.kiroMenuBarDisplayModeRaw = newValue.rawValue } } var multiAccountMenuLayout: MultiAccountMenuLayout { get { MultiAccountMenuLayout(rawValue: self.defaultsState.multiAccountMenuLayoutRaw) ?? .segmented } set { self.defaultsState.multiAccountMenuLayoutRaw = newValue.rawValue self.userDefaults.set(newValue.rawValue, forKey: "multiAccountMenuLayout") self.noteBackgroundWorkSettingsChanged() } } var showAllTokenAccountsInMenu: Bool { get { self.multiAccountMenuLayout == .stacked } set { self.multiAccountMenuLayout = newValue ? .stacked : .segmented } } var historicalTrackingEnabled: Bool { get { self.defaultsState.historicalTrackingEnabled } set { self.defaultsState.historicalTrackingEnabled = newValue self.userDefaults.set(newValue, forKey: "historicalTrackingEnabled") self.noteBackgroundWorkSettingsChanged() } } var menuBarMetricPreferencesRaw: [String: String] { get { self.defaultsState.menuBarMetricPreferencesRaw } set { self.defaultsState.menuBarMetricPreferencesRaw = newValue self.userDefaults.set(newValue, forKey: "menuBarMetricPreferences") } } var menuBarLayout: MenuBarLayout { get { self.defaultsState.storedMenuBarLayout ?? MenuBarLayout.migrated( iconStyle: self.menuBarIconStyle, displayMode: self.menuBarDisplayMode, metricPreference: .automatic, resetTimeDisplayStyle: self.resetTimeDisplayStyle) } set { self.defaultsState.storedMenuBarLayout = newValue self.persistMenuBarLayout(newValue, key: "menuBarLayout") } } var hasStoredMenuBarLayout: Bool { self.defaultsState.storedMenuBarLayout != nil } var menuBarLayoutOverrides: [UsageProvider: MenuBarLayout] { Dictionary(uniqueKeysWithValues: self.defaultsState.menuBarLayoutOverridesRaw.compactMap { key, value in UsageProvider(rawValue: key).map { ($0, value) } }) } func menuBarLayout(for provider: UsageProvider) -> MenuBarLayout { self.menuBarLayoutResolution(for: provider).layout } func menuBarLayoutForGlobalEditing(representativeProvider: UsageProvider?) -> MenuBarLayout { if let stored = self.defaultsState.storedMenuBarLayout { return stored } guard let representativeProvider else { return self.menuBarLayout } return self.menuBarLayoutResolution(for: representativeProvider).layout } func menuBarLayoutResolution(for provider: UsageProvider) -> MenuBarLayoutResolution { if let override = self.defaultsState.menuBarLayoutOverridesRaw[provider.rawValue] { return .stored(override) } if let stored = self.defaultsState.storedMenuBarLayout { return .stored(stored) } return .legacy( iconStyle: self.menuBarIconStyle, displayMode: self.menuBarDisplayMode, metricPreference: self.menuBarMetricPreference(for: provider), resetTimeDisplayStyle: self.resetTimeDisplayStyle, provider: provider) } func setMenuBarLayout(_ layout: MenuBarLayout, for provider: UsageProvider?) { if let provider { self.defaultsState.menuBarLayoutOverridesRaw[provider.rawValue] = layout self.persistMenuBarLayoutOverrides() } else { self.menuBarLayout = layout } } func removeMenuBarLayoutOverride(for provider: UsageProvider) { guard self.defaultsState.menuBarLayoutOverridesRaw.removeValue(forKey: provider.rawValue) != nil else { return } self.persistMenuBarLayoutOverrides() } var menuBarLayoutSize: MenuBarLayoutSize { get { MenuBarLayoutSize(rawValue: self.defaultsState.menuBarLayoutSizeRaw) ?? .regular } set { self.defaultsState.menuBarLayoutSizeRaw = newValue.rawValue self.userDefaults.set(newValue.rawValue, forKey: "menuBarLayoutSize") } } var menuBarLayoutGap: MenuBarLayoutGap { get { MenuBarLayoutGap(rawValue: self.defaultsState.menuBarLayoutGapRaw) ?? .regular } set { self.defaultsState.menuBarLayoutGapRaw = newValue.rawValue self.userDefaults.set(newValue.rawValue, forKey: "menuBarLayoutGap") } } private func persistMenuBarLayout(_ layout: MenuBarLayout, key: String) { guard let data = try? JSONEncoder().encode(layout) else { return } self.userDefaults.set(data, forKey: key) } private func persistMenuBarLayoutOverrides() { guard let data = try? JSONEncoder().encode(self.defaultsState.menuBarLayoutOverridesRaw) else { return } self.userDefaults.set(data, forKey: "menuBarLayoutOverrides") } var copilotIconSecondaryWindowIDRaw: String { get { self.defaultsState.copilotIconSecondaryWindowIDRaw } set { self.defaultsState.copilotIconSecondaryWindowIDRaw = newValue self.userDefaults.set(newValue, forKey: "copilotIconSecondaryWindowID") } } var costUsageEnabled: Bool { get { self.defaultsState.costUsageEnabled } set { let changed = self.defaultsState.costUsageEnabled != newValue self.defaultsState.costUsageEnabled = newValue self.userDefaults.set(newValue, forKey: "tokenCostUsageEnabled") if changed { self.costUsageSettingsRevision &+= 1 }Lines 1–500 of 1015. Load more
import CodexBarCore import Foundation import ServiceManagement extension SettingsStore { private static let mergedOverviewSelectionEditedActiveProvidersKey = "mergedOverviewSelectionEditedActiveProviders" func noteBackgroundWorkSettingsChanged() { self.backgroundWorkSettingsRevision &+= 1 } var refreshFrequency: RefreshFrequency { get { self.defaultsState.refreshFrequency } set { let previousValue = self.defaultsState.refreshFrequency if newValue == .adaptiveAgentAware, previousValue != .adaptiveAgentAware, self.defaultsState.adaptiveActivityScanConsent == .declined { self.defaultsState.adaptiveActivityScanConsent = .undecided self.userDefaults.set( AdaptiveActivityScanConsent.undecided.rawValue, forKey: "adaptiveActivityScanConsent") } self.defaultsState.refreshFrequency = newValue self.userDefaults.set(newValue.rawValue, forKey: "refreshFrequency") self.noteBackgroundWorkSettingsChanged() } } var adaptiveActivityScanConsent: AdaptiveActivityScanConsent { get { self.defaultsState.adaptiveActivityScanConsent } set { self.defaultsState.adaptiveActivityScanConsent = newValue self.userDefaults.set(newValue.rawValue, forKey: "adaptiveActivityScanConsent") self.noteBackgroundWorkSettingsChanged() } } var adaptiveActivityScanningEnabled: Bool { self.refreshFrequency == .adaptiveAgentAware && self.adaptiveActivityScanConsent == .allowed } var shouldRequestAdaptiveActivityScanConsent: Bool { self.refreshFrequency == .adaptiveAgentAware && self.adaptiveActivityScanConsent == .undecided } /// When enabled, keeping the menu open through its short refresh delay fetches usage for every /// enabled provider. The periodic refresh clock remains unchanged. See `scheduleOpenMenuRefresh`. var refreshAllProvidersOnMenuOpen: Bool { get { self.defaultsState.refreshAllProvidersOnMenuOpen } set { self.defaultsState.refreshAllProvidersOnMenuOpen = newValue self.userDefaults.set(newValue, forKey: "refreshAllProvidersOnMenuOpen") } } var launchAtLogin: Bool { get { self.defaultsState.launchAtLogin } set { self.defaultsState.launchAtLogin = newValue self.userDefaults.set(newValue, forKey: "launchAtLogin") LaunchAtLoginManager.setEnabled(newValue) } } var debugMenuEnabled: Bool { get { self.defaultsState.debugMenuEnabled } set { self.defaultsState.debugMenuEnabled = newValue self.userDefaults.set(newValue, forKey: "debugMenuEnabled") } } var debugDisableKeychainAccess: Bool { get { self.defaultsState.debugDisableKeychainAccess } set { self.defaultsState.debugDisableKeychainAccess = newValue self.userDefaults.set(newValue, forKey: "debugDisableKeychainAccess") if Self.shouldBridgeSharedDefaults(for: self.userDefaults) { Self.sharedDefaults?.set(newValue, forKey: "debugDisableKeychainAccess") } KeychainAccessGate.isDisabled = newValue self.noteBackgroundWorkSettingsChanged() } } var debugFileLoggingEnabled: Bool { get { self.defaultsState.debugFileLoggingEnabled } set { self.defaultsState.debugFileLoggingEnabled = newValue self.userDefaults.set(newValue, forKey: "debugFileLoggingEnabled") CodexBarLog.setFileLoggingEnabled(newValue) } } var debugLogLevel: CodexBarLog.Level { get { let raw = self.defaultsState.debugLogLevelRaw return CodexBarLog.parseLevel(raw) ?? .verbose } set { self.defaultsState.debugLogLevelRaw = newValue.rawValue self.userDefaults.set(newValue.rawValue, forKey: "debugLogLevel") CodexBarLog.setLogLevel(newValue) } } var debugKeepCLISessionsAlive: Bool { get { self.defaultsState.debugKeepCLISessionsAlive } set { self.defaultsState.debugKeepCLISessionsAlive = newValue self.userDefaults.set(newValue, forKey: "debugKeepCLISessionsAlive") self.noteBackgroundWorkSettingsChanged() } } var isVerboseLoggingEnabled: Bool { self.debugLogLevel.rank <= CodexBarLog.Level.verbose.rank } private var debugLoadingPatternRaw: String? { get { self.defaultsState.debugLoadingPatternRaw } set { self.defaultsState.debugLoadingPatternRaw = newValue if let raw = newValue { self.userDefaults.set(raw, forKey: "debugLoadingPattern") } else { self.userDefaults.removeObject(forKey: "debugLoadingPattern") } } } var statusChecksEnabled: Bool { get { self.defaultsState.statusChecksEnabled } set { self.defaultsState.statusChecksEnabled = newValue self.userDefaults.set(newValue, forKey: "statusChecksEnabled") self.noteBackgroundWorkSettingsChanged() } } var sessionQuotaNotificationsEnabled: Bool { get { self.defaultsState.sessionQuotaNotificationsEnabled } set { self.defaultsState.sessionQuotaNotificationsEnabled = newValue self.userDefaults.set(newValue, forKey: "sessionQuotaNotificationsEnabled") self.noteBackgroundWorkSettingsChanged() } } var quotaWarningNotificationsEnabled: Bool { get { self.defaultsState.quotaWarningNotificationsEnabled } set { self.defaultsState.quotaWarningNotificationsEnabled = newValue self.userDefaults.set(newValue, forKey: "quotaWarningNotificationsEnabled") self.noteBackgroundWorkSettingsChanged() } } var predictivePaceWarningNotificationsEnabled: Bool { get { self.defaultsState.predictivePaceWarningNotificationsEnabled } set { guard self.defaultsState.predictivePaceWarningNotificationsEnabled != newValue else { return } self.defaultsState.predictivePaceWarningNotificationsEnabled = newValue self.userDefaults.set(newValue, forKey: "predictivePaceWarningNotificationsEnabled") self.noteBackgroundWorkSettingsChanged() } } var quotaWarningThresholds: [Int] { get { QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningThresholdsRaw) } set { let sanitized = QuotaWarningThresholds.sanitized(newValue) guard QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningThresholdsRaw) != sanitized || QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningSessionThresholdsRaw) != sanitized || QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningWeeklyThresholdsRaw) != sanitized else { return } self.defaultsState.quotaWarningThresholdsRaw = sanitized self.defaultsState.quotaWarningSessionThresholdsRaw = sanitized self.defaultsState.quotaWarningWeeklyThresholdsRaw = sanitized self.userDefaults.set(sanitized, forKey: "quotaWarningThresholds") self.userDefaults.set(sanitized, forKey: "quotaWarningSessionThresholds") self.userDefaults.set(sanitized, forKey: "quotaWarningWeeklyThresholds") self.noteBackgroundWorkSettingsChanged() } } func quotaWarningThresholds(_ window: QuotaWarningWindow) -> [Int] { switch window { case .session: QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningSessionThresholdsRaw) case .weekly: QuotaWarningThresholds.sanitized(self.defaultsState.quotaWarningWeeklyThresholdsRaw) } } func setQuotaWarningThresholds(_ window: QuotaWarningWindow, thresholds: [Int]) { let sanitized = QuotaWarningThresholds.sanitized(thresholds) guard self.quotaWarningThresholds(window) != sanitized else { return } switch window { case .session: self.defaultsState.quotaWarningSessionThresholdsRaw = sanitized self.userDefaults.set(sanitized, forKey: "quotaWarningSessionThresholds") case .weekly: self.defaultsState.quotaWarningWeeklyThresholdsRaw = sanitized self.userDefaults.set(sanitized, forKey: "quotaWarningWeeklyThresholds") } self.noteBackgroundWorkSettingsChanged() } func quotaWarningWindowEnabled(_ window: QuotaWarningWindow) -> Bool { switch window { case .session: self.defaultsState.quotaWarningSessionEnabled case .weekly: self.defaultsState.quotaWarningWeeklyEnabled } } func setQuotaWarningWindowEnabled(_ window: QuotaWarningWindow, enabled: Bool) { switch window { case .session: self.defaultsState.quotaWarningSessionEnabled = enabled self.userDefaults.set(enabled, forKey: "quotaWarningSessionEnabled") case .weekly: self.defaultsState.quotaWarningWeeklyEnabled = enabled self.userDefaults.set(enabled, forKey: "quotaWarningWeeklyEnabled") } self.noteBackgroundWorkSettingsChanged() } var quotaWarningSoundEnabled: Bool { get { self.defaultsState.quotaWarningSoundEnabled } set { self.defaultsState.quotaWarningSoundEnabled = newValue self.userDefaults.set(newValue, forKey: "quotaWarningSoundEnabled") self.noteBackgroundWorkSettingsChanged() } } var quotaWarningOnScreenAlertEnabled: Bool { get { self.defaultsState.quotaWarningOnScreenAlertEnabled } set { self.defaultsState.quotaWarningOnScreenAlertEnabled = newValue self.userDefaults.set(newValue, forKey: "quotaWarningOnScreenAlertEnabled") } } var quotaWarningMarkersVisible: Bool { get { self.defaultsState.quotaWarningMarkersVisible } set { self.defaultsState.quotaWarningMarkersVisible = newValue self.userDefaults.set(newValue, forKey: "quotaWarningMarkersVisible") } } var weeklyProgressWorkDays: Int? { get { self.defaultsState.weeklyProgressWorkDays } set { self.defaultsState.weeklyProgressWorkDays = newValue if let newValue { self.userDefaults.set(newValue, forKey: "weeklyProgressWorkDays") } else { self.userDefaults.removeObject(forKey: "weeklyProgressWorkDays") } } } var usageBarsShowUsed: Bool { get { self.defaultsState.usageBarsShowUsed } set { self.defaultsState.usageBarsShowUsed = newValue self.userDefaults.set(newValue, forKey: "usageBarsShowUsed") } } var resetTimesShowAbsolute: Bool { get { self.defaultsState.resetTimesShowAbsolute } set { self.defaultsState.resetTimesShowAbsolute = newValue self.userDefaults.set(newValue, forKey: "resetTimesShowAbsolute") } } var providerChangelogLinksEnabled: Bool { get { self.defaultsState.providerChangelogLinksEnabled } set { self.defaultsState.providerChangelogLinksEnabled = newValue self.userDefaults.set(newValue, forKey: "providerChangelogLinksEnabled") } } var menuBarShowsBrandIconWithPercent: Bool { get { self.defaultsState.menuBarShowsBrandIconWithPercent } set { self.defaultsState.menuBarShowsBrandIconWithPercent = newValue self.userDefaults.set(newValue, forKey: "menuBarShowsBrandIconWithPercent") } } var menuBarHidesCritters: Bool { get { self.defaultsState.menuBarHidesCritters } set { self.defaultsState.menuBarHidesCritters = newValue self.userDefaults.set(newValue, forKey: "menuBarHidesCritters") } } var menuBarHighContrastOnInactiveDisplays: Bool { get { self.defaultsState.menuBarHighContrastOnInactiveDisplays } set { self.defaultsState.menuBarHighContrastOnInactiveDisplays = newValue self.userDefaults.set(newValue, forKey: "menuBarHighContrastOnInactiveDisplays") } } private var menuBarDisplayModeRaw: String? { get { self.defaultsState.menuBarDisplayModeRaw } set { self.defaultsState.menuBarDisplayModeRaw = newValue if let raw = newValue { self.userDefaults.set(raw, forKey: "menuBarDisplayMode") } else { self.userDefaults.removeObject(forKey: "menuBarDisplayMode") } } } var menuBarDisplayMode: MenuBarDisplayMode { get { MenuBarDisplayMode(rawValue: self.menuBarDisplayModeRaw ?? "") ?? .percent } set { self.menuBarDisplayModeRaw = newValue.rawValue } } var menuBarShowsResetTimeWhenExhausted: Bool { get { self.defaultsState.menuBarShowsResetTimeWhenExhausted } set { self.defaultsState.menuBarShowsResetTimeWhenExhausted = newValue self.userDefaults.set(newValue, forKey: "menuBarShowsResetTimeWhenExhausted") } } private var kiroMenuBarDisplayModeRaw: String? { get { self.defaultsState.kiroMenuBarDisplayModeRaw } set { self.defaultsState.kiroMenuBarDisplayModeRaw = newValue if let raw = newValue { self.userDefaults.set(raw, forKey: "kiroMenuBarDisplayMode") } else { self.userDefaults.removeObject(forKey: "kiroMenuBarDisplayMode") } } } var kiroMenuBarDisplayMode: KiroMenuBarDisplayMode { get { KiroMenuBarDisplayMode(rawValue: self.kiroMenuBarDisplayModeRaw ?? "") ?? .automatic } set { self.kiroMenuBarDisplayModeRaw = newValue.rawValue } } var multiAccountMenuLayout: MultiAccountMenuLayout { get { MultiAccountMenuLayout(rawValue: self.defaultsState.multiAccountMenuLayoutRaw) ?? .segmented } set { self.defaultsState.multiAccountMenuLayoutRaw = newValue.rawValue self.userDefaults.set(newValue.rawValue, forKey: "multiAccountMenuLayout") self.noteBackgroundWorkSettingsChanged() } } var showAllTokenAccountsInMenu: Bool { get { self.multiAccountMenuLayout == .stacked } set { self.multiAccountMenuLayout = newValue ? .stacked : .segmented } } var historicalTrackingEnabled: Bool { get { self.defaultsState.historicalTrackingEnabled } set { self.defaultsState.historicalTrackingEnabled = newValue self.userDefaults.set(newValue, forKey: "historicalTrackingEnabled") self.noteBackgroundWorkSettingsChanged() } } var menuBarMetricPreferencesRaw: [String: String] { get { self.defaultsState.menuBarMetricPreferencesRaw } set { self.defaultsState.menuBarMetricPreferencesRaw = newValue self.userDefaults.set(newValue, forKey: "menuBarMetricPreferences") } } var menuBarLayout: MenuBarLayout { get { self.defaultsState.storedMenuBarLayout ?? MenuBarLayout.migrated( iconStyle: self.menuBarIconStyle, displayMode: self.menuBarDisplayMode, metricPreference: .automatic, resetTimeDisplayStyle: self.resetTimeDisplayStyle) } set { self.defaultsState.storedMenuBarLayout = newValue self.persistMenuBarLayout(newValue, key: "menuBarLayout") } } var hasStoredMenuBarLayout: Bool { self.defaultsState.storedMenuBarLayout != nil } var menuBarLayoutOverrides: [UsageProvider: MenuBarLayout] { Dictionary(uniqueKeysWithValues: self.defaultsState.menuBarLayoutOverridesRaw.compactMap { key, value in UsageProvider(rawValue: key).map { ($0, value) } }) } func menuBarLayout(for provider: UsageProvider) -> MenuBarLayout { self.menuBarLayoutResolution(for: provider).layout } func menuBarLayoutForGlobalEditing(representativeProvider: UsageProvider?) -> MenuBarLayout { if let stored = self.defaultsState.storedMenuBarLayout { return stored } guard let representativeProvider else { return self.menuBarLayout } return self.menuBarLayoutResolution(for: representativeProvider).layout } func menuBarLayoutResolution(for provider: UsageProvider) -> MenuBarLayoutResolution { if let override = self.defaultsState.menuBarLayoutOverridesRaw[provider.rawValue] { return .stored(override) } if let stored = self.defaultsState.storedMenuBarLayout { return .stored(stored) } return .legacy( iconStyle: self.menuBarIconStyle, displayMode: self.menuBarDisplayMode, metricPreference: self.menuBarMetricPreference(for: provider), resetTimeDisplayStyle: self.resetTimeDisplayStyle, provider: provider) } func setMenuBarLayout(_ layout: MenuBarLayout, for provider: UsageProvider?) { if let provider { self.defaultsState.menuBarLayoutOverridesRaw[provider.rawValue] = layout self.persistMenuBarLayoutOverrides() } else { self.menuBarLayout = layout } } func removeMenuBarLayoutOverride(for provider: UsageProvider) { guard self.defaultsState.menuBarLayoutOverridesRaw.removeValue(forKey: provider.rawValue) != nil else { return } self.persistMenuBarLayoutOverrides() } var menuBarLayoutSize: MenuBarLayoutSize { get { MenuBarLayoutSize(rawValue: self.defaultsState.menuBarLayoutSizeRaw) ?? .regular } set { self.defaultsState.menuBarLayoutSizeRaw = newValue.rawValue self.userDefaults.set(newValue.rawValue, forKey: "menuBarLayoutSize") } } var menuBarLayoutGap: MenuBarLayoutGap { get { MenuBarLayoutGap(rawValue: self.defaultsState.menuBarLayoutGapRaw) ?? .regular } set { self.defaultsState.menuBarLayoutGapRaw = newValue.rawValue self.userDefaults.set(newValue.rawValue, forKey: "menuBarLayoutGap") } } private func persistMenuBarLayout(_ layout: MenuBarLayout, key: String) { guard let data = try? JSONEncoder().encode(layout) else { return } self.userDefaults.set(data, forKey: key) } private func persistMenuBarLayoutOverrides() { guard let data = try? JSONEncoder().encode(self.defaultsState.menuBarLayoutOverridesRaw) else { return } self.userDefaults.set(data, forKey: "menuBarLayoutOverrides") } var copilotIconSecondaryWindowIDRaw: String { get { self.defaultsState.copilotIconSecondaryWindowIDRaw } set { self.defaultsState.copilotIconSecondaryWindowIDRaw = newValue self.userDefaults.set(newValue, forKey: "copilotIconSecondaryWindowID") } } var costUsageEnabled: Bool { get { self.defaultsState.costUsageEnabled } set { let changed = self.defaultsState.costUsageEnabled != newValue self.defaultsState.costUsageEnabled = newValue self.userDefaults.set(newValue, forKey: "tokenCostUsageEnabled") if changed { self.costUsageSettingsRevision &+= 1 }