From a12b6dd276270fa50bc42d9e7543c4157c3a1e54 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Thu, 13 Jul 2023 13:12:57 -0700 Subject: [PATCH] expose repeat mode through MPRIS --- backend/mpris.go | 29 +++++++++++++++++++++++++++-- backend/playbackmanager.go | 30 +++++++++++++++++++++++++++--- ui/bottompanel.go | 2 +- ui/widgets/auxcontrols.go | 10 ++++++---- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/backend/mpris.go b/backend/mpris.go index edd9e40..1b89376 100644 --- a/backend/mpris.go +++ b/backend/mpris.go @@ -15,8 +15,9 @@ import ( const dbusTrackIDPrefix = "/Supersonic/Track/" var ( - _ types.OrgMprisMediaPlayer2Adapter = (*MPRISHandler)(nil) - _ types.OrgMprisMediaPlayer2PlayerAdapter = (*MPRISHandler)(nil) + _ types.OrgMprisMediaPlayer2Adapter = (*MPRISHandler)(nil) + _ types.OrgMprisMediaPlayer2PlayerAdapter = (*MPRISHandler)(nil) + _ types.OrgMprisMediaPlayer2PlayerAdapterLoopStatus = (*MPRISHandler)(nil) ) var ( @@ -186,6 +187,30 @@ func (m *MPRISHandler) PlaybackStatus() (types.PlaybackStatus, error) { return "", errors.New("unknown playback status") } +func (m *MPRISHandler) LoopStatus() (types.LoopStatus, error) { + switch m.pm.LoopMode() { + case LoopModeAll: + return types.LoopStatusPlaylist, nil + case LoopModeOne: + return types.LoopStatusTrack, nil + case LoopModeNone: + return types.LoopStatusNone, nil + } + return "", errors.New("unknown loop status") +} + +func (m *MPRISHandler) SetLoopStatus(status types.LoopStatus) error { + switch status { + case types.LoopStatusPlaylist: + return m.pm.SetLoopMode(LoopModeAll) + case types.LoopStatusTrack: + return m.pm.SetLoopMode(LoopModeOne) + case types.LoopStatusNone: + return m.pm.SetLoopMode(LoopModeNone) + } + return errors.New("unknown loop status") +} + func (m *MPRISHandler) Rate() (float64, error) { return 1, nil } diff --git a/backend/playbackmanager.go b/backend/playbackmanager.go index fb121bf..8622db8 100644 --- a/backend/playbackmanager.go +++ b/backend/playbackmanager.go @@ -17,6 +17,14 @@ const ( ReplayGainTrack = string(player.ReplayGainTrack) ) +type LoopMode int + +const ( + LoopModeNone LoopMode = LoopMode(player.LoopNone) + LoopModeAll LoopMode = LoopMode(player.LoopAll) + LoopModeOne LoopMode = LoopMode(player.LoopOne) +) + // A high-level Subsonic-aware playback backend. // Manages loading tracks into the Player queue, // sending callbacks on play time updates and track changes. @@ -40,7 +48,7 @@ type PlaybackManager struct { onSongChange []func(nowPlaying, justScrobbledIfAny *mediaprovider.Track) onPlayTimeUpdate []func(float64, float64) - onLoopModeChange []func(string) + onLoopModeChange []func(LoopMode) } func NewPlaybackManager( @@ -130,7 +138,7 @@ func (p *PlaybackManager) OnPlayTimeUpdate(cb func(float64, float64)) { } // Registers a callback that is notified whenever the loop mode changes. -func (p *PlaybackManager) OnLoopModeChange(cb func(string)) { +func (p *PlaybackManager) OnLoopModeChange(cb func(LoopMode)) { p.onLoopModeChange = append(p.onLoopModeChange, cb) } @@ -305,12 +313,28 @@ func (p *PlaybackManager) SetNextLoopMode() error { } for _, cb := range p.onLoopModeChange { - cb(p.player.GetLoopMode().String()) + cb(LoopMode(p.player.GetLoopMode())) } return nil } +func (p *PlaybackManager) SetLoopMode(loopMode LoopMode) error { + if err := p.player.SetLoopMode(player.LoopMode(loopMode)); err != nil { + return err + } + + for _, cb := range p.onLoopModeChange { + cb(loopMode) + } + + return nil +} + +func (p *PlaybackManager) LoopMode() LoopMode { + return LoopMode(p.player.GetLoopMode()) +} + // call BEFORE updating p.nowPlayingIdx func (p *PlaybackManager) checkScrobble() { if !p.scrobbleCfg.Enabled || len(p.playQueue) == 0 || p.nowPlayingIdx < 0 { diff --git a/ui/bottompanel.go b/ui/bottompanel.go index 36ad8cc..f451667 100644 --- a/ui/bottompanel.go +++ b/ui/bottompanel.go @@ -54,7 +54,7 @@ func NewBottomPanel(p *player.Player, pm *backend.PlaybackManager, contr *contro p.OnStopped(func() { bp.Controls.SetPlaying(false) }) - pm.OnLoopModeChange(func(mode string) { + pm.OnLoopModeChange(func(mode backend.LoopMode) { bp.AuxControls.SetLoopMode(mode) }) diff --git a/ui/widgets/auxcontrols.go b/ui/widgets/auxcontrols.go index 0119e23..0589438 100644 --- a/ui/widgets/auxcontrols.go +++ b/ui/widgets/auxcontrols.go @@ -7,6 +7,7 @@ import ( "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" + "github.com/dweymouth/supersonic/backend" myTheme "github.com/dweymouth/supersonic/ui/theme" "github.com/dweymouth/supersonic/ui/util" ) @@ -67,14 +68,15 @@ func (a *AuxControls) OnChangeLoopMode(f func()) { a.loop.OnTapped = f } -func (a *AuxControls) SetLoopMode(mode string) { - if mode == "all" { +func (a *AuxControls) SetLoopMode(mode backend.LoopMode) { + switch mode { + case backend.LoopModeAll: a.loop.Importance = widget.HighImportance a.loop.Icon = myTheme.RepeatIcon - } else if mode == "one" { + case backend.LoopModeOne: a.loop.Importance = widget.HighImportance a.loop.Icon = myTheme.RepeatOneIcon - } else { + case backend.LoopModeNone: a.loop.Importance = widget.MediumImportance a.loop.Icon = myTheme.RepeatIcon }