Some checks failed
Release / build (push) Failing after 19s
Full Syncthing tray wrapper with: - System tray with 5 icon states (idle/syncing/paused/error/disconnected) - Syncthing REST API client with auto-discovered API key - Long-polling event listener for real-time status - Transfer rate monitoring, folder tracking, recent files, conflict counting - Full context menu with folders, recent files, settings toggles - Embedded admin panel binary (webview, requires CGO) - OS notifications via beeep (per-event configurable) - Syncthing process management with auto-restart - Cross-platform installer with autostart - CI pipeline for Linux (.deb + .tar.gz) and Windows (.zip) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
88 lines
1.8 KiB
Go
88 lines
1.8 KiB
Go
package tray
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.davoryn.de/calic/syncwarden/internal/icons"
|
|
"git.davoryn.de/calic/syncwarden/internal/monitor"
|
|
)
|
|
|
|
// formatTooltip generates the tooltip text from aggregate status.
|
|
func formatTooltip(s monitor.AggregateStatus, showRate bool) string {
|
|
stateStr := stateLabel(s.State)
|
|
|
|
tip := fmt.Sprintf("SyncWarden: %s", stateStr)
|
|
|
|
// Devices
|
|
tip += fmt.Sprintf(" | %d/%d devices", s.DevicesOnline, s.DevicesTotal)
|
|
|
|
// Transfer rate
|
|
if showRate && (s.DownRate > 0 || s.UpRate > 0) {
|
|
tip += fmt.Sprintf(" | ↓%s ↑%s", formatBytes(s.DownRate), formatBytes(s.UpRate))
|
|
}
|
|
|
|
// Last sync
|
|
if !s.LastSync.IsZero() {
|
|
tip += fmt.Sprintf(" | Last sync: %s", formatTimeAgo(s.LastSync))
|
|
}
|
|
|
|
return tip
|
|
}
|
|
|
|
func stateLabel(s icons.State) string {
|
|
switch s {
|
|
case icons.StateIdle:
|
|
return "Idle"
|
|
case icons.StateSyncing:
|
|
return "Syncing"
|
|
case icons.StatePaused:
|
|
return "Paused"
|
|
case icons.StateError:
|
|
return "Error"
|
|
case icons.StateDisconnected:
|
|
return "Disconnected"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
func formatBytes(bps float64) string {
|
|
if bps < 1024 {
|
|
return fmt.Sprintf("%.0f B/s", bps)
|
|
}
|
|
if bps < 1024*1024 {
|
|
return fmt.Sprintf("%.1f KB/s", bps/1024)
|
|
}
|
|
if bps < 1024*1024*1024 {
|
|
return fmt.Sprintf("%.1f MB/s", bps/(1024*1024))
|
|
}
|
|
return fmt.Sprintf("%.1f GB/s", bps/(1024*1024*1024))
|
|
}
|
|
|
|
func formatTimeAgo(t time.Time) string {
|
|
d := time.Since(t)
|
|
if d < time.Minute {
|
|
return "just now"
|
|
}
|
|
if d < time.Hour {
|
|
m := int(d.Minutes())
|
|
if m == 1 {
|
|
return "1 min ago"
|
|
}
|
|
return fmt.Sprintf("%d min ago", m)
|
|
}
|
|
if d < 24*time.Hour {
|
|
h := int(d.Hours())
|
|
if h == 1 {
|
|
return "1 hour ago"
|
|
}
|
|
return fmt.Sprintf("%d hours ago", h)
|
|
}
|
|
days := int(d.Hours()) / 24
|
|
if days == 1 {
|
|
return "1 day ago"
|
|
}
|
|
return fmt.Sprintf("%d days ago", days)
|
|
}
|