Remove standalone fetcher, add setup tool with install/uninstall workflow
All checks were successful
Release / build (push) Successful in 1m45s
All checks were successful
Release / build (push) Successful in 1m45s
Drop claude-fetcher binary and cron job — the widget's built-in BackgroundFetcher is the sole fetcher now. Add cmd/setup with cross-platform install and uninstall (--uninstall): kills widget, removes binaries + autostart, cleans Claude Code statusline setting, optionally removes config dir. Also includes: browser-based login (chromedp), ICO wrapper for Windows tray icon, and reduced icon size (64px). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,11 +2,13 @@ package tray
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"fyne.io/systray"
|
||||
"git.davoryn.de/calic/claude-statusline/internal/browser"
|
||||
"git.davoryn.de/calic/claude-statusline/internal/config"
|
||||
"git.davoryn.de/calic/claude-statusline/internal/fetcher"
|
||||
"git.davoryn.de/calic/claude-statusline/internal/renderer"
|
||||
@@ -49,8 +51,11 @@ func (a *App) onReady() {
|
||||
systray.SetTooltip("Claude Usage: loading...")
|
||||
|
||||
// Set initial icon (0%)
|
||||
if iconData, err := renderer.RenderIconPNG(0); err == nil {
|
||||
iconData, err := renderer.RenderIconForTray(0)
|
||||
log.Printf("initial icon: %d bytes, render err=%v", len(iconData), err)
|
||||
if err == nil {
|
||||
systray.SetIcon(iconData)
|
||||
log.Println("SetIcon called (initial)")
|
||||
}
|
||||
|
||||
// Usage display items (non-clickable info)
|
||||
@@ -82,8 +87,9 @@ func (a *App) onReady() {
|
||||
a.menuItems.intervalRadio = append(a.menuItems.intervalRadio, item)
|
||||
}
|
||||
|
||||
// Session key
|
||||
mSessionKey := systray.AddMenuItem("Session Key...", "Open session key config file")
|
||||
// Login / logout
|
||||
mLogin := systray.AddMenuItem("Login in Browser", "Open browser to log in to claude.ai")
|
||||
mLogout := systray.AddMenuItem("Logout", "Clear session key and browser profile")
|
||||
|
||||
systray.AddSeparator()
|
||||
mQuit := systray.AddMenuItem("Quit", "Exit Claude Usage Widget")
|
||||
@@ -98,8 +104,10 @@ func (a *App) onReady() {
|
||||
select {
|
||||
case <-mRefresh.ClickedCh:
|
||||
a.bf.Refresh()
|
||||
case <-mSessionKey.ClickedCh:
|
||||
a.openSessionKeyFile()
|
||||
case <-mLogin.ClickedCh:
|
||||
go a.doLogin()
|
||||
case <-mLogout.ClickedCh:
|
||||
a.doLogout()
|
||||
case <-mQuit.ClickedCh:
|
||||
systray.Quit()
|
||||
return
|
||||
@@ -133,8 +141,12 @@ func (a *App) onUsageUpdate(data fetcher.ParsedUsage) {
|
||||
if data.Error == "" {
|
||||
pct = data.FiveHourPct
|
||||
}
|
||||
if iconData, err := renderer.RenderIconPNG(pct); err == nil {
|
||||
log.Printf("onUsageUpdate: pct=%d, error=%q", pct, data.Error)
|
||||
if iconData, err := renderer.RenderIconForTray(pct); err == nil {
|
||||
systray.SetIcon(iconData)
|
||||
log.Printf("SetIcon called (pct=%d, %d bytes)", pct, len(iconData))
|
||||
} else {
|
||||
log.Printf("RenderIconPNG error: %v", err)
|
||||
}
|
||||
|
||||
// Update tooltip
|
||||
@@ -200,16 +212,19 @@ func (a *App) setInterval(idx int) {
|
||||
a.bf.SetInterval(intervals[idx].seconds)
|
||||
}
|
||||
|
||||
func (a *App) openSessionKeyFile() {
|
||||
path := config.SessionKeyPath()
|
||||
var cmd *exec.Cmd
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
cmd = exec.Command("notepad", path)
|
||||
case "darwin":
|
||||
cmd = exec.Command("open", "-t", path)
|
||||
default:
|
||||
cmd = exec.Command("xdg-open", path)
|
||||
func (a *App) doLogin() {
|
||||
systray.SetTooltip("Claude Usage: logging in...")
|
||||
_, err := browser.LoginAndGetSessionKey()
|
||||
if err != nil {
|
||||
systray.SetTooltip(fmt.Sprintf("Claude Usage: login failed — %s", err))
|
||||
return
|
||||
}
|
||||
_ = cmd.Start()
|
||||
a.bf.Refresh()
|
||||
}
|
||||
|
||||
func (a *App) doLogout() {
|
||||
_ = os.Remove(config.SessionKeyPath())
|
||||
profileDir := filepath.Join(config.ConfigDir(), "browser-profile")
|
||||
_ = os.RemoveAll(profileDir)
|
||||
a.bf.Refresh()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user