From 61f8dd00ff5289601c0345258cf20e7d8134aa85 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sat, 1 Jun 2024 17:11:23 -0700 Subject: [PATCH] add context menu to radio list for enqueuing next or later --- ui/browsing/radiospage.go | 86 +++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/ui/browsing/radiospage.go b/ui/browsing/radiospage.go index 3145677..cdcbf7b 100644 --- a/ui/browsing/radiospage.go +++ b/ui/browsing/radiospage.go @@ -10,6 +10,7 @@ import ( "github.com/dweymouth/supersonic/sharedutil" "github.com/dweymouth/supersonic/ui/controller" "github.com/dweymouth/supersonic/ui/layouts" + myTheme "github.com/dweymouth/supersonic/ui/theme" "github.com/dweymouth/supersonic/ui/widgets" "fyne.io/fyne/v2" @@ -52,10 +53,8 @@ func newRadiosPage(contr *controller.Controller, rp mediaprovider.RadioProvider, a.ExtendBaseWidget(a) a.titleDisp.Segments[0].(*widget.TextSegment).Style.SizeName = theme.SizeNameHeadingText a.list = NewRadioList(&a.nowPlayingID) - a.list.OnPlay = func(station *mediaprovider.RadioStation) { - pm.LoadRadioStation(station, backend.Replace) - pm.PlayFromBeginning() - } + a.list.OnPlay = a.onPlay + a.list.OnQueue = a.onQueue a.searcher = widgets.NewSearchEntry() a.searcher.PlaceHolder = "Search page" a.searcher.OnSearched = a.onSearched @@ -107,6 +106,19 @@ func (a *RadiosPage) load(searchOnLoad bool, scrollPos float32) { } } +func (a *RadiosPage) onPlay(station *mediaprovider.RadioStation) { + a.pm.LoadRadioStation(station, backend.Replace) + a.pm.PlayFromBeginning() +} + +func (a *RadiosPage) onQueue(station *mediaprovider.RadioStation, next bool) { + queueMode := backend.Append + if next { + queueMode = backend.InsertNext + } + a.pm.LoadRadioStation(station, queueMode) +} + func (a *RadiosPage) onSearched(query string) { // since the radios list is returned in full non-paginated, we will do our own // simple search based on the radio name, rather than calling a server API @@ -193,22 +205,26 @@ func (a *RadiosPage) CreateRenderer() fyne.WidgetRenderer { type RadioList struct { widget.BaseWidget - OnPlay func(*mediaprovider.RadioStation) + OnPlay func(*mediaprovider.RadioStation) + OnQueue func(r *mediaprovider.RadioStation, next bool) - radios []*mediaprovider.RadioStation + radios []*mediaprovider.RadioStation + selected *RadioListRow columnsLayout *layouts.ColumnsLayout hdr *widgets.ListHeader list *widgets.FocusList container *fyne.Container playingIcon fyne.CanvasObject + menu *widget.PopUpMenu } type RadioListRow struct { widgets.FocusListRowBase - Item *mediaprovider.RadioStation - IsPlaying bool + Item *mediaprovider.RadioStation + IsPlaying bool + OnTappedSecondary func(*fyne.PointEvent) nameLabel *widget.RichText homePageLink *widget.Hyperlink @@ -226,6 +242,12 @@ func NewRadioListRow(layout *layouts.ColumnsLayout) *RadioListRow { return a } +func (a *RadioListRow) TappedSecondary(e *fyne.PointEvent) { + if a.OnTappedSecondary != nil { + a.OnTappedSecondary(e) + } +} + func NewRadioList(nowPlayingIDPtr *string) *RadioList { a := &RadioList{ columnsLayout: layouts.NewColumnsLayout([]float32{-1, -1}), @@ -243,7 +265,21 @@ func NewRadioList(nowPlayingIDPtr *string) *RadioList { func() int { return len(a.radios) }, func() fyne.CanvasObject { r := NewRadioListRow(a.columnsLayout) + r.OnTapped = func() { + r.Selected = true + if a.selected != nil { + // unselect old row + a.selected.Selected = false + a.selected.Refresh() + } + a.selected = r + r.Refresh() + } r.OnDoubleTapped = func() { a.onPlayRadio(r.Item) } + r.OnTappedSecondary = func(e *fyne.PointEvent) { + r.OnTapped() // handle selection + a.showMenu(e.AbsolutePosition) + } r.OnFocusNeighbor = func(up bool) { a.list.FocusNeighbor(r.ItemID(), up) } @@ -286,6 +322,40 @@ func NewRadioList(nowPlayingIDPtr *string) *RadioList { return a } +func (a *RadioList) showMenu(pos fyne.Position) { + if a.menu == nil { + play := fyne.NewMenuItem("Play", func() { + if a.OnPlay != nil { + a.OnPlay(a.selected.Item) + } + }) + play.Icon = theme.MediaPlayIcon() + + playNext := fyne.NewMenuItem("Play next", func() { + if a.OnQueue != nil { + a.OnQueue(a.selected.Item, true) + } + }) + playNext.Icon = myTheme.PlayNextIcon + + append := fyne.NewMenuItem("Add to queue", func() { + if a.OnQueue != nil { + a.OnQueue(a.selected.Item, false) + } + }) + append.Icon = theme.ContentAddIcon() + + a.menu = widget.NewPopUpMenu(fyne.NewMenu("", + play, + playNext, + append, + ), + fyne.CurrentApp().Driver().CanvasForObject(a), + ) + } + a.menu.ShowAtPosition(pos) +} + func (g *RadioList) SetRadios(radios []*mediaprovider.RadioStation) { g.radios = radios g.Refresh()