enable drag and drop reordering

This commit is contained in:
Drew Weymouth
2024-06-22 17:10:26 -07:00
parent f5a4146e2b
commit 4545839e92
9 changed files with 79 additions and 160 deletions
+3 -2
View File
@@ -129,6 +129,7 @@ func NewNowPlayingPage(
a.queueList = widgets.NewPlayQueueList(a.im, false)
a.relatedList = widgets.NewPlayQueueList(a.im, true)
a.queueList.Reorderable = true
a.queueList.OnReorderItems = a.doSetNewTrackOrder
a.queueList.OnDownload = contr.ShowDownloadDialog
a.queueList.OnShare = func(tracks []*mediaprovider.Track) {
@@ -502,7 +503,7 @@ func (a *NowPlayingPage) Refresh() {
a.BaseWidget.Refresh()
}
func (a *NowPlayingPage) doSetNewTrackOrder(trackIDs []string, op sharedutil.TrackReorderOp) {
func (a *NowPlayingPage) doSetNewTrackOrder(trackIDs []string, insertPos int) {
trackIDSet := sharedutil.ToSet(trackIDs)
idxs := make([]int, 0, len(trackIDs))
for i, tr := range a.queue {
@@ -510,7 +511,7 @@ func (a *NowPlayingPage) doSetNewTrackOrder(trackIDs []string, op sharedutil.Tra
idxs = append(idxs, i)
}
}
newTracks := sharedutil.ReorderItems(a.queue, idxs, op)
newTracks := sharedutil.ReorderItems(a.queue, idxs, insertPos)
a.pm.UpdatePlayQueue(newTracks)
}
+10 -10
View File
@@ -86,17 +86,16 @@ func newPlaylistPage(
a.tracklist.OnVisibleColumnsChanged = func(cols []string) {
conf.TracklistColumns = cols
}
a.tracklist.OnReorderTracks = a.doSetNewTrackOrder
_, canRate := a.sm.Server.(mediaprovider.SupportsRating)
_, canShare := a.sm.Server.(mediaprovider.SupportsSharing)
remove := fyne.NewMenuItem("Remove from playlist", a.onRemoveSelectedFromPlaylist)
remove.Icon = theme.ContentClearIcon()
a.tracklist.Options = widgets.TracklistOptions{
DisableRating: !canRate,
DisableSharing: !canShare,
AuxiliaryMenuItems: []*fyne.MenuItem{
util.NewReorderTracksSubmenu(a.doSetNewTrackOrder),
remove,
},
Reorderable: true,
DisableRating: !canRate,
DisableSharing: !canShare,
AuxiliaryMenuItems: []*fyne.MenuItem{remove},
}
// connect tracklist actions
a.contr.ConnectTracklistActions(a.tracklist)
@@ -118,6 +117,7 @@ func (a *PlaylistPage) Save() SavedPage {
p.trackSort = a.tracklist.Sorting()
p.widgetPool.Release(util.WidgetTypePlaylistPageHeader, a.header)
a.tracklist.Clear()
a.tracklist.OnReorderTracks = nil
p.widgetPool.Release(util.WidgetTypeTracklist, a.tracklist)
return &p
}
@@ -178,19 +178,19 @@ func renumberTracks(tracks []*mediaprovider.Track) {
}
}
func (a *PlaylistPage) doSetNewTrackOrder(op sharedutil.TrackReorderOp) {
func (a *PlaylistPage) doSetNewTrackOrder(ids []string, newPos int) {
// 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
idSet := sharedutil.ToSet(a.tracklist.SelectedTrackIDs())
idSet := sharedutil.ToSet(ids)
idxs := make([]int, 0, len(idSet))
for i, tr := range a.tracks {
if _, ok := idSet[tr.ID]; ok {
idxs = append(idxs, i)
}
}
newTracks := sharedutil.ReorderItems(a.tracks, idxs, op)
ids := sharedutil.TracksToIDs(newTracks)
newTracks := sharedutil.ReorderItems(a.tracks, idxs, newPos)
ids = sharedutil.TracksToIDs(newTracks)
if err := a.sm.Server.ReplacePlaylistTracks(a.playlistID, ids); err != nil {
log.Printf("error updating playlist: %s", err.Error())
} else {
-13
View File
@@ -17,7 +17,6 @@ import (
"fyne.io/fyne/v2/widget"
"github.com/dweymouth/supersonic/backend/mediaprovider"
"github.com/dweymouth/supersonic/res"
"github.com/dweymouth/supersonic/sharedutil"
myTheme "github.com/dweymouth/supersonic/ui/theme"
"golang.org/x/net/html"
)
@@ -227,18 +226,6 @@ func NewRatingSubmenu(onSetRating func(int)) *fyne.MenuItem {
return ratingMenu
}
func NewReorderTracksSubmenu(onReorderTracks func(sharedutil.TrackReorderOp)) *fyne.MenuItem {
reorderMenu := fyne.NewMenuItem("Reorder tracks", nil)
reorderMenu.Icon = myTheme.SortIcon
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 {
return AddHeaderBackgroundWithColorName(obj, myTheme.ColorNamePageHeader)
}
+21 -15
View File
@@ -31,6 +31,7 @@ type PlayQueueListModel struct {
type PlayQueueList struct {
widget.BaseWidget
Reorderable bool
DisableRating bool
DisableSharing bool
@@ -46,7 +47,7 @@ type PlayQueueList struct {
OnDownload func(tracks []*mediaprovider.Track, downloadName string)
OnShare func(tracks []*mediaprovider.Track)
OnShowArtistPage func(artistID string)
OnReorderItems func(itemIDs []string, op sharedutil.TrackReorderOp)
OnReorderItems func(itemIDs []string, reorderTo int)
useNonQueueMenu bool
menu *widget.PopUpMenu // ctx menu for when only tracks are selected
@@ -102,6 +103,17 @@ func NewPlayQueueList(im *backend.ImageManager, useNonQueueMenu bool) *PlayQueue
tr.Update(model, itemID+1)
},
)
p.list.OnDragBegin = func(id int) {
if !p.items[id].Selected {
p.selectTrack(id)
p.list.Refresh()
}
}
p.list.OnDragEnd = func(dragged, insertPos int) {
if p.OnReorderItems != nil {
p.OnReorderItems(p.selectedItemIDs(), insertPos)
}
}
return p
}
@@ -149,7 +161,12 @@ func (p *PlayQueueList) UnselectAll() {
p.tracksMutex.RLock()
util.UnselectAllItems(p.items)
p.tracksMutex.RUnlock()
p.Refresh()
p.list.Refresh()
}
func (p *PlayQueueList) Refresh() {
p.list.EnableDragging = p.Reorderable
p.BaseWidget.Refresh()
}
func (p *PlayQueueList) lenTracks() int {
@@ -292,15 +309,9 @@ func (p *PlayQueueList) ensureTracksMenu() {
}
})
remove.Icon = theme.ContentRemoveIcon()
reorder := util.NewReorderTracksSubmenu(func(tro sharedutil.TrackReorderOp) {
if p.OnReorderItems != nil {
p.OnReorderItems(p.selectedItemIDs(), tro)
}
})
menuItems = append(menuItems,
fyne.NewMenuItemSeparator(),
remove,
reorder)
remove)
}
p.menu = widget.NewPopUpMenu(
@@ -319,13 +330,8 @@ func (p *PlayQueueList) ensureRadiosMenu() {
}
})
remove.Icon = theme.ContentRemoveIcon()
reorder := util.NewReorderTracksSubmenu(func(tro sharedutil.TrackReorderOp) {
if p.OnReorderItems != nil {
p.OnReorderItems(p.selectedItemIDs(), tro)
}
})
p.radiosMenu = widget.NewPopUpMenu(
fyne.NewMenu("", remove, reorder),
fyne.NewMenu("", remove),
fyne.CurrentApp().Driver().CanvasForObject(p),
)
}
+16
View File
@@ -33,6 +33,9 @@ type TracklistOptions struct {
// or to use the number from the track's metadata
AutoNumber bool
// Reorderable sets whether the tracklist supports drag-and-drop reordering.
Reorderable bool
// ShowDiscNumber sets whether to display the disc number as part of the '#' column,
// (with format %d.%02d). Only applies if AutoNumber==false.
ShowDiscNumber bool
@@ -74,6 +77,7 @@ type Tracklist struct {
OnDownload func(tracks []*mediaprovider.Track, downloadName string)
OnShare func(trackID string)
OnPlaySongRadio func(track *mediaprovider.Track)
OnReorderTracks func(trackIDs []string, insertPos int)
OnShowArtistPage func(artistID string)
OnShowAlbumPage func(albumID string)
@@ -182,6 +186,17 @@ func NewTracklist(tracks []*mediaprovider.Track, im *backend.ImageManager, useCo
t.OnTrackShown(itemID)
}
})
t.list.OnDragBegin = func(id int) {
if !t.tracks[id].Selected {
t.selectTrack(id)
t.list.Refresh()
}
}
t.list.OnDragEnd = func(dragged, insertPos int) {
if t.OnReorderTracks != nil {
t.OnReorderTracks(t.SelectedTrackIDs(), insertPos)
}
}
t.container = container.NewBorder(t.hdr, nil, nil, nil, t.list)
return t
}
@@ -371,6 +386,7 @@ func (t *Tracklist) CreateRenderer() fyne.WidgetRenderer {
}
func (t *Tracklist) Refresh() {
t.list.EnableDragging = t.Options.Reorderable
t.hdr.DisableSorting = t.Options.DisableSorting
t.BaseWidget.Refresh()
}