Files
cmbone/internal/services/appservice.go
T
2026-07-09 00:34:47 +08:00

187 lines
4.8 KiB
Go

package services
import (
"cmbone/internal/models"
"embed"
"encoding/json"
"fmt"
"log"
"runtime"
"sync"
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/wailsapp/wails/v3/pkg/events"
)
type AppService struct {
App *application.App
SecondWindow *application.WebviewWindow
MainWindow *application.WebviewWindow
Config *AppConfigService
windowStateMu sync.Mutex
Tray *application.SystemTray
I18nFS embed.FS
Menu *application.Menu
MenuQuit *application.MenuItem
MenuSetting *application.MenuItem
MenuSecondBar *application.MenuItem
MenuVersion *application.MenuItem
}
const HotkeyShowSecondWindow = 1
const (
mainWindowWidth = 1280
mainWindowHeight = 800
mainWindowMinWidth = 1024
mainWindowMinHeight = 720
secondWindowWidth = 340
secondWindowHeight = 320
)
func ConfigureAppService(a *AppService, app *application.App, i18nFS embed.FS, suidb *SuiStore) {
a.App = app
a.I18nFS = i18nFS
a.Config = NewAppConfigService(suidb)
isWindows := runtime.GOOS == "windows"
mainWindowState := a.loadMainWindowStateOptions()
mainWindow := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "main",
Name: "main",
Width: mainWindowState.Width,
Height: mainWindowState.Height,
MinWidth: mainWindowMinWidth,
MinHeight: mainWindowMinHeight,
InitialPosition: application.WindowCentered,
StartState: mainWindowState.StartState,
DisableResize: false,
Frameless: isWindows,
Mac: application.MacWindow{
InvisibleTitleBarHeight: 50,
Backdrop: application.MacBackdropTranslucent,
TitleBar: application.MacTitleBarHiddenInset,
},
Windows: application.WindowsWindow{
DisableIcon: true,
},
URL: "/",
})
secondWindow := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "second",
Name: "second",
Width: secondWindowWidth,
Height: secondWindowHeight,
Mac: application.MacWindow{
InvisibleTitleBarHeight: 50,
TitleBar: application.MacTitleBarHidden,
Backdrop: application.MacBackdropTransparent,
},
BackgroundColour: application.NewRGB(27, 38, 54),
URL: "/#/second",
})
secondWindow.Hide()
a.SecondWindow = secondWindow
a.MainWindow = mainWindow
a.registerMainWindowStatePersistence()
RegisterWindowAndCallback(HotkeyShowSecondWindow, a.SecondWindow, func() {
if a.SecondWindow == nil {
return
}
a.SecondWindow.Show()
a.SecondWindow.Focus()
})
a.MainWindow.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) {
a.persistMainWindowState()
a.MainWindow.Hide()
e.Cancel()
})
a.SecondWindow.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) {
a.SecondWindow.Hide()
e.Cancel()
})
initTray(a, NewAppConfigService(suidb).GetLanguage())
}
func (a *AppService) OpenSecondWindow() {
if a.SecondWindow != nil {
a.SecondWindow.Show()
}
}
func initTray(a *AppService, langValue string) {
a.Tray = a.App.NewSystemTray()
a.Tray.SetLabel("cmbone")
loadAppMenu(a, langValue)
}
func loadLang(i18nemb embed.FS, lang string) (*models.Lang, error) {
file := fmt.Sprintf("frontend/src/locales/%s.json", lang)
data, err := i18nemb.ReadFile(file)
if err != nil {
return nil, err
}
var i18nva models.Lang
err = json.Unmarshal(data, &i18nva)
return &i18nva, err
}
func loadAppMenu(a *AppService, langValue string) {
lang, langerr := loadLang(a.I18nFS, langValue)
if langerr != nil {
log.Printf("load language %q failed: %v", langValue, langerr)
return
}
a.Menu = application.NewMenu()
a.MenuSecondBar = a.Menu.Add(lang.AppMenu.Second).OnClick(func(ctx *application.Context) {
a.SecondWindow.Show()
a.SecondWindow.Focus()
})
a.MenuSetting = a.Menu.Add(lang.AppMenu.Preferences).OnClick(func(ctx *application.Context) {
a.MainWindow.Show()
a.MainWindow.Focus()
})
a.Menu.AddSeparator()
item := a.Menu.Add(lang.AppMenu.Version)
item.SetEnabled(false)
a.MenuVersion = item
a.Menu.AddSeparator()
a.MenuQuit = a.Menu.Add(lang.AppMenu.Quit).OnClick(func(ctx *application.Context) {
a.App.Quit()
})
a.Tray.SetMenu(a.Menu)
}
func updateAppMenu(a *AppService, langValue string) {
lang, langerr := loadLang(a.I18nFS, langValue)
if langerr != nil {
log.Printf("load language %q failed: %v", langValue, langerr)
return
}
a.MenuSecondBar.SetLabel(lang.AppMenu.Second)
a.MenuSetting.SetLabel(lang.AppMenu.Preferences)
a.MenuVersion.SetLabel(lang.AppMenu.Version)
a.MenuQuit.SetLabel(lang.AppMenu.Quit)
if runtime.GOOS == "darwin" {
a.Menu.Update()
} else {
a.Tray.SetMenu(a.Menu)
}
}
func (s *AppService) SetLanguage(lang string) error {
current := s.Config.GetLanguage()
if current == lang {
return nil
}
updateAppMenu(s, lang)
return s.Config.SetLanguage(lang)
}