f4a88f4b2c
golangci-lint / lint (push) Failing after 4s
- Complete GUI overhaul with Fyne framework * Modern dark theme with indigo/pink accent colors * 4-step setup wizard (Welcome → Server → Auth → Finish) * Dashboard with proxy list, real-time logs, and config viewer * Windows Service manager (install/start/stop/uninstall) * System tray integration with quick controls - WiX v7 MSI installer * Auto-registers as Windows Service (manual start) * Feature tree UI for optional components * Desktop shortcut and PATH options * Build script: packaging/windows/build-msi.ps1 - Build system updates * Added kanholec-windows-gui target (CGO required) * Added kanholec-windows-msi target * Separate main_gui.go entry point for GUI builds GUI binary: bin/kanholec-windows-amd64.exe (31.4 MB) MSI installer: bin/kanholec-0.69.0-amd64.msi (12.1 MB)
134 lines
2.8 KiB
Go
134 lines
2.8 KiB
Go
//go:build kanholec_gui
|
|
|
|
package gui
|
|
|
|
import (
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/systray"
|
|
)
|
|
|
|
type TrayManager struct {
|
|
app *App
|
|
running bool
|
|
|
|
mShow *systray.MenuItem
|
|
mStatus *systray.MenuItem
|
|
mStart *systray.MenuItem
|
|
mStop *systray.MenuItem
|
|
mQuit *systray.MenuItem
|
|
}
|
|
|
|
func NewTrayManager(app *App) *TrayManager {
|
|
return &TrayManager{app: app}
|
|
}
|
|
|
|
func (t *TrayManager) Start() {
|
|
go t.run()
|
|
}
|
|
|
|
func (t *TrayManager) run() {
|
|
defer func() {
|
|
recover()
|
|
}()
|
|
systray.Run(t.onReady, t.onExit)
|
|
}
|
|
|
|
func (t *TrayManager) onReady() {
|
|
t.running = true
|
|
|
|
systray.SetIcon(trayIconData())
|
|
systray.SetTitle("kanholec")
|
|
systray.SetTooltip("kanholec - kanhole Client")
|
|
|
|
t.mShow = systray.AddMenuItem("Show Dashboard", "Open kanholec GUI")
|
|
systray.AddSeparator()
|
|
t.mStatus = systray.AddMenuItem("Status: Disconnected", "")
|
|
t.mStatus.Disable()
|
|
systray.AddSeparator()
|
|
t.mStart = systray.AddMenuItem("Start Client", "Start the kanholec client")
|
|
t.mStop = systray.AddMenuItem("Stop Client", "Stop the kanholec client")
|
|
t.mStop.Disable()
|
|
systray.AddSeparator()
|
|
t.mQuit = systray.AddMenuItem("Quit", "Exit kanholec")
|
|
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-t.mShow.ClickedCh:
|
|
if t.app.window != nil {
|
|
t.app.window.Show()
|
|
t.app.window.RequestFocus()
|
|
}
|
|
case <-t.mStart.ClickedCh:
|
|
t.app.startClient()
|
|
t.mStart.Disable()
|
|
t.mStop.Enable()
|
|
t.mStatus.SetTitle("Status: Running")
|
|
case <-t.mStop.ClickedCh:
|
|
t.app.stopClient()
|
|
t.mStart.Enable()
|
|
t.mStop.Disable()
|
|
t.mStatus.SetTitle("Status: Stopped")
|
|
case <-t.mQuit.ClickedCh:
|
|
t.app.Quit()
|
|
systray.Quit()
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (t *TrayManager) onExit() {
|
|
t.running = false
|
|
}
|
|
|
|
func (t *TrayManager) SetStatus(status string) {
|
|
if !t.running || t.mStatus == nil {
|
|
return
|
|
}
|
|
t.mStatus.SetTitle("Status: " + status)
|
|
}
|
|
|
|
func (t *TrayManager) SetRunning(running bool) {
|
|
if !t.running {
|
|
return
|
|
}
|
|
if running {
|
|
t.mStart.Disable()
|
|
t.mStop.Enable()
|
|
t.mStatus.SetTitle("Status: Running")
|
|
} else {
|
|
t.mStart.Enable()
|
|
t.mStop.Disable()
|
|
t.mStatus.SetTitle("Status: Stopped")
|
|
}
|
|
}
|
|
|
|
func (t *TrayManager) Stop() {
|
|
if t.running {
|
|
systray.Quit()
|
|
}
|
|
}
|
|
|
|
func (t *TrayManager) IsSupported() bool {
|
|
return t.running
|
|
}
|
|
|
|
func trayIconResource() *fyne.StaticResource {
|
|
return &fyne.StaticResource{
|
|
StaticName: "kanholec.ico",
|
|
StaticContent: trayIconData(),
|
|
}
|
|
}
|
|
|
|
func trayIconData() []byte {
|
|
return []byte{
|
|
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x00,
|
|
0x20, 0x00, 0x68, 0x04, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00,
|
|
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
}
|
|
}
|