Skip to content

Commit 643cc0a

Browse files
committed
v1.3.0
- Added a native system tray icon that shows current 5-hour usage as a percentage badge. - Added tray icon tooltip support showing both 5h and 7d countdown/usage values. - Added tray icon interactions: left-click toggles the taskbar widget, right-click opens the context menu. - Anchored widget to the bottom of the taskbar - Added embedded app icon loading so tray fallback uses the app's own icon. - Updated countdown timer logic to stop cases where 61m is shown - Updated README.md
1 parent 1d8ec6c commit 643cc0a

File tree

5 files changed

+37
-57
lines changed

5 files changed

+37
-57
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "claude-code-usage-monitor"
3-
version = "1.2.11"
3+
version = "1.3.0"
44
edition = "2021"
55
license = "MIT"
66
description = "Claude Code Usage Monitor"

README.md

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1+
![Windows](https://img.shields.io/badge/platform-Windows-blue)
2+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
3+
14
# Claude Code Usage Monitor
25

6+
![Screenshot](.github/animation.gif)
7+
38
A lightweight Windows taskbar widget for people already using Claude Code.
49

510
It sits in your taskbar and shows how much of your Claude Code usage window you have left, without needing to open the terminal or the Claude site.
611

7-
![Windows](https://img.shields.io/badge/platform-Windows-blue)
8-
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9-
10-
![Screenshot](.github/animation.gif)
11-
1212
## What You Get
1313

1414
- A **5h** bar for your current 5-hour Claude usage window
@@ -59,15 +59,7 @@ Once running, it will appear in your taskbar and as a tray icon in the notificat
5959

6060
### System Tray Icon
6161

62-
The tray icon shows your current 5-hour usage as a color-coded percentage badge:
63-
64-
| Color | Meaning |
65-
|--------|-------------------|
66-
| Green | Under 50% used |
67-
| Yellow | 50–75% used |
68-
| Orange | 75–90% used |
69-
| Red | 90% or more used |
70-
| Gray | No data available |
62+
The tray icon shows your current 5-hour usage as a color-coded percentage badge.
7163

7264
Hovering over the tray icon shows a tooltip with both your 5h and 7d usage.
7365

src/poller.rs

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -663,55 +663,48 @@ fn format_countdown(resets_at: Option<SystemTime>, strings: Strings) -> String {
663663
Err(_) => return strings.now.to_string(),
664664
};
665665

666-
let total_secs = remaining.as_secs();
666+
format_countdown_from_secs(remaining.as_secs(), strings)
667+
}
668+
669+
/// Calculate how long until the display text would change
670+
pub fn time_until_display_change(resets_at: Option<SystemTime>) -> Option<Duration> {
671+
let reset = resets_at?;
672+
let remaining = reset.duration_since(SystemTime::now()).ok()?;
673+
Some(time_until_display_change_from_secs(remaining.as_secs()))
674+
}
675+
676+
fn format_countdown_from_secs(total_secs: u64, strings: Strings) -> String {
667677
let total_mins = total_secs / 60;
668678
let total_hours = total_secs / 3600;
669679
let total_days = total_secs / 86400;
670680

671681
if total_days >= 1 {
672682
format!("{total_days}{}", strings.day_suffix)
673-
} else if total_mins > 61 {
683+
} else if total_hours >= 1 {
674684
format!("{total_hours}{}", strings.hour_suffix)
675-
} else if total_secs > 60 {
685+
} else if total_mins >= 1 {
676686
format!("{total_mins}{}", strings.minute_suffix)
677687
} else {
678688
format!("{total_secs}{}", strings.second_suffix)
679689
}
680690
}
681691

682-
/// Calculate how long until the display text would change
683-
pub fn time_until_display_change(resets_at: Option<SystemTime>) -> Option<Duration> {
684-
let reset = resets_at?;
685-
let remaining = reset.duration_since(SystemTime::now()).ok()?;
686-
687-
let total_secs = remaining.as_secs();
692+
fn time_until_display_change_from_secs(total_secs: u64) -> Duration {
688693
let total_mins = total_secs / 60;
689694
let total_hours = total_secs / 3600;
690695
let total_days = total_secs / 86400;
691696

692-
if total_secs <= 60 {
693-
// Update every second during final countdown
694-
return Some(Duration::from_secs(1));
695-
}
696-
697-
let next_boundary = if total_days >= 1 {
698-
Duration::from_secs(total_days * 86400)
699-
} else if total_mins > 61 {
700-
if total_hours > 1 {
701-
Duration::from_secs(total_hours * 3600)
702-
} else {
703-
Duration::from_secs(61 * 60)
704-
}
697+
let current_bucket_start = if total_days >= 1 {
698+
total_days * 86400
699+
} else if total_hours >= 1 {
700+
total_hours * 3600
701+
} else if total_mins >= 1 {
702+
total_mins * 60
705703
} else {
706-
Duration::from_secs(total_mins * 60)
704+
total_secs
707705
};
708706

709-
let delay = remaining.saturating_sub(next_boundary);
710-
if delay > Duration::ZERO {
711-
Some(delay + Duration::from_secs(1))
712-
} else {
713-
Some(Duration::from_secs(1))
714-
}
707+
Duration::from_secs(total_secs.saturating_sub(current_bucket_start) + 1)
715708
}
716709

717710
/// Returns true if either section has reached "now" (reset time has passed).

src/window.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,8 +1179,8 @@ fn paint_content(
11791179
let _ = DeleteObject(right_brush);
11801180

11811181
let content_x = sc(LEFT_DIVIDER_W) + sc(DIVIDER_RIGHT_MARGIN);
1182-
let row1_y = sc(5);
1183-
let row2_y = sc(5) + sc(SEGMENT_H) + sc(10);
1182+
let row2_y = height - sc(5) - sc(SEGMENT_H);
1183+
let row1_y = row2_y - sc(10) - sc(SEGMENT_H);
11841184

11851185
let _ = SetBkMode(hdc, TRANSPARENT);
11861186
let _ = SetTextColor(hdc, COLORREF(text_color.to_colorref()));
@@ -1408,14 +1408,12 @@ fn position_at_taskbar() {
14081408

14091409
let taskbar_height = taskbar_rect.bottom - taskbar_rect.top;
14101410
let mut tray_left = taskbar_rect.right;
1411-
let mut anchor_top = taskbar_rect.top;
1412-
let mut anchor_height = taskbar_height;
1411+
let anchor_top = taskbar_rect.top;
1412+
let anchor_height = taskbar_height;
14131413

14141414
if let Some(tray_hwnd) = native_interop::find_child_window(taskbar_hwnd, "TrayNotifyWnd") {
14151415
if let Some(tray_rect) = native_interop::get_window_rect_safe(tray_hwnd) {
14161416
tray_left = tray_rect.left;
1417-
anchor_top = tray_rect.top;
1418-
anchor_height = tray_rect.bottom - tray_rect.top;
14191417
}
14201418
}
14211419

@@ -1443,8 +1441,7 @@ fn position_at_taskbar() {
14431441

14441442
fn compute_anchor_y(anchor_top: i32, anchor_height: i32, widget_height: i32) -> i32 {
14451443
let anchor_bottom = anchor_top + anchor_height;
1446-
let bottom_padding = (anchor_height - widget_height).clamp(0, sc(6));
1447-
(anchor_bottom - widget_height - bottom_padding).max(anchor_top)
1444+
(anchor_bottom - widget_height).max(anchor_top)
14481445
}
14491446

14501447
/// WinEvent callback for tray icon location changes
@@ -1667,16 +1664,14 @@ unsafe extern "system" fn wnd_proc(
16671664
if let Some(taskbar_rect) = native_interop::get_taskbar_rect(taskbar_hwnd) {
16681665
let taskbar_height = taskbar_rect.bottom - taskbar_rect.top;
16691666
let mut tray_left = taskbar_rect.right;
1670-
let mut anchor_top = taskbar_rect.top;
1671-
let mut anchor_height = taskbar_height;
1667+
let anchor_top = taskbar_rect.top;
1668+
let anchor_height = taskbar_height;
16721669
if let Some(tray_hwnd) =
16731670
native_interop::find_child_window(taskbar_hwnd, "TrayNotifyWnd")
16741671
{
16751672
if let Some(tray_rect) = native_interop::get_window_rect_safe(tray_hwnd)
16761673
{
16771674
tray_left = tray_rect.left;
1678-
anchor_top = tray_rect.top;
1679-
anchor_height = tray_rect.bottom - tray_rect.top;
16801675
}
16811676
}
16821677
let widget_width = total_widget_width();

0 commit comments

Comments
 (0)