Skip to content

Commit b093129

Browse files
authored
fix: honor usage direction in plugin cards (#2837)
1 parent abad945 commit b093129

3 files changed

Lines changed: 49 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## 0.49.2 — Unreleased
44

55
### Fixed
6+
- Plugins: honor the “Usage bars fill” remaining/used setting in user-installed provider cards, keeping percentage labels and bar direction aligned (#2749). Thanks @RyloRiz!
67
- Sub2API: localize and group menu-card quota labels and request, token, and cost totals into a compact usage summary (#2835). Thanks @weirdo-adam!
78
- Codex: avoid repeatedly converting historical token snapshots during cost-cache refreshes, preventing sustained CPU usage on large session histories.
89

Sources/CodexBar/StatusItemController+UserPlugins.swift

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extension StatusItemController {
1818
snapshot: snapshot,
1919
error: error,
2020
isRefreshing: self.store.refreshingProviders.contains(plugin.manifest.id),
21+
showUsed: self.settings.usageBarsShowUsed,
2122
width: width,
2223
onRefresh: { [weak store = self.store] in
2324
Task { @MainActor in await store?.refreshUserPlugin(plugin.manifest.id) }
@@ -37,11 +38,25 @@ extension StatusItemController {
3738
}
3839
}
3940

41+
struct UserPluginQuotaPresentation: Equatable {
42+
let percent: Double
43+
let text: String
44+
45+
static func make(usedPercent: Double, showUsed: Bool) -> Self {
46+
let used = min(100, max(0, usedPercent))
47+
let remaining = 100 - used
48+
return Self(
49+
percent: showUsed ? used : remaining,
50+
text: UsageFormatter.usageLine(remaining: remaining, used: used, showUsed: showUsed))
51+
}
52+
}
53+
4054
private struct UserPluginMenuCardView: View {
4155
let plugin: UserProviderPlugin
4256
let snapshot: UsageSnapshot?
4357
let error: String?
4458
let isRefreshing: Bool
59+
let showUsed: Bool
4560
let width: CGFloat
4661
let onRefresh: () -> Void
4762

@@ -129,15 +144,18 @@ private struct UserPluginMenuCardView: View {
129144
@ViewBuilder
130145
private func window(_ title: String, _ window: RateWindow?) -> some View {
131146
if let window {
147+
let presentation = UserPluginQuotaPresentation.make(
148+
usedPercent: window.usedPercent,
149+
showUsed: self.showUsed)
132150
VStack(alignment: .leading, spacing: 4) {
133151
HStack {
134152
Text(title).foregroundStyle(.secondary)
135153
Spacer()
136-
Text("\(Int(window.usedPercent.rounded()))% used").monospacedDigit()
154+
Text(presentation.text).monospacedDigit()
137155
}
138156
.font(.caption)
139157
UsageProgressBar(
140-
percent: window.usedPercent,
158+
percent: presentation.percent,
141159
tint: self.tint,
142160
accessibilityLabel: "\(title) usage")
143161
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import Testing
2+
@testable import CodexBar
3+
4+
#if canImport(JavaScriptCore)
5+
struct UserPluginQuotaPresentationTests {
6+
@Test
7+
func `remaining mode aligns plugin label and bar`() {
8+
let presentation = UserPluginQuotaPresentation.make(usedPercent: 4, showUsed: false)
9+
10+
#expect(presentation.percent == 96)
11+
#expect(presentation.text == "96% left")
12+
}
13+
14+
@Test
15+
func `used mode aligns plugin label and bar`() {
16+
let presentation = UserPluginQuotaPresentation.make(usedPercent: 4, showUsed: true)
17+
18+
#expect(presentation.percent == 4)
19+
#expect(presentation.text == "4% used")
20+
}
21+
22+
@Test
23+
func `plugin percentage is clamped before presentation`() {
24+
#expect(UserPluginQuotaPresentation.make(usedPercent: -5, showUsed: true).percent == 0)
25+
#expect(UserPluginQuotaPresentation.make(usedPercent: 105, showUsed: false).percent == 0)
26+
}
27+
}
28+
#endif

0 commit comments

Comments
 (0)