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
10 changes: 10 additions & 0 deletions src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::time::SystemTime;
pub struct UsageSection {
pub percentage: f64,
pub resets_at: Option<SystemTime>,
pub has_bucket: bool,
}

#[derive(Clone, Debug, Default)]
Expand All @@ -12,9 +13,18 @@ pub struct UsageData {
pub weekly: UsageSection,
}

#[derive(Clone, Debug, Default)]
pub struct AccountUsage {
pub credit_pct: f64,
pub credit_expiry: Option<SystemTime>,
pub spend_used: f64,
pub spend_limit: f64,
}

#[derive(Clone, Debug, Default)]
pub struct AppUsageData {
pub claude_code: Option<UsageData>,
pub codex: Option<UsageData>,
pub antigravity: Option<UsageData>,
pub account: Option<AccountUsage>,
}
40 changes: 40 additions & 0 deletions src/native_interop.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use windows::core::PCWSTR;
use windows::Win32::Foundation::{BOOL, HWND, LPARAM, RECT};
use windows::Win32::Globalization::GetLocaleInfoW;
use windows::Win32::UI::Accessibility::{SetWinEventHook, UnhookWinEvent, HWINEVENTHOOK};
use windows::Win32::UI::Shell::{SHAppBarMessage, ABM_GETTASKBARPOS, APPBARDATA};
use windows::Win32::UI::WindowsAndMessaging::*;

const LOCALE_USER_DEFAULT: u32 = 0x0400;
// Short date format pattern (e.g. "M/d/yyyy")
const LOCALE_SSHORTDATE: u32 = 0x001F;

// Window style constants
pub const WS_POPUP_STYLE: u32 = 0x80000000;
pub const WS_CHILD_STYLE: u32 = 0x40000000;
Expand Down Expand Up @@ -181,6 +186,41 @@ pub fn wide_str(s: &str) -> Vec<u16> {
s.encode_utf16().chain(std::iter::once(0)).collect()
}

/// Format a month/day pair respecting the Windows system locale
/// (separator, and whether day or month comes first).
/// Returns e.g. "9/15" (en-US), "15/9" (en-GB), "15.9" (de-DE).
pub fn format_month_day_locale(month: u8, day: u8) -> String {
if let Some(pattern) = locale_short_date_pattern() {
let lower = pattern.to_lowercase();
// Find the separator: first non-alphabetic, non-quote character
let sep = lower
.chars()
.find(|c| !c.is_alphabetic() && *c != '\'')
.unwrap_or('/');
// day-first when 'd' appears before 'm' in the pattern (e.g. "dd/MM/yyyy")
let d_pos = lower.find('d');
let m_pos = lower.find('m');
return match (d_pos, m_pos) {
(Some(d), Some(m)) if d < m => format!("{}{}{}", day, sep, month),
(Some(_), Some(_)) => format!("{}{}{}", month, sep, day),
_ => format!("{}/{}", month, day), // malformed pattern — safe fallback
};
}
format!("{}/{}", month, day)
}

fn locale_short_date_pattern() -> Option<String> {
unsafe {
let mut buf = [0u16; 256];
let len = GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, Some(&mut buf));
if len > 1 && (len as usize) <= buf.len() {
Some(String::from_utf16_lossy(&buf[..len as usize - 1]).to_string())
} else {
None
}
}
}

/// COLORREF wrapper (RGB packed into u32)
pub fn colorref(r: u8, g: u8, b: u8) -> u32 {
r as u32 | (g as u32) << 8 | (b as u32) << 16
Expand Down
Loading