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>
This commit is contained in:
68
claude_usage_widget/menu.py
Normal file
68
claude_usage_widget/menu.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""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()),
|
||||
)
|
||||
Reference in New Issue
Block a user