From 6572e74aa8a364a484c24da34003aa0a2cb744fb Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Wed, 1 Jan 2025 14:23:02 -0800 Subject: [PATCH] Fix #496: Persist repeat mode setting across restarts --- backend/app.go | 10 +++++++++- backend/config.go | 8 ++++++++ backend/playbackengine.go | 7 +++++++ backend/playbackmanager.go | 3 ++- ui/bottompanel.go | 2 +- ui/mainwindow.go | 8 ++++++++ ui/widgets/auxcontrols.go | 3 ++- ui/widgets/iconbutton.go | 13 +++++++++---- 8 files changed, 46 insertions(+), 8 deletions(-) diff --git a/backend/app.go b/backend/app.go index e2d3592..3507929 100644 --- a/backend/app.go +++ b/backend/app.go @@ -119,7 +119,7 @@ func StartupApp(appName, displayAppName, appVersion, appVersionTag, latestReleas } a.ServerManager = NewServerManager(appName, appVersion, a.Config, !portableMode /*use keyring*/) - a.PlaybackManager = NewPlaybackManager(a.bgrndCtx, a.ServerManager, a.LocalPlayer, &a.Config.Scrobbling, &a.Config.Transcoding, &a.Config.Application) + a.PlaybackManager = NewPlaybackManager(a.bgrndCtx, a.ServerManager, a.LocalPlayer, &a.Config.Playback, &a.Config.Scrobbling, &a.Config.Transcoding, &a.Config.Application) a.ImageManager = NewImageManager(a.bgrndCtx, a.ServerManager, cacheDir) a.Config.Application.MaxImageCacheSizeMB = clamp(a.Config.Application.MaxImageCacheSizeMB, 1, 500) a.ImageManager.SetMaxOnDiskCacheSizeBytes(int64(a.Config.Application.MaxImageCacheSizeMB) * 1_048_576) @@ -336,6 +336,14 @@ func (a *App) DeleteServerCacheDir(serverID uuid.UUID) error { } func (a *App) Shutdown() { + repeatMode := "None" + switch a.PlaybackManager.GetLoopMode() { + case LoopOne: + repeatMode = "One" + case LoopAll: + repeatMode = "All" + } + a.Config.Playback.RepeatMode = repeatMode a.Config.LocalPlayback.Volume = a.LocalPlayer.GetVolume() a.SavePlayQueueIfEnabled() a.SaveConfigFile() diff --git a/backend/config.go b/backend/config.go index 26263ed..41626fc 100644 --- a/backend/config.go +++ b/backend/config.go @@ -98,6 +98,10 @@ type NowPlayingPageConfig struct { InitialView string } +type PlaybackConfig struct { + RepeatMode string +} + type LocalPlaybackConfig struct { AudioDeviceName string AudioExclusive bool @@ -146,6 +150,7 @@ type Config struct { PlaylistsPage PlaylistsPageConfig TracksPage TracksPageConfig NowPlayingConfig NowPlayingPageConfig + Playback PlaybackConfig LocalPlayback LocalPlaybackConfig Scrobbling ScrobbleConfig ReplayGain ReplayGainConfig @@ -209,6 +214,9 @@ func DefaultConfig(appVersionTag string) *Config { TracksPage: TracksPageConfig{ TracklistColumns: []string{"Album", "Time", "Plays"}, }, + Playback: PlaybackConfig{ + RepeatMode: "None", + }, LocalPlayback: LocalPlaybackConfig{ // "auto" is the name to pass to MPV for autoselecting the output device AudioDeviceName: "auto", diff --git a/backend/playbackengine.go b/backend/playbackengine.go index 470e53c..17295c3 100644 --- a/backend/playbackengine.go +++ b/backend/playbackengine.go @@ -78,6 +78,7 @@ func NewPlaybackEngine( ctx context.Context, s *ServerManager, p player.BasePlayer, + playbackCfg *PlaybackConfig, scrobbleCfg *ScrobbleConfig, transcodeCfg *TranscodingConfig, ) *playbackEngine { @@ -92,6 +93,12 @@ func NewPlaybackEngine( nowPlayingIdx: -1, wasStopped: true, } + switch playbackCfg.RepeatMode { + case "All": + pm.loopMode = LoopAll + case "One": + pm.loopMode = LoopOne + } p.OnTrackChange(pm.handleOnTrackChange) p.OnSeek(func() { pm.doUpdateTimePos(true) diff --git a/backend/playbackmanager.go b/backend/playbackmanager.go index 3b869ef..f338e3c 100644 --- a/backend/playbackmanager.go +++ b/backend/playbackmanager.go @@ -25,11 +25,12 @@ func NewPlaybackManager( ctx context.Context, s *ServerManager, p player.BasePlayer, + playbackCfg *PlaybackConfig, scrobbleCfg *ScrobbleConfig, transcodeCfg *TranscodingConfig, appCfg *AppConfig, ) *PlaybackManager { - e := NewPlaybackEngine(ctx, s, p, scrobbleCfg, transcodeCfg) + e := NewPlaybackEngine(ctx, s, p, playbackCfg, scrobbleCfg, transcodeCfg) q := NewCommandQueue() pm := &PlaybackManager{ engine: e, diff --git a/ui/bottompanel.go b/ui/bottompanel.go index c54b8cd..5851ffc 100644 --- a/ui/bottompanel.go +++ b/ui/bottompanel.go @@ -102,7 +102,7 @@ func NewBottomPanel(pm *backend.PlaybackManager, im *backend.ImageManager, contr pm.SeekFraction(f) }) - bp.AuxControls = widgets.NewAuxControls(pm.Volume()) + bp.AuxControls = widgets.NewAuxControls(pm.Volume(), pm.GetLoopMode()) pm.OnLoopModeChange(bp.AuxControls.SetLoopMode) pm.OnVolumeChange(bp.AuxControls.VolumeControl.SetVolume) bp.AuxControls.VolumeControl.OnSetVolume = func(v int) { diff --git a/ui/mainwindow.go b/ui/mainwindow.go index 614f0a6..ad852c7 100644 --- a/ui/mainwindow.go +++ b/ui/mainwindow.go @@ -147,6 +147,14 @@ func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, // TODO: when all shutdowns exit cleanly, remove these lines // as they are already executed in app.Shutdown() app.Config.LocalPlayback.Volume = app.LocalPlayer.GetVolume() + repeatMode := "None" + switch app.PlaybackManager.GetLoopMode() { + case backend.LoopOne: + repeatMode = "One" + case backend.LoopAll: + repeatMode = "All" + } + app.Config.Playback.RepeatMode = repeatMode app.SavePlayQueueIfEnabled() app.SaveConfigFile() diff --git a/ui/widgets/auxcontrols.go b/ui/widgets/auxcontrols.go index a5a2d92..582657d 100644 --- a/ui/widgets/auxcontrols.go +++ b/ui/widgets/auxcontrols.go @@ -25,7 +25,7 @@ type AuxControls struct { container *fyne.Container } -func NewAuxControls(initialVolume int) *AuxControls { +func NewAuxControls(initialVolume int, initialLoopMode backend.LoopMode) *AuxControls { a := &AuxControls{ VolumeControl: NewVolumeControl(initialVolume), loop: NewIconButton(myTheme.RepeatIcon, nil), @@ -33,6 +33,7 @@ func NewAuxControls(initialVolume int) *AuxControls { } a.loop.IconSize = IconButtonSizeSmaller a.loop.SetToolTip(lang.L("Repeat")) + a.SetLoopMode(initialLoopMode) a.showQueue.IconSize = IconButtonSizeSmaller a.showQueue.SetToolTip(lang.L("Show play queue")) a.container = container.NewHBox( diff --git a/ui/widgets/iconbutton.go b/ui/widgets/iconbutton.go index cb9750d..9d51cc6 100644 --- a/ui/widgets/iconbutton.go +++ b/ui/widgets/iconbutton.go @@ -120,10 +120,7 @@ func (i *IconButton) iconSize() fyne.Size { } } -func (i *IconButton) Refresh() { - if i.img == nil { - return - } +func (i *IconButton) updateColor() { if i.Highlighted || i.focused { i.themed.ColorName = theme.ColorNamePrimary } else if i.hovered { @@ -131,6 +128,13 @@ func (i *IconButton) Refresh() { } else { i.themed.ColorName = myTheme.ColorNameIconButton } +} + +func (i *IconButton) Refresh() { + if i.img == nil { + return + } + i.updateColor() i.img.SetMinSize(i.iconSize()) i.img.Refresh() } @@ -141,6 +145,7 @@ func (i *IconButton) CreateRenderer() fyne.WidgetRenderer { i.img = canvas.NewImageFromResource(i.themed) i.img.FillMode = canvas.ImageFillContain i.img.SetMinSize(i.iconSize()) + i.updateColor() } return widget.NewSimpleRenderer(container.NewCenter(i.img)) }