dreamfactory_cmd/cmd/v2/ui/mainwindow.go
2023-06-09 21:58:02 +08:00

458 lines
12 KiB
Go

package ui
import (
"errors"
"fmt"
"go_dreamfactory/cmd/v2/lib/common"
"go_dreamfactory/cmd/v2/lib/storage"
"go_dreamfactory/cmd/v2/service/observer"
"go_dreamfactory/comm"
// "go_dreamfactory/modules/user"
"go_dreamfactory/pb"
"strings"
"time"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/BabySid/gobase"
"github.com/Pallinder/go-randomdata"
"github.com/sirupsen/logrus"
"github.com/spf13/cast"
)
var (
globalWin *MainWindowImpl
)
type MainWindow interface {
WindowInterface
}
type MainWindowImpl struct {
UIImpl
WindowDefaultOptions
parent fyne.Window
w fyne.Window
tb *toolBar //工具条
toys *toys // side
sb *statusBar //状态栏
at *appContainer //tabs
mm *mainMenu //菜单
}
func NewMainWindow(ui *UIImpl, parent fyne.Window) MainWindow {
gobase.NewScheduler().Start()
gobase.RegisterAtExit(gobase.GlobalScheduler.Stop)
mw := &MainWindowImpl{
UIImpl: *ui,
parent: parent,
}
globalWin = mw
ui.obs.AddListener(observer.EVENT_PING, observer.Listener{
OnNotify: func(data interface{}, args ...interface{}) {
ui.obs.Remove(observer.EVENT_PING)
logrus.Debug("即将与服务器断开链接")
conf := dialog.NewConfirm("链接中断", data.(error).Error(), func(
b bool) {
ui.app.Quit()
}, globalWin.w)
conf.SetDismissText("取消")
conf.SetConfirmText("退出")
conf.Show()
},
})
return mw
}
// createWindowContainer create a container with the window content
func (ui *MainWindowImpl) createWindowContainer() {
// create main layout
// status bar
ui.sb = newStatusBar()
// tool bar
toolbar := widget.NewToolbar(
// widget.NewToolbarAction(theme.MediaVideoIcon(), func() {
// openApp(ui.at, common.TOOLBAR_MONITOR)
// }),
// widget.NewToolbarAction(theme.DocumentIcon(), func() {
// openApp(ui.at, common.TOOLBAR_TESTER)
// }),
// widget.NewToolbarAction(theme.StorageIcon(), func() {
// openApp(ui.at, common.TOOLBAR_AUTO)
// }),
// widget.NewToolbarSpacer(),
// widget.NewToolbarAction(theme.FileIcon(), func() {
// newLogViewer().Win.Show()
// }),
)
ui.tb = newToolBar(toolbar)
// Fun Toys
ui.toys = newToys(ui.obs)
// Main Menu
ui.mm = newMainMenu()
ui.w.SetMainMenu(ui.mm.MainMenu)
// main app tabs
ui.at = newAppContainer(appRegister, ui.pttService, ui.obs)
content := container.NewBorder(ui.tb.toolbar, ui.sb.widget, nil, ui.toys.widget, ui.at)
ui.w.SetContent(content)
ui.w.CenterOnScreen()
ui.w.SetCloseIntercept(ui.quiteHandle)
}
func (ui *MainWindowImpl) SetStatusMsg(msg string) {
ui.sb.setMessage(fmt.Sprintf("err:%s", msg))
}
func (ui *MainWindowImpl) quiteHandle() {
dialog.ShowConfirm("提示", "确定退出吗", func(b bool) {
if !b {
return
}
ui.app.Quit()
}, ui.w)
}
// CreateWindow ....
func (ui *MainWindowImpl) CreateWindow(_ string, width, height float32, _ bool) {
// init window
title := fmt.Sprintf(common.APP_WIN_TITLE, "登录", ui.app.Metadata().Version, ui.app.Metadata().Build, common.APP_NAME)
w := ui.app.NewWindow(title)
ui.AddWindow("main", w)
ui.w = w
if ui.windowAspect == common.WindowAspect_FullScreen {
w.SetFullScreen(true)
} else {
w.Resize(fyne.NewSize(width, height))
}
// w.SetMaster()
w.CenterOnScreen()
w.SetCloseIntercept(func() {
ui.parent.Show()
})
_ = ui.createChooseServerPopUp(w)
}
// createChooseServerPopUp
func (ui *MainWindowImpl) createChooseServerPopUp(w fyne.Window) error {
ch := make(chan string)
title := fmt.Sprintf(common.APP_WIN_TITLE, "选服", ui.app.Metadata().Version, ui.app.Metadata().Build, common.APP_NAME)
selServerWin := ui.createChooseServerWindow(title, ch)
go func() {
data := <-ch
selServerWin.Hide()
ui.NewWelcomeLabel(data)
ui.w.Show()
}()
return nil
}
func (ui *MainWindowImpl) configForm(w fyne.Window, call func()) *widget.Form {
//区服编号
sId := widget.NewEntry()
//区服地址
sAddr := widget.NewEntry()
//区服名称
sName := widget.NewEntry()
configForm := widget.NewForm()
configForm.AppendItem(widget.NewFormItem("区服编号", sId))
configForm.AppendItem(widget.NewFormItem("区服地址", sAddr))
configForm.AppendItem(widget.NewFormItem("区服名称", sName))
configForm.OnSubmit = func() {
defer func() {
w.Close()
call()
}()
ui.config.Servers = append(ui.config.Servers, &storage.ServerConfig{
Name: sName.Text,
SId: sId.Text,
Url: sAddr.Text,
})
if err := ui.storage.StoreConfig(ui.config); err != nil {
dialog.ShowError(err, w)
return
}
}
configForm.SubmitText = "保存配置"
configForm.Refresh()
return configForm
}
// createChooseServerWindow
func (ui *MainWindowImpl) createChooseServerWindow(title string, ch chan string) fyne.Window {
w := fyne.CurrentApp().NewWindow(title)
// choose server button func
makeButton := func(s *storage.ServerConfig, parent fyne.Window) *widget.Button {
btn := widget.NewButton(s.Name, func() {
d := dialog.NewInformation("", common.INFO_WAIT, parent)
d.SetDismissText(common.BUTTON_CANCEL)
d.Show()
logrus.WithFields(logrus.Fields{"server": s.Name, "sid": s.SId}).Debug("choose server")
//conn server
if err := ui.connService.WsConnect(s.Url); err != nil {
d.Hide()
dialog.ShowError(err, parent)
} else {
ch <- fmt.Sprintf("%s:%s", s.SId, s.Name)
}
})
return btn
}
sGrid := container.NewGridWithColumns(2)
if len(ui.config.Servers) == 0 {
c := storage.NewDefaultConfig()
ui.config.Servers = append(ui.config.Servers, c.Servers...)
}
if len(ui.config.Servers) != 0 {
for _, s := range ui.config.Servers {
box := makeButton(s, w)
sGrid.Add(container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.DeleteIcon(), func() {
defer func() {
w.Close()
ui.parent.Show()
}()
txt := box.Text
for i, ss := range ui.config.Servers {
if txt == ss.Name {
ui.config.Servers = append(ui.config.Servers[:i], ui.config.Servers[i+1:]...)
i--
}
}
if err := ui.storage.StoreConfig(ui.config); err != nil {
dialog.ShowError(err, w)
}
}), box))
}
sGrid.Add(widget.NewButtonWithIcon("", theme.ContentAddIcon(), func() {
addWin := fyne.CurrentApp().NewWindow("添加区服")
addWin.SetContent(ui.configForm(addWin, func() {
w.Close()
ui.parent.Show()
}))
addWin.SetFixedSize(true)
addWin.Resize(fyne.NewSize(500, 200))
addWin.Show()
addWin.CenterOnScreen()
}))
w.SetContent(sGrid)
} else {
w.SetContent(ui.configForm(w, func() {
w.Close()
ui.parent.Show()
}))
}
w.SetFixedSize(true)
w.Resize(fyne.NewSize(500, 200))
w.Show()
w.SetCloseIntercept(func() {
ui.parent.Show()
w.Close()
})
w.CenterOnScreen()
return w
}
// createLoginWin
func (ui *MainWindowImpl) createLoginWin(sid, sname string) {
account := widget.NewEntry()
// account.Text = "user8080" //default account
items := []*widget.FormItem{
widget.NewFormItem(common.LABEL_ACCOUNT, account),
}
dialog.ShowForm(common.FORM_TITLE_LOGIN, common.BUTTON_LOGIN, common.BUTTON_CANCEL, items, func(b bool) {
if !b {
logrus.Debug("cancel login")
} else {
if account.Text != "" {
logrus.WithField("account", account.Text).Debug("submit login")
ui.createWindowContainer()
appName, err := ui.at.openDefaultApp(common.TOOLBAR_MONITOR)
if err != nil {
logrus.WithField("appName", appName).Error(err)
}
// hide toolbar
ui.tb.toolbar.Hide()
// call after ui.createWindowContainer
ui.connService.ListenerPush()
if errdata := ui.pttService.Login(sid, account.Text); errdata != nil {
err := fmt.Errorf("login err: %v[%d]", errdata, int32(errdata.Code))
dialog.ShowError(err, ui.w)
} else {
ui.obs.AddListener(observer.EVENT_REQ_RSP, observer.Listener{
OnNotify: func(data interface{}, args ...interface{}) {
if data == nil {
return
}
msg := data.(*pb.UserMessage)
if msg.MainType == string("user") &&
msg.SubType == "login" {
rsp := &pb.UserLoginResp{}
if !comm.ProtoUnmarshal(msg, rsp) {
logrus.Error("unmarshal err")
return
}
//ping
go func() {
timer := time.NewTimer(10 * time.Second)
for {
if !timer.Stop() {
select {
case <-timer.C:
default:
}
}
timer.Reset(10 * time.Second)
select {
case <-timer.C:
ui.pttService.Ping(sid, account.Text)
continue
}
}
}()
// reset main window title
subTitle := fmt.Sprintf("%s[%s]", sname, sid)
ui.w.SetTitle(fmt.Sprintf(common.APP_WIN_TITLE, subTitle, ui.app.Metadata().Version, ui.app.Metadata().Build, common.APP_NAME))
ui.pttService.SetUser(rsp.Data, rsp.Ex)
// isCreateRole
if rsp.Data.Created {
// set statusbar message
ui.sb.setMessage(common.LABEL_WELCOME + rsp.Data.Binduid)
// update userinfo
ui.obs.Notify(observer.EVENT_USERINFO, ui.pttService.GetUser())
// show toolbar
ui.tb.toolbar.Show()
} else {
// create role
ui.createRoleWindowPopUp()
}
} else if msg.MainType == "notify" && msg.SubType == "errornotify" {
push := &pb.NotifyErrorNotifyPush{}
if !comm.ProtoUnmarshal(msg, push) {
logrus.Error("unmarsh err")
return
}
if push.Code == pb.ErrorCode_UserLogined {
cf := dialog.NewError(errors.New("【"+account.Text+"】账号已在其它终端登录,退出重新登录"), ui.w)
cf.SetOnClosed(func() {
ui.app.Quit()
})
cf.Show()
}
}
},
})
}
}
}
}, ui.w)
}
// createMainWindowMenu create the main window menu
func (ui *MainWindowImpl) createMainWindowMenu() *fyne.MainMenu {
menuItems := []*fyne.MenuItem{}
menu := fyne.Menu{
Label: common.MENU_FILE,
Items: menuItems,
}
return fyne.NewMainMenu(&menu)
}
// createRoleWindowPopUp
func (ui *MainWindowImpl) createRoleWindowPopUp() {
nickname := widget.NewEntry()
c := container.NewBorder(nil, nil, nil,
widget.NewButtonWithIcon("", theme.ViewRefreshIcon(), func() {
nickname.SetText(randomdata.SillyName())
}),
nickname,
)
figure := widget.NewEntry()
figure.PlaceHolder = "形象ID"
figure.Text = "1"
var gender int32
genderSel := widget.NewSelect([]string{"男", "女"}, func(s string) {
if s == "男" {
gender = 0
} else if s == "女" {
gender = 1
}
})
genderSel.Selected = "男"
items := []*widget.FormItem{
widget.NewFormItem("性别", genderSel),
widget.NewFormItem("形象", figure),
widget.NewFormItem(common.LABEL_NICKNAME, c),
}
d := dialog.NewForm(common.FORM_TITLE_CREATEROLE, common.BUTTON_OK, common.BUTTON_CANCEL, items, func(b bool) {
if nickname.Text != "" {
logrus.WithField("nickname", nickname.Text).Debug("submit crete role")
if errdata := ui.pttService.CreateRole(nickname.Text, gender, cast.ToInt32(figure.Text)); errdata != nil {
err := fmt.Errorf("login err: %v[%d]", errdata, int32(errdata.Code))
dialog.ShowError(err, ui.w)
} else {
user := ui.pttService.GetUser()
logrus.WithField("uid", user.DbUser.Uid).Debug("create role succ")
ui.obs.Notify(observer.EVENT_USERINFO, ui.pttService.GetUser())
ui.tb.toolbar.Show()
}
}
}, ui.w)
d.Resize(fyne.NewSize(300, 200))
d.Show()
}
// NewWelcomeLabel
func (ui *MainWindowImpl) NewWelcomeLabel(data string) {
p := strings.Split(data, ":")
if len(p) != 2 {
logrus.WithField("param", p).Error("choose service")
return
}
c := container.NewCenter(container.NewVBox(
widget.NewLabelWithStyle(fmt.Sprintf(common.LABEL_CHOOSE, p[0], p[1]),
fyne.TextAlignCenter,
fyne.TextStyle{Bold: true}),
container.NewCenter(container.NewHBox(
widget.NewButton(common.BUTTON_LOGIN, func() {
ui.createLoginWin(p[0], p[1])
}),
)),
))
ui.w.SetContent(c)
ui.w.SetCloseIntercept(func() {
ui.w.Close()
ui.parent.Show()
})
}