Commit Graph

7 Commits

Author SHA1 Message Date
tiennm99 3e1af07ec2 feat(i18n): switch supported languages to en/ja/ko/vi/zh-TW
Drop nl/es/fr/de locales (no native-speaker maintenance) and add
Vietnamese. The supported set is now the languages with active
users we can support: English, Japanese, Korean, Vietnamese, and
Traditional Chinese.
2026-05-21 16:51:15 +07:00
tiennm99 1cd5b778f4 feat(update): replace cmd.exe handoff with native Win32 spawn
Both the in-app restart and the auto-update install previously
shelled out to cmd.exe so the new instance could wait for the old
one to release the singleton mutex and the locked exe file. On
some Windows configurations the `start ""` inside `cmd /c ...` can
flash a console window despite CREATE_NO_WINDOW + DETACHED_PROCESS
flags. The replacement spawns the child binary directly via
CreateProcessW; since the main exe is built with
windows_subsystem = "windows", no console is ever allocated.

- New `src/update/handoff.rs` exposes `spawn_detached`,
  `wait_for_parent_exit`, and `cleanup_stale_old_exes`.
- New CLI flags `--wait-pid <pid>` and `--updated-to <version>`
  parsed early in `main`; the child waits up to 5s on the parent
  PID via OpenProcess+WaitForSingleObject before falling through
  to a 3s mutex-acquisition retry.
- `restart_app` and `install::begin` both spawn detached children
  using the new helper.
- Update install now uses MoveFileExW twice (rename running exe
  sideways, then move staged exe into place with
  MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED so portable
  installs on non-system drives still work). Rollback restores
  the backup if either the swap OR the post-swap detached spawn
  fails, and a MessageBoxW modal surfaces the backup path if the
  rollback itself fails.
- First launch after an auto-update shows a blue-info tray
  balloon "Updated to vX.Y.Z" via a new `tray::notify_info` (the
  existing `tray::notify` is split into `notify_warning` +
  `notify_info` sharing a `notify_inner`).
- Startup sweeps stale `<exe>.old.<pid>` siblings left by past
  in-place updates.
- Three new `LocaleStrings` fields translated across all 8
  supported locales (en/nl/es/fr/de/ja/ko/zh-TW).
2026-05-21 16:28:25 +07:00
tiennm99 f1dfe15000 feat(menu): add Restart action between separator and Exit
One-click relaunch of the running binary via a detached cmd.exe handoff:
timeout /t 1 /nobreak >/dev/null & start "" "<exe>" — the 1s wait outlives the
parent so the relaunched instance acquires Global\ClaudeCodeUsageBubble
without ERROR_ALREADY_EXISTS.

- New IDM_RESTART (33) wired into show_context_menu + on_menu_command.
- Match arm placed above the IDM_LANG_BASE guard so future ids in the
  static band can't be swallowed by the dynamic-language catch-all.
- Settings flushed defensively before quit (clone-then-save to avoid
  blocking the UI thread on disk I/O while holding lock_state).
- Rejects current_exe paths containing '%' (same defense as
  update::install — cmd.exe expands %var% inside quotes).
- New 'restart' string in LocaleStrings + translation in all 8 locales.
2026-05-18 10:39:19 +07:00
tiennm99 ed9b8b2042 feat: threshold balloons + dark/light auto-follow
- Threshold balloons fire the cycle utilization crosses 80% or 95%
  on either provider, with the title showing "{Provider} · {N}%" and
  body translated per shipped locale. Reuses the existing
  BALLOON_COOLDOWN so notifications stay calm.
- Dark/light auto-follow: bubble's WM_SETTINGCHANGE handler now calls
  app::recheck_theme(), which re-reads HKCU\…\Personalize, updates
  state.is_dark if changed, and triggers a UI repaint + tray refresh.
  Windows posts WM_SETTINGCHANGE to every top-level window when the
  user toggles light/dark in Settings, so the bubble repaints in
  near-real-time.
- Adds 2 new i18n keys (threshold_80_body, threshold_95_body) across
  all eight shipped locales.

Bumps version to 0.1.5.
2026-05-16 13:57:15 +07:00
tiennm99 2ca5052915 feat: configurable auto-update check frequency
Adds a "Settings > Auto-update check" submenu with Disabled / Hourly /
Daily / Weekly. Hourly is the default; existing settings files pick it
up automatically via serde default. Manual "Check for updates" is
unchanged and still fires when auto is disabled.

The 24-hour hardcoded interval is replaced by reading
Settings.update_check_interval_secs in both the startup scheduler and
the post-check rearm path. None means auto is disabled and no timer is
armed.

Adds five new i18n keys across all eight locales.
2026-05-16 12:57:50 +07:00
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 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