Skip to content

Commit 8adc2c7

Browse files
authored
fix: coalesce deferred menu refreshes (#1483)
1 parent 581f8b0 commit 8adc2c7

3 files changed

Lines changed: 21 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## 0.34.1 — Unreleased
44

5+
- Menu bar: avoid starting a duplicate background provider refresh when the menu closes while its initial missing-data refresh is still in flight.
56
- Menu bar: rebuild merged provider content inside AppKit's active tracking run loop so provider switches no longer wait for the menu to close or the default run loop to resume.
67
- Diagnostics: enforce probe timeouts even when an underlying provider operation ignores Swift task cancellation.
78
- Kimi: add usage fetching from the official Code API key flow, with optional compatible HTTPS proxy support (#1424). Thanks @kiranmagic7!

Sources/CodexBar/StatusItemController+MenuInteractionRefresh.swift

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ extension StatusItemController {
124124
self.deferredMenuInteractionRefreshTask = nil
125125
return
126126
}
127+
let pendingProviders = self.deferredMenuInteractionRefreshProviders
128+
let hasProviderRefreshInFlight = pendingProviders.contains {
129+
self.store.refreshingProviders.contains($0)
130+
}
131+
guard !self.store.isRefreshing, !hasProviderRefreshInFlight else {
132+
self.deferredMenuInteractionRefreshTask = nil
133+
self.scheduleDeferredMenuInteractionRefreshIfNeeded(
134+
delay: Self.defaultDeferredMenuInteractionRefreshDelay)
135+
return
136+
}
137+
self.clearSatisfiedDeferredMenuInteractionRefreshes(for: Array(pendingProviders))
127138
let shouldRefreshStore = self.deferredMenuInteractionRefreshPending
128139
let openAIDashboardRefreshReason = self.deferredOpenAIDashboardRefreshReason
129140
guard shouldRefreshStore || openAIDashboardRefreshReason != nil else {
@@ -134,13 +145,6 @@ extension StatusItemController {
134145
self.deferredMenuInteractionRefreshTask = nil
135146
return
136147
}
137-
guard !self.store.isRefreshing else {
138-
self.deferredMenuInteractionRefreshTask = nil
139-
self
140-
.scheduleDeferredMenuInteractionRefreshIfNeeded(delay: Self
141-
.defaultDeferredMenuInteractionRefreshDelay)
142-
return
143-
}
144148
self.deferredMenuInteractionRefreshTask = nil
145149
self.deferredMenuInteractionRefreshProviders.removeAll()
146150
self.deferredOpenAIDashboardRefreshReason = nil

Tests/CodexBarTests/StatusMenuInstantOpenTests.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,11 +1298,19 @@ extension StatusMenuTests {
12981298
defer { StatusItemController.resetDeferredMenuInteractionRefreshDelayForTesting() }
12991299
StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
13001300
defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }
1301+
var deferredRefreshCount = 0
1302+
controller.onDeferredMenuInteractionRefreshForTesting = {
1303+
deferredRefreshCount += 1
1304+
}
13011305

13021306
let menu = controller.makeMenu()
13031307
controller.menuWillOpen(menu)
13041308
await refreshGate.waitUntilStarted(count: 1)
13051309
controller.menuDidClose(menu)
1310+
for _ in 0..<80 {
1311+
await Task.yield()
1312+
}
1313+
#expect(deferredRefreshCount == 0)
13061314
await refreshGate.releaseFirst()
13071315

13081316
for _ in 0..<80 where controller.deferredMenuInteractionRefreshPending {
@@ -1313,6 +1321,7 @@ extension StatusMenuTests {
13131321
}
13141322

13151323
#expect(await refreshGate.startCount == 1)
1324+
#expect(deferredRefreshCount == 0)
13161325
#expect(!controller.deferredMenuInteractionRefreshPending)
13171326
}
13181327

0 commit comments

Comments
 (0)