diff --git a/backend/app.go b/backend/app.go index e731f20..97c453f 100644 --- a/backend/app.go +++ b/backend/app.go @@ -60,6 +60,7 @@ type App struct { // UI callbacks to be set in main OnReactivate func() OnExit func() + OnReloadTheme func() appName string displayAppName string @@ -227,7 +228,8 @@ func StartupApp(appName, displayAppName, appVersion, appVersionTag, latestReleas ipcRatingHandler, a.ServerManager, a.callOnReactivate, - func() { _ = a.callOnExit() }) + func() { _ = a.callOnExit() }, + a.callOnReloadTheme) go a.ipcServer.Serve(listener) } else { log.Printf("error starting IPC server: %s", err.Error()) @@ -336,6 +338,12 @@ func (a *App) callOnReactivate() { } } +func (a *App) callOnReloadTheme() { + if a.OnReloadTheme != nil { + a.OnReloadTheme() + } +} + func (a *App) callOnExit() error { if a.OnExit == nil { return errors.New("no quit handler registered") @@ -658,6 +666,8 @@ func (a *App) checkFlagsAndSendIPCMsg(cli *ipc.Client) error { return cli.PauseAfterCurrent() case *FlagShow: return cli.Show() + case *FlagReloadTheme: + return cli.ReloadTheme() case VolumeCLIArg >= 0: return cli.SetVolume(VolumeCLIArg) case VolumePctCLIArg != 0: diff --git a/backend/cmdlineoptions.go b/backend/cmdlineoptions.go index 6bcc489..a06b970 100644 --- a/backend/cmdlineoptions.go +++ b/backend/cmdlineoptions.go @@ -32,6 +32,7 @@ var ( FlagPauseAfterCurrent = flag.Bool("pause-after-current", false, "pause playback after current track") FlagStartMinimized = flag.Bool("start-minimized", false, "start app minimized") FlagShow = flag.Bool("show", false, "show minimized app") + FlagReloadTheme = flag.Bool("reload-theme", false, "reload the current theme") FlagShuffle = flag.Bool("shuffle", false, "shuffle the tracklist (to be used with either -play-album-by-id or -play-playlist-by-id)") FlagVersion = flag.Bool("version", false, "print app version and exit") FlagHelp = flag.Bool("help", false, "print command line options and exit") diff --git a/backend/ipc/api.go b/backend/ipc/api.go index 60028d6..4038475 100644 --- a/backend/ipc/api.go +++ b/backend/ipc/api.go @@ -26,6 +26,7 @@ const ( VolumePath = "/volume" // ?v= VolumeAdjustPath = "/volume/adjust" // ?pct=<+/- percentage> ShowPath = "/window/show" + ReloadThemePath = "/window/reload-theme" QuitPath = "/window/quit" RateCurrentTrackPath = "/current_track/rate" // ?r= ) diff --git a/backend/ipc/client.go b/backend/ipc/client.go index 41cb310..1656ca3 100644 --- a/backend/ipc/client.go +++ b/backend/ipc/client.go @@ -128,6 +128,11 @@ func (c *Client) Show() error { return err } +func (c *Client) ReloadTheme() error { + _, err := c.sendRequest(ReloadThemePath) + return err +} + func (c *Client) Quit() error { _, err := c.sendRequest(QuitPath) return err diff --git a/backend/ipc/server.go b/backend/ipc/server.go index 3ded536..0f8d61a 100644 --- a/backend/ipc/server.go +++ b/backend/ipc/server.go @@ -41,16 +41,17 @@ type ServerManager interface { } type serverImpl struct { - server *http.Server - pbHandler PlaybackHandler - rateFn func(int) - sm ServerManager - showFn func() - quitFn func() + server *http.Server + pbHandler PlaybackHandler + rateFn func(int) + sm ServerManager + showFn func() + quitFn func() + reloadThemeFn func() } -func NewServer(pbHandler PlaybackHandler, rateFn func(int), sm ServerManager, showFn, quitFn func()) IPCServer { - s := &serverImpl{pbHandler: pbHandler, rateFn: rateFn, sm: sm, showFn: showFn, quitFn: quitFn} +func NewServer(pbHandler PlaybackHandler, rateFn func(int), sm ServerManager, showFn, quitFn, reloadThemeFn func()) IPCServer { + s := &serverImpl{pbHandler: pbHandler, rateFn: rateFn, sm: sm, showFn: showFn, quitFn: quitFn, reloadThemeFn: reloadThemeFn} s.server = &http.Server{ Handler: s.createHandler(), } @@ -77,6 +78,7 @@ func (s *serverImpl) createHandler() http.Handler { m.HandleFunc(ShowPath, s.makeSimpleEndpointHandler(func() { s.showFn() })) + m.HandleFunc(ReloadThemePath, s.makeSimpleEndpointHandler(s.reloadThemeFn)) m.HandleFunc(QuitPath, s.makeSimpleEndpointHandler(func() { s.quitFn() })) diff --git a/main.go b/main.go index de68eef..0f972fa 100644 --- a/main.go +++ b/main.go @@ -110,6 +110,7 @@ func main() { mainWindow.Window.SetMaster() myApp.OnReactivate = util.FyneDoFunc(mainWindow.Show) myApp.OnExit = util.FyneDoFunc(mainWindow.Quit) + myApp.OnReloadTheme = util.FyneDoFunc(mainWindow.ReloadTheme) if runtime.GOOS == "windows" { windowStartupTasks := sync.OnceFunc(func() { diff --git a/ui/mainwindow.go b/ui/mainwindow.go index 7e11c4e..e6cb5b8 100644 --- a/ui/mainwindow.go +++ b/ui/mainwindow.go @@ -273,6 +273,11 @@ func (m *MainWindow) setInitialSize() { m.Window.Resize(m.DesiredSize()) } +func (m *MainWindow) ReloadTheme() { + m.theme.ReloadThemeFile() + fyne.CurrentApp().Settings().SetTheme(m.theme) +} + func (m *MainWindow) StartupPage() controller.Route { switch m.App.Config.Application.StartupPage { case "Artists": diff --git a/ui/theme/theme.go b/ui/theme/theme.go index 9b22de8..0c46dc2 100644 --- a/ui/theme/theme.go +++ b/ui/theme/theme.go @@ -110,6 +110,11 @@ func NewMyTheme(config *backend.ThemeConfig, themeFileDir string) *MyTheme { return m } +// ReloadThemeFile reloads the currently loaded theme file. +func (m *MyTheme) ReloadThemeFile() { + m.loadedThemeFile = nil +} + func (m *MyTheme) Color(name fyne.ThemeColorName, defVariant fyne.ThemeVariant) color.Color { // load theme file if necessary if m.loadedThemeFile == nil || m.config.ThemeFile != m.loadedThemeFilename {