Fix #33: allow reordering of play queue

This commit is contained in:
Drew Weymouth
2024-01-06 14:22:18 -08:00
parent 8683999f29
commit 9c2f72d9f2
4 changed files with 93 additions and 25 deletions
+56
View File
@@ -221,6 +221,42 @@ func (p *PlaybackManager) LoadTracks(tracks []*mediaprovider.Track, appendToQueu
return nil
}
// Replaces the play queue with the given set of tracks.
// Does not stop playback if the currently playing track is in the new queue,
// but updates the now playing index to point to the first instance of the track in the new queue.
func (p *PlaybackManager) UpdatePlayQueue(tracks []*mediaprovider.Track) error {
newQueue := make([]*mediaprovider.Track, len(tracks))
for i, tr := range tracks {
// ensure a deep copy of the track info so that we can maintain our own state
// (tracking play count increases, favorite, and rating) without messing up
// other views' track models
track := *tr
newQueue[i] = &track
}
newNowPlayingIdx := -1
if p.nowPlayingIdx >= 0 {
nowPlayingID := p.playQueue[p.nowPlayingIdx].ID
for i, tr := range newQueue {
if tr.ID == nowPlayingID {
newNowPlayingIdx = i
break
}
}
}
p.playQueue = newQueue
if p.nowPlayingIdx >= 0 && newNowPlayingIdx == -1 {
return p.Stop()
}
needToUpdateNext := p.nowPlayingIdx >= 0
p.nowPlayingIdx = newNowPlayingIdx
if needToUpdateNext {
p.setNextTrackAfterQueueUpdate()
}
return nil
}
func (p *PlaybackManager) PlayAlbum(albumID string, firstTrack int, shuffle bool) error {
if err := p.LoadAlbum(albumID, false, shuffle); err != nil {
return err
@@ -563,6 +599,26 @@ func (p *PlaybackManager) setNextTrackBasedOnLoopMode(onLoopModeChange bool) {
}
}
func (p *PlaybackManager) setNextTrackAfterQueueUpdate() {
switch p.loopMode {
case LoopNone:
if p.nowPlayingIdx < len(p.playQueue)-1 {
p.setNextTrack(p.nowPlayingIdx + 1)
} else {
// need to erase next track
p.setNextTrack(-1)
}
case LoopOne:
p.setNextTrack(p.nowPlayingIdx)
case LoopAll:
if p.nowPlayingIdx >= len(p.playQueue)-1 {
p.setNextTrack(0)
} else {
p.setNextTrack(p.nowPlayingIdx + 1)
}
}
}
func (p *PlaybackManager) setTrack(idx int, next bool) error {
if urlP, ok := p.player.(player.URLPlayer); ok {
url := ""
+21
View File
@@ -77,6 +77,7 @@ func NewNowPlayingPage(
DisablePlaybackMenu: true,
DisableRating: !canRate,
AuxiliaryMenuItems: []*fyne.MenuItem{
util.NewReorderTracksSubmenu(a.doSetNewTrackOrder),
fyne.NewMenuItem("Remove from queue", a.onRemoveSelectedFromQueue),
},
}
@@ -208,6 +209,26 @@ func (a *NowPlayingPage) onRemoveSelectedFromQueue() {
a.Reload()
}
func (a *NowPlayingPage) doSetNewTrackOrder(op sharedutil.TrackReorderOp) {
// Since the tracklist view may be sorted in a different order than the
// actual running order, we need to get the IDs of the selected tracks
// from the tracklist and convert them to indices in the *original* run order
ids := a.tracklist.SelectedTrackIDs()
idxs := make([]int, 0, len(ids))
for i, tr := range a.queue {
if sharedutil.SliceContains(ids, tr.ID) {
idxs = append(idxs, i)
}
}
newTracks := sharedutil.ReorderTracks(a.queue, idxs, op)
a.pm.UpdatePlayQueue(newTracks)
// force-switch back to unsorted view to show new track order
a.tracklist.SetSorting(widgets.TracklistSort{})
a.tracklist.SetTracks(newTracks)
a.tracklist.UnselectAll()
}
// does not make calls to server - can safely be run in UI callbacks
func (a *NowPlayingPage) load(highlightedTrackID string) {
a.queue = a.pm.GetPlayQueue()
+4 -25
View File
@@ -86,18 +86,13 @@ func newPlaylistPage(
a.tracklist.OnVisibleColumnsChanged = func(cols []string) {
conf.TracklistColumns = cols
}
reorderMenu := fyne.NewMenuItem("Reorder tracks", nil)
reorderMenu.ChildMenu = fyne.NewMenu("", []*fyne.MenuItem{
fyne.NewMenuItem("Move to top", a.onMoveSelectedToTop),
fyne.NewMenuItem("Move up", a.onMoveSelectedUp),
fyne.NewMenuItem("Move down", a.onMoveSelectedDown),
fyne.NewMenuItem("Move to bottom", a.onMoveSelectedToBottom),
}...)
_, canRate := a.sm.Server.(mediaprovider.SupportsRating)
a.tracklist.Options = widgets.TracklistOptions{
DisableRating: !canRate,
AuxiliaryMenuItems: []*fyne.MenuItem{reorderMenu,
fyne.NewMenuItem("Remove from playlist", a.onRemoveSelectedFromPlaylist)},
AuxiliaryMenuItems: []*fyne.MenuItem{
util.NewReorderTracksSubmenu(a.doSetNewTrackOrder),
fyne.NewMenuItem("Remove from playlist", a.onRemoveSelectedFromPlaylist),
},
}
// connect tracklist actions
a.contr.ConnectTracklistActions(a.tracklist)
@@ -171,22 +166,6 @@ func renumberTracks(tracks []*mediaprovider.Track) {
}
}
func (a *PlaylistPage) onMoveSelectedToTop() {
a.doSetNewTrackOrder(sharedutil.MoveToTop)
}
func (a *PlaylistPage) onMoveSelectedUp() {
a.doSetNewTrackOrder(sharedutil.MoveUp)
}
func (a *PlaylistPage) onMoveSelectedDown() {
a.doSetNewTrackOrder(sharedutil.MoveDown)
}
func (a *PlaylistPage) onMoveSelectedToBottom() {
a.doSetNewTrackOrder(sharedutil.MoveToBottom)
}
func (a *PlaylistPage) doSetNewTrackOrder(op sharedutil.TrackReorderOp) {
// Since the tracklist view may be sorted in a different order than the
// actual running order, we need to get the IDs of the selected tracks
+12
View File
@@ -15,6 +15,7 @@ import (
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/dweymouth/supersonic/backend/mediaprovider"
"github.com/dweymouth/supersonic/sharedutil"
"github.com/dweymouth/supersonic/ui/layouts"
myTheme "github.com/dweymouth/supersonic/ui/theme"
"golang.org/x/net/html"
@@ -180,6 +181,17 @@ func NewRatingSubmenu(onSetRating func(int)) *fyne.MenuItem {
return ratingMenu
}
func NewReorderTracksSubmenu(onReorderTracks func(sharedutil.TrackReorderOp)) *fyne.MenuItem {
reorderMenu := fyne.NewMenuItem("Reorder tracks", nil)
reorderMenu.ChildMenu = fyne.NewMenu("", []*fyne.MenuItem{
fyne.NewMenuItem("Move to top", func() { onReorderTracks(sharedutil.MoveToTop) }),
fyne.NewMenuItem("Move up", func() { onReorderTracks(sharedutil.MoveUp) }),
fyne.NewMenuItem("Move down", func() { onReorderTracks(sharedutil.MoveDown) }),
fyne.NewMenuItem("Move to bottom", func() { onReorderTracks(sharedutil.MoveToBottom) }),
}...)
return reorderMenu
}
func AddHeaderBackground(obj fyne.CanvasObject) *fyne.Container {
bgrnd := myTheme.NewThemedRectangle(myTheme.ColorNamePageHeader)
bgrnd.CornerRadiusName = theme.SizeNameInputRadius