Commit Graph

4 Commits

Author SHA1 Message Date
tiennm99 5df75c901e feat(bubble): apply full UX review — labels, inline percent, accent, snaps
Implements every recommendation from the UI/UX review of the two-bar
bubble: readability bump, faster glanceability, per-provider identity,
smarter resize curve, and a richer snap behavior set.

Readability + sizing:
- Default width 180 → 200, min 120 → 140 (Windows shell minimum legible
  status-text floor is 12 px; previous breakpoint produced 11 px text)
- Discrete breakpoint table replaces the linear bar_h = h/4 formula —
  140/200/280/360 widths map to (bar_h, font, row_gap) of
  (12,11,4)/(16,13,6)/(20,15,8)/(24,17,10)
- Aspect tapers 3:1 → 2.8:1 → 2.6:1 as width grows so bars stay
  proportionally chunky at large sizes
- Right-column width now derived from GetTextExtentPoint32W of
  "100% · 23h" against the real font instead of the bar_h * 6 heuristic

Glanceability:
- ring_color_for_percent rewritten as a 4-band cliff: orange < 60,
  amber 60-80, red 80-95, deep red ≥ 95 — gradient hid the 75 vs 85
  difference at narrow bar widths
- Percent moved inside the bar (right-aligned with auto-contrast picked
  from luminance of the underlying fill or track)
- Right column now shows only the countdown ("2h 14m"), not the
  combined "X% · 2h 14m" string. i18n::format_countdown is now pub so
  the bubble can request countdown-only; the panel still renders the
  combined string via format_window
- "5h" / "7d" muted labels added in a new left column
- Rows whose bar is ≥ 95 % get a 15 %-red blush behind the entire row;
  fill color also brightens via a slow triangle wave (TIMER_PULSE,
  80 ms, only armed when at least one bar is in the alarm band)

Per-provider identity:
- 4-px vertical accent stripe at the left edge — Claude orange
  (#D97757), Codex green (#10A37F) — disambiguates the two bubbles
  when both are enabled. Mirrored into the expanded panel so the
  identity carries across surfaces

Snap behavior:
- Corner snap: release within 32 px of a work-area corner slams the
  bubble into the corner with a 12-px inset
- Taskbar-adjacency: SHAppBarMessage(ABM_GETTASKBARPOS) supplies the
  taskbar rect/edge; bubble docks against the inner face with a
  4-px gap on the docked edge
- Peer-Y alignment: when a second bubble exists within ±8 px on Y
  at release time, the dragged bubble snaps to share its top edge
- WM_SETTINGCHANGE handler re-clamps bubbles into the new work area
  when taskbar moves / auto-hides / DPI changes

Color packing:
- Direct DIB writes use rgb_to_dib (B,G,R,X memory order) instead of
  into_colorref (R,G,B,X COLORREF order). Already corrected in the
  previous redesign for the bar fills, but the accent stripe and blush
  go through the same path now
2026-05-16 11:35:02 +07:00
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
tiennm99 aa6217d2cf feat: clean-room rewrite — replace ported modules with original implementations
Every Rust module under src/ that previously contained upstream-derivative
code has been replaced by a from-scratch implementation:

  diag/    log + simplelog file appender (was: diagnose.rs)
  os/      color, dpi, registry, string, theme (was: theme.rs, native_interop.rs)
  net/     WinHTTP-based HTTP client (was: ureq + native-tls)
  i18n/    TOML-embedded locale tables (was: localization/*.rs)
  usage/   trait UsageProvider + ClaudeProvider + ChatGptProvider + refresh
           orchestrator + registry (was: poller.rs, models.rs)
  creds/   trait CredentialSource + local/WSL/Codex impls (was: poller.rs)
  tray/    stateless tray manager + tiny-skia anti-aliased badge renderer
           (was: tray_icon.rs)
  update/  release fetch + inline cmd /c handoff installer
           (was: updater.rs's helper-exe pattern)

Application files (app.rs, bubble.rs, panel.rs, settings.rs) migrated to
the new modules. main.rs declares only the new modules.

NOTICE deleted; LICENSE is plain Apache-2.0; README updated to credit
inspiration rather than claim derivation. Cargo.toml drops ureq + native-tls
+ winres in favour of log + simplelog + thiserror + toml + tiny-skia +
embed-resource. Build script swapped to embed-resource via res/icon.rc.

External contracts preserved unchanged: Anthropic + ChatGPT endpoints and
headers, ~/.claude/.credentials.json + Codex auth.json paths, WSL bridging
via wsl.exe, CLI-driven token refresh, GitHub Releases JSON shape, Windows
registry path for startup, single-instance mutex name.

Phase docs: plans/260516-0707-cleanroom-rewrite/.
2026-05-16 10:09:43 +07:00
tiennm99 c0f3e3f860 feat: initial port of claude-code-usage-monitor as a floating bubble
Windows-only floating, draggable circular bubble showing Claude Code
and Codex usage. Derivative of CodeZeno/Claude-Code-Usage-Monitor (MIT),
relicensed under Apache 2.0 with upstream attribution in NOTICE.

- Ported verbatim: poller, updater, tray_icon, theme, localization,
  diagnose, models (~2,700 LOC)
- Original: bubble (circular layered window, drag-anywhere via
  WM_NCHITTEST+HTCAPTION, snap-to-edge, Ctrl+Wheel resize, auto-hide
  on fullscreen), panel (expanded 5h/7d view), app (orchestrator,
  single-instance mutex, polling thread, context menu, dual-bubble
  lifecycle), settings (settings.json persistence)
- Cargo.toml features cover Win32 GDI, HiDpi, Registry, Threading,
  Shell, WindowsAndMessaging, and KeyboardAndMouse
2026-05-15 21:27:31 +07:00