refactor: Extract tracklist context menu as own component
This commit is contained in:
@@ -0,0 +1,137 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/theme"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TrackContextMenu struct {
|
||||||
|
ratingSubmenu *fyne.MenuItem
|
||||||
|
shareMenuItem *fyne.MenuItem
|
||||||
|
songRadioMenuItem *fyne.MenuItem
|
||||||
|
infoMenuItem *fyne.MenuItem
|
||||||
|
|
||||||
|
OnPlay func(shuffle bool)
|
||||||
|
OnAddToQueue func(next bool)
|
||||||
|
OnPlaySongRadio func()
|
||||||
|
OnDownload func()
|
||||||
|
OnAddToPlaylist func()
|
||||||
|
OnShowInfo func()
|
||||||
|
OnShare func()
|
||||||
|
OnFavorite func(fav bool)
|
||||||
|
OnSetRating func(rating int)
|
||||||
|
|
||||||
|
menu *fyne.Menu
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTrackContextMenu(disablePlaybackMenu bool, auxItems []*fyne.MenuItem) *TrackContextMenu {
|
||||||
|
tcm := &TrackContextMenu{}
|
||||||
|
|
||||||
|
tcm.menu = fyne.NewMenu("")
|
||||||
|
if !disablePlaybackMenu {
|
||||||
|
play := fyne.NewMenuItem(lang.L("Play"), func() {
|
||||||
|
if tcm.OnPlay != nil {
|
||||||
|
tcm.OnPlay(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
play.Icon = theme.MediaPlayIcon()
|
||||||
|
shuffle := fyne.NewMenuItem(lang.L("Shuffle"), func() {
|
||||||
|
if tcm.OnPlay != nil {
|
||||||
|
tcm.OnPlay(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
shuffle.Icon = myTheme.ShuffleIcon
|
||||||
|
playNext := fyne.NewMenuItem(lang.L("Play next"), func() {
|
||||||
|
if tcm.OnAddToQueue != nil {
|
||||||
|
tcm.OnAddToQueue(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
playNext.Icon = myTheme.PlayNextIcon
|
||||||
|
add := fyne.NewMenuItem(lang.L("Add to queue"), func() {
|
||||||
|
if tcm.OnAddToQueue != nil {
|
||||||
|
tcm.OnAddToQueue(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
add.Icon = theme.ContentAddIcon()
|
||||||
|
tcm.songRadioMenuItem = fyne.NewMenuItem(lang.L("Play song radio"), func() {
|
||||||
|
if tcm.OnPlaySongRadio != nil {
|
||||||
|
tcm.OnPlaySongRadio()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tcm.songRadioMenuItem.Icon = myTheme.RadioIcon
|
||||||
|
tcm.menu.Items = append(tcm.menu.Items,
|
||||||
|
play, shuffle, playNext, add, tcm.songRadioMenuItem)
|
||||||
|
}
|
||||||
|
playlist := fyne.NewMenuItem(lang.L("Add to playlist")+"...", func() {
|
||||||
|
if tcm.OnAddToPlaylist != nil {
|
||||||
|
tcm.OnAddToPlaylist()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
playlist.Icon = myTheme.PlaylistIcon
|
||||||
|
download := fyne.NewMenuItem(lang.L("Download")+"...", func() {
|
||||||
|
if tcm.OnDownload != nil {
|
||||||
|
tcm.OnDownload()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
download.Icon = theme.DownloadIcon()
|
||||||
|
tcm.infoMenuItem = fyne.NewMenuItem(lang.L("Show info")+"...", func() {
|
||||||
|
if tcm.OnShowInfo != nil {
|
||||||
|
tcm.OnShowInfo()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tcm.infoMenuItem.Icon = theme.InfoIcon()
|
||||||
|
favorite := fyne.NewMenuItem(lang.L("Set favorite"), func() {
|
||||||
|
if tcm.OnFavorite != nil {
|
||||||
|
tcm.OnFavorite(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
favorite.Icon = myTheme.FavoriteIcon
|
||||||
|
unfavorite := fyne.NewMenuItem(lang.L("Unset favorite"), func() {
|
||||||
|
if tcm.OnFavorite != nil {
|
||||||
|
tcm.OnFavorite(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
unfavorite.Icon = myTheme.NotFavoriteIcon
|
||||||
|
tcm.menu.Items = append(tcm.menu.Items, fyne.NewMenuItemSeparator(),
|
||||||
|
playlist, download, tcm.infoMenuItem)
|
||||||
|
tcm.shareMenuItem = fyne.NewMenuItem(lang.L("Share")+"...", func() {
|
||||||
|
if tcm.OnShare != nil {
|
||||||
|
tcm.OnShare()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tcm.shareMenuItem.Icon = myTheme.ShareIcon
|
||||||
|
tcm.menu.Items = append(tcm.menu.Items, tcm.shareMenuItem)
|
||||||
|
tcm.menu.Items = append(tcm.menu.Items, fyne.NewMenuItemSeparator())
|
||||||
|
tcm.menu.Items = append(tcm.menu.Items, favorite, unfavorite)
|
||||||
|
tcm.ratingSubmenu = NewRatingSubmenu(func(rating int) {
|
||||||
|
if tcm.OnSetRating != nil {
|
||||||
|
tcm.OnSetRating(rating)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tcm.menu.Items = append(tcm.menu.Items, tcm.ratingSubmenu)
|
||||||
|
if len(auxItems) > 0 {
|
||||||
|
tcm.menu.Items = append(tcm.menu.Items, fyne.NewMenuItemSeparator())
|
||||||
|
tcm.menu.Items = append(tcm.menu.Items, auxItems...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tcm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tcm *TrackContextMenu) SetRatingDisabled(disabled bool) {
|
||||||
|
tcm.ratingSubmenu.Disabled = disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tcm *TrackContextMenu) SetShareDisabled(disabled bool) {
|
||||||
|
tcm.shareMenuItem.Disabled = disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tcm *TrackContextMenu) SetInfoDisabled(disabled bool) {
|
||||||
|
tcm.infoMenuItem.Disabled = disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tcm *TrackContextMenu) ShowAtPosition(pos fyne.Position, canvas fyne.Canvas) {
|
||||||
|
widget.ShowPopUpMenuAtPosition(tcm.menu, canvas, pos)
|
||||||
|
}
|
||||||
@@ -52,12 +52,13 @@ func SelectedIndexes(items []*TrackListModel) []int {
|
|||||||
return selected
|
return selected
|
||||||
}
|
}
|
||||||
|
|
||||||
func SelectItem(items []*TrackListModel, idx int) {
|
func SelectItem(items []*TrackListModel, idx int) bool {
|
||||||
if items[idx].Selected {
|
if items[idx].Selected {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
UnselectAllItems(items)
|
UnselectAllItems(items)
|
||||||
items[idx].Selected = true
|
items[idx].Selected = true
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func SelectAllItems(items []*TrackListModel) {
|
func SelectAllItems(items []*TrackListModel) {
|
||||||
|
|||||||
+43
-91
@@ -6,13 +6,10 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"fyne.io/fyne/v2/lang"
|
|
||||||
|
|
||||||
"github.com/dweymouth/supersonic/backend"
|
"github.com/dweymouth/supersonic/backend"
|
||||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||||
"github.com/dweymouth/supersonic/sharedutil"
|
"github.com/dweymouth/supersonic/sharedutil"
|
||||||
"github.com/dweymouth/supersonic/ui/layouts"
|
"github.com/dweymouth/supersonic/ui/layouts"
|
||||||
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
|
||||||
"github.com/dweymouth/supersonic/ui/util"
|
"github.com/dweymouth/supersonic/ui/util"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
@@ -93,17 +90,13 @@ type Tracklist struct {
|
|||||||
tracks []*util.TrackListModel
|
tracks []*util.TrackListModel
|
||||||
tracksOrigOrder []*util.TrackListModel
|
tracksOrigOrder []*util.TrackListModel
|
||||||
|
|
||||||
nowPlayingID string
|
nowPlayingID string
|
||||||
colLayout *layouts.ColumnsLayout
|
colLayout *layouts.ColumnsLayout
|
||||||
hdr *ListHeader
|
hdr *ListHeader
|
||||||
list *FocusList
|
list *FocusList
|
||||||
ctxMenu *fyne.Menu
|
ctxMenu *util.TrackContextMenu
|
||||||
ratingSubmenu *fyne.MenuItem
|
loadingDots *LoadingDots
|
||||||
shareMenuItem *fyne.MenuItem
|
container *fyne.Container
|
||||||
songRadioMenuItem *fyne.MenuItem
|
|
||||||
infoMenuItem *fyne.MenuItem
|
|
||||||
loadingDots *LoadingDots
|
|
||||||
container *fyne.Container
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTracklist(tracks []*mediaprovider.Track, im *backend.ImageManager, useCompactRows bool) *Tracklist {
|
func NewTracklist(tracks []*mediaprovider.Track, im *backend.ImageManager, useCompactRows bool) *Tracklist {
|
||||||
@@ -491,8 +484,8 @@ func (t *Tracklist) selectAddOrRemove(idx int) {
|
|||||||
t.tracks[idx].Selected = !t.tracks[idx].Selected
|
t.tracks[idx].Selected = !t.tracks[idx].Selected
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracklist) selectTrack(idx int) {
|
func (t *Tracklist) selectTrack(idx int) bool {
|
||||||
util.SelectItem(t.tracks, idx)
|
return util.SelectItem(t.tracks, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracklist) selectRange(idx int) {
|
func (t *Tracklist) selectRange(idx int) {
|
||||||
@@ -500,88 +493,47 @@ func (t *Tracklist) selectRange(idx int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
|
func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
|
||||||
t.selectTrack(trackIdx)
|
if t.selectTrack(trackIdx) {
|
||||||
t.list.Refresh()
|
t.list.Refresh()
|
||||||
|
}
|
||||||
if t.ctxMenu == nil {
|
if t.ctxMenu == nil {
|
||||||
t.ctxMenu = fyne.NewMenu("")
|
t.ctxMenu = util.NewTrackContextMenu(t.Options.DisablePlaybackMenu, t.Options.AuxiliaryMenuItems)
|
||||||
if !t.Options.DisablePlaybackMenu {
|
t.ctxMenu.OnPlay = func(shuffle bool) {
|
||||||
play := fyne.NewMenuItem(lang.L("Play"), func() {
|
t.OnPlaySelection(t.selectedTracks(), shuffle)
|
||||||
if t.OnPlaySelection != nil {
|
|
||||||
t.OnPlaySelection(t.selectedTracks(), false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
play.Icon = theme.MediaPlayIcon()
|
|
||||||
shuffle := fyne.NewMenuItem(lang.L("Shuffle"), func() {
|
|
||||||
if t.OnPlaySelection != nil {
|
|
||||||
t.OnPlaySelection(t.selectedTracks(), true)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
shuffle.Icon = myTheme.ShuffleIcon
|
|
||||||
playNext := fyne.NewMenuItem(lang.L("Play next"), func() {
|
|
||||||
if t.OnPlaySelection != nil {
|
|
||||||
t.OnPlaySelectionNext(t.selectedTracks())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
playNext.Icon = myTheme.PlayNextIcon
|
|
||||||
add := fyne.NewMenuItem(lang.L("Add to queue"), func() {
|
|
||||||
if t.OnPlaySelection != nil {
|
|
||||||
t.OnAddToQueue(t.selectedTracks())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
add.Icon = theme.ContentAddIcon()
|
|
||||||
t.songRadioMenuItem = fyne.NewMenuItem(lang.L("Play song radio"), func() {
|
|
||||||
t.onPlaySongRadio(t.selectedTracks())
|
|
||||||
})
|
|
||||||
t.songRadioMenuItem.Icon = myTheme.RadioIcon
|
|
||||||
t.ctxMenu.Items = append(t.ctxMenu.Items,
|
|
||||||
play, shuffle, playNext, add, t.songRadioMenuItem)
|
|
||||||
}
|
}
|
||||||
playlist := fyne.NewMenuItem(lang.L("Add to playlist")+"...", func() {
|
t.ctxMenu.OnAddToQueue = func(next bool) {
|
||||||
if t.OnAddToPlaylist != nil {
|
if next {
|
||||||
t.OnAddToPlaylist(t.SelectedTrackIDs())
|
t.OnPlaySelectionNext(t.selectedTracks())
|
||||||
|
} else {
|
||||||
|
t.OnAddToQueue(t.selectedTracks())
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
playlist.Icon = myTheme.PlaylistIcon
|
t.ctxMenu.OnPlaySongRadio = func() {
|
||||||
download := fyne.NewMenuItem(lang.L("Download")+"...", func() {
|
t.onPlaySongRadio(t.selectedTracks())
|
||||||
|
}
|
||||||
|
t.ctxMenu.OnAddToPlaylist = func() {
|
||||||
|
t.OnAddToPlaylist(t.SelectedTrackIDs())
|
||||||
|
}
|
||||||
|
t.ctxMenu.OnDownload = func() {
|
||||||
t.onDownload(t.selectedTracks(), "Selected tracks")
|
t.onDownload(t.selectedTracks(), "Selected tracks")
|
||||||
})
|
}
|
||||||
download.Icon = theme.DownloadIcon()
|
t.ctxMenu.OnShowInfo = func() {
|
||||||
t.infoMenuItem = fyne.NewMenuItem(lang.L("Show info")+"...", func() {
|
t.OnShowTrackInfo(t.selectedTracks()[0])
|
||||||
if t.OnShowTrackInfo != nil {
|
}
|
||||||
t.OnShowTrackInfo(t.selectedTracks()[0])
|
t.ctxMenu.OnFavorite = func(fav bool) {
|
||||||
}
|
t.onSetFavorites(t.selectedTracks(), fav, true /*needRefresh*/)
|
||||||
})
|
}
|
||||||
t.infoMenuItem.Icon = theme.InfoIcon()
|
t.ctxMenu.OnShare = func() {
|
||||||
favorite := fyne.NewMenuItem(lang.L("Set favorite"), func() {
|
|
||||||
t.onSetFavorites(t.selectedTracks(), true, true)
|
|
||||||
})
|
|
||||||
favorite.Icon = myTheme.FavoriteIcon
|
|
||||||
unfavorite := fyne.NewMenuItem(lang.L("Unset favorite"), func() {
|
|
||||||
t.onSetFavorites(t.selectedTracks(), false, true)
|
|
||||||
})
|
|
||||||
unfavorite.Icon = myTheme.NotFavoriteIcon
|
|
||||||
t.ctxMenu.Items = append(t.ctxMenu.Items, fyne.NewMenuItemSeparator(),
|
|
||||||
playlist, download, t.infoMenuItem)
|
|
||||||
t.shareMenuItem = fyne.NewMenuItem(lang.L("Share")+"...", func() {
|
|
||||||
t.onShare(t.selectedTracks())
|
t.onShare(t.selectedTracks())
|
||||||
})
|
}
|
||||||
t.shareMenuItem.Icon = myTheme.ShareIcon
|
t.ctxMenu.OnSetRating = func(rating int) {
|
||||||
t.ctxMenu.Items = append(t.ctxMenu.Items, t.shareMenuItem)
|
t.onSetRatings(t.selectedTracks(), rating, true /*needRefresh*/)
|
||||||
t.ctxMenu.Items = append(t.ctxMenu.Items, fyne.NewMenuItemSeparator())
|
|
||||||
t.ctxMenu.Items = append(t.ctxMenu.Items, favorite, unfavorite)
|
|
||||||
t.ratingSubmenu = util.NewRatingSubmenu(func(rating int) {
|
|
||||||
t.onSetRatings(t.selectedTracks(), rating, true)
|
|
||||||
})
|
|
||||||
t.ctxMenu.Items = append(t.ctxMenu.Items, t.ratingSubmenu)
|
|
||||||
if len(t.Options.AuxiliaryMenuItems) > 0 {
|
|
||||||
t.ctxMenu.Items = append(t.ctxMenu.Items, fyne.NewMenuItemSeparator())
|
|
||||||
t.ctxMenu.Items = append(t.ctxMenu.Items, t.Options.AuxiliaryMenuItems...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.ratingSubmenu.Disabled = t.Options.DisableRating
|
t.ctxMenu.SetRatingDisabled(t.Options.DisableRating)
|
||||||
t.shareMenuItem.Disabled = t.Options.DisableSharing || len(t.selectedTracks()) != 1
|
t.ctxMenu.SetShareDisabled(t.Options.DisableSharing || len(t.selectedTracks()) != 1)
|
||||||
t.infoMenuItem.Disabled = len(t.selectedTracks()) != 1
|
t.ctxMenu.SetInfoDisabled(len(t.selectedTracks()) != 1)
|
||||||
widget.ShowPopUpMenuAtPosition(t.ctxMenu, fyne.CurrentApp().Driver().CanvasForObject(t), e.AbsolutePosition)
|
t.ctxMenu.ShowAtPosition(e.AbsolutePosition, fyne.CurrentApp().Driver().CanvasForObject(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracklist) onSetFavorite(trackID string, fav bool) {
|
func (t *Tracklist) onSetFavorite(trackID string, fav bool) {
|
||||||
|
|||||||
Reference in New Issue
Block a user