diff --git a/backend/mediaprovider/mediaprovider.go b/backend/mediaprovider/mediaprovider.go index 46ea267f..f7fe0b17 100644 --- a/backend/mediaprovider/mediaprovider.go +++ b/backend/mediaprovider/mediaprovider.go @@ -151,6 +151,7 @@ type SupportsRating interface { type SupportsSharing interface { CreateShareURL(id string) (*url.URL, error) + CanShareArtists() bool } type JukeboxProvider interface { diff --git a/backend/mediaprovider/subsonic/subsonicmediaprovider.go b/backend/mediaprovider/subsonic/subsonicmediaprovider.go index 00588491..5c858eb9 100644 --- a/backend/mediaprovider/subsonic/subsonicmediaprovider.go +++ b/backend/mediaprovider/subsonic/subsonicmediaprovider.go @@ -330,6 +330,12 @@ func (s *subsonicMediaProvider) CreateShareURL(id string) (*url.URL, error) { return shareUrl, nil } +func (s *subsonicMediaProvider) CanShareArtists() bool { + // TODO: Change to true when we decide to allow sharing artists, in case an OpenSubsonic extension + // is approved to share artists in addition to albums and tracks. + return false +} + func (s *subsonicMediaProvider) DownloadTrack(trackID string) (io.Reader, error) { return s.client.Download(trackID) } diff --git a/ui/browsing/albumpage.go b/ui/browsing/albumpage.go index ff857ad7..13078dd1 100644 --- a/ui/browsing/albumpage.go +++ b/ui/browsing/albumpage.go @@ -94,9 +94,9 @@ func newAlbumPage( a.tracklist.SetVisibleColumns(a.cfg.TracklistColumns) a.tracklist.SetSorting(sort) _, canRate := a.mp.(mediaprovider.SupportsRating) - _, canShare := a.mp.(mediaprovider.SupportsRating) + _, canShare := a.mp.(mediaprovider.SupportsSharing) a.tracklist.Options.DisableRating = !canRate - a.tracklist.Options.HideSharing = !canShare + a.tracklist.Options.DisableSharing = !canShare a.tracklist.OnVisibleColumnsChanged = func(cols []string) { a.cfg.TracklistColumns = cols } @@ -185,6 +185,7 @@ type AlbumPageHeader struct { artistLabelSpace *util.HSpace // TODO: remove when no longer needed genreLabel *widgets.MultiHyperlink miscLabel *widget.Label + shareMenuItem *fyne.MenuItem toggleFavButton *widgets.FavoriteButton @@ -248,19 +249,15 @@ func NewAlbumPageHeader(page *AlbumPage) *AlbumPageHeader { a.page.contr.ShowAlbumInfoDialog(a.albumID, a.titleLabel.String(), a.cover.Image()) }) info.Icon = theme.InfoIcon() - menuItems := []*fyne.MenuItem{queue, playlist, download, info} - - _, canShare := page.mp.(mediaprovider.SupportsSharing) - if canShare { - share := fyne.NewMenuItem("Share...", func() { - a.page.contr.ShowShareDialog(a.albumID) - }) - share.Icon = myTheme.ShareIcon - menuItems = append(menuItems, share) - } - menu := fyne.NewMenu("", menuItems...) + a.shareMenuItem = fyne.NewMenuItem("Share...", func() { + a.page.contr.ShowShareDialog(a.albumID) + }) + a.shareMenuItem.Icon = myTheme.ShareIcon + menu := fyne.NewMenu("", queue, playlist, download, info, a.shareMenuItem) pop = widget.NewPopUpMenu(menu, fyne.CurrentApp().Driver().CanvasForObject(a)) } + _, canShare := page.mp.(mediaprovider.SupportsSharing) + a.shareMenuItem.Disabled = !canShare pos := fyne.CurrentApp().Driver().AbsolutePositionForObject(menuBtn) pop.ShowAtPosition(fyne.NewPos(pos.X, pos.Y+menuBtn.Size().Height)) } diff --git a/ui/browsing/artistpage.go b/ui/browsing/artistpage.go index 4c69c65a..b237e507 100644 --- a/ui/browsing/artistpage.go +++ b/ui/browsing/artistpage.go @@ -239,7 +239,7 @@ func (a *ArtistPage) showTopTracks() { _, canRate := a.mp.(mediaprovider.SupportsRating) _, canShare := a.mp.(mediaprovider.SupportsSharing) tl.Options.DisableRating = !canRate - tl.Options.HideSharing = !canShare + tl.Options.DisableSharing = !canShare tl.SetVisibleColumns(a.cfg.TracklistColumns) tl.SetSorting(a.trackSort) tl.OnVisibleColumnsChanged = func(cols []string) { @@ -296,6 +296,7 @@ type ArtistPageHeader struct { playRadioBtn *widget.Button menuBtn *widget.Button container *fyne.Container + shareMenuItem *fyne.MenuItem } func NewArtistPageHeader(page *ArtistPage) *ArtistPageHeader { @@ -322,23 +323,26 @@ func NewArtistPageHeader(page *ArtistPage) *ArtistPageHeader { }) a.playRadioBtn = widget.NewButtonWithIcon("Play Artist Radio", myTheme.ShuffleIcon, a.artistPage.playArtistRadio) - _, canShare := a.artistPage.mp.(mediaprovider.SupportsSharing) - if canShare { - var pop *widget.PopUpMenu - a.menuBtn = widget.NewButtonWithIcon("", theme.MoreHorizontalIcon(), nil) - a.menuBtn.OnTapped = func() { - if pop == nil { - share := fyne.NewMenuItem("Share...", func() { - a.artistPage.contr.ShowShareDialog(a.artistID) - }) - share.Icon = myTheme.ShareIcon - menu := fyne.NewMenu("", share) - pop = widget.NewPopUpMenu(menu, fyne.CurrentApp().Driver().CanvasForObject(a)) - } - pos := fyne.CurrentApp().Driver().AbsolutePositionForObject(a.menuBtn) - pop.ShowAtPosition(fyne.NewPos(pos.X, pos.Y+a.menuBtn.Size().Height)) - } - } + // TODO: Uncomment when at least one media provider supports sharing artists. + // a.shareMenuItem = fyne.NewMenuItem("Share...", func() { + // a.artistPage.contr.ShowShareDialog(a.artistID) + // }) + // a.shareMenuItem.Icon = myTheme.ShareIcon + // var pop *widget.PopUpMenu + // a.menuBtn = widget.NewButtonWithIcon("", theme.MoreHorizontalIcon(), nil) + // a.menuBtn.OnTapped = func() { + // if pop == nil { + // menu := fyne.NewMenu("", a.shareMenuItem) + // pop = widget.NewPopUpMenu(menu, fyne.CurrentApp().Driver().CanvasForObject(a)) + // } + // pos := fyne.CurrentApp().Driver().AbsolutePositionForObject(a.menuBtn) + // pop.ShowAtPosition(fyne.NewPos(pos.X, pos.Y+a.menuBtn.Size().Height)) + // } + // canShareArtists := false + // if r, canShare := a.artistPage.mp.(mediaprovider.SupportsSharing); canShare { + // canShareArtists = r.CanShareArtists() + // } + // a.shareMenuItem.Disabled = !canShareArtists a.biographyDisp.Wrapping = fyne.TextWrapWord a.biographyDisp.Truncation = fyne.TextTruncateEllipsis diff --git a/ui/browsing/artistspage.go b/ui/browsing/artistspage.go index dc8ae589..40d610f1 100644 --- a/ui/browsing/artistspage.go +++ b/ui/browsing/artistspage.go @@ -86,6 +86,11 @@ func newArtistsPage( } else { a.grid = widgets.NewFixedGridView(nil, a.im, myTheme.ArtistIcon) } + canShareArtists := false + if r, canShare := mp.(mediaprovider.SupportsSharing); canShare { + canShareArtists = r.CanShareArtists() + } + a.grid.DisableSharing = !canShareArtists a.contr.ConnectArtistGridActions(a.grid) searchVbox := container.NewVBox(layout.NewSpacer(), a.searcher, layout.NewSpacer()) diff --git a/ui/browsing/favoritespage.go b/ui/browsing/favoritespage.go index 17c11659..50a0195b 100644 --- a/ui/browsing/favoritespage.go +++ b/ui/browsing/favoritespage.go @@ -336,6 +336,11 @@ func (a *FavoritesPage) onShowFavoriteArtists() { } else { a.artistGrid = widgets.NewFixedGridView(model, a.im, myTheme.ArtistIcon) } + canShareArtists := false + if r, canShare := a.mp.(mediaprovider.SupportsSharing); canShare { + canShareArtists = r.CanShareArtists() + } + a.artistGrid.DisableSharing = !canShareArtists a.contr.ConnectArtistGridActions(a.artistGrid) a.container.Objects[0] = a.artistGrid a.Refresh() @@ -397,7 +402,7 @@ func (a *FavoritesPage) onShowFavoriteSongs() { _, canRate := a.mp.(mediaprovider.SupportsRating) _, canShare := a.mp.(mediaprovider.SupportsSharing) tracklist.Options.DisableRating = !canRate - tracklist.Options.HideSharing = !canShare + tracklist.Options.DisableSharing = !canShare tracklist.SetVisibleColumns(a.cfg.TracklistColumns) tracklist.SetSorting(a.trackSort) tracklist.OnVisibleColumnsChanged = func(cols []string) { diff --git a/ui/browsing/gridviewpage.go b/ui/browsing/gridviewpage.go index 4884c762..7815765f 100644 --- a/ui/browsing/gridviewpage.go +++ b/ui/browsing/gridviewpage.go @@ -112,6 +112,7 @@ func NewGridViewPage( gp.ExtendBaseWidget(gp) gp.createTitleAndSort() + _, canShare := mp.(mediaprovider.SupportsSharing) iter := adapter.Iter(gp.getSortOrder(), gp.getFilter()) if g := pool.Obtain(util.WidgetTypeGridView); g != nil { gp.grid = g.(*widgets.GridView) @@ -120,6 +121,7 @@ func NewGridViewPage( } else { gp.grid = widgets.NewGridView(iter, im, adapter.PlaceholderResource()) } + gp.grid.DisableSharing = !canShare adapter.ConnectGridActions(gp.grid) gp.createSearchAndFilter() gp.createContainer() diff --git a/ui/browsing/nowplayingpage.go b/ui/browsing/nowplayingpage.go index e14afa32..702f7b3d 100644 --- a/ui/browsing/nowplayingpage.go +++ b/ui/browsing/nowplayingpage.go @@ -43,11 +43,12 @@ type NowPlayingPage struct { } type nowPlayingPageState struct { - contr *controller.Controller - pool *util.WidgetPool - pm *backend.PlaybackManager - im *backend.ImageManager - canRate bool + contr *controller.Controller + pool *util.WidgetPool + pm *backend.PlaybackManager + im *backend.ImageManager + canRate bool + canShare bool } func NewNowPlayingPage( @@ -56,9 +57,10 @@ func NewNowPlayingPage( im *backend.ImageManager, pm *backend.PlaybackManager, canRate bool, + canShare bool, ) *NowPlayingPage { a := &NowPlayingPage{nowPlayingPageState: nowPlayingPageState{ - contr: contr, pool: pool, im: im, pm: pm, canRate: canRate, + contr: contr, pool: pool, im: im, pm: pm, canRate: canRate, canShare: canShare, }} a.ExtendBaseWidget(a) @@ -82,8 +84,15 @@ func NewNowPlayingPage( } a.queueList = widgets.NewPlayQueueList(a.im) + a.queueList.DisableRating = !canRate + a.queueList.DisableSharing = !canShare a.queueList.OnReorderTracks = a.doSetNewTrackOrder a.queueList.OnDownload = contr.ShowDownloadDialog + a.queueList.OnShare = func(tracks []*mediaprovider.Track) { + if len(tracks) > 0 { + a.contr.ShowShareDialog(tracks[0].ID) + } + } a.queueList.OnAddToPlaylist = contr.DoAddTracksToPlaylistWorkflow a.queueList.OnPlayTrackAt = func(tracknum int) { _ = a.pm.PlayTrackAt(tracknum) @@ -199,7 +208,7 @@ func (s *nowPlayingPageState) Restore() Page { page.Reload() return page } - return NewNowPlayingPage(s.contr, s.pool, s.im, s.pm, s.canRate) + return NewNowPlayingPage(s.contr, s.pool, s.im, s.pm, s.canRate, s.canShare) } var _ CanShowPlayTime = (*NowPlayingPage)(nil) diff --git a/ui/browsing/playlistpage.go b/ui/browsing/playlistpage.go index e990643e..63b394ea 100644 --- a/ui/browsing/playlistpage.go +++ b/ui/browsing/playlistpage.go @@ -91,8 +91,8 @@ func newPlaylistPage( remove := fyne.NewMenuItem("Remove from playlist", a.onRemoveSelectedFromPlaylist) remove.Icon = theme.ContentClearIcon() a.tracklist.Options = widgets.TracklistOptions{ - DisableRating: !canRate, - HideSharing: !canShare, + DisableRating: !canRate, + DisableSharing: !canShare, AuxiliaryMenuItems: []*fyne.MenuItem{ util.NewReorderTracksSubmenu(a.doSetNewTrackOrder), remove, diff --git a/ui/browsing/router.go b/ui/browsing/router.go index 900ce7e4..c92d2e97 100644 --- a/ui/browsing/router.go +++ b/ui/browsing/router.go @@ -31,6 +31,7 @@ func NewRouter(app *backend.App, controller *controller.Controller, nav Navigati func (r Router) CreatePage(rte controller.Route) Page { _, canRate := r.App.ServerManager.Server.(mediaprovider.SupportsRating) + _, canShare := r.App.ServerManager.Server.(mediaprovider.SupportsSharing) switch rte.Page { case controller.Album: return NewAlbumPage(rte.Arg, &r.App.Config.AlbumPage, r.widgetPool, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager, r.Controller) @@ -43,13 +44,13 @@ func (r Router) CreatePage(rte controller.Route) Page { case controller.Favorites: return NewFavoritesPage(&r.App.Config.FavoritesPage, r.widgetPool, r.Controller, r.App.ServerManager.Server, r.App.PlaybackManager, r.App.ImageManager) case controller.Fullscreen: - return NewNowPlayingPage(r.Controller, r.widgetPool, r.App.ImageManager, r.App.PlaybackManager, canRate) + return NewNowPlayingPage(r.Controller, r.widgetPool, r.App.ImageManager, r.App.PlaybackManager, canRate, canShare) case controller.Genre: return NewGenrePage(rte.Arg, r.widgetPool, r.Controller, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager) case controller.Genres: return NewGenresPage(r.Controller, r.App.ServerManager.Server) case controller.NowPlaying: - return NewNowPlayingPage(r.Controller, r.widgetPool, r.App.ImageManager, r.App.PlaybackManager, canRate) + return NewNowPlayingPage(r.Controller, r.widgetPool, r.App.ImageManager, r.App.PlaybackManager, canRate, canShare) case controller.Playlist: return NewPlaylistPage(rte.Arg, &r.App.Config.PlaylistPage, r.widgetPool, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager) case controller.Playlists: diff --git a/ui/browsing/trackspage.go b/ui/browsing/trackspage.go index 98a9108f..4b6884a5 100644 --- a/ui/browsing/trackspage.go +++ b/ui/browsing/trackspage.go @@ -53,7 +53,7 @@ func NewTracksPage(contr *controller.Controller, conf *backend.TracksPageConfig, t.tracklist.Options = widgets.TracklistOptions{ DisableSorting: true, DisableRating: !t.canRate, - HideSharing: !t.canShare, + DisableSharing: !t.canShare, AutoNumber: true, } t.tracklist.SetVisibleColumns(conf.TracklistColumns) @@ -140,7 +140,7 @@ func (t *TracksPage) doSearch(query string) { AutoNumber: true, DisableSorting: true, DisableRating: !t.canRate, - HideSharing: !t.canShare, + DisableSharing: !t.canShare, } t.searchTracklist.SetVisibleColumns(t.conf.TracklistColumns) t.searchTracklist.SetNowPlaying(t.nowPlayingID) diff --git a/ui/controller/controller.go b/ui/controller/controller.go index c107449a..f600144b 100644 --- a/ui/controller/controller.go +++ b/ui/controller/controller.go @@ -141,12 +141,8 @@ func (m *Controller) connectTracklistActionsWithReplayGainMode(tracklist *widget m.ClosePopUpOnEscape(pop) } tracklist.OnDownload = m.ShowDownloadDialog - - _, canShare := m.App.ServerManager.Server.(mediaprovider.SupportsSharing) - if canShare { - tracklist.OnShare = func(trackID string) { - go m.ShowShareDialog(trackID) - } + tracklist.OnShare = func(trackID string) { + go m.ShowShareDialog(trackID) } } @@ -183,12 +179,8 @@ func (m *Controller) ConnectAlbumGridActions(grid *widgets.GridView) { m.ShowDownloadDialog(album.Tracks, album.Name) }() } - - _, canShare := m.App.ServerManager.Server.(mediaprovider.SupportsSharing) - if canShare { - grid.OnShare = func(albumID string) { - go m.ShowShareDialog(albumID) - } + grid.OnShare = func(albumID string) { + go m.ShowShareDialog(albumID) } } diff --git a/ui/widgets/gridview.go b/ui/widgets/gridview.go index 53d5419a..ec88fbf9 100644 --- a/ui/widgets/gridview.go +++ b/ui/widgets/gridview.go @@ -79,6 +79,7 @@ type GridView struct { itemForIndex map[int]*GridViewItem itemWidth float32 numColsCached int + shareMenuItem *fyne.MenuItem } type GridViewState struct { @@ -89,6 +90,8 @@ type GridViewState struct { highestShown int done bool + DisableSharing bool + OnPlay func(id string, shuffle bool) OnAddToQueue func(id string) OnAddToPlaylist func(id string) @@ -408,19 +411,14 @@ func (g *GridView) showContextMenu(card *GridViewItem, pos fyne.Position) { } }) download.Icon = theme.DownloadIcon() - menuItems := []*fyne.MenuItem{play, shuffle, queue, playlist, download} - - if g.OnShare != nil { - share := fyne.NewMenuItem("Share...", func() { - g.OnShare(g.menuGridViewItemId) - }) - share.Icon = myTheme.ShareIcon - menuItems = append(menuItems, share) - } - - g.menu = widget.NewPopUpMenu(fyne.NewMenu("", menuItems...), + g.shareMenuItem = fyne.NewMenuItem("Share...", func() { + g.OnShare(g.menuGridViewItemId) + }) + g.shareMenuItem.Icon = myTheme.ShareIcon + g.menu = widget.NewPopUpMenu(fyne.NewMenu("", play, shuffle, queue, playlist, download, g.shareMenuItem), fyne.CurrentApp().Driver().CanvasForObject(g)) } + g.shareMenuItem.Disabled = g.DisableSharing g.menu.ShowAtPosition(pos) } diff --git a/ui/widgets/playqueuelist.go b/ui/widgets/playqueuelist.go index c8855d94..0ab59269 100644 --- a/ui/widgets/playqueuelist.go +++ b/ui/widgets/playqueuelist.go @@ -26,7 +26,8 @@ const thumbnailSize = 52 type PlayQueueList struct { widget.BaseWidget - DisableRating bool + DisableRating bool + DisableSharing bool // user action callbacks OnAddToPlaylist func(trackIDs []string) @@ -34,6 +35,7 @@ type PlayQueueList struct { OnSetRating func(trackIDs []string, rating int) OnRemoveFromQueue func(trackIDs []string) OnDownload func(tracks []*mediaprovider.Track, downloadName string) + OnShare func(tracks []*mediaprovider.Track) OnShowArtistPage func(artistID string) OnPlayTrackAt func(idx int) OnReorderTracks func(trackIDs []string, op sharedutil.TrackReorderOp) @@ -41,6 +43,7 @@ type PlayQueueList struct { list *FocusList menu *widget.PopUpMenu ratingSubmenu *fyne.MenuItem + shareMenuItem *fyne.MenuItem nowPlayingID string colLayout *layouts.ColumnsLayout @@ -200,6 +203,12 @@ func (p *PlayQueueList) onShowContextMenu(e *fyne.PointEvent, trackIdx int) { } }) download.Icon = theme.DownloadIcon() + p.shareMenuItem = fyne.NewMenuItem("Share...", func() { + if p.OnShare != nil { + p.OnShare(p.selectedTracks()) + } + }) + p.shareMenuItem.Icon = myTheme.ShareIcon favorite := fyne.NewMenuItem("Set favorite", func() { if p.OnSetFavorite != nil { p.OnSetFavorite(p.selectedTrackIDs(), true) @@ -233,6 +242,7 @@ func (p *PlayQueueList) onShowContextMenu(e *fyne.PointEvent, trackIdx int) { fyne.NewMenu("", playlist, download, + p.shareMenuItem, fyne.NewMenuItemSeparator(), favorite, unfavorite, @@ -245,6 +255,7 @@ func (p *PlayQueueList) onShowContextMenu(e *fyne.PointEvent, trackIdx int) { ) } p.ratingSubmenu.Disabled = p.DisableRating + p.shareMenuItem.Disabled = p.DisableSharing || len(p.selectedTracks()) != 1 p.menu.ShowAtPosition(e.AbsolutePosition) } diff --git a/ui/widgets/tracklist.go b/ui/widgets/tracklist.go index 576ee0d9..27c40762 100644 --- a/ui/widgets/tracklist.go +++ b/ui/widgets/tracklist.go @@ -73,8 +73,8 @@ type TracklistOptions struct { // Disables the five star rating widget. DisableRating bool - // Hides the sharing option. - HideSharing bool + // Disables the sharing option. + DisableSharing bool } type Tracklist struct { @@ -560,13 +560,11 @@ func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) { }) unfavorite.Icon = myTheme.NotFavoriteIcon t.ctxMenu.Items = append(t.ctxMenu.Items, playlist, download) - if !t.Options.HideSharing { - t.shareMenuItem = fyne.NewMenuItem("Share...", func() { - t.onShare(t.selectedTracks()) - }) - t.shareMenuItem.Icon = myTheme.ShareIcon - t.ctxMenu.Items = append(t.ctxMenu.Items, t.shareMenuItem) - } + t.shareMenuItem = fyne.NewMenuItem("Share...", func() { + t.onShare(t.selectedTracks()) + }) + t.shareMenuItem.Icon = myTheme.ShareIcon + t.ctxMenu.Items = append(t.ctxMenu.Items, t.shareMenuItem) 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) { @@ -579,9 +577,7 @@ func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) { } } t.ratingSubmenu.Disabled = t.Options.DisableRating - if t.shareMenuItem != nil { - t.shareMenuItem.Disabled = len(t.selectedTracks()) != 1 - } + t.shareMenuItem.Disabled = t.Options.DisableSharing || len(t.selectedTracks()) != 1 widget.ShowPopUpMenuAtPosition(t.ctxMenu, fyne.CurrentApp().Driver().CanvasForObject(t), e.AbsolutePosition) } @@ -646,9 +642,8 @@ func (t *Tracklist) onDownload(tracks []*mediaprovider.Track, downloadName strin func (t *Tracklist) onShare(tracks []*mediaprovider.Track) { if t.OnShare != nil { - selectedTrackIDs := t.SelectedTrackIDs() - if len(selectedTrackIDs) > 0 { - t.OnShare(selectedTrackIDs[0]) + if len(tracks) > 0 { + t.OnShare(tracks[0].ID) } } }