feat: add tray streaming status and app icon
- tray icon and tooltip now reflect engine state: grey when stopped, green + live frame/drop counters in the tooltip while streaming - generate a proper app icon (assets/, via cmd/teleportfling-icon) and embed it so the window and tray carry the icon without runtime files - add a .desktop entry template for launching from an app menu - run Fyne UI updates (status label, tray icon/tooltip) on the main thread via fyne.Do to satisfy the threading model
This commit is contained in:
+37
-1
@@ -8,6 +8,7 @@ package gui
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image/color"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -18,7 +19,9 @@ import (
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/driver/desktop"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"fyne.io/systray"
|
||||
|
||||
"teleportfling/assets"
|
||||
"teleportfling/internal/config"
|
||||
"teleportfling/internal/flinger"
|
||||
)
|
||||
@@ -38,11 +41,15 @@ const appID = "io.teleportfling"
|
||||
type App struct {
|
||||
fyneApp fyne.App
|
||||
win fyne.Window
|
||||
desk desktop.App
|
||||
|
||||
cfg config.Config
|
||||
eng *flinger.Engine
|
||||
lock bool // serialises start/stop against UI actions
|
||||
|
||||
// Tray state icons, built once at startup.
|
||||
iconIdle, iconActive *staticResource
|
||||
|
||||
// UI state.
|
||||
startBtn *widget.Button
|
||||
statusLab *widget.Label
|
||||
@@ -62,6 +69,9 @@ func Run() {
|
||||
|
||||
g.fyneApp = app.NewWithID(appID)
|
||||
g.win = g.fyneApp.NewWindow("TeleportFling")
|
||||
g.fyneApp.SetIcon(fyne.NewStaticResource("teleportfling", assets.AppIcon))
|
||||
g.iconIdle = newTrayResource(color.NRGBA{R: 90, G: 90, B: 95, A: 255}, color.NRGBA{R: 60, G: 60, B: 65, A: 255})
|
||||
g.iconActive = newTrayResource(color.NRGBA{R: 46, G: 125, B: 50, A: 255}, color.NRGBA{R: 150, G: 220, B: 140, A: 255})
|
||||
|
||||
// Load persisted settings (falling back to defaults).
|
||||
g.cfg = mustLoadConfig()
|
||||
@@ -207,6 +217,7 @@ func (g *App) start() {
|
||||
g.startBtn.Importance = widget.DangerImportance
|
||||
g.statusLab.SetText("Streaming (port " + itoa(g.cfg.Port) + ")")
|
||||
g.statusLab.Importance = widget.SuccessImportance
|
||||
g.setTrayState(true, "TeleportFling · Streaming")
|
||||
g.refresh()
|
||||
g.watchStats()
|
||||
}
|
||||
@@ -225,7 +236,13 @@ func (g *App) watchStats() {
|
||||
return
|
||||
}
|
||||
st := g.eng.Status()
|
||||
g.statusLab.SetText(formatStatus(st))
|
||||
frames := itoa(int(st.Frames))
|
||||
dropped := itoa(int(st.Dropped))
|
||||
// Fyne UI calls must run on the main thread.
|
||||
fyne.Do(func() {
|
||||
g.statusLab.SetText(formatStatus(st))
|
||||
g.setTrayState(true, "TeleportFling · "+frames+" frames, "+dropped+" dropped")
|
||||
})
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
@@ -256,6 +273,7 @@ func (g *App) stop() {
|
||||
g.startBtn.Importance = widget.HighImportance
|
||||
g.statusLab.SetText("Stopped")
|
||||
g.statusLab.Importance = widget.MediumImportance
|
||||
g.setTrayState(false, "TeleportFling")
|
||||
g.refresh()
|
||||
}
|
||||
|
||||
@@ -274,6 +292,7 @@ func (g *App) setupTray() {
|
||||
log.Printf("gui: system tray not supported on this desktop")
|
||||
return
|
||||
}
|
||||
g.desk = desk
|
||||
|
||||
m := fyne.NewMenu("TeleportFling",
|
||||
fyne.NewMenuItem("Show", func() {
|
||||
@@ -301,4 +320,21 @@ func (g *App) setupTray() {
|
||||
// Left-clicking the tray icon shows the settings window.
|
||||
desk.SetSystemTrayWindow(g.win)
|
||||
g.win.SetOnClosed(func() { g.fyneApp.Quit() })
|
||||
|
||||
// Show the "stopped" state icon initially.
|
||||
g.setTrayState(false, "TeleportFling")
|
||||
}
|
||||
|
||||
// setTrayState swaps the tray icon and tooltip to reflect the streaming state.
|
||||
// It is a no-op if the tray is unavailable.
|
||||
func (g *App) setTrayState(streaming bool, tooltip string) {
|
||||
if g.desk == nil || g.iconIdle == nil || g.iconActive == nil {
|
||||
return
|
||||
}
|
||||
icon := fyne.Resource(g.iconIdle)
|
||||
if streaming {
|
||||
icon = g.iconActive
|
||||
}
|
||||
g.desk.SetSystemTrayIcon(icon)
|
||||
systray.SetTooltip(tooltip)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user