From c7bcede28a2fbcb105b2de04d16d8831c12818d2 Mon Sep 17 00:00:00 2001 From: jinyaoMa Date: Wed, 14 Sep 2022 00:20:06 -0400 Subject: [PATCH] . --- README.md | 2 +- backend/app/app.go | 10 +- backend/app/wails.go | 8 +- backend/i18n/i18n.go | 33 +++-- backend/i18n/{locales.go => locale.go} | 36 +++--- backend/i18n/locales/en.json | 6 +- backend/i18n/locales/zh.json | 10 +- backend/tray/menus/api_service.go | 120 +++++++++++++++++++ backend/tray/menus/color_theme.go | 111 +++++++++++++++++ backend/tray/menus/display_language.go | 88 ++++++++++++++ backend/tray/menus/open_window.go | 66 ++++++++++ backend/tray/menus/quit.go | 66 ++++++++++ backend/tray/tray.go | 159 ++++++++++++++++++++++++- main.go | 7 +- package.json | 2 +- wails.json | 4 +- 16 files changed, 676 insertions(+), 52 deletions(-) rename backend/i18n/{locales.go => locale.go} (58%) create mode 100644 backend/tray/menus/api_service.go create mode 100644 backend/tray/menus/color_theme.go create mode 100644 backend/tray/menus/display_language.go create mode 100644 backend/tray/menus/open_window.go create mode 100644 backend/tray/menus/quit.go diff --git a/README.md b/README.md index 0097689..9ab8d82 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # My App (my-app) -My App is a continuously updated service collection. +My App is a continuously updated personal service collection. Prepare and install environment for development? diff --git a/backend/app/app.go b/backend/app/app.go index eb34a29..9703ac2 100644 --- a/backend/app/app.go +++ b/backend/app/app.go @@ -6,22 +6,22 @@ import ( var ( once sync.Once - instance *Application + instance *app ) -type Application struct { +type app struct { wlc *WailsLifeCycle } -func App() *Application { +func App() *app { once.Do(func() { - instance = &Application{ + instance = &app{ wlc: &WailsLifeCycle{}, } }) return instance } -func (a *Application) WailsLifeCycle() *WailsLifeCycle { +func (a *app) WailsLifeCycle() *WailsLifeCycle { return a.wlc } diff --git a/backend/app/wails.go b/backend/app/wails.go index 9de89af..a76c001 100644 --- a/backend/app/wails.go +++ b/backend/app/wails.go @@ -3,6 +3,9 @@ package app import ( "context" "log" + "my-app/backend/i18n" + "my-app/backend/tray" + "my-app/backend/tray/menus" ) // Wailsapp Life Cycle @@ -12,7 +15,10 @@ type WailsLifeCycle struct { func (wlc *WailsLifeCycle) Startup(ctx context.Context) { wlc.ctx = ctx - + tray.Tray(). + SetWailsContext(ctx). + ChangeTheme(menus.ColorThemeSystem). + ChangeLanguage(i18n.I18n().GetCurrentLanguage()) log.Println("WAILS START UP") } diff --git a/backend/i18n/i18n.go b/backend/i18n/i18n.go index 8be472a..d3ff3c1 100644 --- a/backend/i18n/i18n.go +++ b/backend/i18n/i18n.go @@ -12,37 +12,48 @@ var ( ) type i18n struct { - localeMap localeMap + localeMap map[string]Locale availableLanguages []string - currentLocale string + currentLanguage string } func I18n() *i18n { once.Do(func() { localeMap, availableLanguages := load() - currentLocale := "" + currentLanguage := "" if len(availableLanguages) > 0 { - currentLocale = availableLanguages[0] + currentLanguage = availableLanguages[0] } instance = &i18n{ localeMap: localeMap, availableLanguages: availableLanguages, - currentLocale: currentLocale, + currentLanguage: currentLanguage, } }) return instance } -func (i *i18n) Change(lang string) (ok bool) { +func (i *i18n) Change(lang string) *i18n { if slices.Contains(i.availableLanguages, lang) { - i.currentLocale = lang - return true + i.currentLanguage = lang } - return false + return i } -func (i *i18n) Locale() (l locale) { - return i.localeMap[i.currentLocale] +func (i *i18n) Get(lang string) (l Locale) { + return i.localeMap[lang] +} + +func (i *i18n) GetCurrentLanguage() string { + return i.currentLanguage +} + +func (i *i18n) GetLangText(lang string) string { + return i.localeMap[lang].Lang.Text +} + +func (i *i18n) Locale() (l Locale) { + return i.Get(i.currentLanguage) } diff --git a/backend/i18n/locales.go b/backend/i18n/locale.go similarity index 58% rename from backend/i18n/locales.go rename to backend/i18n/locale.go index fce5e28..f8da388 100644 --- a/backend/i18n/locales.go +++ b/backend/i18n/locale.go @@ -3,34 +3,36 @@ package i18n import ( "embed" "encoding/json" - "path/filepath" ) //go:embed locales var locales embed.FS const ( - dirLocales = "locales" + En = "en" + Zh = "zh" ) -type locale struct { +type Locale struct { Lang struct { Code string `json:"code"` Text string `json:"text"` } `json:"lang"` AppName string `json:"appname"` + OpenWindow string `json:"open_window"` + Quit string `json:"quit"` DisplayLanguage string `json:"display_language"` ColorTheme struct { - Title string `json:"title"` - Light string `json:"light"` - Dark string `json:"dark"` + Title string `json:"title"` + System string `json:"system"` + Light string `json:"light"` + Dark string `json:"dark"` } `json:"color_theme"` ApiService struct { + Swagger string `json:"swagger"` Start string `json:"start"` Stop string `json:"stop"` - Swagger string `json:"swagger"` } `json:"api_service"` - Quit string `json:"quit"` QuitDialog struct { Message string `json:"message"` DefaultButton string `json:"default_button"` @@ -38,19 +40,19 @@ type locale struct { } `json:"quit_dialog"` } -type localeMap map[string]locale - -func load() (tm localeMap, availableLanguages []string) { - tm = make(localeMap) +func load() (localeMap map[string]Locale, availableLanguages []string) { + dirLocales := "locales" + var al []string + lm := make(map[string]Locale) files, _ := locales.ReadDir(dirLocales) for _, f := range files { if !f.IsDir() { // load only locale JSON file - t := locale{} - data, _ := locales.ReadFile(filepath.Join(dirLocales, f.Name())) + t := Locale{} + data, _ := locales.ReadFile(dirLocales + "/" + f.Name()) // embed use slash as separator json.Unmarshal(data, &t) - tm[t.Lang.Code] = t - availableLanguages = append(availableLanguages, t.Lang.Code) + lm[t.Lang.Code] = t + al = append(al, t.Lang.Code) } } - return + return lm, al } diff --git a/backend/i18n/locales/en.json b/backend/i18n/locales/en.json index b979a0b..c60d6df 100644 --- a/backend/i18n/locales/en.json +++ b/backend/i18n/locales/en.json @@ -4,17 +4,19 @@ "text": "English" }, "appname": "My Application", + "open_window": "Open My Application", "quit": "Quit", "display_language": "Display Language", "color_theme": { "title": "Color Theme", + "system": "System Default", "light": "Light", "dark": "Dark" }, "api_service": { + "swagger": "Open API docs", "start": "Enable API service", - "stop": "Disable API service", - "swagger": "Open API docs" + "stop": "Disable API service" }, "quit_dialog": { "message": "Are you sure to quit?", diff --git a/backend/i18n/locales/zh.json b/backend/i18n/locales/zh.json index 786cb95..20d40ab 100644 --- a/backend/i18n/locales/zh.json +++ b/backend/i18n/locales/zh.json @@ -4,17 +4,19 @@ "text": "简体中文" }, "appname": "我的应用程序", + "open_window": "打开 我的应用程序", "quit": "退出", "display_language": "选择 显示语言", "color_theme": { "title": "选择 颜色主题", - "light": "默认浅色", - "dark": "默认深色" + "system": "跟随系统", + "light": "浅色", + "dark": "深色" }, "api_service": { + "swagger": "打开 API 文档", "start": "开启 API 服务", - "stop": "关闭 API 服务", - "swagger": "打开 API 文档" + "stop": "关闭 API 服务" }, "quit_dialog": { "message": "确认退出 我的应用程序 吗?", diff --git a/backend/tray/menus/api_service.go b/backend/tray/menus/api_service.go new file mode 100644 index 0000000..9daaf7d --- /dev/null +++ b/backend/tray/menus/api_service.go @@ -0,0 +1,120 @@ +package menus + +import ( + "my-app/backend/i18n" + + "github.com/getlantern/systray" +) + +type ApiServiceListener struct { + OnOpenSwagger func() + OnStart func() (ok bool) + OnStop func() (ok bool) +} + +type ApiService struct { + isWatched bool + chanStop chan struct{} + isEnabled bool + swagger *systray.MenuItem + start *systray.MenuItem + stop *systray.MenuItem +} + +func NewApiService() *ApiService { + return &ApiService{ + chanStop: make(chan struct{}, 1), + swagger: systray.AddMenuItem("", ""), + start: systray.AddMenuItem("", ""), + stop: systray.AddMenuItem("", ""), + } +} + +func (as *ApiService) SetIconSwagger(templateIconBytes []byte, regularIconBytes []byte) *ApiService { + as.swagger.SetTemplateIcon(templateIconBytes, regularIconBytes) + return as +} + +func (as *ApiService) SetIconStart(templateIconBytes []byte, regularIconBytes []byte) *ApiService { + as.start.SetTemplateIcon(templateIconBytes, regularIconBytes) + return as +} + +func (as *ApiService) SetIconStop(templateIconBytes []byte, regularIconBytes []byte) *ApiService { + as.stop.SetTemplateIcon(templateIconBytes, regularIconBytes) + return as +} + +func (as *ApiService) SetLocale(locale i18n.Locale) *ApiService { + as.start.SetTitle(locale.ApiService.Start) + as.start.SetTooltip(locale.ApiService.Start) + as.stop.SetTitle(locale.ApiService.Stop) + as.stop.SetTooltip(locale.ApiService.Stop) + as.swagger.SetTitle(locale.ApiService.Swagger) + as.swagger.SetTooltip(locale.ApiService.Swagger) + if as.isEnabled { + as.start.Hide() + as.stop.Show() + as.swagger.Show() + } else { + as.start.Show() + as.stop.Hide() + as.swagger.Hide() + } + return as +} + +func (as *ApiService) Watch(listener ApiServiceListener) *ApiService { + if as.isWatched { + return as + } + + as.isWatched = true + go func() { + for { + select { + case <-as.start.ClickedCh: + if listener.OnStart() { + as.start.Hide() + as.stop.Show() + as.swagger.Show() + as.isEnabled = true + } + case <-as.stop.ClickedCh: + if listener.OnStop() { + as.start.Show() + as.stop.Hide() + as.swagger.Hide() + as.isEnabled = false + } + case <-as.swagger.ClickedCh: + listener.OnOpenSwagger() + case <-as.chanStop: + return + } + } + }() + return as +} + +func (as *ApiService) StopWatch() *ApiService { + if as.isWatched { + as.chanStop <- struct{}{} + } + return as +} + +func (as *ApiService) ClickOpenSwagger() *ApiService { + as.swagger.ClickedCh <- struct{}{} + return as +} + +func (as *ApiService) ClickStart() *ApiService { + as.start.ClickedCh <- struct{}{} + return as +} + +func (as *ApiService) ClickStop() *ApiService { + as.stop.ClickedCh <- struct{}{} + return as +} diff --git a/backend/tray/menus/color_theme.go b/backend/tray/menus/color_theme.go new file mode 100644 index 0000000..06574cf --- /dev/null +++ b/backend/tray/menus/color_theme.go @@ -0,0 +1,111 @@ +package menus + +import ( + "my-app/backend/i18n" + + "github.com/getlantern/systray" +) + +const ( + ColorThemeSystem = "system" + ColorThemeLight = "light" + ColorThemeDark = "dark" +) + +type ColorThemeListener struct { + OnColorThemeChanged func(theme string) (ok bool) +} + +type ColorTheme struct { + isWatched bool + chanStop chan struct{} + title *systray.MenuItem + system *systray.MenuItem + light *systray.MenuItem + dark *systray.MenuItem +} + +func NewColorTheme() *ColorTheme { + return &ColorTheme{ + chanStop: make(chan struct{}, 1), + title: systray.AddMenuItem("", ""), + system: systray.AddMenuItem("", ""), + light: systray.AddMenuItem("", ""), + dark: systray.AddMenuItem("", ""), + } +} + +func (ct *ColorTheme) SetIcon(templateIconBytes []byte, regularIconBytes []byte) *ColorTheme { + ct.title.SetTemplateIcon(templateIconBytes, regularIconBytes) + return ct +} + +func (ct *ColorTheme) SetLocale(locale i18n.Locale) *ColorTheme { + ct.title.SetTitle(locale.ColorTheme.Title) + ct.title.SetTooltip(locale.ColorTheme.Title) + ct.title.Disable() + ct.system.SetTitle(locale.ColorTheme.System) + ct.system.SetTooltip(locale.ColorTheme.System) + ct.light.SetTitle(locale.ColorTheme.Light) + ct.light.SetTooltip(locale.ColorTheme.Light) + ct.dark.SetTitle(locale.ColorTheme.Dark) + ct.dark.SetTooltip(locale.ColorTheme.Dark) + return ct +} + +func (ct *ColorTheme) Watch(listener ColorThemeListener) *ColorTheme { + if ct.isWatched { + return ct + } + + ct.isWatched = true + go func() { + for { + select { + case <-ct.system.ClickedCh: + if listener.OnColorThemeChanged(ColorThemeSystem) { + ct.system.Check() + ct.light.Uncheck() + ct.dark.Uncheck() + } + case <-ct.light.ClickedCh: + if listener.OnColorThemeChanged(ColorThemeLight) { + ct.system.Uncheck() + ct.light.Check() + ct.dark.Uncheck() + } + case <-ct.dark.ClickedCh: + if listener.OnColorThemeChanged(ColorThemeDark) { + ct.system.Uncheck() + ct.light.Uncheck() + ct.dark.Check() + } + case <-ct.chanStop: + return + } + } + }() + return ct +} + +func (ct *ColorTheme) StopWatch() *ColorTheme { + if ct.isWatched { + ct.chanStop <- struct{}{} + } + return ct +} + +func (ct *ColorTheme) ClickSystem() *ColorTheme { + ct.system.ClickedCh <- struct{}{} + return ct +} + +func (ct *ColorTheme) ClickLight() *ColorTheme { + ct.light.ClickedCh <- struct{}{} + return ct +} + +func (ct *ColorTheme) ClickDark() *ColorTheme { + ct.dark.ClickedCh <- struct{}{} + return ct +} diff --git a/backend/tray/menus/display_language.go b/backend/tray/menus/display_language.go new file mode 100644 index 0000000..f9ddfcb --- /dev/null +++ b/backend/tray/menus/display_language.go @@ -0,0 +1,88 @@ +package menus + +import ( + "my-app/backend/i18n" + + "github.com/getlantern/systray" +) + +type DisplayLanguageListener struct { + OnDisplayLanguageChanged func(lang string) (ok bool) +} + +type DisplayLanguage struct { + isWatched bool + chanStop chan struct{} + title *systray.MenuItem + english *systray.MenuItem + chinese *systray.MenuItem +} + +func NewDisplayLanguage() *DisplayLanguage { + return &DisplayLanguage{ + chanStop: make(chan struct{}, 1), + title: systray.AddMenuItem("", ""), + english: systray.AddMenuItem("", ""), + chinese: systray.AddMenuItem("", ""), + } +} + +func (dl *DisplayLanguage) SetIcon(templateIconBytes []byte, regularIconBytes []byte) *DisplayLanguage { + dl.title.SetTemplateIcon(templateIconBytes, regularIconBytes) + return dl +} + +func (dl *DisplayLanguage) SetLocale(locale i18n.Locale) *DisplayLanguage { + dl.title.SetTitle(locale.DisplayLanguage) + dl.title.SetTooltip(locale.DisplayLanguage) + dl.title.Disable() + dl.english.SetTitle(i18n.I18n().GetLangText(i18n.En)) + dl.english.SetTooltip(i18n.I18n().GetLangText(i18n.En)) + dl.chinese.SetTitle(i18n.I18n().GetLangText(i18n.Zh)) + dl.chinese.SetTooltip(i18n.I18n().GetLangText(i18n.Zh)) + return dl +} + +func (dl *DisplayLanguage) Watch(listener DisplayLanguageListener) *DisplayLanguage { + if dl.isWatched { + return dl + } + + dl.isWatched = true + go func() { + for { + select { + case <-dl.english.ClickedCh: + if listener.OnDisplayLanguageChanged(i18n.En) { + dl.chinese.Uncheck() + dl.english.Check() + } + case <-dl.chinese.ClickedCh: + if listener.OnDisplayLanguageChanged(i18n.Zh) { + dl.chinese.Check() + dl.english.Uncheck() + } + case <-dl.chanStop: + return + } + } + }() + return dl +} + +func (dl *DisplayLanguage) StopWatch() *DisplayLanguage { + if dl.isWatched { + dl.chanStop <- struct{}{} + } + return dl +} + +func (dl *DisplayLanguage) ClickEnglish() *DisplayLanguage { + dl.english.ClickedCh <- struct{}{} + return dl +} + +func (dl *DisplayLanguage) ClickChinese() *DisplayLanguage { + dl.chinese.ClickedCh <- struct{}{} + return dl +} diff --git a/backend/tray/menus/open_window.go b/backend/tray/menus/open_window.go new file mode 100644 index 0000000..e9d9429 --- /dev/null +++ b/backend/tray/menus/open_window.go @@ -0,0 +1,66 @@ +package menus + +import ( + "my-app/backend/i18n" + + "github.com/getlantern/systray" +) + +type OpenWindowListener struct { + OnOpenWindow func() +} + +type OpenWindow struct { + isWatched bool + chanStop chan struct{} + item *systray.MenuItem +} + +func NewOpenWindow() *OpenWindow { + return &OpenWindow{ + chanStop: make(chan struct{}, 1), + item: systray.AddMenuItem("", ""), + } +} + +func (ow *OpenWindow) SetIcon(templateIconBytes []byte, regularIconBytes []byte) *OpenWindow { + ow.item.SetTemplateIcon(templateIconBytes, regularIconBytes) + return ow +} + +func (ow *OpenWindow) SetLocale(locale i18n.Locale) *OpenWindow { + ow.item.SetTitle(locale.OpenWindow) + ow.item.SetTooltip(locale.OpenWindow) + return ow +} + +func (ow *OpenWindow) Watch(listener OpenWindowListener) *OpenWindow { + if ow.isWatched { + return ow + } + + ow.isWatched = true + go func() { + for { + select { + case <-ow.item.ClickedCh: + listener.OnOpenWindow() + case <-ow.chanStop: + return + } + } + }() + return ow +} + +func (ow *OpenWindow) StopWatch() *OpenWindow { + if ow.isWatched { + ow.chanStop <- struct{}{} + } + return ow +} + +func (ow *OpenWindow) Click() *OpenWindow { + ow.item.ClickedCh <- struct{}{} + return ow +} diff --git a/backend/tray/menus/quit.go b/backend/tray/menus/quit.go new file mode 100644 index 0000000..2db110c --- /dev/null +++ b/backend/tray/menus/quit.go @@ -0,0 +1,66 @@ +package menus + +import ( + "my-app/backend/i18n" + + "github.com/getlantern/systray" +) + +type QuitListener struct { + OnQuit func() +} + +type Quit struct { + isWatched bool + chanStop chan struct{} + item *systray.MenuItem +} + +func NewQuit() *Quit { + return &Quit{ + chanStop: make(chan struct{}, 1), + item: systray.AddMenuItem("", ""), + } +} + +func (q *Quit) SetIcon(templateIconBytes []byte, regularIconBytes []byte) *Quit { + q.item.SetTemplateIcon(templateIconBytes, regularIconBytes) + return q +} + +func (q *Quit) SetLocale(locale i18n.Locale) *Quit { + q.item.SetTitle(locale.Quit) + q.item.SetTooltip(locale.Quit) + return q +} + +func (q *Quit) Watch(listener QuitListener) *Quit { + if q.isWatched { + return q + } + + q.isWatched = true + go func() { + for { + select { + case <-q.item.ClickedCh: + listener.OnQuit() + case <-q.chanStop: + return + } + } + }() + return q +} + +func (q *Quit) StopWatch() *Quit { + if q.isWatched { + q.chanStop <- struct{}{} + } + return q +} + +func (q *Quit) Click() *Quit { + q.item.ClickedCh <- struct{}{} + return q +} diff --git a/backend/tray/tray.go b/backend/tray/tray.go index ce5e58a..9e943e6 100644 --- a/backend/tray/tray.go +++ b/backend/tray/tray.go @@ -1,32 +1,185 @@ package tray import ( + "context" _ "embed" + "log" + "my-app/backend/i18n" + "my-app/backend/tray/menus" "sync" "github.com/getlantern/systray" + "github.com/wailsapp/wails/v2/pkg/runtime" ) //go:embed icons/icon.ico var icon []byte +//go:embed icons/open-window.ico +var iconOpenWindow []byte + +//go:embed icons/api-start.ico +var iconApiStart []byte + +//go:embed icons/api-stop.ico +var iconApiStop []byte + var ( once sync.Once instance *tray ) type tray struct { + wailsCtx context.Context + openWindow *menus.OpenWindow + apiService *menus.ApiService + displayLanguage *menus.DisplayLanguage + colorTheme *menus.ColorTheme + quit *menus.Quit } func Tray() *tray { once.Do(func() { instance = &tray{} - systray.Register(instance.onReady, nil) + systray.Register(instance.onReady, instance.onQuit) }) return instance } -func (st *tray) onReady() { +func (t *tray) SetWailsContext(ctx context.Context) *tray { + t.wailsCtx = ctx + return t +} + +func (t *tray) ChangeLanguage(lang string) *tray { + switch lang { + case i18n.Zh: + t.displayLanguage.ClickChinese() + case i18n.En: + t.displayLanguage.ClickEnglish() + } + return t +} + +func (t *tray) ChangeTheme(theme string) *tray { + switch theme { + case menus.ColorThemeSystem: + t.colorTheme.ClickSystem() + case menus.ColorThemeLight: + t.colorTheme.ClickLight() + case menus.ColorThemeDark: + t.colorTheme.ClickDark() + } + return t +} + +func (t *tray) updateLocales() { + locale := i18n.I18n().Locale() + systray.SetTitle(locale.AppName) + systray.SetTooltip(locale.AppName) + t.openWindow.SetLocale(locale) + t.apiService.SetLocale(locale) + t.displayLanguage.SetLocale(locale) + t.colorTheme.SetLocale(locale) + t.quit.SetLocale(locale) +} + +func (t *tray) onReady() { systray.SetTemplateIcon(icon, icon) - systray.SetTitle("Webview example") + + t.openWindow = menus. + NewOpenWindow(). + SetIcon(iconOpenWindow, iconOpenWindow). + Watch(menus.OpenWindowListener{ + OnOpenWindow: func() { + runtime.Show(t.wailsCtx) + }, + }) + + systray.AddSeparator() + + t.apiService = menus. + NewApiService(). + SetIconStart(iconApiStart, iconApiStart). + SetIconStop(iconApiStop, iconApiStop). + Watch(menus.ApiServiceListener{ + OnStart: func() bool { + return true + }, + OnStop: func() bool { + return true + }, + OnOpenSwagger: func() { + runtime.BrowserOpenURL( + t.wailsCtx, + "https://www.baidu.com", + ) + }, + }) + + systray.AddSeparator() + + t.displayLanguage = menus. + NewDisplayLanguage(). + Watch(menus.DisplayLanguageListener{ + OnDisplayLanguageChanged: func(lang string) bool { + locale := i18n.I18n().Change(lang).Locale() + runtime.WindowSetTitle(t.wailsCtx, locale.AppName) + runtime.EventsEmit(t.wailsCtx, "onLanguageChanged", lang) + t.updateLocales() + return true + }, + }) + + systray.AddSeparator() + + t.colorTheme = menus. + NewColorTheme(). + Watch(menus.ColorThemeListener{ + OnColorThemeChanged: func(theme string) bool { + switch theme { + case menus.ColorThemeSystem: + runtime.WindowSetSystemDefaultTheme(t.wailsCtx) + case menus.ColorThemeLight: + runtime.WindowSetLightTheme(t.wailsCtx) + case menus.ColorThemeDark: + runtime.WindowSetDarkTheme(t.wailsCtx) + } + return true + }, + }) + + systray.AddSeparator() + + t.quit = menus. + NewQuit(). + Watch(menus.QuitListener{ + OnQuit: func() { + locale := i18n.I18n().Locale() + dialog, err := runtime.MessageDialog(t.wailsCtx, runtime.MessageDialogOptions{ + Type: runtime.QuestionDialog, + Title: locale.AppName, + Message: locale.QuitDialog.Message, + Buttons: []string{}, + DefaultButton: locale.QuitDialog.DefaultButton, + CancelButton: locale.QuitDialog.CancelButton, + }) + if err != nil { + log.Fatalf("fail to open quit dialog: %+v\n", err) + } + if dialog == "Yes" { // when default button => "Yes" is clicked + systray.Quit() + runtime.Quit(t.wailsCtx) + } + }, + }) +} + +func (t *tray) onQuit() { + // end menus properly + t.openWindow.StopWatch() + t.apiService.StopWatch() + t.displayLanguage.StopWatch() + t.colorTheme.StopWatch() + t.quit.StopWatch() } diff --git a/main.go b/main.go index b5fbb22..1c629bb 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,6 @@ import ( "embed" "log" "my-app/backend/app" - "my-app/backend/i18n" "my-app/backend/tray" "github.com/wailsapp/wails/v2" @@ -19,9 +18,7 @@ import ( var frontend embed.FS func main() { - tray.Tray() - - i18n.I18n() + tray.Tray() // systray must run at very beginning... wlc := app.App().WailsLifeCycle() @@ -37,7 +34,7 @@ func main() { MaxWidth: -1, MaxHeight: -1, StartHidden: false, - HideWindowOnClose: false, + HideWindowOnClose: true, AlwaysOnTop: false, // BackgroundColour: &options.RGBA{R: 242, G: 242, B: 242, A: 0}, // RGBA: &options.RGBA{}, diff --git a/package.json b/package.json index 7b66197..1b07acd 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "install:swag": "cross-env GOBIN=\"%cd%\\.tools\" go install github.com/swaggo/swag/cmd/swag@latest", "install:upx": "curl -L https://github.com/upx/upx/releases/download/v3.96/upx-3.96-win64.zip > upx.zip && unzip -p upx.zip '*/upx.exe' > .tools/upx.exe && rm upx.zip", "install:wails": "cross-env GOBIN=\"%cd%\\.tools\" go install github.com/wailsapp/wails/v2/cmd/wails@latest", - "install": "pnpm install:wails && pnpm install:upx && pnpm install:swag && pnpm docs:build && pnpm frontend:build" + "install": "pnpm install:wails && pnpm install:upx && pnpm install:swag && pnpm docs:build && pnpm frontend:build && go mod tidy" }, "devDependencies": { "@types/node": "^18.7.16", diff --git a/wails.json b/wails.json index 039725a..00cce4d 100644 --- a/wails.json +++ b/wails.json @@ -9,9 +9,9 @@ "debounceMS": 1000, "info": { "companyName": "Jinyao Ma's Individual Project", - "productName": "My App - Continuously updated service collection.", + "productName": "My App - Continuously updated personal service collection.", "productVersion": "1.0.0", "copyright": "Copyright © 2022 jinyaoMa", - "comments": "Continuously updated service collection. Built using Wails (https://wails.app)" + "comments": "Continuously updated personal service collection. Built using Wails (https://wails.app)" } }