Compare commits

...
3 Commits
Author SHA1 Message Date
tiennm99 51889d3c39 fix(ui): scale weekly bar thickness 2026-05-23 21:43:11 +07:00
tiennm99 6661a7a10b chore: bump version to 0.3.1 2026-05-23 21:07:05 +07:00
tiennm99 6cafffc883 fix(bubble): show 7d percent at default size and 125% DPI
v0.3.0 introduced a tail 7d% reading but the layout-collapse guard
fired at every common bubble configuration — at the default 200-logical
size on both 100% and 125% DPI, after reserving the CJK worst-case
countdown column ("999시간") and the "100%" text rect, the tail had
less than 20 logical of bar room left. The guard collapsed the % rect
to zero width and the paint code's `if rect.right > rect.left` skip
ran on every frame, so the feature was effectively dead on arrival
for the majority of users.

The 20-logical bar minimum was the pre-feature bar floor, used to
guarantee a readable bar at very small bubble sizes. It does not need
to apply when the % is shown — the % is the actual data and the bar
becomes secondary visual context. Split into two thresholds:

- `bar_min_with_pct = 8 logical` decides whether the % can fit. With
  8 logical of bar room the bar still renders as a short pill.
- `bar_min = 20 logical` only applies on the fallback (140-logical
  minimum bubble) path where the % has been dropped — preserving
  the pre-feature readable-bar behavior at the smallest size.

The bar's render floor now follows the active path (`bar_render_min`)
so a thin bar in the pct-active case does not overlap the countdown.
2026-05-23 21:06:26 +07:00
3 changed files with 18 additions and 12 deletions
Generated
+1 -1
View File
@@ -59,7 +59,7 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]] [[package]]
name = "claude-code-usage-bubble" name = "claude-code-usage-bubble"
version = "0.3.0" version = "0.3.2"
dependencies = [ dependencies = [
"dirs", "dirs",
"embed-resource", "embed-resource",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "claude-code-usage-bubble" name = "claude-code-usage-bubble"
version = "0.3.0" version = "0.3.2"
edition = "2021" edition = "2021"
license = "Apache-2.0" license = "Apache-2.0"
description = "Floating bubble showing Claude Code and Codex usage on Windows" description = "Floating bubble showing Claude Code and Codex usage on Windows"
+16 -10
View File
@@ -1031,24 +1031,30 @@ fn compute_bubble_layout(size_logical: i32, dpi: u32, mem_dc: HDC) -> BubbleLayo
let tail_countdown_right = tail_right; let tail_countdown_right = tail_right;
let tail_countdown_left = tail_countdown_right - countdown_w; let tail_countdown_left = tail_countdown_right - countdown_w;
// Try to seat a 7d% text between the "7d" label and the bar. If that would // Try to seat a 7d% text between the "7d" label and the bar. The %
// squeeze the bar below the 20-logical minimum, collapse the % rect (zero // number is the actual data, so it takes precedence over keeping the
// width) and fall back to the original label→bar→countdown layout. This // bar at its pre-feature minimum: when the % shows, the bar may
// keeps the 140-logical bubble legible without dropping the bar. // compress to `bar_min_with_pct` (still visible as a pill). Only when
// even that small bar wouldn't fit do we collapse the % rect entirely
// and restore the pre-feature `bar_min` to keep the bar readable.
// Without this two-tier threshold, the worst-case CJK countdown column
// ("999시간") leaves <20 logical of bar room at the default 200-logical
// size on both 100% and 125% DPI, and the % silently disappears.
let bar_min = scale_to_dpi(20, dpi); let bar_min = scale_to_dpi(20, dpi);
let (tail_pct_left, tail_pct_right, tail_bar_left) = { let bar_min_with_pct = scale_to_dpi(8, dpi);
let (tail_pct_left, tail_pct_right, tail_bar_left, bar_render_min) = {
let pct_left = tail_label_right + pad; let pct_left = tail_label_right + pad;
let pct_right = pct_left + pct_reserve_w; let pct_right = pct_left + pct_reserve_w;
let bar_left = pct_right + pad; let bar_left = pct_right + pad;
if (tail_countdown_left - pad) - bar_left >= bar_min { if (tail_countdown_left - pad) - bar_left >= bar_min_with_pct {
(pct_left, pct_right, bar_left) (pct_left, pct_right, bar_left, bar_min_with_pct)
} else { } else {
let bar_left = tail_label_right + pad; let bar_left = tail_label_right + pad;
(bar_left, bar_left, bar_left) (bar_left, bar_left, bar_left, bar_min)
} }
}; };
let tail_bar_right = (tail_countdown_left - pad).max(tail_bar_left + bar_min); let tail_bar_right = (tail_countdown_left - pad).max(tail_bar_left + bar_render_min);
let tail_bar_h = scale_to_dpi(5, dpi); let tail_bar_h = (height_px * 9 / 100).clamp(scale_to_dpi(5, dpi), scale_to_dpi(12, dpi));
let tail_bar_top = (height_px - tail_bar_h) / 2; let tail_bar_top = (height_px - tail_bar_h) / 2;
BubbleLayout { BubbleLayout {