Files
claude-code-usage-bubble/src/main.rs
T
tiennm99 ee4e1c9b26 feat: redesign bubble as two-bar rounded rect, finish port wiring
Bubble shape changes from circle to rounded rectangle showing two stacked
horizontal bars — top: session (5h), bottom: weekly (7d) — each followed
by a right-aligned "X% · Yh Zm" string (percent + countdown).

Bubble surface:
- BubbleConfig/BubbleState carry session+weekly percents and texts (mirrors
  PanelData); update_percentage renamed to update_data
- Aspect ratio fixed at 3:1; size_logical is interpreted as width with
  height derived. Clamp is 120..360 (was 32..128 square)
- Hit-testing uses a rounded-rect predicate (point_in_rounded_rect) shared
  with the alpha mask so paint and click area can't drift
- New rgb_to_dib helper for direct DIB writes — BI_RGB 32bpp stores B,G,R,X
  in memory which is the opposite of COLORREF. The previous code wrote
  COLORREF-packed u32 straight into DIB pixels; invisible while every color
  was gray, but the new orange/red bar fills would have rendered blue
- bar_h capped at h/4 (range 6..18) so the text font derived from it stays
  small enough that "100% · 23h" fits in right_text_w (= 6×bar_h, min 56);
  the first iteration had a 19-px font in a 60-px column and ellipsized
  away the countdown
- Initial session_text/weekly_text seeded with "…" so the bubble has
  visible feedback during the first poll instead of two empty grey tracks

Compile + cleanup needed to make the port build at all:
- Color::from_hex added back as an infallible wrapper around parse_hex
  (15 call sites in bubble.rs/panel.rs assumed the old infallible API)
- Color::to_colorref → into_colorref at 5 call sites
- GetModuleFileNameW added to the LibraryLoader import in bubble.rs
- usage::Error gains Creds(#[from] creds::Error) so `?` works in the
  Anthropic and ChatGPT providers
- FlattenBoxed::flatten renamed to flatten_box — the std Option::flatten
  was shadowing it and yielding Option<Box<T>> instead of Option<T>
- PanelState marked unsafe Send (HWND has *mut c_void; state is only
  touched from the UI thread, Mutex is for OnceLock satisfaction)
- Crate-level #![allow(dead_code)] for in-progress port API surface
  (creds, usage, update, os::dpi); unused pub-use re-exports removed

App wiring:
- propagate_to_ui now feeds both windows + their formatted texts into
  update_data (was a single percent)
2026-05-16 11:11:34 +07:00

44 lines
1.0 KiB
Rust

#![windows_subsystem = "windows"]
// Several modules (creds, usage, update, os::dpi, …) expose API that the
// app surface doesn't fully call yet — they're scaffolding for in-progress
// port phases. Allow at the crate root rather than scattering attributes.
#![allow(dead_code)]
// Original infrastructure.
mod creds;
mod diag;
mod i18n;
mod net;
mod os;
mod tray;
mod update;
mod usage;
// Application surface.
mod app;
mod bubble;
mod panel;
mod settings;
fn main() {
let args: Vec<String> = std::env::args().collect();
let diagnose_enabled = args.iter().any(|a| a == "--diagnose");
if diagnose_enabled {
if let Ok(Some(path)) = diag::init(true) {
log::info!("startup args={args:?} log_path={}", path.display());
}
}
if let Some(exit_code) = update::run_cli(&args) {
if diagnose_enabled {
log::info!("cli mode exited with code {exit_code}");
}
std::process::exit(exit_code);
}
if diagnose_enabled {
log::info!("entering app::run");
}
app::run();
}