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() }) }