import CodexBarCoreimport SwiftUIimport WidgetKit extension EnvironmentValues { @Entry fileprivate var widgetUsageShowsUsed: Bool = false} struct CodexBarUsageWidgetView: View { @Environment(\.widgetFamily) private var family let entry: CodexBarWidgetEntry var body: some View { let providerEntry = self.entry.snapshot.entries.first { $0.provider == self.entry.provider } ZStack { Color.black.opacity(0.02) if let providerEntry { self.content(providerEntry: providerEntry) } else { self.emptyState } } .containerBackground(.fill.tertiary, for: .widget) .environment(\.widgetUsageShowsUsed, self.entry.snapshot.usageBarsShowUsed) } @ViewBuilder private func content(providerEntry: WidgetSnapshot.ProviderEntry) -> some View { switch self.family { case .systemSmall: SmallUsageView(entry: providerEntry) case .systemMedium: MediumUsageView(entry: providerEntry) default: LargeUsageView(entry: providerEntry) } } private var emptyState: some View { VStack(alignment: .leading, spacing: 6) { Text("Open CodexBar") .font(.body) .fontWeight(.semibold) Text("Usage data will appear once the app refreshes.") .font(.caption) .foregroundStyle(.secondary) } .padding(12) }} struct CodexBarHistoryWidgetView: View { @Environment(\.widgetFamily) private var family let entry: CodexBarWidgetEntry var body: some View { let providerEntry = self.entry.snapshot.entries.first { $0.provider == self.entry.provider } ZStack { Color.black.opacity(0.02) if let providerEntry { HistoryView(entry: providerEntry, isLarge: self.family == .systemLarge) } else { self.emptyState } } .containerBackground(.fill.tertiary, for: .widget) } private var emptyState: some View { VStack(alignment: .leading, spacing: 6) { Text("Open CodexBar") .font(.body) .fontWeight(.semibold) Text("Usage history will appear after a refresh.") .font(.caption) .foregroundStyle(.secondary) } .padding(12) }} struct CodexBarCompactWidgetView: View { let entry: CodexBarCompactEntry var body: some View { let providerEntry = self.entry.snapshot.entries.first { $0.provider == self.entry.provider } ZStack { Color.black.opacity(0.02) if let providerEntry { CompactMetricView(entry: providerEntry, metric: self.entry.metric) } else { self.emptyState } } .containerBackground(.fill.tertiary, for: .widget) } private var emptyState: some View { VStack(alignment: .leading, spacing: 6) { Text("Open CodexBar") .font(.body) .fontWeight(.semibold) Text("Usage data will appear once the app refreshes.") .font(.caption) .foregroundStyle(.secondary) } .padding(12) }} struct CodexBarSwitcherWidgetView: View { @Environment(\.widgetFamily) private var family let entry: CodexBarSwitcherEntry var body: some View { let providerEntry = self.entry.snapshot.entries.first { $0.provider == self.entry.provider } ZStack { Color.black.opacity(0.02) VStack(alignment: .leading, spacing: 10) { ProviderSwitcherRow( providers: self.entry.availableProviders, selected: self.entry.provider, updatedAt: providerEntry?.updatedAt ?? Date(), compact: self.family == .systemSmall, showsTimestamp: self.family != .systemSmall) if let providerEntry { self.content(providerEntry: providerEntry) } else { self.emptyState } } .padding(12) } .containerBackground(.fill.tertiary, for: .widget) .environment(\.widgetUsageShowsUsed, self.entry.snapshot.usageBarsShowUsed) } @ViewBuilder private func content(providerEntry: WidgetSnapshot.ProviderEntry) -> some View { switch self.family { case .systemSmall: SwitcherSmallUsageView(entry: providerEntry) case .systemMedium: SwitcherMediumUsageView(entry: providerEntry) default: SwitcherLargeUsageView(entry: providerEntry) } } private var emptyState: some View { VStack(alignment: .leading, spacing: 6) { Text("Open CodexBar") .font(.caption) .foregroundStyle(.secondary) Text("Usage data appears after a refresh.") .font(.caption2) .foregroundStyle(.secondary) } }} private struct CompactMetricView: View { let entry: WidgetSnapshot.ProviderEntry let metric: CompactMetric var body: some View { let display = CompactMetricFormatter.display(for: self.entry, metric: self.metric) VStack(alignment: .leading, spacing: 8) { HeaderView(provider: self.entry.provider, updatedAt: self.entry.updatedAt) VStack(alignment: .leading, spacing: 2) { Text(display.value) .font(.title2) .fontWeight(.semibold) Text(display.label) .font(.caption2) .foregroundStyle(.secondary) if let detail = display.detail { Text(detail) .font(.caption2) .foregroundStyle(.secondary) } } } .padding(12) }} struct CompactMetricDisplay: Equatable { let value: String let label: String let detail: String?} enum CompactMetricFormatter { static func display(for entry: WidgetSnapshot.ProviderEntry, metric: CompactMetric) -> CompactMetricDisplay { switch metric { case .credits: if let cost = WidgetBalanceFormatter.extraUsageCost(for: entry) { return CompactMetricDisplay( value: WidgetFormat.currency(cost.used, code: cost.currencyCode), label: "Extra usage balance", detail: nil) } let value = entry.creditsRemaining.map(WidgetFormat.credits) ?? "—" return CompactMetricDisplay(value: value, label: "Credits left", detail: nil) case .todayCost: let value = entry.tokenUsage.map { token in token.sessionCostUSD.map { WidgetFormat.currency($0, code: token.currencyCode) } ?? "—" } ?? "—" let detail = entry.tokenUsage?.sessionTokens.map(WidgetFormat.tokenCount) let label = entry.tokenUsage.map { "\($0.sessionLabel) cost" } ?? "Today cost" return CompactMetricDisplay(value: value, label: label, detail: detail) case .last30DaysCost: let value = entry.tokenUsage.map { token in token.last30DaysCostUSD.map { WidgetFormat.currency($0, code: token.currencyCode) } ?? "—" } ?? "—" let detail = entry.tokenUsage?.last30DaysTokens.map(WidgetFormat.tokenCount) let label = entry.tokenUsage.map { "\($0.last30DaysLabel) cost" } ?? "30d cost" return CompactMetricDisplay(value: value, label: label, detail: detail) } }} private struct ProviderSwitcherRow: View { let providers: [UsageProvider] let selected: UsageProvider let updatedAt: Date let compact: Bool let showsTimestamp: Bool var body: some View { HStack(spacing: self.compact ? 4 : 6) { ForEach(self.providers, id: \.self) { provider in ProviderSwitchChip( provider: provider, selected: provider == self.selected, compact: self.compact) } if self.showsTimestamp { Spacer(minLength: 6) Text(WidgetFormat.relativeDate(self.updatedAt)) .font(.caption2) .foregroundStyle(.secondary) } } }} private struct ProviderSwitchChip: View { let provider: UsageProvider let selected: Bool let compact: Bool var body: some View { let label = self.compact ? self.shortLabel : self.longLabel let background = self.selected ? WidgetColors.color(for: self.provider).opacity(0.2) : Color.primary.opacity(0.08) if let choice = ProviderChoice(provider: self.provider) { Button(intent: SwitchWidgetProviderIntent(provider: choice)) { Text(label) .font(self.compact ? .caption2.weight(.semibold) : .caption.weight(.semibold)) .foregroundStyle(self.selected ? Color.primary : Color.secondary) .padding(.horizontal, self.compact ? 6 : 8) .padding(.vertical, self.compact ? 3 : 4) .background(Capsule().fill(background)) } .buttonStyle(.plain) } else { Text(label) .font(self.compact ? .caption2.weight(.semibold) : .caption.weight(.semibold)) .foregroundStyle(self.selected ? Color.primary : Color.secondary) .padding(.horizontal, self.compact ? 6 : 8) .padding(.vertical, self.compact ? 3 : 4) .background(Capsule().fill(background)) } } private var longLabel: String { ProviderDefaults.metadata[self.provider]?.displayName ?? self.provider.rawValue.capitalized } private var shortLabel: String { switch self.provider { case .codex: "Codex" case .openai: "OpenAI" case .azureopenai: "Azure OpenAI" case .claude: "Claude" case .gemini: "Gemini" case .antigravity: "Anti" case .cursor: "Cursor" case .opencode: "OpenCode" case .opencodego: "OpenCode Go" case .alibaba: "Alibaba" case .alibabatokenplan: "Token Plan" case .zai: "z.ai" case .factory: "Droid" case .copilot: "Copilot" case .devin: "Devin" case .minimax: "MiniMax" case .manus: "Manus" case .vertexai: "Vertex" case .kilo: "Kilo" case .kiro: "Kiro" case .augment: "Augment" case .jetbrains: "JetBrains" case .kimi: "Kimi" case .kimik2: "Kimi K2" case .moonshot: "Moonshot" case .amp: "Amp" case .t3chat: "T3 Chat" case .ollama: "Ollama" case .synthetic: "Synthetic" case .openrouter: "OpenRouter" case .crossmodel: "CrossModel" case .clawrouter: "ClawRouter" case .elevenlabs: "ElevenLabs" case .warp: "Warp" case .windsurf: "Windsurf" case .perplexity: "Pplx" case .mimo: "MiMo" case .doubao: "Doubao" case .sakana: "Sakana" case .abacus: "Abacus" case .mistral: "Mistral" case .deepseek: "DeepSeek" case .codebuff: "Codebuff" case .crof: "Crof" case .venice: "Venice" case .commandcode: "Command Code" case .qoder: "Qoder" case .stepfun: "StepFun" case .bedrock: "Bedrock" case .grok: "Grok" case .groq: "Groq" case .llmproxy: "LLM Proxy" case .litellm: "LiteLLM" case .deepgram: "Deepgram" case .poe: "Poe" case .chutes: "Chutes" case .zed: "Zed" } }} private struct SwitcherSmallUsageView: View { let entry: WidgetSnapshot.ProviderEntry var body: some View { VStack(alignment: .leading, spacing: 8) { ForEach(WidgetUsageRow.rows( for: self.entry, limit: WidgetUsageRow.smallWidgetRowLimit(for: self.entry))) { row in UsageBarRow( title: row.title, percentLeft: row.percentLeft, color: WidgetColors.color(for: self.entry.provider)) } if let codeReview = entry.codeReviewRemainingPercent { UsageBarRow( title: "Code review", percentLeft: codeReview, color: WidgetColors.color(for: self.entry.provider)) } if let token = WidgetUsageRow.compactTokenUsage(for: self.entry) { ValueLine( title: token.sessionLabel, value: WidgetFormat.costAndTokens( cost: token.sessionCostUSD, tokens: token.sessionTokens, currencyCode: token.currencyCode)) } if let balance = extraUsageBalanceLine(for: entry) { balance } } }} private struct SwitcherMediumUsageView: View { let entry: WidgetSnapshot.ProviderEntry var body: some View { VStack(alignment: .leading, spacing: 10) { ForEach(WidgetUsageRow.rows( for: self.entry, limit: WidgetUsageRow.mediumWidgetRowLimit(for: self.entry))) { row in UsageBarRow( title: row.title, percentLeft: row.percentLeft, color: WidgetColors.color(for: self.entry.provider)) } if let credits = entry.creditsRemaining { ValueLine(title: "Credits", value: WidgetFormat.credits(credits)) } if let token = entry.tokenUsage { ValueLine( title: token.sessionLabel, value: WidgetFormat.costAndTokens( cost: token.sessionCostUSD, tokens: token.sessionTokens, currencyCode: token.currencyCode)) } if let balance = extraUsageBalanceLine(for: entry) { balance } } }} private struct SwitcherLargeUsageView: View { let entry: WidgetSnapshot.ProviderEntry var body: some View { VStack(alignment: .leading, spacing: 12) { ForEach(WidgetUsageRow.rows(for: self.entry)) { row in UsageBarRow( title: row.title, percentLeft: row.percentLeft, color: WidgetColors.color(for: self.entry.provider)) } if let codeReview = entry.codeReviewRemainingPercent { UsageBarRow( title: "Code review", percentLeft: codeReview, color: WidgetColors.color(for: self.entry.provider)) } if let credits = entry.creditsRemaining { ValueLine(title: "Credits", value: WidgetFormat.credits(credits)) } if let token = entry.tokenUsage { VStack(alignment: .leading, spacing: 4) { ValueLine( title: token.sessionLabel, value: WidgetFormat.costAndTokens( cost: token.sessionCostUSD, tokens: token.sessionTokens, currencyCode: token.currencyCode)) ValueLine( title: token.last30DaysLabel, value: WidgetFormat.costAndTokens( cost: token.last30DaysCostUSD, tokens: token.last30DaysTokens, currencyCode: token.currencyCode)) } } if let balance = extraUsageBalanceLine(for: entry) { balance } UsageHistoryChart( points: self.entry.dailyUsage, color: WidgetColors.color(for: self.entry.provider), currencyCode: self.entry.tokenUsage?.currencyCode) .frame(height: 50) } }} private struct SmallUsageView: View { let entry: WidgetSnapshot.ProviderEntry var body: some View { VStack(alignment: .leading, spacing: 8) { HeaderView(provider: self.entry.provider, updatedAt: self.entry.updatedAt) ForEach(WidgetUsageRow.rows( for: self.entry, limit: WidgetUsageRow.smallWidgetRowLimit(for: self.entry))) { row in UsageBarRow( title: row.title, percentLeft: row.percentLeft, color: WidgetColors.color(for: self.entry.provider)) } if let codeReview = entry.codeReviewRemainingPercent { UsageBarRow( title: "Code review", percentLeft: codeReview, color: WidgetColors.color(for: self.entry.provider)) } if let token = WidgetUsageRow.compactTokenUsage(for: self.entry) { ValueLine( title: token.sessionLabel, value: WidgetFormat.costAndTokens( cost: token.sessionCostUSD, tokens: token.sessionTokens, currencyCode: token.currencyCode)) } if let balance = extraUsageBalanceLine(for: entry) { balance } } .padding(12) }} private struct MediumUsageView: View { let entry: WidgetSnapshot.ProviderEntryLines 1–500 of 1057. Load more
import CodexBarCore import SwiftUI import WidgetKit extension EnvironmentValues { @Entry fileprivate var widgetUsageShowsUsed: Bool = false } struct CodexBarUsageWidgetView: View { @Environment(\.widgetFamily) private var family let entry: CodexBarWidgetEntry var body: some View { let providerEntry = self.entry.snapshot.entries.first { $0.provider == self.entry.provider } ZStack { Color.black.opacity(0.02) if let providerEntry { self.content(providerEntry: providerEntry) } else { self.emptyState } } .containerBackground(.fill.tertiary, for: .widget) .environment(\.widgetUsageShowsUsed, self.entry.snapshot.usageBarsShowUsed) } @ViewBuilder private func content(providerEntry: WidgetSnapshot.ProviderEntry) -> some View { switch self.family { case .systemSmall: SmallUsageView(entry: providerEntry) case .systemMedium: MediumUsageView(entry: providerEntry) default: LargeUsageView(entry: providerEntry) } } private var emptyState: some View { VStack(alignment: .leading, spacing: 6) { Text("Open CodexBar") .font(.body) .fontWeight(.semibold) Text("Usage data will appear once the app refreshes.") .font(.caption) .foregroundStyle(.secondary) } .padding(12) } } struct CodexBarHistoryWidgetView: View { @Environment(\.widgetFamily) private var family let entry: CodexBarWidgetEntry var body: some View { let providerEntry = self.entry.snapshot.entries.first { $0.provider == self.entry.provider } ZStack { Color.black.opacity(0.02) if let providerEntry { HistoryView(entry: providerEntry, isLarge: self.family == .systemLarge) } else { self.emptyState } } .containerBackground(.fill.tertiary, for: .widget) } private var emptyState: some View { VStack(alignment: .leading, spacing: 6) { Text("Open CodexBar") .font(.body) .fontWeight(.semibold) Text("Usage history will appear after a refresh.") .font(.caption) .foregroundStyle(.secondary) } .padding(12) } } struct CodexBarCompactWidgetView: View { let entry: CodexBarCompactEntry var body: some View { let providerEntry = self.entry.snapshot.entries.first { $0.provider == self.entry.provider } ZStack { Color.black.opacity(0.02) if let providerEntry { CompactMetricView(entry: providerEntry, metric: self.entry.metric) } else { self.emptyState } } .containerBackground(.fill.tertiary, for: .widget) } private var emptyState: some View { VStack(alignment: .leading, spacing: 6) { Text("Open CodexBar") .font(.body) .fontWeight(.semibold) Text("Usage data will appear once the app refreshes.") .font(.caption) .foregroundStyle(.secondary) } .padding(12) } } struct CodexBarSwitcherWidgetView: View { @Environment(\.widgetFamily) private var family let entry: CodexBarSwitcherEntry var body: some View { let providerEntry = self.entry.snapshot.entries.first { $0.provider == self.entry.provider } ZStack { Color.black.opacity(0.02) VStack(alignment: .leading, spacing: 10) { ProviderSwitcherRow( providers: self.entry.availableProviders, selected: self.entry.provider, updatedAt: providerEntry?.updatedAt ?? Date(), compact: self.family == .systemSmall, showsTimestamp: self.family != .systemSmall) if let providerEntry { self.content(providerEntry: providerEntry) } else { self.emptyState } } .padding(12) } .containerBackground(.fill.tertiary, for: .widget) .environment(\.widgetUsageShowsUsed, self.entry.snapshot.usageBarsShowUsed) } @ViewBuilder private func content(providerEntry: WidgetSnapshot.ProviderEntry) -> some View { switch self.family { case .systemSmall: SwitcherSmallUsageView(entry: providerEntry) case .systemMedium: SwitcherMediumUsageView(entry: providerEntry) default: SwitcherLargeUsageView(entry: providerEntry) } } private var emptyState: some View { VStack(alignment: .leading, spacing: 6) { Text("Open CodexBar") .font(.caption) .foregroundStyle(.secondary) Text("Usage data appears after a refresh.") .font(.caption2) .foregroundStyle(.secondary) } } } private struct CompactMetricView: View { let entry: WidgetSnapshot.ProviderEntry let metric: CompactMetric var body: some View { let display = CompactMetricFormatter.display(for: self.entry, metric: self.metric) VStack(alignment: .leading, spacing: 8) { HeaderView(provider: self.entry.provider, updatedAt: self.entry.updatedAt) VStack(alignment: .leading, spacing: 2) { Text(display.value) .font(.title2) .fontWeight(.semibold) Text(display.label) .font(.caption2) .foregroundStyle(.secondary) if let detail = display.detail { Text(detail) .font(.caption2) .foregroundStyle(.secondary) } } } .padding(12) } } struct CompactMetricDisplay: Equatable { let value: String let label: String let detail: String? } enum CompactMetricFormatter { static func display(for entry: WidgetSnapshot.ProviderEntry, metric: CompactMetric) -> CompactMetricDisplay { switch metric { case .credits: if let cost = WidgetBalanceFormatter.extraUsageCost(for: entry) { return CompactMetricDisplay( value: WidgetFormat.currency(cost.used, code: cost.currencyCode), label: "Extra usage balance", detail: nil) } let value = entry.creditsRemaining.map(WidgetFormat.credits) ?? "—" return CompactMetricDisplay(value: value, label: "Credits left", detail: nil) case .todayCost: let value = entry.tokenUsage.map { token in token.sessionCostUSD.map { WidgetFormat.currency($0, code: token.currencyCode) } ?? "—" } ?? "—" let detail = entry.tokenUsage?.sessionTokens.map(WidgetFormat.tokenCount) let label = entry.tokenUsage.map { "\($0.sessionLabel) cost" } ?? "Today cost" return CompactMetricDisplay(value: value, label: label, detail: detail) case .last30DaysCost: let value = entry.tokenUsage.map { token in token.last30DaysCostUSD.map { WidgetFormat.currency($0, code: token.currencyCode) } ?? "—" } ?? "—" let detail = entry.tokenUsage?.last30DaysTokens.map(WidgetFormat.tokenCount) let label = entry.tokenUsage.map { "\($0.last30DaysLabel) cost" } ?? "30d cost" return CompactMetricDisplay(value: value, label: label, detail: detail) } } } private struct ProviderSwitcherRow: View { let providers: [UsageProvider] let selected: UsageProvider let updatedAt: Date let compact: Bool let showsTimestamp: Bool var body: some View { HStack(spacing: self.compact ? 4 : 6) { ForEach(self.providers, id: \.self) { provider in ProviderSwitchChip( provider: provider, selected: provider == self.selected, compact: self.compact) } if self.showsTimestamp { Spacer(minLength: 6) Text(WidgetFormat.relativeDate(self.updatedAt)) .font(.caption2) .foregroundStyle(.secondary) } } } } private struct ProviderSwitchChip: View { let provider: UsageProvider let selected: Bool let compact: Bool var body: some View { let label = self.compact ? self.shortLabel : self.longLabel let background = self.selected ? WidgetColors.color(for: self.provider).opacity(0.2) : Color.primary.opacity(0.08) if let choice = ProviderChoice(provider: self.provider) { Button(intent: SwitchWidgetProviderIntent(provider: choice)) { Text(label) .font(self.compact ? .caption2.weight(.semibold) : .caption.weight(.semibold)) .foregroundStyle(self.selected ? Color.primary : Color.secondary) .padding(.horizontal, self.compact ? 6 : 8) .padding(.vertical, self.compact ? 3 : 4) .background(Capsule().fill(background)) } .buttonStyle(.plain) } else { Text(label) .font(self.compact ? .caption2.weight(.semibold) : .caption.weight(.semibold)) .foregroundStyle(self.selected ? Color.primary : Color.secondary) .padding(.horizontal, self.compact ? 6 : 8) .padding(.vertical, self.compact ? 3 : 4) .background(Capsule().fill(background)) } } private var longLabel: String { ProviderDefaults.metadata[self.provider]?.displayName ?? self.provider.rawValue.capitalized } private var shortLabel: String { switch self.provider { case .codex: "Codex" case .openai: "OpenAI" case .azureopenai: "Azure OpenAI" case .claude: "Claude" case .gemini: "Gemini" case .antigravity: "Anti" case .cursor: "Cursor" case .opencode: "OpenCode" case .opencodego: "OpenCode Go" case .alibaba: "Alibaba" case .alibabatokenplan: "Token Plan" case .zai: "z.ai" case .factory: "Droid" case .copilot: "Copilot" case .devin: "Devin" case .minimax: "MiniMax" case .manus: "Manus" case .vertexai: "Vertex" case .kilo: "Kilo" case .kiro: "Kiro" case .augment: "Augment" case .jetbrains: "JetBrains" case .kimi: "Kimi" case .kimik2: "Kimi K2" case .moonshot: "Moonshot" case .amp: "Amp" case .t3chat: "T3 Chat" case .ollama: "Ollama" case .synthetic: "Synthetic" case .openrouter: "OpenRouter" case .crossmodel: "CrossModel" case .clawrouter: "ClawRouter" case .elevenlabs: "ElevenLabs" case .warp: "Warp" case .windsurf: "Windsurf" case .perplexity: "Pplx" case .mimo: "MiMo" case .doubao: "Doubao" case .sakana: "Sakana" case .abacus: "Abacus" case .mistral: "Mistral" case .deepseek: "DeepSeek" case .codebuff: "Codebuff" case .crof: "Crof" case .venice: "Venice" case .commandcode: "Command Code" case .qoder: "Qoder" case .stepfun: "StepFun" case .bedrock: "Bedrock" case .grok: "Grok" case .groq: "Groq" case .llmproxy: "LLM Proxy" case .litellm: "LiteLLM" case .deepgram: "Deepgram" case .poe: "Poe" case .chutes: "Chutes" case .zed: "Zed" } } } private struct SwitcherSmallUsageView: View { let entry: WidgetSnapshot.ProviderEntry var body: some View { VStack(alignment: .leading, spacing: 8) { ForEach(WidgetUsageRow.rows( for: self.entry, limit: WidgetUsageRow.smallWidgetRowLimit(for: self.entry))) { row in UsageBarRow( title: row.title, percentLeft: row.percentLeft, color: WidgetColors.color(for: self.entry.provider)) } if let codeReview = entry.codeReviewRemainingPercent { UsageBarRow( title: "Code review", percentLeft: codeReview, color: WidgetColors.color(for: self.entry.provider)) } if let token = WidgetUsageRow.compactTokenUsage(for: self.entry) { ValueLine( title: token.sessionLabel, value: WidgetFormat.costAndTokens( cost: token.sessionCostUSD, tokens: token.sessionTokens, currencyCode: token.currencyCode)) } if let balance = extraUsageBalanceLine(for: entry) { balance } } } } private struct SwitcherMediumUsageView: View { let entry: WidgetSnapshot.ProviderEntry var body: some View { VStack(alignment: .leading, spacing: 10) { ForEach(WidgetUsageRow.rows( for: self.entry, limit: WidgetUsageRow.mediumWidgetRowLimit(for: self.entry))) { row in UsageBarRow( title: row.title, percentLeft: row.percentLeft, color: WidgetColors.color(for: self.entry.provider)) } if let credits = entry.creditsRemaining { ValueLine(title: "Credits", value: WidgetFormat.credits(credits)) } if let token = entry.tokenUsage { ValueLine( title: token.sessionLabel, value: WidgetFormat.costAndTokens( cost: token.sessionCostUSD, tokens: token.sessionTokens, currencyCode: token.currencyCode)) } if let balance = extraUsageBalanceLine(for: entry) { balance } } } } private struct SwitcherLargeUsageView: View { let entry: WidgetSnapshot.ProviderEntry var body: some View { VStack(alignment: .leading, spacing: 12) { ForEach(WidgetUsageRow.rows(for: self.entry)) { row in UsageBarRow( title: row.title, percentLeft: row.percentLeft, color: WidgetColors.color(for: self.entry.provider)) } if let codeReview = entry.codeReviewRemainingPercent { UsageBarRow( title: "Code review", percentLeft: codeReview, color: WidgetColors.color(for: self.entry.provider)) } if let credits = entry.creditsRemaining { ValueLine(title: "Credits", value: WidgetFormat.credits(credits)) } if let token = entry.tokenUsage { VStack(alignment: .leading, spacing: 4) { ValueLine( title: token.sessionLabel, value: WidgetFormat.costAndTokens( cost: token.sessionCostUSD, tokens: token.sessionTokens, currencyCode: token.currencyCode)) ValueLine( title: token.last30DaysLabel, value: WidgetFormat.costAndTokens( cost: token.last30DaysCostUSD, tokens: token.last30DaysTokens, currencyCode: token.currencyCode)) } } if let balance = extraUsageBalanceLine(for: entry) { balance } UsageHistoryChart( points: self.entry.dailyUsage, color: WidgetColors.color(for: self.entry.provider), currencyCode: self.entry.tokenUsage?.currencyCode) .frame(height: 50) } } } private struct SmallUsageView: View { let entry: WidgetSnapshot.ProviderEntry var body: some View { VStack(alignment: .leading, spacing: 8) { HeaderView(provider: self.entry.provider, updatedAt: self.entry.updatedAt) ForEach(WidgetUsageRow.rows( for: self.entry, limit: WidgetUsageRow.smallWidgetRowLimit(for: self.entry))) { row in UsageBarRow( title: row.title, percentLeft: row.percentLeft, color: WidgetColors.color(for: self.entry.provider)) } if let codeReview = entry.codeReviewRemainingPercent { UsageBarRow( title: "Code review", percentLeft: codeReview, color: WidgetColors.color(for: self.entry.provider)) } if let token = WidgetUsageRow.compactTokenUsage(for: self.entry) { ValueLine( title: token.sessionLabel, value: WidgetFormat.costAndTokens( cost: token.sessionCostUSD, tokens: token.sessionTokens, currencyCode: token.currencyCode)) } if let balance = extraUsageBalanceLine(for: entry) { balance } } .padding(12) } } private struct MediumUsageView: View { let entry: WidgetSnapshot.ProviderEntry