Files
claude-statusline/claude_usage_widget/menu.py
Axel Meyer 6a1b4bd022 Add desktop tray widget + installer wizard
- Desktop widget (Python/pystray): system tray icon showing 5h usage as
  circular progress bar with Claude starburst logo, 10-step green-to-red
  color scale, right-click menu with usage stats and configuration
- Shared cache: both widget and CLI statusline read/write the same
  /tmp/claude_usage.json — only one fetcher needs to run
- Installer wizard (install_wizard.py): interactive cross-platform setup
  with component selection, session key prompt, cron/autostart config
- OS wrappers: install.sh (Linux/macOS) and install.ps1 (Windows) find
  Python 3.9+ and launch the wizard
- README with topology diagram, usage docs, and configuration reference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:54:32 +00:00

69 lines
2.2 KiB
Python

"""pystray Menu builder with dynamic text and radio interval selection."""
import pystray
_INTERVALS = [
(60, "1 min"),
(300, "5 min"),
(900, "15 min"),
(1800, "30 min"),
]
def build_menu(app):
"""Build the right-click menu. `app` must expose:
- app.usage_data (dict from fetcher.parse_usage)
- app.fetcher (UsageFetcher instance)
- app.on_refresh()
- app.on_set_interval(seconds)
- app.on_session_key()
- app.on_quit()
"""
def _five_hour_text(_):
d = app.usage_data
if not d or d.get("error"):
return f"5h Usage: {d.get('error', '?')}" if d else "5h Usage: loading..."
return f"5h Usage: {d.get('five_hour_pct', 0)}%"
def _five_hour_reset(_):
d = app.usage_data
r = d.get("five_hour_resets_in", "") if d else ""
return f"Resets in: {r}" if r else "Resets in: —"
def _seven_day_text(_):
d = app.usage_data
if not d or d.get("error"):
return "7d Usage: —"
return f"7d Usage: {d.get('seven_day_pct', 0)}%"
def _seven_day_reset(_):
d = app.usage_data
r = d.get("seven_day_resets_in", "") if d else ""
return f"Resets in: {r}" if r else "Resets in: —"
def _make_interval_item(seconds, label):
return pystray.MenuItem(
label,
lambda _, s=seconds: app.on_set_interval(s),
checked=lambda _, s=seconds: app.fetcher.interval == s,
radio=True,
)
interval_items = [_make_interval_item(s, l) for s, l in _INTERVALS]
return pystray.Menu(
pystray.MenuItem(_five_hour_text, None, enabled=False),
pystray.MenuItem(_five_hour_reset, None, enabled=False),
pystray.Menu.SEPARATOR,
pystray.MenuItem(_seven_day_text, None, enabled=False),
pystray.MenuItem(_seven_day_reset, None, enabled=False),
pystray.Menu.SEPARATOR,
pystray.MenuItem("Refresh Now", lambda _: app.on_refresh()),
pystray.MenuItem("Refresh Interval", pystray.Menu(*interval_items)),
pystray.MenuItem("Session Key...", lambda _: app.on_session_key()),
pystray.Menu.SEPARATOR,
pystray.MenuItem("Quit", lambda _: app.on_quit()),
)