Skip to content
Open
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
32 changes: 32 additions & 0 deletions src/app_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ pub const POLL_1_HOUR: u32 = POLL_1_HOUR_SECONDS * 1_000;
// SetTimer clamps longer intervals to USER_TIMER_MAXIMUM (i32::MAX ms).
pub const MAX_POLL_MINUTES: u32 = i32::MAX as u32 / POLL_1_MIN;

/// Which long window the OpenCode widget row shows.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum OpenCodeLongWindow {
/// Always show the 7-day window.
Weekly,
/// Always show the 30-day window.
#[default]
Monthly,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SettingsFile {
#[serde(default)]
Expand Down Expand Up @@ -66,6 +77,9 @@ pub struct SettingsFile {
show_grok: bool,
#[serde(default)]
show_copilot: bool,
/// Which long window the OpenCode widget row shows.
#[serde(default)]
pub opencode_long_window: OpenCodeLongWindow,
#[serde(default = "default_true")]
pub custom_theme_enabled: bool,
/// Show what is left of each allowance instead of what has been spent, so
Expand Down Expand Up @@ -137,6 +151,7 @@ impl Default for SettingsFile {
show_cursor: false,
show_grok: false,
show_copilot: false,
opencode_long_window: OpenCodeLongWindow::Monthly,
custom_theme_enabled: true,
usage_countdown: false,
active_theme_path: None,
Expand Down Expand Up @@ -504,6 +519,23 @@ fn now_unix() -> u64 {
mod tests {
use super::*;

#[test]
fn opencode_long_window_defaults_to_monthly_and_round_trips() {
// A fresh settings file (missing the key) deserialises to Monthly.
let settings = decode_settings("{}").unwrap();
assert_eq!(settings.opencode_long_window, OpenCodeLongWindow::Monthly);

// All variants survive a round-trip.
for variant in [OpenCodeLongWindow::Weekly, OpenCodeLongWindow::Monthly] {
let settings = SettingsFile {
opencode_long_window: variant,
..Default::default()
};
let decoded = decode_settings(&settings_json(&settings).to_string()).unwrap();
assert_eq!(decoded.opencode_long_window, variant);
}
}

#[test]
fn taskbar_lock_is_opt_in_and_survives_settings_round_trip() {
assert!(!decode_settings("{}").unwrap().lock_taskbar);
Expand Down
3 changes: 3 additions & 0 deletions src/localization/locales/de.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ copilot_window_title = "Copilot-Nutzungsmonitor"
"Close Builder" = "Baukasten schließen"
"Codex" = "Codex"
"Collect usage from Anthropic" = "Nutzungsdaten von Anthropic abrufen"
"Collect usage from Cursor" = "Nutzungsdaten von Cursor abrufen"
"Collect usage from GitHub" = "Nutzungsdaten von GitHub abrufen"
"Collect usage from Google" = "Nutzungsdaten von Google abrufen"
"Collect usage from OpenAI" = "Nutzungsdaten von OpenAI abrufen"
"Collect usage from OpenCode Go" = "Nutzungsdaten von OpenCode Go abrufen"
"Collect usage from xAI" = "Nutzungsdaten von xAI abrufen"
"Colour" = "Farbe"
"Column" = "Column"
Expand Down Expand Up @@ -457,3 +459,4 @@ copilot_window_title = "Copilot-Nutzungsmonitor"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "Langer Zeitraum"
3 changes: 3 additions & 0 deletions src/localization/locales/en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ copilot_window_title = "Copilot Usage Monitor"
"Close Builder" = "Close Builder"
"Codex" = "Codex"
"Collect usage from Anthropic" = "Collect usage from Anthropic"
"Collect usage from Cursor" = "Collect usage from Cursor"
"Collect usage from GitHub" = "Collect usage from GitHub"
"Collect usage from Google" = "Collect usage from Google"
"Collect usage from OpenAI" = "Collect usage from OpenAI"
"Collect usage from OpenCode Go" = "Collect usage from OpenCode Go"
"Collect usage from xAI" = "Collect usage from xAI"
"Colour" = "Colour"
"Column" = "Column"
Expand Down Expand Up @@ -457,3 +459,4 @@ copilot_window_title = "Copilot Usage Monitor"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "Long period"
3 changes: 3 additions & 0 deletions src/localization/locales/es.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ copilot_window_title = "Monitor de uso de Copilot"
"Close Builder" = "Cerrar Constructor"
"Codex" = "Codex"
"Collect usage from Anthropic" = "Recopilar uso de Anthropic"
"Collect usage from Cursor" = "Recopilar uso de Cursor"
"Collect usage from GitHub" = "Recopilar uso de GitHub"
"Collect usage from Google" = "Recopilar uso de Google"
"Collect usage from OpenAI" = "Recopilar uso de OpenAI"
"Collect usage from OpenCode Go" = "Recopilar uso de OpenCode Go"
"Collect usage from xAI" = "Recopilar uso de xAI"
"Colour" = "Color"
"Column" = "Column"
Expand Down Expand Up @@ -457,3 +459,4 @@ copilot_window_title = "Monitor de uso de Copilot"
"Lock in taskbar" = "Fijar en la barra"
"Keep the widget docked; never float automatically" = "Mantener el widget acoplado; no flotar automáticamente"
"Locked" = "Fijado"
"Long period" = "Período largo"
3 changes: 3 additions & 0 deletions src/localization/locales/fr.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ copilot_window_title = "Moniteur d'utilisation Copilot"
"Close Builder" = "Fermer le Constructeur"
"Codex" = "Codex"
"Collect usage from Anthropic" = "Collecter l'utilisation depuis Anthropic"
"Collect usage from Cursor" = "Collecter l'utilisation depuis Cursor"
"Collect usage from GitHub" = "Collecter l'utilisation depuis GitHub"
"Collect usage from Google" = "Collecter l'utilisation depuis Google"
"Collect usage from OpenAI" = "Collecter l'utilisation depuis OpenAI"
"Collect usage from OpenCode Go" = "Collecter l'utilisation depuis OpenCode Go"
"Collect usage from xAI" = "Collecter l'utilisation depuis xAI"
"Colour" = "Couleur"
"Column" = "Column"
Expand Down Expand Up @@ -457,3 +459,4 @@ copilot_window_title = "Moniteur d'utilisation Copilot"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "Période longue"
3 changes: 3 additions & 0 deletions src/localization/locales/ja.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ copilot_window_title = "Copilot 使用量モニター"
"Close Builder" = "ビルダーを閉じる"
"Codex" = "Codex"
"Collect usage from Anthropic" = "Anthropic から使用量を取得"
"Collect usage from Cursor" = "Cursor から使用量を取得"
"Collect usage from GitHub" = "GitHub から使用量を取得"
"Collect usage from Google" = "Google から使用量を取得"
"Collect usage from OpenAI" = "OpenAI から使用量を取得"
"Collect usage from OpenCode Go" = "OpenCode Go から使用量を取得"
"Collect usage from xAI" = "xAI から使用量を取得"
"Colour" = "色"
"Column" = "Column"
Expand Down Expand Up @@ -459,3 +461,4 @@ copilot_window_title = "Copilot 使用量モニター"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "長期間"
3 changes: 3 additions & 0 deletions src/localization/locales/ko.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ copilot_window_title = "Copilot 사용량 모니터"
"Close Builder" = "빌더 닫기"
"Codex" = "Codex"
"Collect usage from Anthropic" = "Anthropic에서 사용량 수집"
"Collect usage from Cursor" = "Cursor에서 사용량 수집"
"Collect usage from GitHub" = "GitHub에서 사용량 수집"
"Collect usage from Google" = "Google에서 사용량 수집"
"Collect usage from OpenAI" = "OpenAI에서 사용량 수집"
"Collect usage from OpenCode Go" = "OpenCode Go에서 사용량 수집"
"Collect usage from xAI" = "xAI에서 사용량 수집"
"Colour" = "색상"
"Column" = "Column"
Expand Down Expand Up @@ -459,3 +461,4 @@ copilot_window_title = "Copilot 사용량 모니터"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "장기간"
3 changes: 3 additions & 0 deletions src/localization/locales/nl.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ copilot_window_title = "Copilot-gebruiksmonitor"
"Close Builder" = "Bouwer sluiten"
"Codex" = "Codex"
"Collect usage from Anthropic" = "Gebruiksgegevens ophalen bij Anthropic"
"Collect usage from Cursor" = "Gebruiksgegevens ophalen bij Cursor"
"Collect usage from GitHub" = "Gebruiksgegevens ophalen bij GitHub"
"Collect usage from Google" = "Gebruiksgegevens ophalen bij Google"
"Collect usage from OpenAI" = "Gebruiksgegevens ophalen bij OpenAI"
"Collect usage from OpenCode Go" = "Gebruiksgegevens ophalen bij OpenCode Go"
"Collect usage from xAI" = "Gebruiksgegevens ophalen bij xAI"
"Colour" = "Kleur"
"Column" = "Column"
Expand Down Expand Up @@ -457,3 +459,4 @@ copilot_window_title = "Copilot-gebruiksmonitor"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "Lange periode"
3 changes: 3 additions & 0 deletions src/localization/locales/pl.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ copilot_window_title = "Monitor zużycia Copilot"
"Close Builder" = "Zamknij kreator"
"Codex" = "Codex"
"Collect usage from Anthropic" = "Zbieraj dane o zużyciu z Anthropic"
"Collect usage from Cursor" = "Zbieraj dane o zużyciu z Cursor"
"Collect usage from GitHub" = "Zbieraj dane o zużyciu z GitHuba"
"Collect usage from Google" = "Zbieraj dane o zużyciu z Google"
"Collect usage from OpenAI" = "Zbieraj dane o zużyciu z OpenAI"
"Collect usage from OpenCode Go" = "Zbieraj dane o zużyciu z OpenCode Go"
"Collect usage from xAI" = "Zbieraj dane o zużyciu z xAI"
"Colour" = "Kolor"
"Column" = "Kolumna"
Expand Down Expand Up @@ -457,3 +459,4 @@ copilot_window_title = "Monitor zużycia Copilot"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "Długi okres"
3 changes: 3 additions & 0 deletions src/localization/locales/pt-BR.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ copilot_window_title = "Monitor de uso do Copilot"
"Close Builder" = "Fechar Construtor"
"Codex" = "Codex"
"Collect usage from Anthropic" = "Coletar uso da Anthropic"
"Collect usage from Cursor" = "Coletar uso do Cursor"
"Collect usage from GitHub" = "Coletar uso do GitHub"
"Collect usage from Google" = "Coletar uso do Google"
"Collect usage from OpenAI" = "Coletar uso da OpenAI"
"Collect usage from OpenCode Go" = "Coletar uso do OpenCode Go"
"Collect usage from xAI" = "Coletar uso da xAI"
"Colour" = "Cor"
"Column" = "Column"
Expand Down Expand Up @@ -457,3 +459,4 @@ copilot_window_title = "Monitor de uso do Copilot"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "Período longo"
3 changes: 3 additions & 0 deletions src/localization/locales/ru.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ copilot_window_title = "Монитор использования Copilot"
"Close Builder" = "Закрыть конструктор"
"Codex" = "Codex"
"Collect usage from Anthropic" = "Получать данные об использовании Anthropic"
"Collect usage from Cursor" = "Получать данные об использовании Cursor"
"Collect usage from GitHub" = "Получать данные об использовании GitHub"
"Collect usage from Google" = "Получать данные об использовании Google"
"Collect usage from OpenAI" = "Получать данные об использовании OpenAI"
"Collect usage from OpenCode Go" = "Получать данные об использовании OpenCode Go"
"Collect usage from xAI" = "Получать данные об использовании xAI"
"Colour" = "Цвет"
"Column" = "Column"
Expand Down Expand Up @@ -457,3 +459,4 @@ copilot_window_title = "Монитор использования Copilot"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "Длительный период"
3 changes: 3 additions & 0 deletions src/localization/locales/th.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ copilot_window_title = "ตัวติดตามการใช้งาน C
"Close Builder" = "ปิดตัวสร้าง"
"Codex" = "Codex"
"Collect usage from Anthropic" = "ดึงข้อมูลการใช้งานจาก Anthropic"
"Collect usage from Cursor" = "ดึงข้อมูลการใช้งานจาก Cursor"
"Collect usage from GitHub" = "ดึงข้อมูลการใช้งานจาก GitHub"
"Collect usage from Google" = "ดึงข้อมูลการใช้งานจาก Google"
"Collect usage from OpenAI" = "ดึงข้อมูลการใช้งานจาก OpenAI"
"Collect usage from OpenCode Go" = "ดึงข้อมูลการใช้งานจาก OpenCode Go"
"Collect usage from xAI" = "ดึงข้อมูลการใช้งานจาก xAI"
"Colour" = "สี"
"Column" = "คอลัมน์"
Expand Down Expand Up @@ -459,3 +461,4 @@ copilot_window_title = "ตัวติดตามการใช้งาน C
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "ระยะเวลานาน"
3 changes: 3 additions & 0 deletions src/localization/locales/tr.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ copilot_window_title = "Copilot Kullanım İzleyicisi"
"Close Builder" = "Oluşturucuyu kapat"
"Codex" = "Codex"
"Collect usage from Anthropic" = "Anthropic kullanımını topla"
"Collect usage from Cursor" = "Cursor kullanımını topla"
"Collect usage from GitHub" = "GitHub kullanımını topla"
"Collect usage from Google" = "Google kullanımını topla"
"Collect usage from OpenAI" = "OpenAI kullanımını topla"
"Collect usage from OpenCode Go" = "OpenCode Go kullanımını topla"
"Collect usage from xAI" = "xAI kullanımını topla"
"Colour" = "Renk"
"Column" = "Column"
Expand Down Expand Up @@ -457,3 +459,4 @@ copilot_window_title = "Copilot Kullanım İzleyicisi"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "Uzun dönem"
3 changes: 3 additions & 0 deletions src/localization/locales/zh-CN.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ copilot_window_title = "Copilot 使用量监控"
"Close Builder" = "关闭构建器"
"Codex" = "Codex"
"Collect usage from Anthropic" = "从 Anthropic 获取使用量"
"Collect usage from Cursor" = "从 Cursor 获取使用量"
"Collect usage from GitHub" = "从 GitHub 获取使用量"
"Collect usage from Google" = "从 Google 获取使用量"
"Collect usage from OpenAI" = "从 OpenAI 获取使用量"
"Collect usage from OpenCode Go" = "从 OpenCode Go 获取使用量"
"Collect usage from xAI" = "从 xAI 获取使用量"
"Colour" = "颜色"
"Column" = "Column"
Expand Down Expand Up @@ -459,3 +461,4 @@ copilot_window_title = "Copilot 使用量监控"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "长周期"
3 changes: 3 additions & 0 deletions src/localization/locales/zh-TW.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ copilot_window_title = "Copilot 使用量監控"
"Close Builder" = "關閉建構器"
"Codex" = "Codex"
"Collect usage from Anthropic" = "從 Anthropic 取得使用量"
"Collect usage from Cursor" = "從 Cursor 取得使用量"
"Collect usage from GitHub" = "從 GitHub 取得使用量"
"Collect usage from Google" = "從 Google 取得使用量"
"Collect usage from OpenAI" = "從 OpenAI 取得使用量"
"Collect usage from OpenCode Go" = "從 OpenCode Go 取得使用量"
"Collect usage from xAI" = "從 xAI 取得使用量"
"Colour" = "色彩"
"Column" = "Column"
Expand Down Expand Up @@ -459,3 +461,4 @@ copilot_window_title = "Copilot 使用量監控"
"Lock in taskbar" = "Lock in taskbar"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
"Long period" = "長週期"
38 changes: 38 additions & 0 deletions src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ pub struct UsageData {
/// Kept separate from `weekly` so themes can choose how to display it.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub monthly: Option<UsageSection>,
/// The raw 7-day window for OpenCode, always set when available, independent
/// of the `weekly` auto-selection. Themes read this when
/// `opencode_long_window` is `Weekly` or `Both`.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub weekly_7d: Option<UsageSection>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub credits: Option<CreditsSection>,
/// Additional API quotas, exposed only through opt-in theme bindings.
Expand Down Expand Up @@ -127,6 +132,7 @@ impl UsageData {
[&self.session, &self.weekly]
.into_iter()
.chain(self.monthly.iter())
.chain(self.weekly_7d.iter())
.chain(self.limits.iter().map(|limit| &limit.usage))
.chain(external_sections)
}
Expand Down Expand Up @@ -631,6 +637,38 @@ mod tests {
assert!(json.get("antigravity_external").is_none());
}

#[test]
fn weekly_7d_field_round_trips_and_stays_absent_when_not_set() {
// Present: serialises and deserialises correctly.
let section = UsageSection {
available: true,
percentage: 37.5,
resets_at: None,
};
let data = UsageData {
weekly_7d: Some(section.clone()),
..Default::default()
};
let json = serde_json::to_value(&data).unwrap();
assert_eq!(json["weekly_7d"]["percentage"], 37.5);
let decoded: UsageData = serde_json::from_value(json).unwrap();
assert_eq!(decoded.weekly_7d.as_ref().unwrap().percentage, 37.5);

// Absent: skipped from serialisation (no phantom key).
let empty = UsageData::default();
let json = serde_json::to_value(&empty).unwrap();
assert!(
json.get("weekly_7d").is_none(),
"weekly_7d must be omitted when None"
);
let decoded: UsageData = serde_json::from_value(json).unwrap();
assert!(decoded.weekly_7d.is_none());

// sections() iterator includes weekly_7d when present.
let sections: Vec<_> = data.sections().collect();
assert!(sections.iter().any(|s| s.percentage == 37.5));
}

#[test]
fn absent_window_is_cached_without_a_percentage() {
let section = UsageSection::default();
Expand Down
4 changes: 4 additions & 0 deletions src/poller/opencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ fn poll_dashboard(credentials: &DashboardCredentials) -> Result<UsageData, PollE
// auto-selected `weekly` slot (which prefers the more constrained
// of the two windows, as before).
monthly: usage.monthly.as_ref().map(section_from_window),
// The raw 7-day window, always set when available, independent of the
// auto-selection. Themes read this when opencode_long_window is Weekly
// or Both.
weekly_7d: usage.weekly.as_ref().map(section_from_window),
credits: None,
stale: false,
..Default::default()
Expand Down
1 change: 1 addition & 0 deletions src/studio_app/studio_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ impl StudioApp {
self.settings.antigravity_external_enabled(),
1.0,
)
.with_opencode_long_window(self.settings.opencode_long_window)
}

pub(super) fn theme_runtime_for_surface(&self, surface_index: usize) -> ThemeRuntime {
Expand Down
2 changes: 1 addition & 1 deletion src/studio_app/studio_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ fn window_label(provider: &str, window: &str) -> &'static str {
match (provider, window) {
("cursor", "session") => "Auto",
("cursor", "weekly") => "API",
("opencode", "weekly") => "Long window",
("opencode", "weekly") => "Long period",
(_, "session") => "Session",
(_, "five_hour") => "5-hour",
(_, "weekly") => "Weekly",
Expand Down
Loading