diff --git a/Sources/CodexBar/StatusItemController+Menu.swift b/Sources/CodexBar/StatusItemController+Menu.swift index 225331c5b2..fa2367fb25 100644 --- a/Sources/CodexBar/StatusItemController+Menu.swift +++ b/Sources/CodexBar/StatusItemController+Menu.swift @@ -165,7 +165,7 @@ extension StatusItemController { if !isPersistentMenu { self.menuProviders.removeValue(forKey: key) self.menuVersions.removeValue(forKey: key) - } else if self.menuNeedsRefresh(menu) { + } else if Self.isClosedMenuPreparationEnabled, self.menuNeedsRefresh(menu) { self.rebuildClosedMenuIfNeeded(menu) } self.parentMenuRebuildsDeferredDuringTracking.remove(key) diff --git a/Sources/CodexBar/StatusItemController+MenuTracking.swift b/Sources/CodexBar/StatusItemController+MenuTracking.swift index 4922f9cc6a..c5f7004df3 100644 --- a/Sources/CodexBar/StatusItemController+MenuTracking.swift +++ b/Sources/CodexBar/StatusItemController+MenuTracking.swift @@ -3,9 +3,12 @@ import CodexBarCore extension StatusItemController { private static let defaultClosedMenuPreparationDelay: Duration = .milliseconds(350) + private static let defaultClosedMenuPreparationEnabled = false // Avoid idle SwiftUI layout work. #if DEBUG private static var closedMenuPreparationDelayForTesting: Duration = defaultClosedMenuPreparationDelay + private static var closedMenuPreparationEnabledForTesting = defaultClosedMenuPreparationEnabled + static func setClosedMenuPreparationDelayForTesting(_ delay: Duration) { self.closedMenuPreparationDelayForTesting = delay } @@ -13,6 +16,14 @@ extension StatusItemController { static func resetClosedMenuPreparationDelayForTesting() { self.closedMenuPreparationDelayForTesting = self.defaultClosedMenuPreparationDelay } + + static func setClosedMenuPreparationEnabledForTesting(_ enabled: Bool) { + self.closedMenuPreparationEnabledForTesting = enabled + } + + static func resetClosedMenuPreparationEnabledForTesting() { + self.closedMenuPreparationEnabledForTesting = self.defaultClosedMenuPreparationEnabled + } #endif private static var closedMenuPreparationDelay: Duration { @@ -23,6 +34,14 @@ extension StatusItemController { #endif } + static var isClosedMenuPreparationEnabled: Bool { + #if DEBUG + closedMenuPreparationEnabledForTesting + #else + defaultClosedMenuPreparationEnabled + #endif + } + func invalidateMenus( refreshOpenMenus: Bool = false, deferOpenParentMenuRebuild: Bool = false, @@ -49,6 +68,7 @@ extension StatusItemController { func prepareAttachedClosedMenusIfNeeded() { guard self.isMenuRefreshEnabled else { return } + guard Self.isClosedMenuPreparationEnabled else { return } guard self.openMenus.isEmpty else { return } guard !self.isMenuDataRefreshInFlight else { return } for menu in self.attachedMenusForClosedPreparation() { diff --git a/Tests/CodexBarTests/ProviderSettingsDescriptorTests.swift b/Tests/CodexBarTests/ProviderSettingsDescriptorTests.swift index 43ae2fe0e4..a5ab477812 100644 --- a/Tests/CodexBarTests/ProviderSettingsDescriptorTests.swift +++ b/Tests/CodexBarTests/ProviderSettingsDescriptorTests.swift @@ -63,7 +63,7 @@ struct ProviderSettingsDescriptorTests { } @Test - func `codex exposes open AI web extras toggle as default off opt in`() throws { + func `codex exposes open AI web extras toggle as default off with battery saver off`() throws { let fixture = try self.makeSettingsFixture(suite: "ProviderSettingsDescriptorTests-codex-openai-toggle") let context = fixture.settingsContext(provider: .codex) diff --git a/Tests/CodexBarTests/SettingsStoreTests.swift b/Tests/CodexBarTests/SettingsStoreTests.swift index 7c3b70790d..bffbc6a802 100644 --- a/Tests/CodexBarTests/SettingsStoreTests.swift +++ b/Tests/CodexBarTests/SettingsStoreTests.swift @@ -1000,11 +1000,11 @@ struct SettingsStoreTests { #expect(store.openAIWebBatterySaverEnabled == false) - store.openAIWebBatterySaverEnabled = false - #expect(defaults.bool(forKey: "openAIWebBatterySaverEnabled") == false) + store.openAIWebBatterySaverEnabled = true + #expect(defaults.bool(forKey: "openAIWebBatterySaverEnabled") == true) store.openAIWebAccessEnabled = true - #expect(store.openAIWebBatterySaverEnabled == false) + #expect(store.openAIWebBatterySaverEnabled == true) } @Test diff --git a/Tests/CodexBarTests/StatusMenuOpenRefreshTests.swift b/Tests/CodexBarTests/StatusMenuOpenRefreshTests.swift index 3d622dd3d0..c47952ffb5 100644 --- a/Tests/CodexBarTests/StatusMenuOpenRefreshTests.swift +++ b/Tests/CodexBarTests/StatusMenuOpenRefreshTests.swift @@ -169,7 +169,7 @@ extension StatusMenuTests { } @Test - func `closed attached menu is prepared before next open after invalidation`() async { + func `closed attached menu stays stale after invalidation until next open`() async { self.disableMenuCardsForTesting() let settings = self.makeSettings() settings.statusChecksEnabled = false @@ -200,11 +200,17 @@ extension StatusMenuTests { let openedVersion = controller.menuVersions[key] controller.invalidateMenus() - for _ in 0..<40 where controller.menuVersions[key] == openedVersion { + for _ in 0..<40 { await Task.yield() } #expect(controller.openMenus.isEmpty) + #expect(controller.closedMenuRebuildTasks[key] == nil) + #expect(controller.menuVersions[key] == openedVersion) + + controller.menuWillOpen(menu) + defer { controller.menuDidClose(menu) } + #expect(controller.menuVersions[key] == controller.menuContentVersion) } @@ -228,6 +234,8 @@ extension StatusMenuTests { defer { controller.releaseStatusItemsForTesting() } StatusItemController.setClosedMenuPreparationDelayForTesting(.zero) defer { StatusItemController.resetClosedMenuPreparationDelayForTesting() } + StatusItemController.setClosedMenuPreparationEnabledForTesting(true) + defer { StatusItemController.resetClosedMenuPreparationEnabledForTesting() } controller.menuRefreshEnabledOverrideForTesting = true let menu = controller.makeMenu() @@ -261,6 +269,8 @@ extension StatusMenuTests { func `closed attached menu preparation waits for token refresh to finish`() async { StatusItemController.setClosedMenuPreparationDelayForTesting(.zero) defer { StatusItemController.resetClosedMenuPreparationDelayForTesting() } + StatusItemController.setClosedMenuPreparationEnabledForTesting(true) + defer { StatusItemController.resetClosedMenuPreparationEnabledForTesting() } self.disableMenuCardsForTesting() let settings = self.makeSettings()