Fix #397: use different context menu for Play Queue and Related lists
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user