From 20563f84414af9581491b03b5b26acbb0d50c827 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Fri, 31 Mar 2023 17:37:14 -0700 Subject: [PATCH 1/6] begin work on settings dialog --- ui/controller/controller.go | 12 ++++++++ ui/dialogs/settingsdialog.go | 58 ++++++++++++++++++++++++++++++++++++ ui/mainwindow.go | 1 + 3 files changed, 71 insertions(+) create mode 100644 ui/dialogs/settingsdialog.go diff --git a/ui/controller/controller.go b/ui/controller/controller.go index b2d71a7..aa67709 100644 --- a/ui/controller/controller.go +++ b/ui/controller/controller.go @@ -304,6 +304,18 @@ func (c *Controller) ShowAboutDialog() { pop.Show() } +func (c *Controller) ShowSettingsDialog() { + dlg := dialogs.NewSettingsDialog(c.App.Config) + pop := widget.NewModalPopUp(dlg, c.MainWindow.Canvas()) + dlg.OnDismiss = func() { + pop.Hide() + c.doModalClosed() + } + c.ClosePopUpOnEscape(pop) + c.haveModal = true + pop.Show() +} + func (c *Controller) trySetPasswordAndConnectToServer(server *backend.ServerConfig, password string) error { if err := c.App.ServerManager.SetServerPassword(server, password); err != nil { log.Printf("error setting keyring credentials: %v", err) diff --git a/ui/dialogs/settingsdialog.go b/ui/dialogs/settingsdialog.go new file mode 100644 index 0000000..c8ae3a7 --- /dev/null +++ b/ui/dialogs/settingsdialog.go @@ -0,0 +1,58 @@ +package dialogs + +import ( + "supersonic/backend" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/widget" +) + +var boldStyle = widget.RichTextStyle{TextStyle: fyne.TextStyle{Bold: true}} + +type SettingsDialog struct { + widget.BaseWidget + + OnReplayGainSettingsChanged func() + OnAudioExclusiveSettingChanged func() + OnDismiss func() + + config *backend.Config + + content fyne.CanvasObject +} + +func NewSettingsDialog(config *backend.Config) *SettingsDialog { + s := &SettingsDialog{config: config} + s.ExtendBaseWidget(s) + + replayGainSelect := widget.NewSelect([]string{"None", "Album", "Track"}, nil) + + tabs := container.NewAppTabs( + container.NewTabItem("General", container.NewVBox( + widget.NewRichText(&widget.TextSegment{Text: "Scrobbling", Style: boldStyle}), + widget.NewCheckWithData("Send playback statistics to server", binding.BindBool(&config.Scrobbling.Enabled)))), + container.NewTabItem("Playback", container.NewVBox( + widget.NewRichText(&widget.TextSegment{Text: "ReplayGain", Style: boldStyle}), + container.New(layout.NewFormLayout(), + widget.NewLabel("ReplayGain mode"), replayGainSelect, + widget.NewLabel("Prevent clipping"), widget.NewCheckWithData("", binding.BindBool(&config.ReplayGain.PreventClipping)), + ), + widget.NewSeparator(), + widget.NewCheckWithData("Audio exclusive mode", binding.BindBool(&config.LocalPlayback.AudioExclusive)))), + ) + s.content = container.NewVBox(tabs, widget.NewSeparator(), + container.NewHBox(layout.NewSpacer(), widget.NewButton("Close", func() { + if s.OnDismiss != nil { + s.OnDismiss() + } + }))) + + return s +} + +func (s *SettingsDialog) CreateRenderer() fyne.WidgetRenderer { + return widget.NewSimpleRenderer(s.content) +} diff --git a/ui/mainwindow.go b/ui/mainwindow.go index aa5bc32..2995cc8 100644 --- a/ui/mainwindow.go +++ b/ui/mainwindow.go @@ -108,6 +108,7 @@ func NewMainWindow(fyneApp fyne.App, appName, appVersion string, app *backend.Ap } }() }) + m.BrowsingPane.AddSettingsMenuItem("Settings...", m.Controller.ShowSettingsDialog) m.BrowsingPane.AddSettingsMenuItem("About...", m.Controller.ShowAboutDialog) m.addNavigationButtons() m.BrowsingPane.DisableNavigationButtons() From 19202dc0e87b0fdf49fccd697fba23d0e5e8d96d Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Fri, 31 Mar 2023 17:57:10 -0700 Subject: [PATCH 2/6] more settings dialog work --- ui/dialogs/settingsdialog.go | 18 ++++++++++++-- ui/widgets/textrestrictedentry.go | 41 +++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 ui/widgets/textrestrictedentry.go diff --git a/ui/dialogs/settingsdialog.go b/ui/dialogs/settingsdialog.go index c8ae3a7..3b19008 100644 --- a/ui/dialogs/settingsdialog.go +++ b/ui/dialogs/settingsdialog.go @@ -2,6 +2,8 @@ package dialogs import ( "supersonic/backend" + "supersonic/ui/widgets" + "unicode" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" @@ -30,10 +32,21 @@ func NewSettingsDialog(config *backend.Config) *SettingsDialog { replayGainSelect := widget.NewSelect([]string{"None", "Album", "Track"}, nil) + percentEntry := widgets.NewTextRestrictedEntry(func(text string, r rune) bool { + return unicode.IsDigit(r) && len(text) < 2 + }) + percentEntry.SetMinCharWidth(2) + tabs := container.NewAppTabs( container.NewTabItem("General", container.NewVBox( widget.NewRichText(&widget.TextSegment{Text: "Scrobbling", Style: boldStyle}), - widget.NewCheckWithData("Send playback statistics to server", binding.BindBool(&config.Scrobbling.Enabled)))), + widget.NewCheckWithData("Send playback statistics to server", binding.BindBool(&config.Scrobbling.Enabled)), + container.NewHBox( + widget.NewLabel("Scrobble when"), + percentEntry, + widget.NewLabel("percent of track is played"), + ), + )), container.NewTabItem("Playback", container.NewVBox( widget.NewRichText(&widget.TextSegment{Text: "ReplayGain", Style: boldStyle}), container.New(layout.NewFormLayout(), @@ -41,7 +54,8 @@ func NewSettingsDialog(config *backend.Config) *SettingsDialog { widget.NewLabel("Prevent clipping"), widget.NewCheckWithData("", binding.BindBool(&config.ReplayGain.PreventClipping)), ), widget.NewSeparator(), - widget.NewCheckWithData("Audio exclusive mode", binding.BindBool(&config.LocalPlayback.AudioExclusive)))), + widget.NewCheckWithData("Audio exclusive mode", binding.BindBool(&config.LocalPlayback.AudioExclusive)), + )), ) s.content = container.NewVBox(tabs, widget.NewSeparator(), container.NewHBox(layout.NewSpacer(), widget.NewButton("Close", func() { diff --git a/ui/widgets/textrestrictedentry.go b/ui/widgets/textrestrictedentry.go new file mode 100644 index 0000000..9f8c83a --- /dev/null +++ b/ui/widgets/textrestrictedentry.go @@ -0,0 +1,41 @@ +package widgets + +import ( + "strings" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" +) + +type TextRestrictedEntry struct { + widget.Entry + + charAllowed func(string, rune) bool + + minWidth float32 +} + +func NewTextRestrictedEntry(charAllowed func(curText string, r rune) bool) *TextRestrictedEntry { + e := &TextRestrictedEntry{charAllowed: charAllowed} + e.ExtendBaseWidget(e) + return e +} + +func (e *TextRestrictedEntry) TypedRune(r rune) { + if e.charAllowed == nil || e.charAllowed(e.Text, r) { + e.Entry.TypedRune(r) + } +} + +func (e *TextRestrictedEntry) SetMinCharWidth(numChars int) { + e.minWidth = theme.Padding()*2 + fyne.MeasureText(strings.Repeat("W", numChars), + fyne.CurrentApp().Settings().Theme().Size(theme.SizeNameText), e.TextStyle).Width +} + +func (e *TextRestrictedEntry) MinSize() fyne.Size { + if e.minWidth < 0.001 { + return e.Entry.MinSize() + } + return fyne.NewSize(e.minWidth, e.Entry.MinSize().Height) +} From 7aaa82e52ae5f5556b4f7306b173cf545c290fc9 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sat, 1 Apr 2023 09:29:50 -0700 Subject: [PATCH 3/6] complete scrobble settings implementation --- ui/dialogs/settingsdialog.go | 119 +++++++++++++++++++++++++++-------- 1 file changed, 94 insertions(+), 25 deletions(-) diff --git a/ui/dialogs/settingsdialog.go b/ui/dialogs/settingsdialog.go index 3b19008..67bba8e 100644 --- a/ui/dialogs/settingsdialog.go +++ b/ui/dialogs/settingsdialog.go @@ -1,6 +1,8 @@ package dialogs import ( + "math" + "strconv" "supersonic/backend" "supersonic/ui/widgets" "unicode" @@ -30,32 +32,9 @@ func NewSettingsDialog(config *backend.Config) *SettingsDialog { s := &SettingsDialog{config: config} s.ExtendBaseWidget(s) - replayGainSelect := widget.NewSelect([]string{"None", "Album", "Track"}, nil) - - percentEntry := widgets.NewTextRestrictedEntry(func(text string, r rune) bool { - return unicode.IsDigit(r) && len(text) < 2 - }) - percentEntry.SetMinCharWidth(2) - tabs := container.NewAppTabs( - container.NewTabItem("General", container.NewVBox( - widget.NewRichText(&widget.TextSegment{Text: "Scrobbling", Style: boldStyle}), - widget.NewCheckWithData("Send playback statistics to server", binding.BindBool(&config.Scrobbling.Enabled)), - container.NewHBox( - widget.NewLabel("Scrobble when"), - percentEntry, - widget.NewLabel("percent of track is played"), - ), - )), - container.NewTabItem("Playback", container.NewVBox( - widget.NewRichText(&widget.TextSegment{Text: "ReplayGain", Style: boldStyle}), - container.New(layout.NewFormLayout(), - widget.NewLabel("ReplayGain mode"), replayGainSelect, - widget.NewLabel("Prevent clipping"), widget.NewCheckWithData("", binding.BindBool(&config.ReplayGain.PreventClipping)), - ), - widget.NewSeparator(), - widget.NewCheckWithData("Audio exclusive mode", binding.BindBool(&config.LocalPlayback.AudioExclusive)), - )), + s.createGeneralTab(), + s.createPlaybackTab(), ) s.content = container.NewVBox(tabs, widget.NewSeparator(), container.NewHBox(layout.NewSpacer(), widget.NewButton("Close", func() { @@ -67,6 +46,96 @@ func NewSettingsDialog(config *backend.Config) *SettingsDialog { return s } +func (s *SettingsDialog) createGeneralTab() *container.TabItem { + twoDigitValidator := func(text string, r rune) bool { + return unicode.IsDigit(r) && len(text) < 2 + } + + percentEntry := widgets.NewTextRestrictedEntry(twoDigitValidator) + percentEntry.SetMinCharWidth(2) + percentEntry.OnChanged = func(str string) { + if i, err := strconv.Atoi(str); err == nil { + s.config.Scrobbling.ThresholdPercent = i + } + } + percentEntry.Text = strconv.Itoa(s.config.Scrobbling.ThresholdPercent) + + durationEntry := widgets.NewTextRestrictedEntry(twoDigitValidator) + durationEntry.SetMinCharWidth(2) + durationEntry.OnChanged = func(str string) { + if i, err := strconv.Atoi(str); err == nil { + s.config.Scrobbling.ThresholdTimeSeconds = i * 60 + } + } + if secs := s.config.Scrobbling.ThresholdTimeSeconds; secs >= 0 { + val := int(math.Round(float64(secs) / 60.)) + durationEntry.Text = strconv.Itoa(val) + } + + lastScrobbleText := durationEntry.Text + if lastScrobbleText == "" { + lastScrobbleText = "4" // default scrobble minutes + } + durationEnabled := widget.NewCheck("or when", func(checked bool) { + if !checked { + s.config.Scrobbling.ThresholdTimeSeconds = -1 + lastScrobbleText = durationEntry.Text + durationEntry.Text = "" + durationEntry.Disable() + } else { + durationEntry.Text = lastScrobbleText + durationEntry.Enable() + durationEntry.Refresh() + durationEntry.OnChanged(durationEntry.Text) + } + }) + durationEnabled.Checked = s.config.Scrobbling.ThresholdTimeSeconds >= 0 + + scrobbleEnabled := widget.NewCheckWithData("Send playback statistics to server", binding.BindBool(&s.config.Scrobbling.Enabled)) + scrobbleEnabled.OnChanged = func(checked bool) { + if !checked { + percentEntry.Disable() + durationEnabled.Disable() + durationEntry.Disable() + } else { + percentEntry.Enable() + durationEnabled.Enable() + if durationEnabled.Checked { + durationEntry.Enable() + } + } + } + + return container.NewTabItem("General", container.NewVBox( + widget.NewRichText(&widget.TextSegment{Text: "Scrobbling", Style: boldStyle}), + scrobbleEnabled, + container.NewHBox( + widget.NewLabel("Scrobble when"), + percentEntry, + widget.NewLabel("percent of track is played"), + ), + container.NewHBox( + durationEnabled, + durationEntry, + widget.NewLabel("minutes of track have been played"), + ), + )) +} + +func (s *SettingsDialog) createPlaybackTab() *container.TabItem { + replayGainSelect := widget.NewSelect([]string{"None", "Album", "Track"}, nil) + + return container.NewTabItem("Playback", container.NewVBox( + widget.NewRichText(&widget.TextSegment{Text: "ReplayGain", Style: boldStyle}), + container.New(layout.NewFormLayout(), + widget.NewLabel("ReplayGain mode"), replayGainSelect, + widget.NewLabel("Prevent clipping"), widget.NewCheckWithData("", binding.BindBool(&s.config.ReplayGain.PreventClipping)), + ), + widget.NewSeparator(), + widget.NewCheckWithData("Audio exclusive mode", binding.BindBool(&s.config.LocalPlayback.AudioExclusive)), + )) +} + func (s *SettingsDialog) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(s.content) } From 4740446c1355341ac062f010a156276a87627594 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sat, 1 Apr 2023 10:06:04 -0700 Subject: [PATCH 4/6] connect replaygain config UI to config object --- ui/dialogs/settingsdialog.go | 67 ++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/ui/dialogs/settingsdialog.go b/ui/dialogs/settingsdialog.go index 67bba8e..f309da0 100644 --- a/ui/dialogs/settingsdialog.go +++ b/ui/dialogs/settingsdialog.go @@ -4,6 +4,7 @@ import ( "math" "strconv" "supersonic/backend" + "supersonic/ui/layouts" "supersonic/ui/widgets" "unicode" @@ -124,18 +125,78 @@ func (s *SettingsDialog) createGeneralTab() *container.TabItem { func (s *SettingsDialog) createPlaybackTab() *container.TabItem { replayGainSelect := widget.NewSelect([]string{"None", "Album", "Track"}, nil) + replayGainSelect.OnChanged = func(_ string) { + switch replayGainSelect.SelectedIndex() { + case 0: + s.config.ReplayGain.Mode = backend.ReplayGainNone + case 1: + s.config.ReplayGain.Mode = backend.ReplayGainAlbum + case 2: + s.config.ReplayGain.Mode = backend.ReplayGainTrack + } + s.onReplayGainSettingsChanged() + } + + // set initially selected option + switch s.config.ReplayGain.Mode { + case backend.ReplayGainAlbum: + replayGainSelect.SetSelectedIndex(1) + case backend.ReplayGainTrack: + replayGainSelect.SetSelectedIndex(2) + default: + replayGainSelect.SetSelectedIndex(0) + } + + preampGain := widgets.NewTextRestrictedEntry(func(curText string, r rune) bool { + return (curText == "" && r == '-') || + (curText == "" && unicode.IsDigit(r)) || + ((curText == "-" || curText == "0") && unicode.IsDigit(r)) + }) + preampGain.SetMinCharWidth(2) + preampGain.OnChanged = func(text string) { + if f, err := strconv.ParseFloat(text, 64); err == nil { + s.config.ReplayGain.PreampGainDB = f + s.onReplayGainSettingsChanged() + } + } + initVal := math.Round(s.config.ReplayGain.PreampGainDB) + if initVal < -9 { + initVal = -9 + } else if initVal > 9 { + initVal = 9 + } + preampGain.Text = strconv.Itoa(int(initVal)) + + preventClipping := widget.NewCheckWithData("", binding.BindBool(&s.config.ReplayGain.PreventClipping)) + preventClipping.OnChanged = func(_ bool) { s.onReplayGainSettingsChanged() } + + audioExclusive := widget.NewCheckWithData("Audio exclusive mode", binding.BindBool(&s.config.LocalPlayback.AudioExclusive)) + audioExclusive.OnChanged = func(_ bool) { s.onAudioExclusiveSettingsChanged() } return container.NewTabItem("Playback", container.NewVBox( widget.NewRichText(&widget.TextSegment{Text: "ReplayGain", Style: boldStyle}), container.New(layout.NewFormLayout(), widget.NewLabel("ReplayGain mode"), replayGainSelect, - widget.NewLabel("Prevent clipping"), widget.NewCheckWithData("", binding.BindBool(&s.config.ReplayGain.PreventClipping)), + widget.NewLabel("ReplayGain preamp"), container.NewHBox(preampGain, widget.NewLabel("dB")), + widget.NewLabel("Prevent clipping"), container.NewHBox(preventClipping, layout.NewSpacer()), ), - widget.NewSeparator(), - widget.NewCheckWithData("Audio exclusive mode", binding.BindBool(&s.config.LocalPlayback.AudioExclusive)), + container.New(&layouts.MaxPadLayout{PadLeft: 15, PadRight: 15}, widget.NewSeparator()), + container.NewHBox(audioExclusive, layout.NewSpacer()), )) } +func (s *SettingsDialog) onReplayGainSettingsChanged() { + if s.OnReplayGainSettingsChanged != nil { + s.OnReplayGainSettingsChanged() + } +} + +func (s *SettingsDialog) onAudioExclusiveSettingsChanged() { + if s.OnAudioExclusiveSettingChanged != nil { + s.OnAudioExclusiveSettingChanged() + } +} + func (s *SettingsDialog) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(s.content) } From d84c0d71edc2ab3e7f9777d7b5d0329a773f4647 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sat, 1 Apr 2023 10:42:15 -0700 Subject: [PATCH 5/6] hook up playback config onchanged --- backend/app.go | 3 ++- backend/playbackmanager.go | 8 ++++++++ player/player.go | 23 ++++++++++++++++++----- ui/controller/controller.go | 6 ++++++ ui/dialogs/settingsdialog.go | 31 +++++++++++++++++++++++-------- 5 files changed, 57 insertions(+), 14 deletions(-) diff --git a/backend/app.go b/backend/app.go index d26bd00..fe9de0e 100644 --- a/backend/app.go +++ b/backend/app.go @@ -68,6 +68,7 @@ func StartupApp(appName, appVersionTag, configFile, latestReleaseURL string) (*A PreventClipping: a.Config.ReplayGain.PreventClipping, PreampGain: a.Config.ReplayGain.PreampGainDB, }) + a.Player.SetAudioExclusive(a.Config.LocalPlayback.AudioExclusive) a.ServerManager = NewServerManager(appName) a.PlaybackManager = NewPlaybackManager(a.bgrndCtx, a.ServerManager, a.Player, &a.Config.Scrobbling) @@ -100,7 +101,7 @@ func (a *App) initMPV() error { p := player.NewWithClientName(a.appName) c := a.Config.LocalPlayback c.InMemoryCacheSizeMB = clamp(c.InMemoryCacheSizeMB, 10, 500) - if err := p.Init(c.AudioExclusive, c.InMemoryCacheSizeMB); err != nil { + if err := p.Init(c.InMemoryCacheSizeMB); err != nil { return fmt.Errorf("failed to initialize mpv player: %s", err.Error()) } a.Player = p diff --git a/backend/playbackmanager.go b/backend/playbackmanager.go index 1db3131..1af7591 100644 --- a/backend/playbackmanager.go +++ b/backend/playbackmanager.go @@ -270,6 +270,14 @@ func (p *PlaybackManager) StopAndClearPlayQueue() { p.playQueue = nil } +func (p *PlaybackManager) SetReplayGainOptions(config ReplayGainConfig) { + p.player.SetReplayGainOptions(player.ReplayGainOptions{ + Mode: player.ReplayGainMode(config.Mode), + PreventClipping: config.PreventClipping, + PreampGain: config.PreampGainDB, + }) +} + // call BEFORE updating p.nowPlayingIdx func (p *PlaybackManager) checkScrobble(playDur time.Duration) { if !p.scrobbleCfg.Enabled || len(p.playQueue) == 0 || p.nowPlayingIdx < 0 { diff --git a/player/player.go b/player/player.go index 15ee9e6..87f6bf8 100644 --- a/player/player.go +++ b/player/player.go @@ -63,6 +63,7 @@ type Player struct { vol int replayGainOpts ReplayGainOptions haveRGainOpts bool + audioExclusive bool status Status seeking bool curPlaylistPos int64 @@ -96,7 +97,7 @@ func NewWithClientName(c string) *Player { // Initializes the Player and makes it ready for playback. // Most Player functions will return ErrUnitialized if called before Init. -func (p *Player) Init(audioExclusive bool, maxCacheMB int) error { +func (p *Player) Init(maxCacheMB int) error { if !p.initialized { m, err := CreateMPV() if err != nil { @@ -118,9 +119,7 @@ func (p *Player) Init(audioExclusive bool, maxCacheMB int) error { } m.SetOption("volume", MPVFormatInt64, p.vol) - if audioExclusive { - m.SetOptionString("audio-exclusive", "yes") - } + p.SetAudioExclusive(p.audioExclusive) if p.haveRGainOpts { p.SetReplayGainOptions(p.replayGainOpts) } @@ -259,7 +258,7 @@ func (p *Player) SetVolume(vol int) error { // Sets the ReplayGain options of the player. // Unlike most Player functions, SetReplayGainOptions can be called -// before Init, to set the initial volume of the player on startup. +// before Init, to set the initial replaygain options of the player on startup. func (p *Player) SetReplayGainOptions(options ReplayGainOptions) error { p.replayGainOpts = options p.haveRGainOpts = true @@ -281,6 +280,20 @@ func (p *Player) SetReplayGainOptions(options ReplayGainOptions) error { return nil } +// Sets the audio exclusive option of the player. +// Unlike most Player functions, SetAudioExclusive can be called +// before Init, to set the initial option of the player on startup. +func (p *Player) SetAudioExclusive(tf bool) { + p.audioExclusive = tf + if p.initialized { + val := "no" + if tf { + val = "yes" + } + p.mpv.SetOptionString("audio-exclusive", val) + } +} + // Gets the current volume of the player. func (p *Player) GetVolume() int { return p.vol diff --git a/ui/controller/controller.go b/ui/controller/controller.go index aa67709..4859b16 100644 --- a/ui/controller/controller.go +++ b/ui/controller/controller.go @@ -306,6 +306,12 @@ func (c *Controller) ShowAboutDialog() { func (c *Controller) ShowSettingsDialog() { dlg := dialogs.NewSettingsDialog(c.App.Config) + dlg.OnReplayGainSettingsChanged = func() { + c.App.PlaybackManager.SetReplayGainOptions(c.App.Config.ReplayGain) + } + dlg.OnAudioExclusiveSettingChanged = func() { + c.App.Player.SetAudioExclusive(c.App.Config.LocalPlayback.AudioExclusive) + } 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 f309da0..10930ae 100644 --- a/ui/dialogs/settingsdialog.go +++ b/ui/dialogs/settingsdialog.go @@ -10,7 +10,6 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/data/binding" "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/widget" ) @@ -60,6 +59,9 @@ func (s *SettingsDialog) createGeneralTab() *container.TabItem { } } percentEntry.Text = strconv.Itoa(s.config.Scrobbling.ThresholdPercent) + if !s.config.Scrobbling.Enabled { + percentEntry.Disable() + } durationEntry := widgets.NewTextRestrictedEntry(twoDigitValidator) durationEntry.SetMinCharWidth(2) @@ -72,6 +74,9 @@ func (s *SettingsDialog) createGeneralTab() *container.TabItem { val := int(math.Round(float64(secs) / 60.)) durationEntry.Text = strconv.Itoa(val) } + if !s.config.Scrobbling.Enabled { + durationEntry.Disable() + } lastScrobbleText := durationEntry.Text if lastScrobbleText == "" { @@ -91,9 +96,12 @@ func (s *SettingsDialog) createGeneralTab() *container.TabItem { } }) durationEnabled.Checked = s.config.Scrobbling.ThresholdTimeSeconds >= 0 + if !s.config.Scrobbling.Enabled { + durationEnabled.Disable() + } - scrobbleEnabled := widget.NewCheckWithData("Send playback statistics to server", binding.BindBool(&s.config.Scrobbling.Enabled)) - scrobbleEnabled.OnChanged = func(checked bool) { + scrobbleEnabled := widget.NewCheck("Send playback statistics to server", func(checked bool) { + s.config.Scrobbling.Enabled = checked if !checked { percentEntry.Disable() durationEnabled.Disable() @@ -105,7 +113,8 @@ func (s *SettingsDialog) createGeneralTab() *container.TabItem { durationEntry.Enable() } } - } + }) + scrobbleEnabled.Checked = s.config.Scrobbling.Enabled return container.NewTabItem("General", container.NewVBox( widget.NewRichText(&widget.TextSegment{Text: "Scrobbling", Style: boldStyle}), @@ -167,11 +176,17 @@ func (s *SettingsDialog) createPlaybackTab() *container.TabItem { } preampGain.Text = strconv.Itoa(int(initVal)) - preventClipping := widget.NewCheckWithData("", binding.BindBool(&s.config.ReplayGain.PreventClipping)) - preventClipping.OnChanged = func(_ bool) { s.onReplayGainSettingsChanged() } + preventClipping := widget.NewCheck("", func(checked bool) { + s.config.ReplayGain.PreventClipping = checked + s.onReplayGainSettingsChanged() + }) + preventClipping.Checked = s.config.ReplayGain.PreventClipping - audioExclusive := widget.NewCheckWithData("Audio exclusive mode", binding.BindBool(&s.config.LocalPlayback.AudioExclusive)) - audioExclusive.OnChanged = func(_ bool) { s.onAudioExclusiveSettingsChanged() } + audioExclusive := widget.NewCheck("Audio exclusive mode", func(checked bool) { + s.config.LocalPlayback.AudioExclusive = checked + s.onAudioExclusiveSettingsChanged() + }) + audioExclusive.Checked = s.config.LocalPlayback.AudioExclusive return container.NewTabItem("Playback", container.NewVBox( widget.NewRichText(&widget.TextSegment{Text: "ReplayGain", Style: boldStyle}), From 51d60822f70f9a345adb91d13aad8491558b15bf Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sat, 1 Apr 2023 10:52:14 -0700 Subject: [PATCH 6/6] fix for duration entry enabled on dialog launch --- ui/dialogs/settingsdialog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/dialogs/settingsdialog.go b/ui/dialogs/settingsdialog.go index 10930ae..a1114a1 100644 --- a/ui/dialogs/settingsdialog.go +++ b/ui/dialogs/settingsdialog.go @@ -74,7 +74,7 @@ func (s *SettingsDialog) createGeneralTab() *container.TabItem { val := int(math.Round(float64(secs) / 60.)) durationEntry.Text = strconv.Itoa(val) } - if !s.config.Scrobbling.Enabled { + if !s.config.Scrobbling.Enabled || s.config.Scrobbling.ThresholdTimeSeconds < 0 { durationEntry.Disable() }