From f26e9dbcbf66dbb0caa80aab00e302ff88a91adf Mon Sep 17 00:00:00 2001 From: natilou <30585029+natilou@users.noreply.github.com> Date: Wed, 21 Jun 2023 23:20:40 -0300 Subject: [PATCH] Add UI for viewing the album info returned by Subsonic getAlbumInfo API - Adding "Get Info" in album page's "meatball" menu. When the option is clicked a pop up appears with the album information and links to Last.fm and MusicBrainz. Screenshot: Fixes #105 --- backend/mediaprovider/mediaprovider.go | 2 + backend/mediaprovider/model.go | 6 + .../subsonic/subsonicmediaprovider.go | 13 ++ ui/browsing/albumpage.go | 4 +- ui/controller/controller.go | 19 +++ ui/dialogs/albuminfodialog.go | 111 ++++++++++++++++++ 6 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 ui/dialogs/albuminfodialog.go diff --git a/backend/mediaprovider/mediaprovider.go b/backend/mediaprovider/mediaprovider.go index 9b2fd3c..86a3880 100644 --- a/backend/mediaprovider/mediaprovider.go +++ b/backend/mediaprovider/mediaprovider.go @@ -39,6 +39,8 @@ type MediaProvider interface { GetAlbum(albumID string) (*AlbumWithTracks, error) + GetAlbumInfo(albumID string) (*AlbumInfo, error) + GetArtist(artistID string) (*ArtistWithAlbums, error) GetArtistInfo(artistID string) (*ArtistInfo, error) diff --git a/backend/mediaprovider/model.go b/backend/mediaprovider/model.go index d6ffa63..41858ac 100644 --- a/backend/mediaprovider/model.go +++ b/backend/mediaprovider/model.go @@ -18,6 +18,12 @@ type AlbumWithTracks struct { Tracks []*Track } +type AlbumInfo struct { + Info string + LastFMUrl string + MusicBrainzID string +} + type Artist struct { ID string CoverArtID string diff --git a/backend/mediaprovider/subsonic/subsonicmediaprovider.go b/backend/mediaprovider/subsonic/subsonicmediaprovider.go index 446378f..b33d922 100644 --- a/backend/mediaprovider/subsonic/subsonicmediaprovider.go +++ b/backend/mediaprovider/subsonic/subsonicmediaprovider.go @@ -59,6 +59,19 @@ func (s *subsonicMediaProvider) GetAlbum(albumID string) (*mediaprovider.AlbumWi return album, nil } +func (s *subsonicMediaProvider) GetAlbumInfo(albumID string) (*mediaprovider.AlbumInfo, error) { + al, err := s.client.GetAlbumInfo(albumID) + if err != nil { + return nil, err + } + album := &mediaprovider.AlbumInfo{ + Info: al.Notes, + LastFMUrl: al.LastFmUrl, + MusicBrainzID: al.MusicBrainzID, + } + return album, nil +} + func (s *subsonicMediaProvider) GetArtist(artistID string) (*mediaprovider.ArtistWithAlbums, error) { ar, err := s.client.GetArtist(artistID) if err != nil { diff --git a/ui/browsing/albumpage.go b/ui/browsing/albumpage.go index 22c3f62..1cb93e4 100644 --- a/ui/browsing/albumpage.go +++ b/ui/browsing/albumpage.go @@ -203,7 +203,9 @@ func NewAlbumPageHeader(page *AlbumPage) *AlbumPageHeader { }), fyne.NewMenuItem("Download...", func() { a.page.contr.ShowDownloadDialog(a.page.tracks, a.titleLabel.String()) - + }), + fyne.NewMenuItem("Get Info...", func() { + a.page.contr.ShowAlbumInfoDialog(a.albumID, a.titleLabel.String(), a.cover.Image.Image) })) pop = widget.NewPopUpMenu(menu, fyne.CurrentApp().Driver().CanvasForObject(a)) } diff --git a/ui/controller/controller.go b/ui/controller/controller.go index a365c94..fc564c6 100644 --- a/ui/controller/controller.go +++ b/ui/controller/controller.go @@ -651,3 +651,22 @@ func (c *Controller) sendNotification(title, content string) { Content: content, }) } + +func (c *Controller) ShowAlbumInfoDialog(albumID, albumName string, albumCover image.Image) { + go func() { + albumInfo, err := c.App.ServerManager.Server.GetAlbumInfo(albumID) + if err != nil { + log.Print("Error getting album info: ", err) + return + } + dlg := dialogs.NewAlbumInfoDialog(albumInfo, albumName, albumCover) + pop := widget.NewModalPopUp(dlg, c.MainWindow.Canvas()) + dlg.OnDismiss = func() { + pop.Hide() + c.doModalClosed() + } + c.ClosePopUpOnEscape(pop) + c.haveModal = true + pop.Show() + }() +} diff --git a/ui/dialogs/albuminfodialog.go b/ui/dialogs/albuminfodialog.go new file mode 100644 index 0000000..12004b8 --- /dev/null +++ b/ui/dialogs/albuminfodialog.go @@ -0,0 +1,111 @@ +package dialogs + +import ( + "fmt" + "image" + "net/url" + "strings" + + "github.com/dweymouth/supersonic/backend/mediaprovider" + "github.com/dweymouth/supersonic/ui/layouts" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" +) + +type AlbumInfoDialog struct { + widget.BaseWidget + + OnDismiss func() + + content fyne.CanvasObject +} + +func NewAlbumInfoDialog(albumInfo *mediaprovider.AlbumInfo, albumName string, albumCover image.Image) *AlbumInfoDialog { + a := &AlbumInfoDialog{} + a.ExtendBaseWidget(a) + + a.content = container.NewVBox( + a.buildMainContainer(albumInfo, albumName, albumCover), + widget.NewSeparator(), + container.NewHBox( + layout.NewSpacer(), + widget.NewButton("Close", func() { + if a.OnDismiss != nil { + a.OnDismiss() + } + }), + ), + ) + a.content.Resize(a.MinSize()) + return a +} + +func (a *AlbumInfoDialog) MinSize() fyne.Size { + return fyne.NewSize(550, a.BaseWidget.MinSize().Height) +} + +func (a *AlbumInfoDialog) buildMainContainer(albumInfo *mediaprovider.AlbumInfo, albumName string, albumCover image.Image) *fyne.Container { + iconImage := canvas.NewImageFromImage(albumCover) + iconImage.FillMode = canvas.ImageFillContain + iconImage.SetMinSize(fyne.NewSize(100, 100)) + title := widget.NewRichTextWithText(albumName) + title.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = true + title.Segments[0].(*widget.TextSegment).Style.SizeName = theme.SizeNameSubHeadingText + title.Segments[0].(*widget.TextSegment).Style.Alignment = fyne.TextAlignCenter + + infoContent := widget.NewLabel("Album info not available") + + if albumInfo.Info != "" { + infoContent = a.infoLabel(albumInfo.Info) + } + + urlContainer := a.buildUrlContainer(albumInfo.LastFMUrl, albumInfo.MusicBrainzID) + + return container.NewVBox( + iconImage, + title, + infoContent, + urlContainer, + ) + +} + +func (a *AlbumInfoDialog) CreateRenderer() fyne.WidgetRenderer { + return widget.NewSimpleRenderer(a.content) +} + +func (a *AlbumInfoDialog) infoLabel(info string) *widget.Label { + last := strings.LastIndex(info, " 0 { + urlContainer.Add(widget.NewLabel("ยท")) + } + urlContainer.Add(url) + } + + return container.NewCenter(urlContainer) +}