- 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>
69 lines
2.2 KiB
Python
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()),
|
|
)
|