Skip to content

Commit a854ed1

Browse files
authored
Merge pull request #378 from mm7894215/feat/dynamic-island-polish
feat(mac): polish Dynamic Island interaction, correctness, and menu access
2 parents 4da6910 + 856c5da commit a854ed1

19 files changed

Lines changed: 982 additions & 162 deletions

TokenTrackerBar/TokenTrackerBar/Models/LimitsSettingsStore.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Combine
33

44
extension Notification.Name {
55
static let nativeSettingsChanged = Notification.Name("NativeSettingsChanged")
6+
static let menuBarIconFrameUpdated = Notification.Name("MenuBarIconFrameUpdated")
67
}
78

89
/// How the Usage Limits panel renders utilization values.
@@ -140,6 +141,15 @@ final class LimitsSettingsStore: ObservableObject {
140141
Set(providerVisibility.filter { !$0.value }.keys)
141142
}
142143

144+
/// Formats a raw utilization percent for compact surfaces (menu bar,
145+
/// Dynamic Island wings), honoring the shared used/remaining display mode
146+
/// and rounding to the nearest integer so both surfaces always agree.
147+
static func formatPercentText(_ utilization: Double, defaults: UserDefaults = .standard) -> String {
148+
let raw = min(max(utilization, 0), 100)
149+
let displayed = readDisplayMode(from: defaults) == .remaining ? (100 - raw) : raw
150+
return "\(Int(displayed.rounded()))%"
151+
}
152+
143153
func setDisplayModeFromMenu(_ mode: LimitDisplayMode) {
144154
guard mode != displayMode else { return }
145155
applySnapshot(LimitsPreferencesSnapshot(

TokenTrackerBar/TokenTrackerBar/Models/UsageLimits.swift

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,84 @@ struct UsageLimitsResponse: Codable, Equatable {
2222
}
2323
}
2424

25+
extension UsageLimitsResponse {
26+
/// Raw utilization percent for a menu-bar metric, with the same
27+
/// configured / no-error guards the menu bar applies — so the Dynamic
28+
/// Island never shows a stale value for an unconfigured or erroring
29+
/// provider. Callers format the number (display mode, rounding) via
30+
/// `LimitsSettingsStore.formatPercentText`.
31+
func utilizationPercent(for metric: MenuBarDisplayMetric) -> Double? {
32+
func guarded(_ configured: Bool?, _ error: String?, _ value: Double?) -> Double? {
33+
guard configured == true, error == nil else { return nil }
34+
return value
35+
}
36+
switch metric {
37+
case .todayTokens, .todayCost, .last7dTokens, .totalTokens, .totalCost:
38+
return nil
39+
case .claude5h:
40+
return guarded(claude.configured, claude.error, claude.fiveHour?.utilization)
41+
case .claude7d:
42+
return guarded(claude.configured, claude.error, claude.sevenDay?.utilization)
43+
case .codex5h:
44+
return guarded(codex.configured, codex.error, codex.primaryWindow.map { Double($0.usedPercent) })
45+
case .codex7d:
46+
return guarded(codex.configured, codex.error, codex.secondaryWindow.map { Double($0.usedPercent) })
47+
case .codexCredits:
48+
return guarded(codex.configured, codex.error, codex.creditWindow?.usedPercent)
49+
case .codexSpark5h:
50+
return guarded(codex.configured, codex.error, codex.sparkPrimaryWindow.map { Double($0.usedPercent) })
51+
case .codexSpark7d:
52+
return guarded(codex.configured, codex.error, codex.sparkSecondaryWindow.map { Double($0.usedPercent) })
53+
case .cursorPlan:
54+
return guarded(cursor.configured, cursor.error, cursor.primaryWindow?.usedPercent)
55+
case .cursorAuto:
56+
return guarded(cursor.configured, cursor.error, cursor.secondaryWindow?.usedPercent)
57+
case .cursorAPI:
58+
return guarded(cursor.configured, cursor.error, cursor.tertiaryWindow?.usedPercent)
59+
case .geminiPro:
60+
return guarded(gemini.configured, gemini.error, gemini.primaryWindow?.usedPercent)
61+
case .geminiFlash:
62+
return guarded(gemini.configured, gemini.error, gemini.secondaryWindow?.usedPercent)
63+
case .geminiLite:
64+
return guarded(gemini.configured, gemini.error, gemini.tertiaryWindow?.usedPercent)
65+
case .kimiWeekly:
66+
return guarded(kimi?.configured, kimi?.error, kimi?.primaryWindow?.usedPercent)
67+
case .kimi5h:
68+
return guarded(kimi?.configured, kimi?.error, kimi?.secondaryWindow?.usedPercent)
69+
case .kimiTotal:
70+
return guarded(kimi?.configured, kimi?.error, kimi?.tertiaryWindow?.usedPercent)
71+
case .kiroMonth:
72+
return guarded(kiro.configured, kiro.error, kiro.primaryWindow?.usedPercent)
73+
case .kiroBonus:
74+
return guarded(kiro.configured, kiro.error, kiro.secondaryWindow?.usedPercent)
75+
case .grokMonth:
76+
return guarded(grok?.configured, grok?.error, grok?.primaryWindow?.usedPercent)
77+
case .grokOndemand:
78+
return guarded(grok?.configured, grok?.error, grok?.secondaryWindow?.usedPercent)
79+
case .copilotPremium:
80+
return guarded(copilot?.configured, copilot?.error, copilot?.primaryWindow?.usedPercent)
81+
case .copilotChat:
82+
return guarded(copilot?.configured, copilot?.error, copilot?.secondaryWindow?.usedPercent)
83+
case .antigravityClaudeWeekly:
84+
return guarded(antigravity.configured, antigravity.error, antigravity.primaryWindow?.usedPercent)
85+
case .antigravityClaude5h:
86+
return guarded(antigravity.configured, antigravity.error, antigravity.secondaryWindow?.usedPercent)
87+
case .antigravityGeminiWeekly:
88+
return guarded(antigravity.configured, antigravity.error, antigravity.tertiaryWindow?.usedPercent)
89+
case .antigravityGemini5h:
90+
return guarded(antigravity.configured, antigravity.error, antigravity.quaternaryWindow?.usedPercent)
91+
case .zcodeGlm52:
92+
return guarded(zcode?.configured, zcode?.error, zcode?.primaryWindow?.usedPercent)
93+
case .zcodeGlm5Turbo:
94+
return guarded(zcode?.configured, zcode?.error, zcode?.secondaryWindow?.usedPercent)
95+
case .qoderQuota:
96+
return guarded(qoder?.configured, qoder?.error, qoder?.primaryWindow?.usedPercent)
97+
case .qoderUltimate:
98+
return guarded(qoder?.configured, qoder?.error, qoder?.secondaryWindow?.usedPercent)
99+
}
100+
}
101+
}
102+
25103
enum UsageLimitsCache {
26104
static let defaultsKey = "UsageLimitsLastGoodResponse"
27105

0 commit comments

Comments
 (0)