diff --git a/Sources/CodexBar/PreferencesMenuBarPane.swift b/Sources/CodexBar/PreferencesMenuBarPane.swift index 975fe4f65e..f1eba5ce74 100644 --- a/Sources/CodexBar/PreferencesMenuBarPane.swift +++ b/Sources/CodexBar/PreferencesMenuBarPane.swift @@ -3,7 +3,9 @@ import SwiftUI @MainActor struct MenuBarPane: View { - private static let maxOverviewProviders = SettingsStore.mergedOverviewProviderLimit + private static var maxOverviewProviders: Int { SettingsStore.mergedOverviewProviderLimit } + + @AppStorage("mergedOverviewProviderLimit") private var overviewProviderLimitSetting = 6 @State private var isOverviewProviderPopoverPresented = false @Bindable var settings: SettingsStore @@ -75,6 +77,17 @@ struct MenuBarPane: View { self.overviewProviderRow .disabled(!self.settings.mergeIcons) + + Stepper( + value: self.$overviewProviderLimitSetting, + in: 1 ... 12) { + SettingsRowLabel( + "Overview tab limit", + subtitle: "How many providers can show at once (default 6).") + Text("\(self.overviewProviderLimitSetting)") + .foregroundStyle(.secondary) + } + .disabled(!self.settings.mergeIcons) } header: { Text(L("section_combined_icon")) } diff --git a/Sources/CodexBar/SettingsStore.swift b/Sources/CodexBar/SettingsStore.swift index 62e5dc17e1..fc25401d97 100644 --- a/Sources/CodexBar/SettingsStore.swift +++ b/Sources/CodexBar/SettingsStore.swift @@ -188,7 +188,22 @@ enum CodexAccountMenuProjectionRevalidationResult: Equatable { @Observable final class SettingsStore { static let sharedDefaults = AppGroupSupport.sharedDefaults() - static let mergedOverviewProviderLimit = 6 + /// User-configurable cap on how many providers render in the merged-icon + /// Overview tab. Used as a default-parameter value elsewhere in this file, + /// which Swift requires to be self-independent — hence `static var` (backed + /// by UserDefaults.standard, the same store `@AppStorage` targets) instead + /// of an instance property on `defaultsState`. Default matches the + /// original hardcoded value so existing users see no behavior change + /// unless they raise it. + static var mergedOverviewProviderLimit: Int { + get { + let stored = UserDefaults.standard.integer(forKey: "mergedOverviewProviderLimit") + return stored > 0 ? stored : 6 + } + set { + UserDefaults.standard.set(max(1, newValue), forKey: "mergedOverviewProviderLimit") + } + } static let productionCodexAccountReconciliationSnapshotCacheInterval: TimeInterval = 2 static let isRunningTests: Bool = { let env = ProcessInfo.processInfo.environment diff --git a/Sources/CodexBar/StatusItemController+Menu.swift b/Sources/CodexBar/StatusItemController+Menu.swift index f5d0eaa43c..5081cee1fe 100644 --- a/Sources/CodexBar/StatusItemController+Menu.swift +++ b/Sources/CodexBar/StatusItemController+Menu.swift @@ -8,7 +8,7 @@ import SwiftUI extension StatusItemController { static let menuCardBaseWidth: CGFloat = 310 - private static let maxOverviewProviders = SettingsStore.mergedOverviewProviderLimit + private static var maxOverviewProviders: Int { SettingsStore.mergedOverviewProviderLimit } static let overviewRowIdentifierPrefix = "overviewRow-" static let persistentRefreshMenuItemID = "persistentRefreshAction" private static let defaultMenuOpenRefreshDelay: Duration = .seconds(1.2)