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
72 changes: 68 additions & 4 deletions Sources/CodexBar/MenuCardView+ModelHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,23 @@ extension UsageMenuCardView.Model {
let rightLabel: String?
let pacePercent: Double?
let paceOnTop: Bool
/// True only for text produced by a pace calculation. Defaults to false
/// so provider-owned text sharing the detail slot is preserved.
let isPaceDerived: Bool

init(
leftLabel: String,
rightLabel: String?,
pacePercent: Double?,
paceOnTop: Bool,
isPaceDerived: Bool = false)
{
self.leftLabel = leftLabel
self.rightLabel = rightLabel
self.pacePercent = pacePercent
self.paceOnTop = paceOnTop
self.isPaceDerived = isPaceDerived
}
}

struct PrimaryMetricPresentation {
Expand All @@ -40,6 +57,7 @@ extension UsageMenuCardView.Model {
var detailRight: String?
var pacePercent: Double?
var paceOnTop = true
var detailIsPaceDerived = false
}

static func applyPrimaryQuotaPresentation(
Expand Down Expand Up @@ -187,6 +205,7 @@ extension UsageMenuCardView.Model {
presentation.detailRight = paceDetail.rightLabel
presentation.pacePercent = paceDetail.pacePercent
presentation.paceOnTop = paceDetail.paceOnTop
presentation.detailIsPaceDerived = paceDetail.isPaceDerived
}

private static func nonEmptyResetDescription(_ window: RateWindow) -> String? {
Expand Down Expand Up @@ -215,6 +234,36 @@ extension UsageMenuCardView.Model {
return PersonalInfoRedactor.redactEmails(in: "Team\(detail[separator.lowerBound...])", isEnabled: true)
}

/// Clears the pace stripe and the forecast text when the user hides pace.
/// Copies every `Metric` field so unrelated decorations (quota and workday
/// ticks) survive; dropping one here would silently disable them.
static func paceGatedMetrics(_ metrics: [Metric], paceVisible: Bool) -> [Metric] {
guard !paceVisible else { return metrics }
return metrics.map { metric in
// The detail slots are shared: providers such as Kiro, Copilot, and
// ZenMux put their own credit and reset text there. Clear them only
// when they carry a pace forecast.
Metric(
id: metric.id,
title: metric.title,
percent: metric.percent,
percentStyle: metric.percentStyle,
statusText: metric.statusText,
resetText: metric.resetText,
detailText: metric.detailText,
detailLeftText: metric.detailIsPaceDerived ? nil : metric.detailLeftText,
detailRightText: metric.detailIsPaceDerived ? nil : metric.detailRightText,
pacePercent: nil,
detailIsPaceDerived: metric.detailIsPaceDerived,
paceOnTop: metric.paceOnTop,
warningMarkerPercents: metric.warningMarkerPercents,
workdayMarkerPercents: metric.workdayMarkerPercents,
workdayTickAppearance: metric.workdayTickAppearance,
cardStyle: metric.cardStyle,
sessionEquivalentDetail: nil)
}
}

static func redactedMetrics(
_ metrics: [Metric],
provider: UsageProvider,
Expand All @@ -236,6 +285,7 @@ extension UsageMenuCardView.Model {
detailLeftText: PersonalInfoRedactor.redactEmails(in: metric.detailLeftText, isEnabled: true),
detailRightText: PersonalInfoRedactor.redactEmails(in: metric.detailRightText, isEnabled: true),
pacePercent: metric.pacePercent,
detailIsPaceDerived: metric.detailIsPaceDerived,
paceOnTop: metric.paceOnTop,
warningMarkerPercents: metric.warningMarkerPercents,
workdayMarkerPercents: metric.workdayMarkerPercents,
Expand Down Expand Up @@ -706,7 +756,8 @@ extension UsageMenuCardView.Model {
leftLabel: detail.leftLabel,
rightLabel: detail.rightLabel,
pacePercent: pacePercent,
paceOnTop: paceOnTop)
paceOnTop: paceOnTop,
isPaceDerived: true)
}

static func weeklyPaceDetail(
Expand Down Expand Up @@ -735,7 +786,8 @@ extension UsageMenuCardView.Model {
leftLabel: detail.leftLabel,
rightLabel: detail.rightLabel,
pacePercent: pacePercent,
paceOnTop: paceOnTop)
paceOnTop: paceOnTop,
isPaceDerived: true)
}

static func standardWeeklyPace(input: Input, window: RateWindow) -> UsagePace? {
Expand Down Expand Up @@ -897,6 +949,7 @@ extension UsageMenuCardView.Model {
detailLeftText: usageKnown ? paceDetail?.leftLabel : nil,
detailRightText: usageKnown ? paceDetail?.rightLabel : nil,
pacePercent: usageKnown ? paceDetail?.pacePercent : nil,
detailIsPaceDerived: paceDetail?.isPaceDerived ?? false,
paceOnTop: paceDetail?.paceOnTop ?? true,
sessionEquivalentDetail: usageKnown
? Self.sessionEquivalentDetail(
Expand Down Expand Up @@ -1061,6 +1114,7 @@ extension UsageMenuCardView.Model {
detailLeftText: paceDetail?.leftLabel,
detailRightText: paceDetail?.rightLabel,
pacePercent: paceDetail?.pacePercent,
detailIsPaceDerived: paceDetail?.isPaceDerived ?? false,
paceOnTop: paceDetail?.paceOnTop ?? true)
}

Expand Down Expand Up @@ -1093,7 +1147,12 @@ extension UsageMenuCardView.Model {
} else {
String(format: L("Full in ~%.0f regens"), ceil(ticksToFull))
}
return (resetText, PaceDetail(leftLabel: left, rightLabel: right, pacePercent: nil, paceOnTop: true))
return (resetText, PaceDetail(
leftLabel: left,
rightLabel: right,
pacePercent: nil,
paceOnTop: true,
isPaceDerived: true))
}

static func syntheticRollingRegenDetail(
Expand Down Expand Up @@ -1124,6 +1183,11 @@ extension UsageMenuCardView.Model {
String(format: L("Full in ~%.0f regens"), ceil(ticksToFull))
}

return (resetText, PaceDetail(leftLabel: left, rightLabel: right, pacePercent: nil, paceOnTop: true))
return (resetText, PaceDetail(
leftLabel: left,
rightLabel: right,
pacePercent: nil,
paceOnTop: true,
isPaceDerived: true))
}
}
3 changes: 3 additions & 0 deletions Sources/CodexBar/MenuCardView+ModelInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ extension UsageMenuCardView.Model {
let quotaWarningThresholds: [QuotaWarningWindow: [Int]]
let workDaysPerWeek: Int?
let workdayTickAppearance: WorkdayTickAppearance
let paceVisible: Bool
let usesLiveSubtitle: Bool
let preferredCurrencyCode: String
let now: Date
Expand Down Expand Up @@ -86,6 +87,7 @@ extension UsageMenuCardView.Model {
quotaWarningThresholds: [QuotaWarningWindow: [Int]] = [:],
workDaysPerWeek: Int? = nil,
workdayTickAppearance: WorkdayTickAppearance = .subtle,
paceVisible: Bool = true,
usesLiveSubtitle: Bool = false,
preferredCurrencyCode: String = "auto",
now: Date)
Expand Down Expand Up @@ -128,6 +130,7 @@ extension UsageMenuCardView.Model {
self.quotaWarningThresholds = quotaWarningThresholds
self.workDaysPerWeek = workDaysPerWeek
self.workdayTickAppearance = workdayTickAppearance
self.paceVisible = paceVisible
self.usesLiveSubtitle = usesLiveSubtitle
self.preferredCurrencyCode = preferredCurrencyCode
self.now = now
Expand Down
1 change: 1 addition & 0 deletions Sources/CodexBar/MenuCardView+SessionEquivalent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ extension UsageMenuCardView.Model {
detailLeftText: paceDetail?.leftLabel,
detailRightText: paceDetail?.rightLabel,
pacePercent: paceDetail?.pacePercent,
detailIsPaceDerived: paceDetail?.isPaceDerived ?? false,
paceOnTop: paceDetail?.paceOnTop ?? true,
warningMarkerPercents: Self.warningMarkerPercents(
thresholds: lane.quotaWarningWindow.flatMap { input.quotaWarningThresholds[$0] },
Expand Down
9 changes: 8 additions & 1 deletion Sources/CodexBar/MenuCardView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ struct UsageMenuCardView: View {
let detailLeftText: String?
let detailRightText: String?
let pacePercent: Double?
/// True when detailLeftText/detailRightText came from a pace forecast.
let detailIsPaceDerived: Bool
let paceOnTop: Bool
let warningMarkerPercents: [Double]
let workdayMarkerPercents: [Double]
Expand All @@ -59,6 +61,7 @@ struct UsageMenuCardView: View {
detailLeftText: String?,
detailRightText: String?,
pacePercent: Double?,
detailIsPaceDerived: Bool = false,
paceOnTop: Bool,
warningMarkerPercents: [Double] = [],
workdayMarkerPercents: [Double] = [],
Expand All @@ -76,6 +79,7 @@ struct UsageMenuCardView: View {
self.detailLeftText = detailLeftText
self.detailRightText = detailRightText
self.pacePercent = pacePercent
self.detailIsPaceDerived = detailIsPaceDerived
self.paceOnTop = paceOnTop
self.warningMarkerPercents = warningMarkerPercents
self.workdayMarkerPercents = workdayMarkerPercents
Expand Down Expand Up @@ -944,7 +948,7 @@ extension UsageMenuCardView.Model {
override: input.planOverride,
metadata: input.metadata)
let metrics = Self.redactedMetrics(
Self.metrics(input: input),
Self.paceGatedMetrics(Self.metrics(input: input), paceVisible: input.paceVisible),
provider: input.provider,
hidePersonalInfo: input.hidePersonalInfo)
let openAIAPIUsage = input.snapshot?.openAIAPIUsage
Expand Down Expand Up @@ -1327,6 +1331,7 @@ extension UsageMenuCardView.Model {
detailLeftText: tertiaryPaceDetail?.leftLabel,
detailRightText: tertiaryPaceDetail?.rightLabel,
pacePercent: tertiaryPaceDetail?.pacePercent,
detailIsPaceDerived: tertiaryPaceDetail?.isPaceDerived ?? false,
paceOnTop: tertiaryPaceDetail?.paceOnTop ?? true,
warningMarkerPercents: Self.warningMarkerPercents(
thresholds: input.quotaWarningThresholds[.weekly],
Expand Down Expand Up @@ -1415,6 +1420,7 @@ extension UsageMenuCardView.Model {
detailLeftText: presentation.detailLeft,
detailRightText: presentation.detailRight,
pacePercent: presentation.pacePercent,
detailIsPaceDerived: presentation.detailIsPaceDerived,
paceOnTop: presentation.paceOnTop,
warningMarkerPercents: Self.warningMarkerPercents(
thresholds: input.quotaWarningThresholds[.session],
Expand Down Expand Up @@ -1543,6 +1549,7 @@ extension UsageMenuCardView.Model {
detailLeftText: paceDetail?.leftLabel,
detailRightText: paceDetail?.rightLabel,
pacePercent: paceDetail?.pacePercent,
detailIsPaceDerived: paceDetail?.isPaceDerived ?? false,
paceOnTop: paceDetail?.paceOnTop ?? true,
warningMarkerPercents: Self.warningMarkerPercents(
thresholds: input.quotaWarningThresholds[.weekly],
Expand Down
11 changes: 8 additions & 3 deletions Sources/CodexBar/MenuDescriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -271,13 +271,16 @@ struct MenuDescriptor {
{
entries.append(.text(primaryDetail, .secondary))
}
if presentation.menu.showsPrimaryWeeklyPace,
if settings.paceVisible,
presentation.menu.showsPrimaryWeeklyPace,
let pace = store.weeklyPace(provider: provider, window: primary)
{
let paceSummary = UsagePaceText.weeklySummary(provider: provider, pace: pace)
entries.append(.text(paceSummary, .secondary))
}
if let paceSummary = UsagePaceText.sessionSummary(provider: provider, window: primary) {
if settings.paceVisible,
let paceSummary = UsagePaceText.sessionSummary(provider: provider, window: primary)
{
entries.append(.text(paceSummary, .secondary))
}
}
Expand Down Expand Up @@ -308,7 +311,9 @@ struct MenuDescriptor {
{
entries.append(.text(detail, .secondary))
}
if let pace = store.weeklyPace(provider: provider, window: weekly) {
if settings.paceVisible,
let pace = store.weeklyPace(provider: provider, window: weekly)
{
let paceSummary = UsagePaceText.weeklySummary(provider: provider, pace: pace)
entries.append(.text(paceSummary, .secondary))
}
Expand Down
6 changes: 6 additions & 0 deletions Sources/CodexBar/PreferencesMenuPane.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ struct MenuPane: View {
subtitle: L("show_quota_warning_markers_subtitle"))
}

Toggle(isOn: self.$settings.paceVisible) {
SettingsRowLabel(
L("show_pace_title"),
subtitle: L("show_pace_subtitle"))
}

SettingsMenuPicker(
selection: self.$settings.weeklyProgressWorkDays,
options: MenuSettingsMenuOptions.weeklyProgressWorkDays,
Expand Down
1 change: 1 addition & 0 deletions Sources/CodexBar/PreferencesProvidersPane.swift
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,7 @@ struct ProvidersPane: View {
],
workDaysPerWeek: self.settings.weeklyProgressWorkDays,
workdayTickAppearance: self.settings.workdayTickAppearance,
paceVisible: self.settings.paceVisible,
now: now)
return UsageMenuCardView.Model.make(input)
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/CodexBar/Resources/ar.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,8 @@
"display_mode_subtitle" = "اختر ما تريد عرضه في شريط القائمة (Pace يظهر الاستخدام مقابل المتوقع).";
"show_quota_warning_markers_title" = "عرض علامات التحذير من الحصص";
"show_quota_warning_markers_subtitle" = "ارسم علامات عتبة على أشرطة الاستخدام عند تكوين تحذيرات الحصص.";
"show_pace_title" = "إظهار وتيرة الاستخدام";
"show_pace_subtitle" = "يعرض شريط التقدم أو التأخر ونص التوقعات على أشرطة الاستخدام.";
"weekly_progress_work_days_title" = "أيام العمل الأسبوعية للتقدم";
"weekly_progress_work_days_subtitle" = "حدد أيام عمل لمؤشرات شريط الاستخدام الأسبوعي وحسابات السرعة.";
"workday_tick_appearance_title" = "مظهر علامات أيام العمل";
Expand Down
2 changes: 2 additions & 0 deletions Sources/CodexBar/Resources/ca.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,8 @@
"display_mode_subtitle" = "Trieu què es mostra a la barra de menús (Ritme mostra l'ús respecte al previst).";
"show_quota_warning_markers_title" = "Mostreu els marcadors d'avís de quota";
"show_quota_warning_markers_subtitle" = "Dibuixa marques de llindar a les barres d'ús quan hi ha avisos de quota configurats.";
"show_pace_title" = "Mostra el ritme";
"show_pace_subtitle" = "Mostra la franja d'avançament o retard i el text de previsió a les barres d'ús.";
"weekly_progress_work_days_title" = "Dies laborables del progrés setmanal";
"weekly_progress_work_days_subtitle" = "Definiu els dies laborables per als marcadors de les barres d'ús setmanal i els càlculs de ritme.";
"workday_tick_appearance_title" = "Aparença de les marques dels dies laborables";
Expand Down
2 changes: 2 additions & 0 deletions Sources/CodexBar/Resources/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,8 @@
"display_mode_subtitle" = "Wählen Sie aus, was in der Menüleiste angezeigt werden soll (Pace zeigt die Nutzung im Vergleich zur erwarteten).";
"show_quota_warning_markers_title" = "Quotenwarnmarkierungen anzeigen";
"show_quota_warning_markers_subtitle" = "Zeichnen Sie Schwellenwertmarkierungen auf Nutzungsbalken, wenn Kontingentwarnungen konfiguriert sind.";
"show_pace_title" = "Tempo anzeigen";
"show_pace_subtitle" = "Zeigt den Streifen für Vorsprung oder Rückstand und den Prognosetext auf den Nutzungsbalken.";
"weekly_progress_work_days_title" = "Wöchentliche Fortschrittsarbeitstage";
"weekly_progress_work_days_subtitle" = "Legt Arbeitstage für Markierungen in wöchentlichen Nutzungsbalken und Tempo-Berechnungen fest.";
"workday_tick_appearance_title" = "Darstellung der Arbeitstagsmarkierungen";
Expand Down
2 changes: 2 additions & 0 deletions Sources/CodexBar/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,8 @@
"display_mode_subtitle" = "Choose what to show in the menu bar (Pace shows usage vs. expected).";
"show_quota_warning_markers_title" = "Show quota warning markers";
"show_quota_warning_markers_subtitle" = "Draw threshold tick marks on usage bars when quota warnings are configured.";
"show_pace_title" = "Show pace";
"show_pace_subtitle" = "Show the ahead/behind stripe and forecast text on usage bars.";
"weekly_progress_work_days_title" = "Work days";
"weekly_progress_work_days_subtitle" = "Set work days for weekly usage-bar markers and pace calculations.";
"workday_tick_appearance_title" = "Workday tick appearance";
Expand Down
2 changes: 2 additions & 0 deletions Sources/CodexBar/Resources/es.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,8 @@
"display_mode_subtitle" = "Elige qué mostrar en la barra de menús (Ritmo muestra el uso frente al previsto).";
"show_quota_warning_markers_title" = "Mostrar marcadores de aviso de cuota";
"show_quota_warning_markers_subtitle" = "Dibuja marcas de umbral en las barras de uso cuando hay avisos de cuota configurados.";
"show_pace_title" = "Mostrar el ritmo";
"show_pace_subtitle" = "Muestra la franja de adelanto o retraso y el texto de previsión en las barras de uso.";
"weekly_progress_work_days_title" = "Días laborables del progreso semanal";
"weekly_progress_work_days_subtitle" = "Define los días laborables para los marcadores de las barras de uso semanal y los cálculos de ritmo.";
"workday_tick_appearance_title" = "Aspecto de las marcas de días laborables";
Expand Down
2 changes: 2 additions & 0 deletions Sources/CodexBar/Resources/fa.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,8 @@
"display_mode_subtitle" = "انتخاب کنید که در نوار منو چه چیزی نمایش داده شود (Pace میزان مصرف در مقابل مورد انتظار را نشان می دهد).";
"show_quota_warning_markers_title" = "نشانگرهای هشدار سهمیه را نشان دهید";
"show_quota_warning_markers_subtitle" = "علامت تیک آستانه را روی نوارهای استفاده هنگام پیکربندی هشدارهای سهمیه رسم کنید.";
"show_pace_title" = "نمایش آهنگ مصرف";
"show_pace_subtitle" = "نوار جلوتر یا عقب‌تر بودن و متن پیش‌بینی را روی نوارهای مصرف نشان می‌دهد.";
"weekly_progress_work_days_title" = "روزهای کاری پیشرفت هفتگی";
"weekly_progress_work_days_subtitle" = "روزهای کاری را برای نشانگرهای نوار مصرف هفتگی و محاسبات سرعت تعیین کنید.";
"workday_tick_appearance_title" = "نمایش نشانه‌های روز کاری";
Expand Down
2 changes: 2 additions & 0 deletions Sources/CodexBar/Resources/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,8 @@
"display_mode_subtitle" = "Choisissez ce que vous voulez afficher dans la barre de menu (Pace affiche l'utilisation par rapport à celle attendue).";
"show_quota_warning_markers_title" = "Afficher les marqueurs d'avertissement de quota";
"show_quota_warning_markers_subtitle" = "Dessinez des coches de seuil sur les barres d’utilisation lorsque des avertissements de quota sont configurés.";
"show_pace_title" = "Afficher le rythme";
"show_pace_subtitle" = "Affiche la bande d'avance ou de retard et le texte de prévision sur les barres d'utilisation.";
"weekly_progress_work_days_title" = "Jours de travail hebdomadaires";
"weekly_progress_work_days_subtitle" = "Définit les jours ouvrés pour les repères des barres d’utilisation hebdomadaire et le calcul du rythme.";
"workday_tick_appearance_title" = "Apparence des repères de jours ouvrés";
Expand Down
Loading