залил
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
package gui
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"stream-bot/internal/logger"
|
||||
"time"
|
||||
|
||||
"github.com/lxn/walk"
|
||||
. "github.com/lxn/walk/declarative"
|
||||
)
|
||||
|
||||
const appVersion = "11.0.43"
|
||||
|
||||
func Run(webURL string,
|
||||
getChatStatus func() bool,
|
||||
getEventSubStatus func() (connected bool, subscriptions []string)) {
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
logger.Warn("GUI only supported on Windows, running without window")
|
||||
return
|
||||
}
|
||||
|
||||
var urlLE *walk.LineEdit
|
||||
var openBtn *walk.PushButton
|
||||
var exitBtn *walk.PushButton
|
||||
var chatStatusLabel, eventSubLabel *walk.Label
|
||||
|
||||
var mw *walk.MainWindow
|
||||
exitWithoutMinimize := false // флаг для полного закрытия
|
||||
|
||||
err := MainWindow{
|
||||
AssignTo: &mw,
|
||||
Title: "TTW_Bot v" + appVersion,
|
||||
MinSize: Size{Width: 450, Height: 280},
|
||||
Size: Size{Width: 500, Height: 300},
|
||||
Layout: VBox{},
|
||||
Children: []Widget{
|
||||
Label{Text: "Веб-интерфейс бота доступен по адресу:"},
|
||||
LineEdit{
|
||||
AssignTo: &urlLE,
|
||||
Text: webURL,
|
||||
ReadOnly: true,
|
||||
},
|
||||
PushButton{
|
||||
AssignTo: &openBtn,
|
||||
Text: "🌐 Открыть в браузере",
|
||||
OnClicked: func() {
|
||||
openBrowser(webURL)
|
||||
},
|
||||
},
|
||||
Label{Text: "─────────────────────────────────"},
|
||||
Label{Text: "Статус Twitch чата:"},
|
||||
Label{AssignTo: &chatStatusLabel, Text: "загрузка..."},
|
||||
Label{Text: "Статус EventSub:"},
|
||||
Label{AssignTo: &eventSubLabel, Text: "загрузка..."},
|
||||
Label{Text: "─────────────────────────────────"},
|
||||
PushButton{
|
||||
AssignTo: &exitBtn,
|
||||
Text: "❌ Завершить работу бота",
|
||||
OnClicked: func() {
|
||||
exitWithoutMinimize = true // запоминаем, что хотим выйти
|
||||
_ = mw.Close()
|
||||
},
|
||||
},
|
||||
},
|
||||
}.Create()
|
||||
|
||||
if err != nil {
|
||||
msg := "Failed to create GUI window: " + err.Error()
|
||||
logger.Error(msg)
|
||||
walk.MsgBox(nil, "Ошибка", msg, walk.MsgBoxIconError)
|
||||
return
|
||||
}
|
||||
|
||||
// При закрытии окна – либо сворачиваем в трей, либо завершаем программу
|
||||
mw.Closing().Attach(func(cancel *bool, reason walk.CloseReason) {
|
||||
if exitWithoutMinimize {
|
||||
// полное завершение – не отменяем закрытие
|
||||
return
|
||||
}
|
||||
// иначе – сворачиваем в трей
|
||||
*cancel = true
|
||||
mw.Hide()
|
||||
})
|
||||
|
||||
// Создаём иконку в трее
|
||||
ni, err := walk.NewNotifyIcon(mw)
|
||||
if err != nil {
|
||||
logger.Error("Failed to create notify icon: %v", err)
|
||||
} else {
|
||||
_ = ni.SetToolTip("TTW_Bot")
|
||||
// Устанавливаем иконку (системная иконка информации)
|
||||
if err := ni.SetIcon(walk.IconInformation()); err != nil {
|
||||
logger.Warn("Failed to set icon: %v", err)
|
||||
}
|
||||
|
||||
showAction := walk.NewAction()
|
||||
_ = showAction.SetText("Показать окно")
|
||||
showAction.Triggered().Attach(func() {
|
||||
mw.Show()
|
||||
mw.SetVisible(true)
|
||||
})
|
||||
exitAction := walk.NewAction()
|
||||
_ = exitAction.SetText("Выход")
|
||||
exitAction.Triggered().Attach(func() {
|
||||
exitWithoutMinimize = true
|
||||
_ = mw.Close()
|
||||
})
|
||||
menu := ni.ContextMenu()
|
||||
_ = menu.Actions().Add(showAction)
|
||||
_ = menu.Actions().Add(exitAction)
|
||||
|
||||
ni.MouseDown().Attach(func(x, y int, button walk.MouseButton) {
|
||||
if button == walk.LeftButton {
|
||||
mw.Show()
|
||||
mw.SetVisible(true)
|
||||
}
|
||||
})
|
||||
if err := ni.SetVisible(true); err != nil {
|
||||
logger.Error("Failed to set tray icon visible: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Запускаем периодическое обновление статусов
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
mw.Synchronize(func() {
|
||||
chatConnected := getChatStatus()
|
||||
if chatConnected {
|
||||
_ = chatStatusLabel.SetText("✅ Подключен")
|
||||
} else {
|
||||
_ = chatStatusLabel.SetText("❌ Отключен")
|
||||
}
|
||||
esConnected, subs := getEventSubStatus()
|
||||
if esConnected {
|
||||
_ = eventSubLabel.SetText("✅ Подключен (" + itoa(len(subs)) + " подписок)")
|
||||
} else {
|
||||
_ = eventSubLabel.SetText("❌ Отключен")
|
||||
}
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
mw.Run()
|
||||
ticker.Stop()
|
||||
}
|
||||
|
||||
func openBrowser(url string) {
|
||||
var cmd *exec.Cmd
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
cmd = exec.Command("cmd", "/c", "start", url)
|
||||
case "darwin":
|
||||
cmd = exec.Command("open", url)
|
||||
default:
|
||||
cmd = exec.Command("xdg-open", url)
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
logger.Error("Failed to open browser: %v", err)
|
||||
walk.MsgBox(nil, "Ошибка", "Не удалось открыть браузер: "+err.Error(), walk.MsgBoxIconError)
|
||||
}
|
||||
}
|
||||
|
||||
func itoa(i int) string {
|
||||
if i == 0 {
|
||||
return "0"
|
||||
}
|
||||
digits := ""
|
||||
for i > 0 {
|
||||
digits = string(rune('0'+i%10)) + digits
|
||||
i /= 10
|
||||
}
|
||||
return digits
|
||||
}
|
||||
Reference in New Issue
Block a user