diff --git a/ui/controller/controller.go b/ui/controller/controller.go index f191a1d..54e4658 100644 --- a/ui/controller/controller.go +++ b/ui/controller/controller.go @@ -315,7 +315,7 @@ func (c *Controller) ShowAboutDialog() { pop.Show() } -func (c *Controller) ShowSettingsDialog() { +func (c *Controller) ShowSettingsDialog(themeUpdateCallbk func()) { devs, err := c.App.Player.ListAudioDevices() if err != nil { log.Printf("error listing audio devices: %v", err) @@ -332,6 +332,7 @@ func (c *Controller) ShowSettingsDialog() { dlg.OnAudioDeviceSettingChanged = func() { c.App.Player.SetAudioDevice(c.App.Config.LocalPlayback.AudioDeviceName) } + dlg.OnThemeSettingChanged = themeUpdateCallbk pop := widget.NewModalPopUp(dlg, c.MainWindow.Canvas()) dlg.OnDismiss = func() { pop.Hide() diff --git a/ui/dialogs/settingsdialog.go b/ui/dialogs/settingsdialog.go index a870391..2609ef0 100644 --- a/ui/dialogs/settingsdialog.go +++ b/ui/dialogs/settingsdialog.go @@ -9,6 +9,7 @@ import ( "supersonic/backend" "supersonic/player" "supersonic/ui/layouts" + myTheme "supersonic/ui/theme" "supersonic/ui/util" "supersonic/ui/widgets" "unicode" @@ -31,6 +32,7 @@ type SettingsDialog struct { OnReplayGainSettingsChanged func() OnAudioExclusiveSettingChanged func() OnAudioDeviceSettingChanged func() + OnThemeSettingChanged func() OnDismiss func() config *backend.Config @@ -50,6 +52,10 @@ func NewSettingsDialog(config *backend.Config, audioDeviceList []player.AudioDev s.createPlaybackTab(), s.createExperimentalTab(window), ) + // workaround issue where inactivated tabs don't fully update when theme setting is changed + tabs.OnSelected = func(ti *container.TabItem) { + ti.Content.Refresh() + } s.promptText = widget.NewRichTextWithText("") s.content = container.NewVBox(tabs, widget.NewSeparator(), container.NewHBox(s.promptText, layout.NewSpacer(), widget.NewButton("Close", func() { @@ -62,6 +68,21 @@ func NewSettingsDialog(config *backend.Config, audioDeviceList []player.AudioDev } func (s *SettingsDialog) createGeneralTab() *container.TabItem { + themeSelect := widget.NewSelect([]string{ + string(myTheme.AppearanceDark), + string(myTheme.AppearanceLight), + string(myTheme.AppearanceAuto)}, nil) + themeSelect.OnChanged = func(_ string) { + s.config.Theme.Appearance = themeSelect.Options[themeSelect.SelectedIndex()] + if s.OnThemeSettingChanged != nil { + s.OnThemeSettingChanged() + } + } + themeSelect.SetSelected(s.config.Theme.Appearance) + if themeSelect.Selected == "" { + themeSelect.SetSelectedIndex(0) + } + startupPage := widget.NewSelect(backend.SupportedStartupPages, func(choice string) { s.config.Application.StartupPage = choice }) @@ -161,7 +182,10 @@ func (s *SettingsDialog) createGeneralTab() *container.TabItem { scrobbleEnabled.Checked = s.config.Scrobbling.Enabled return container.NewTabItem("General", container.NewVBox( - container.New(layout.NewFormLayout(), widget.NewLabel("Startup page"), startupPage), + container.New(layout.NewFormLayout(), + widget.NewLabel("Appearance"), container.NewGridWithColumns(2, themeSelect), + widget.NewLabel("Startup page"), container.NewGridWithColumns(2, startupPage), + ), container.NewHBox(systemTrayEnable, closeToTray), s.newSectionSeparator(), diff --git a/ui/mainwindow.go b/ui/mainwindow.go index 18ec5f6..b45f650 100644 --- a/ui/mainwindow.go +++ b/ui/mainwindow.go @@ -43,6 +43,7 @@ type MainWindow struct { BrowsingPane *browsing.BrowsingPane BottomPanel *BottomPanel + theme *theme.MyTheme haveSystemTray bool container *fyne.Container } @@ -52,8 +53,13 @@ func NewMainWindow(fyneApp fyne.App, appName, appVersion string, app *backend.Ap App: app, Window: fyneApp.NewWindow(appName), BrowsingPane: browsing.NewBrowsingPane(app), + theme: theme.NewMyTheme(&app.Config.Theme), } + m.theme.NormalFont = app.Config.Application.FontNormalTTF + m.theme.BoldFont = app.Config.Application.FontBoldTTF + fyneApp.Settings().SetTheme(m.theme) + if app.Config.Application.EnableSystemTray { m.SetupSystemTrayMenu(appName, fyneApp) } @@ -118,7 +124,11 @@ func NewMainWindow(fyneApp fyne.App, appName, appVersion string, app *backend.Ap } }() }) - m.BrowsingPane.AddSettingsMenuItem("Settings...", m.Controller.ShowSettingsDialog) + m.BrowsingPane.AddSettingsMenuItem("Settings...", func() { + m.Controller.ShowSettingsDialog(func() { + fyneApp.Settings().SetTheme(m.theme) + }) + }) m.BrowsingPane.AddSettingsMenuItem("About...", m.Controller.ShowAboutDialog) m.addNavigationButtons() m.BrowsingPane.DisableNavigationButtons() diff --git a/ui/theme/theme.go b/ui/theme/theme.go index 1bcbd66..11d5238 100644 --- a/ui/theme/theme.go +++ b/ui/theme/theme.go @@ -22,6 +22,8 @@ const ( AppearanceLight AppearanceMode = "Light" AppearanceDark AppearanceMode = "Dark" AppearanceAuto AppearanceMode = "Auto" + + DefaultAppearance AppearanceMode = AppearanceDark ) var ( @@ -170,11 +172,11 @@ func (m *MyTheme) Size(name fyne.ThemeSizeName) float32 { } func (m *MyTheme) getVariant() fyne.ThemeVariant { - v := "Dark" // default if config has invalid or missing setting + v := DefaultAppearance // default if config has invalid or missing setting if sharedutil.SliceContains( []string{string(AppearanceLight), string(AppearanceDark), string(AppearanceAuto)}, m.config.Appearance) { - v = m.config.Appearance + v = AppearanceMode(m.config.Appearance) } if AppearanceMode(v) == AppearanceDark {