Fix #397: use different context menu for Play Queue and Related lists

This commit is contained in:
Drew Weymouth
2024-06-08 11:25:45 -07:00
parent 6ae4269114
commit e3dc2e3079
4 changed files with 139 additions and 55 deletions
+15 -4
View File
@@ -210,26 +210,37 @@ func (p *playbackEngine) Continue() error {
return p.player.Continue() return p.player.Continue()
} }
// Load items into the play queue.
// If replacing the current queue (!appendToQueue), playback will be stopped.
func (p *playbackEngine) LoadItems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, shuffle bool) error {
newItems := p.deepCopyMediaItemSlice(items)
return p.doLoaditems(newItems, insertQueueMode, shuffle)
}
// Load tracks into the play queue. // Load tracks into the play queue.
// If replacing the current queue (!appendToQueue), playback will be stopped. // If replacing the current queue (!appendToQueue), playback will be stopped.
func (p *playbackEngine) LoadTracks(tracks []*mediaprovider.Track, insertQueueMode InsertQueueMode, shuffle bool) error { func (p *playbackEngine) LoadTracks(tracks []*mediaprovider.Track, insertQueueMode InsertQueueMode, shuffle bool) error {
newTracks := p.copyTrackSliceToMediaItemSlice(tracks)
return p.doLoaditems(newTracks, insertQueueMode, shuffle)
}
func (p *playbackEngine) doLoaditems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, shuffle bool) error {
if insertQueueMode == Replace { if insertQueueMode == Replace {
p.player.Stop() p.player.Stop()
p.nowPlayingIdx = -1 p.nowPlayingIdx = -1
p.playQueue = nil p.playQueue = nil
} }
needToSetNext := len(tracks) > 0 && (insertQueueMode == InsertNext || (insertQueueMode == Append && p.nowPlayingIdx == len(p.playQueue)-1)) needToSetNext := len(items) > 0 && (insertQueueMode == InsertNext || (insertQueueMode == Append && p.nowPlayingIdx == len(p.playQueue)-1))
newTracks := p.copyTrackSliceToMediaItemSlice(tracks)
if shuffle { if shuffle {
rand.Shuffle(len(newTracks), func(i, j int) { newTracks[i], newTracks[j] = newTracks[j], newTracks[i] }) rand.Shuffle(len(items), func(i, j int) { items[i], items[j] = items[j], items[i] })
} }
insertIdx := len(p.playQueue) insertIdx := len(p.playQueue)
if insertQueueMode == InsertNext { if insertQueueMode == InsertNext {
insertIdx = p.nowPlayingIdx + 1 insertIdx = p.nowPlayingIdx + 1
} }
p.playQueue = append(p.playQueue[:insertIdx], append(newTracks, p.playQueue[insertIdx:]...)...) p.playQueue = append(p.playQueue[:insertIdx], append(items, p.playQueue[insertIdx:]...)...)
if needToSetNext { if needToSetNext {
p.setNextTrack(p.nowPlayingIdx + 1) p.setNextTrack(p.nowPlayingIdx + 1)
+6
View File
@@ -123,6 +123,12 @@ func (p *PlaybackManager) LoadTracks(tracks []*mediaprovider.Track, insertQueueM
return p.engine.LoadTracks(tracks, insertQueueMode, shuffle) return p.engine.LoadTracks(tracks, insertQueueMode, shuffle)
} }
// Load items into the play queue.
// If replacing the current queue (!appendToQueue), playback will be stopped.
func (p *PlaybackManager) LoadItems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, shuffle bool) error {
return p.engine.LoadItems(items, insertQueueMode, shuffle)
}
// Replaces the play queue with the given set of tracks. // Replaces the play queue with the given set of tracks.
// Does not stop playback if the currently playing track is in the new queue, // 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. // but updates the now playing index to point to the first instance of the track in the new queue.
+33 -9
View File
@@ -127,8 +127,8 @@ func NewNowPlayingPage(
a.contr.SetTrackRatings([]string{a.nowPlayingID}, rating) a.contr.SetTrackRatings([]string{a.nowPlayingID}, rating)
} }
a.queueList = widgets.NewPlayQueueList(a.im) a.queueList = widgets.NewPlayQueueList(a.im, false)
a.relatedList = widgets.NewPlayQueueList(a.im) a.relatedList = widgets.NewPlayQueueList(a.im, true)
a.queueList.OnReorderItems = a.doSetNewTrackOrder a.queueList.OnReorderItems = a.doSetNewTrackOrder
a.queueList.OnDownload = contr.ShowDownloadDialog a.queueList.OnDownload = contr.ShowDownloadDialog
a.queueList.OnShare = func(tracks []*mediaprovider.Track) { a.queueList.OnShare = func(tracks []*mediaprovider.Track) {
@@ -137,7 +137,7 @@ func NewNowPlayingPage(
} }
} }
a.queueList.OnAddToPlaylist = contr.DoAddTracksToPlaylistWorkflow a.queueList.OnAddToPlaylist = contr.DoAddTracksToPlaylistWorkflow
a.queueList.OnPlayTrackAt = func(tracknum int) { a.queueList.OnPlayItemAt = func(tracknum int) {
_ = a.pm.PlayTrackAt(tracknum) _ = a.pm.PlayTrackAt(tracknum)
} }
a.queueList.OnShowArtistPage = func(artistID string) { a.queueList.OnShowArtistPage = func(artistID string) {
@@ -163,14 +163,22 @@ func NewNowPlayingPage(
a.relatedList.OnShare = a.queueList.OnShare a.relatedList.OnShare = a.queueList.OnShare
a.relatedList.OnAddToPlaylist = a.queueList.OnAddToPlaylist a.relatedList.OnAddToPlaylist = a.queueList.OnAddToPlaylist
a.relatedList.OnShowArtistPage = a.queueList.OnShowArtistPage a.relatedList.OnShowArtistPage = a.queueList.OnShowArtistPage
a.relatedList.OnRemoveFromQueue = a.queueList.OnRemoveFromQueue
a.relatedList.OnSetRating = a.queueList.OnSetRating a.relatedList.OnSetRating = a.queueList.OnSetRating
a.relatedList.OnSetFavorite = a.queueList.OnSetFavorite a.relatedList.OnSetFavorite = a.queueList.OnSetFavorite
a.relatedList.OnPlayTrackAt = func(idx int) { a.relatedList.OnPlayItemAt = func(idx int) {
a.pm.LoadTracks(a.related, backend.Replace, false) a.pm.LoadTracks([]*mediaprovider.Track{a.related[idx]}, backend.Replace, false)
a.pm.PlayTrackAt(idx) a.pm.PlayTrackAt(idx)
} }
a.relatedList.OnAddToQueue = func(items []mediaprovider.MediaItem) {
a.pm.LoadItems(items, backend.Append, false)
}
a.relatedList.OnPlaySelection = func(items []mediaprovider.MediaItem, shuffle bool) {
a.pm.LoadItems(items, backend.Replace, shuffle)
a.pm.PlayFromBeginning()
}
a.relatedList.OnPlaySelectionNext = func(items []mediaprovider.MediaItem) {
a.pm.LoadItems(items, backend.InsertNext, false)
}
a.lyricsViewer = widgets.NewLyricsViewer() a.lyricsViewer = widgets.NewLyricsViewer()
a.statusLabel = widget.NewLabel("Stopped") a.statusLabel = widget.NewLabel("Stopped")
@@ -458,13 +466,29 @@ func (a *NowPlayingPage) OnPlayTimeUpdate(curTime, _ float64, seeked bool) {
var _ CanSelectAll = (*NowPlayingPage)(nil) var _ CanSelectAll = (*NowPlayingPage)(nil)
func (a *NowPlayingPage) SelectAll() { func (a *NowPlayingPage) SelectAll() {
a.queueList.SelectAll() if a.tabs == nil {
return
}
switch a.tabs.SelectedIndex() {
case 0: /*queue*/
a.queueList.SelectAll()
case 2: /*related*/
a.relatedList.SelectAll()
}
} }
var _ fyne.Tappable = (*NowPlayingPage)(nil) var _ fyne.Tappable = (*NowPlayingPage)(nil)
func (a *NowPlayingPage) Tapped(*fyne.PointEvent) { func (a *NowPlayingPage) Tapped(*fyne.PointEvent) {
a.queueList.UnselectAll() if a.tabs == nil {
return
}
switch a.tabs.SelectedIndex() {
case 0: /*queue*/
a.queueList.UnselectAll()
case 2: /*related*/
a.relatedList.UnselectAll()
}
} }
func (a *NowPlayingPage) Refresh() { func (a *NowPlayingPage) Refresh() {
+85 -42
View File
@@ -35,31 +35,35 @@ type PlayQueueList struct {
DisableSharing bool DisableSharing bool
// user action callbacks // user action callbacks
OnAddToPlaylist func(trackIDs []string) OnPlayItemAt func(idx int)
OnSetFavorite func(trackIDs []string, fav bool) OnPlaySelection func(items []mediaprovider.MediaItem, shuffle bool)
OnSetRating func(trackIDs []string, rating int) OnPlaySelectionNext func(items []mediaprovider.MediaItem)
OnRemoveFromQueue func(itemIDs []string) OnAddToQueue func(items []mediaprovider.MediaItem)
OnDownload func(tracks []*mediaprovider.Track, downloadName string) OnAddToPlaylist func(trackIDs []string)
OnShare func(tracks []*mediaprovider.Track) OnSetFavorite func(trackIDs []string, fav bool)
OnShowArtistPage func(artistID string) OnSetRating func(trackIDs []string, rating int)
OnPlayTrackAt func(idx int) OnRemoveFromQueue func(itemIDs []string)
OnReorderItems func(itemIDs []string, op sharedutil.TrackReorderOp) OnDownload func(tracks []*mediaprovider.Track, downloadName string)
OnShare func(tracks []*mediaprovider.Track)
OnShowArtistPage func(artistID string)
OnReorderItems func(itemIDs []string, op sharedutil.TrackReorderOp)
list *FocusList useNonQueueMenu bool
menu *widget.PopUpMenu // ctx menu for when only tracks are selected menu *widget.PopUpMenu // ctx menu for when only tracks are selected
radiosMenu *widget.PopUpMenu // ctx menu for when selection contains radios radiosMenu *widget.PopUpMenu // ctx menu for when selection contains radios
ratingSubmenu *fyne.MenuItem ratingSubmenu *fyne.MenuItem
shareMenuItem *fyne.MenuItem shareMenuItem *fyne.MenuItem
nowPlayingID string nowPlayingID string
colLayout *layouts.ColumnsLayout
list *FocusList
colLayout *layouts.ColumnsLayout
tracksMutex sync.RWMutex tracksMutex sync.RWMutex
items []*util.TrackListModel items []*util.TrackListModel
} }
func NewPlayQueueList(im *backend.ImageManager) *PlayQueueList { func NewPlayQueueList(im *backend.ImageManager, useNonQueueMenu bool) *PlayQueueList {
p := &PlayQueueList{} p := &PlayQueueList{useNonQueueMenu: useNonQueueMenu}
p.ExtendBaseWidget(p) p.ExtendBaseWidget(p)
// #, Cover, Title/Artist, Time // #, Cover, Title/Artist, Time
@@ -164,8 +168,8 @@ func (t *PlayQueueList) onArtistTapped(artistID string) {
} }
func (p *PlayQueueList) onPlayTrackAt(idx int) { func (p *PlayQueueList) onPlayTrackAt(idx int) {
if p.OnPlayTrackAt != nil { if p.OnPlayItemAt != nil {
p.OnPlayTrackAt(idx) p.OnPlayItemAt(idx)
} }
} }
@@ -233,6 +237,12 @@ func (p *PlayQueueList) ensureTracksMenu() {
if p.menu != nil { if p.menu != nil {
return return
} }
var menuItems []*fyne.MenuItem
if p.useNonQueueMenu {
menuItems = append(menuItems, p.createQueueActionMenuItems()...)
menuItems = append(menuItems, fyne.NewMenuItemSeparator())
}
playlist := fyne.NewMenuItem("Add to playlist...", func() { playlist := fyne.NewMenuItem("Add to playlist...", func() {
if p.OnAddToPlaylist != nil { if p.OnAddToPlaylist != nil {
p.OnAddToPlaylist(p.selectedItemIDs()) p.OnAddToPlaylist(p.selectedItemIDs())
@@ -268,31 +278,36 @@ func (p *PlayQueueList) ensureTracksMenu() {
p.OnSetRating(p.selectedItemIDs(), rating) p.OnSetRating(p.selectedItemIDs(), rating)
} }
}) })
remove := fyne.NewMenuItem("Remove from queue", func() { menuItems = append(menuItems,
if p.OnRemoveFromQueue != nil { playlist,
p.OnRemoveFromQueue(p.selectedItemIDs()) download,
} p.shareMenuItem,
}) fyne.NewMenuItemSeparator(),
remove.Icon = theme.ContentRemoveIcon() favorite,
reorder := util.NewReorderTracksSubmenu(func(tro sharedutil.TrackReorderOp) { unfavorite,
if p.OnReorderItems != nil { p.ratingSubmenu,
p.OnReorderItems(p.selectedItemIDs(), tro) )
}
}) if !p.useNonQueueMenu {
remove := fyne.NewMenuItem("Remove from queue", func() {
if p.OnRemoveFromQueue != nil {
p.OnRemoveFromQueue(p.selectedItemIDs())
}
})
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)
}
p.menu = widget.NewPopUpMenu( p.menu = widget.NewPopUpMenu(
fyne.NewMenu("", fyne.NewMenu("", menuItems...),
playlist,
download,
p.shareMenuItem,
fyne.NewMenuItemSeparator(),
favorite,
unfavorite,
p.ratingSubmenu,
fyne.NewMenuItemSeparator(),
reorder,
remove,
),
fyne.CurrentApp().Driver().CanvasForObject(p), fyne.CurrentApp().Driver().CanvasForObject(p),
) )
} }
@@ -318,6 +333,34 @@ func (p *PlayQueueList) ensureRadiosMenu() {
) )
} }
func (p *PlayQueueList) createQueueActionMenuItems() []*fyne.MenuItem {
play := fyne.NewMenuItem("Play", func() {
if p.OnPlaySelection != nil {
p.OnPlaySelection(p.selectedItems(), false)
}
})
play.Icon = theme.MediaPlayIcon()
shuffle := fyne.NewMenuItem("Shuffle", func() {
if p.OnPlaySelection != nil {
p.OnPlaySelection(p.selectedItems(), true)
}
})
shuffle.Icon = myTheme.ShuffleIcon
playNext := fyne.NewMenuItem("Play next", func() {
if p.OnPlaySelection != nil {
p.OnPlaySelectionNext(p.selectedItems())
}
})
playNext.Icon = myTheme.PlayNextIcon
add := fyne.NewMenuItem("Add to queue", func() {
if p.OnPlaySelection != nil {
p.OnAddToQueue(p.selectedItems())
}
})
add.Icon = theme.ContentAddIcon()
return []*fyne.MenuItem{play, shuffle, playNext, add}
}
func (t *PlayQueueList) selectedItems() []mediaprovider.MediaItem { func (t *PlayQueueList) selectedItems() []mediaprovider.MediaItem {
t.tracksMutex.RLock() t.tracksMutex.RLock()
defer t.tracksMutex.RUnlock() defer t.tracksMutex.RUnlock()