diff --git a/ui/bottompanel.go b/ui/bottompanel.go index d3304fb..4bc2c51 100644 --- a/ui/bottompanel.go +++ b/ui/bottompanel.go @@ -56,6 +56,15 @@ func NewBottomPanel(p *player.Player, contr *controller.Controller) *BottomPanel contr.ShowPopUpImage(im) } } + bp.NowPlaying.OnSetFavorite = func(fav bool) { + contr.SetTrackFavorites([]string{bp.playbackManager.NowPlaying().ID}, fav) + } + bp.NowPlaying.OnSetRating = func(rating int) { + contr.SetTrackRatings([]string{bp.playbackManager.NowPlaying().ID}, rating) + } + bp.NowPlaying.OnAddToPlaylist = func() { + contr.DoAddTracksToPlaylistWorkflow([]string{bp.playbackManager.NowPlaying().ID}) + } bp.NowPlaying.OnAlbumNameTapped(func() { contr.NavigateTo(controller.AlbumRoute(bp.playbackManager.NowPlaying().AlbumID)) }) diff --git a/ui/controller/controller.go b/ui/controller/controller.go index 272bc0b..d3ad1ae 100644 --- a/ui/controller/controller.go +++ b/ui/controller/controller.go @@ -105,18 +105,8 @@ func (m *Controller) ConnectTracklistActions(tracklist *widgets.Tracklist) { m.App.PlaybackManager.LoadTracks(tracks, false, false) m.App.PlaybackManager.PlayFromBeginning() } - tracklist.OnSetFavorite = func(trackIDs []string, fav bool) { - s := m.App.ServerManager.Server - if fav { - go s.Star(subsonic.StarParameters{SongIDs: trackIDs}) - } else { - go s.Unstar(subsonic.StarParameters{SongIDs: trackIDs}) - } - for _, id := range trackIDs { - m.App.PlaybackManager.OnTrackFavoriteStatusChanged(id, fav) - } - } - tracklist.OnSetRating = m.setTrackRatings + tracklist.OnSetFavorite = m.SetTrackFavorites + tracklist.OnSetRating = m.SetTrackRatings tracklist.OnShowAlbumPage = func(albumID string) { m.NavigateTo(AlbumRoute(albumID)) } @@ -417,7 +407,19 @@ func (c *Controller) doModalClosed() { } } -func (c *Controller) setTrackRatings(trackIDs []string, rating int) { +func (c *Controller) SetTrackFavorites(trackIDs []string, favorite bool) { + s := c.App.ServerManager.Server + if favorite { + go s.Star(subsonic.StarParameters{SongIDs: trackIDs}) + } else { + go s.Unstar(subsonic.StarParameters{SongIDs: trackIDs}) + } + for _, id := range trackIDs { + c.App.PlaybackManager.OnTrackFavoriteStatusChanged(id, favorite) + } +} + +func (c *Controller) SetTrackRatings(trackIDs []string, rating int) { // Subsonic doesn't allow bulk setting ratings. // To not overwhelm the server with requests, set rating for // only 5 tracks at a time concurrently diff --git a/ui/util/util.go b/ui/util/util.go index 4178b91..10e3256 100644 --- a/ui/util/util.go +++ b/ui/util/util.go @@ -4,6 +4,7 @@ import ( "fmt" "image" "math" + "strconv" "strings" "fyne.io/fyne/v2" @@ -87,6 +88,28 @@ func RichTextSegsFromHTMLString(s string) []widget.RichTextSegment { return segs } +func NewRatingSubmenu(onSetRating func(int)) *fyne.MenuItem { + newRatingMenuItem := func(rating int) *fyne.MenuItem { + label := "(none)" + if rating > 0 { + label = strconv.Itoa(rating) + } + return fyne.NewMenuItem(label, func() { + onSetRating(rating) + }) + } + ratingMenu := fyne.NewMenuItem("Set rating", nil) + ratingMenu.ChildMenu = fyne.NewMenu("", []*fyne.MenuItem{ + newRatingMenuItem(0), + newRatingMenuItem(1), + newRatingMenuItem(2), + newRatingMenuItem(3), + newRatingMenuItem(4), + newRatingMenuItem(5), + }...) + return ratingMenu +} + type HSpace struct { widget.BaseWidget diff --git a/ui/widgets/nowplayingcard.go b/ui/widgets/nowplayingcard.go index d5b5270..7e057b0 100644 --- a/ui/widgets/nowplayingcard.go +++ b/ui/widgets/nowplayingcard.go @@ -4,6 +4,7 @@ import ( "image" "github.com/dweymouth/supersonic/ui/layouts" + "github.com/dweymouth/supersonic/ui/util" "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" @@ -20,8 +21,12 @@ type NowPlayingCard struct { artistName *CustomHyperlink albumName *CustomHyperlink cover *TappableImage + menu *widget.PopUpMenu OnShowCoverImage func() + OnSetRating func(rating int) + OnSetFavorite func(favorite bool) + OnAddToPlaylist func() c fyne.CanvasObject } @@ -34,6 +39,7 @@ func NewNowPlayingCard() *NowPlayingCard { } n.ExtendBaseWidget(n) n.cover = NewTappableImage(n.onShowCoverImage) + n.cover.OnTappedSecondary = n.showMenu n.trackName.Hidden = true n.artistName.Hidden = true n.albumName.Hidden = true @@ -55,6 +61,24 @@ func (n *NowPlayingCard) onShowCoverImage() { } } +func (n *NowPlayingCard) onSetFavorite(fav bool) { + if n.OnSetFavorite != nil { + n.OnSetFavorite(fav) + } +} + +func (n *NowPlayingCard) onSetRating(rating int) { + if n.OnSetRating != nil { + n.OnSetRating(rating) + } +} + +func (n *NowPlayingCard) onAddToPlaylist() { + if n.OnAddToPlaylist != nil { + n.OnAddToPlaylist() + } +} + func (n *NowPlayingCard) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(n.c) } @@ -82,3 +106,16 @@ func (n *NowPlayingCard) OnAlbumNameTapped(f func()) { func (n *NowPlayingCard) OnTrackNameTapped(f func()) { n.trackName.OnTapped = f } + +func (n *NowPlayingCard) showMenu(pos fyne.Position) { + if n.menu == nil { + ratingMenu := util.NewRatingSubmenu(n.onSetRating) + m := fyne.NewMenu("", + fyne.NewMenuItem("Set favorite", func() { n.onSetFavorite(true) }), + fyne.NewMenuItem("Unset favorite", func() { n.onSetFavorite(false) }), + ratingMenu, + fyne.NewMenuItem("Add to playlist...", func() { n.onAddToPlaylist() })) + n.menu = widget.NewPopUpMenu(m, fyne.CurrentApp().Driver().CanvasForObject(n)) + } + n.menu.ShowAtPosition(pos) +} diff --git a/ui/widgets/tappablewrappers.go b/ui/widgets/tappablewrappers.go index a4af555..a5a84be 100644 --- a/ui/widgets/tappablewrappers.go +++ b/ui/widgets/tappablewrappers.go @@ -50,7 +50,8 @@ type TappableImage struct { widget.BaseWidget canvas.Image - OnTapped func() + OnTapped func() + OnTappedSecondary func(pos fyne.Position) } func NewTappableImage(onTapped func()) *TappableImage { @@ -86,12 +87,18 @@ func (t *TappableImage) Cursor() desktop.Cursor { return desktop.DefaultCursor } -func (t *TappableImage) Tapped(e *fyne.PointEvent) { +func (t *TappableImage) Tapped(_ *fyne.PointEvent) { if t.haveImage() && t.OnTapped != nil { t.OnTapped() } } +func (t *TappableImage) TappedSecondary(e *fyne.PointEvent) { + if t.haveImage() && t.OnTappedSecondary != nil { + t.OnTappedSecondary(e.AbsolutePosition) + } +} + func (t *TappableImage) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(&t.Image) } diff --git a/ui/widgets/tracklist.go b/ui/widgets/tracklist.go index e82c9dc..c903478 100644 --- a/ui/widgets/tracklist.go +++ b/ui/widgets/tracklist.go @@ -308,15 +308,9 @@ func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) { fyne.NewMenuItem("Unset favorite", func() { t.onSetFavorites(t.selectedTracks(), false, true) })) - ratingMenu := fyne.NewMenuItem("Set rating", nil) - ratingMenu.ChildMenu = fyne.NewMenu("", []*fyne.MenuItem{ - t.newRatingMenuItem(0), - t.newRatingMenuItem(1), - t.newRatingMenuItem(2), - t.newRatingMenuItem(3), - t.newRatingMenuItem(4), - t.newRatingMenuItem(5), - }...) + ratingMenu := util.NewRatingSubmenu(func(rating int) { + t.onSetRatings(t.selectedTracks(), rating, true) + }) t.ctxMenu.Items = append(t.ctxMenu.Items, ratingMenu) if len(t.AuxiliaryMenuItems) > 0 { t.ctxMenu.Items = append(t.ctxMenu.Items, fyne.NewMenuItemSeparator()) @@ -326,16 +320,6 @@ func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) { widget.ShowPopUpMenuAtPosition(t.ctxMenu, fyne.CurrentApp().Driver().CanvasForObject(t), e.AbsolutePosition) } -func (t *Tracklist) newRatingMenuItem(rating int) *fyne.MenuItem { - label := "(none)" - if rating > 0 { - label = strconv.Itoa(rating) - } - return fyne.NewMenuItem(label, func() { - t.onSetRatings(t.selectedTracks(), rating, true) - }) -} - func (t *Tracklist) onSetFavorite(trackID string, fav bool) { t.tracksMutex.RLock() tr := sharedutil.FindTrackByID(trackID, t.Tracks)