From ce0e1eb116fec1a2fece032f8b636ad7ca4ddd37 Mon Sep 17 00:00:00 2001 From: iamtoruk Date: Mon, 11 May 2026 11:05:50 -0700 Subject: [PATCH] Make menubar refresh now reset stale state --- mac/Sources/CodeBurnMenubar/AppStore.swift | 11 ++++++ mac/Sources/CodeBurnMenubar/CodeBurnApp.swift | 36 +++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/mac/Sources/CodeBurnMenubar/AppStore.swift b/mac/Sources/CodeBurnMenubar/AppStore.swift index 00b27e8..38d370a 100644 --- a/mac/Sources/CodeBurnMenubar/AppStore.swift +++ b/mac/Sources/CodeBurnMenubar/AppStore.swift @@ -140,6 +140,17 @@ final class AppStore { inFlightKeys.removeAll() } + func resetRefreshState(clearCache: Bool = false) { + switchTask?.cancel() + switchTask = nil + resetLoadingState() + attemptedKeys.removeAll() + lastErrorByKey.removeAll() + if clearCache { + cache.removeAll() + } + } + private let loadingWatchdogSeconds: TimeInterval = 60 @discardableResult diff --git a/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift b/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift index 704c7fd..29ad39c 100644 --- a/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift +++ b/mac/Sources/CodeBurnMenubar/CodeBurnApp.swift @@ -39,6 +39,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate { private var forceRefreshTask: Task? private var forceRefreshStartedAt: Date? private var forceRefreshGeneration: UInt64 = 0 + private var manualRefreshTask: Task? + private var manualRefreshGeneration: UInt64 = 0 func applicationWillFinishLaunching(_ notification: Notification) { // Set accessory policy before the app's focus chain forms. On macOS Tahoe @@ -95,6 +97,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate { self?.forceRefreshTask = nil self?.forceRefreshStartedAt = nil self?.forceRefreshGeneration &+= 1 + self?.manualRefreshTask?.cancel() + self?.manualRefreshTask = nil + self?.manualRefreshGeneration &+= 1 self?.store.resetLoadingState() self?.refreshLoopTask?.cancel() self?.refreshLoopTask = nil @@ -349,17 +354,44 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate { @MainActor func refreshSubscriptionNow() { - Task { [weak self] in + manualRefreshTask?.cancel() + manualRefreshGeneration &+= 1 + let generation = manualRefreshGeneration + forceRefreshTask?.cancel() + forceRefreshTask = nil + forceRefreshStartedAt = nil + forceRefreshGeneration &+= 1 + pendingRefreshWork?.cancel() + pendingRefreshWork = nil + refreshLoopTask?.cancel() + refreshLoopTask = nil + store.resetRefreshState(clearCache: true) + lastRefreshTime = .distantPast + refreshStatusButton() + + manualRefreshTask = Task { [weak self] in guard let self else { return } // "Refresh Now" should refresh the menubar payload AND every - // connected provider's live quota — the user's intent is "make + // connected provider's live quota. The user's intent is "make // this match reality right now." + let needsTodayTotal = self.store.selectedPeriod != .today || self.store.selectedProvider != .all async let payload: Void = self.store.refresh(includeOptimize: false, force: true, showLoading: true) async let claude: Bool = self.store.refreshSubscriptionReportingSuccess() async let codex: Bool = self.store.refreshCodexReportingSuccess() + if needsTodayTotal { + await self.store.refreshQuietly(period: .today) + } _ = await payload + guard self.manualRefreshGeneration == generation, !Task.isCancelled else { return } + self.lastRefreshTime = Date() + self.refreshStatusButton() if await claude { self.lastSubscriptionRefreshAt = Date() } if await codex { self.lastCodexRefreshAt = Date() } + guard self.manualRefreshGeneration == generation, !Task.isCancelled else { return } + self.manualRefreshTask = nil + if self.refreshLoopTask == nil { + self.startRefreshLoop() + } } }