Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
- Usage bars: render values rounded to 0% or 100% as fully empty or full. Thanks @Zihao-Qi!
- Codex web: keep cookie-import deadlines responsive when browser cookie work blocks the shared worker pool.
- z.ai: open the usage dashboard for the configured global or China API region. Thanks @renbaoshuo!
- Usage dashboards: tint inline history bars with each provider's branding color. Thanks @elijahfriedman!
- Codex pace: extrapolate historically exhausted weeks for run-out forecasts and avoid contradictory reset headlines. Thanks @Yuxin-Qiao!
- Localization: correct the German in-progress refresh label. Thanks @ChrisLauinger77!
- Localization: correct misleading literal German UI translations. Thanks @madebyjulz!
Expand Down
29 changes: 26 additions & 3 deletions Sources/CodexBar/InlineUsageDashboardContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ struct InlineUsageDashboardModel: Equatable {
let kpis: [KPI]
let points: [Point]
let detailLines: [String]
/// Provider branding color used to fill the mini usage bars. When nil the bars fall back to a
/// neutral palette derived from `valueStyle`.
var barColor: Color?
}

extension UsageMenuCardView.Model {
Expand Down Expand Up @@ -141,6 +144,19 @@ extension UsageMenuCardView.Model {
}

static func inlineUsageDashboard(input: Input) -> InlineUsageDashboardModel? {
guard var model = self.resolveInlineUsageDashboard(input: input) else { return nil }
model.barColor = Self.inlineDashboardBarColor(for: input.provider)
return model
}

/// Provider branding color for the inline usage bars, matching the provider's switcher tab and
/// detailed cost-history chart.
static func inlineDashboardBarColor(for provider: UsageProvider) -> Color {
let color = ProviderDescriptorRegistry.descriptor(for: provider).branding.color
return Color(red: color.red, green: color.green, blue: color.blue)
}

private static func resolveInlineUsageDashboard(input: Input) -> InlineUsageDashboardModel? {
if self.usesProviderCostHistoryAsPrimaryDashboard(input.provider),
let tokenSnapshot = primaryCostHistorySnapshot(input: input),
!tokenSnapshot.daily.isEmpty
Expand Down Expand Up @@ -757,13 +773,20 @@ struct InlineUsageDashboardContent: View {
if self.isHighlighted {
return Color.white.opacity(0.55 + ratio * 0.35)
}
return self.baseColor.opacity(0.42 + ratio * 0.58)
}

private var baseColor: Color {
if let barColor = self.model.barColor {
return barColor
}
switch self.model.valueStyle {
case .currencyUSD, .currency:
return Color(red: 0.81, green: 0.56, blue: 0.24).opacity(0.42 + ratio * 0.58)
return Color(red: 0.81, green: 0.56, blue: 0.24)
case .tokens:
return Color(red: 0.48, green: 0.41, blue: 0.86).opacity(0.42 + ratio * 0.58)
return Color(red: 0.48, green: 0.41, blue: 0.86)
case .points:
return Color(red: 0.16, green: 0.62, blue: 0.36).opacity(0.42 + ratio * 0.58)
return Color(red: 0.16, green: 0.62, blue: 0.36)
}
}
}
Expand Down
88 changes: 88 additions & 0 deletions Tests/CodexBarTests/InlineUsageDashboardBarColorTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import CodexBarCore
import Foundation
import SwiftUI
import Testing
@testable import CodexBar

struct InlineUsageDashboardBarColorTests {
/// The inline usage bars must be tinted with each provider's branding color (the same color
/// used by the switcher tab and the detailed cost-history chart) rather than a fixed palette.
@Test
func `bar color matches branding for every provider`() {
for provider in UsageProvider.allCases {
let branding = ProviderDescriptorRegistry.descriptor(for: provider).branding.color
let expected = Color(red: branding.red, green: branding.green, blue: branding.blue)
#expect(
UsageMenuCardView.Model.inlineDashboardBarColor(for: provider) == expected,
"inline bar color did not match branding for \(provider.rawValue)")
}
}

/// The resolved dashboard model must actually carry the provider's branding color, and two
/// providers with different branding must end up with different bar colors.
@Test
func `resolved dashboard carries provider branding color`() throws {
let now = Date(timeIntervalSince1970: 1_700_179_200)
let daily = [
CostUsageDailyReport.Entry(
date: "2023-11-14",
inputTokens: 100,
outputTokens: 50,
totalTokens: 150,
costUSD: 0.12,
modelsUsed: ["gpt-5"],
modelBreakdowns: nil),
CostUsageDailyReport.Entry(
date: "2023-11-15",
inputTokens: 200,
outputTokens: 75,
totalTokens: 275,
costUSD: 0.25,
modelsUsed: ["gpt-5"],
modelBreakdowns: nil),
]

func makeModel(provider: UsageProvider) throws -> UsageMenuCardView.Model {
let metadata = try #require(ProviderDefaults.metadata[provider])
let tokenSnapshot = CostUsageTokenSnapshot(
sessionTokens: 275,
sessionCostUSD: 0.25,
last30DaysTokens: 425,
last30DaysCostUSD: 0.37,
historyDays: 30,
daily: daily,
updatedAt: now)
return UsageMenuCardView.Model.make(.init(
provider: provider,
metadata: metadata,
snapshot: UsageSnapshot(
primary: RateWindow(usedPercent: 10, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
secondary: nil,
updatedAt: now),
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: tokenSnapshot,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: true,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
}

let codex = try makeModel(provider: .codex)
let claude = try makeModel(provider: .claude)

#expect(codex.inlineUsageDashboard?.barColor
== UsageMenuCardView.Model.inlineDashboardBarColor(for: .codex))
#expect(claude.inlineUsageDashboard?.barColor
== UsageMenuCardView.Model.inlineDashboardBarColor(for: .claude))
#expect(codex.inlineUsageDashboard?.barColor != claude.inlineUsageDashboard?.barColor)
}
}