From e7197824371f54b416ef0e08082dee07d8eeb296 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sat, 17 Feb 2024 16:50:50 -0800 Subject: [PATCH] beginning of work on fullscreen page --- ui/bottompanel.go | 10 +-- ui/browsing/fullscreenpage.go | 78 ++++++++++++++++++++ ui/browsing/router.go | 4 +- ui/controller/routes.go | 5 ++ ui/widgets/largenowplayingcard.go | 115 ++++++++++++++++++++++++++++++ ui/widgets/nowplayingcard.go | 6 +- 6 files changed, 206 insertions(+), 12 deletions(-) create mode 100644 ui/browsing/fullscreenpage.go create mode 100644 ui/widgets/largenowplayingcard.go diff --git a/ui/bottompanel.go b/ui/bottompanel.go index e80f504..a4210f3 100644 --- a/ui/bottompanel.go +++ b/ui/bottompanel.go @@ -2,7 +2,6 @@ package ui import ( "image" - "log" "time" "github.com/dweymouth/supersonic/backend" @@ -53,13 +52,8 @@ func NewBottomPanel(pm *backend.PlaybackManager, contr *controller.Controller) * }) bp.NowPlaying = widgets.NewNowPlayingCard() - bp.NowPlaying.OnShowCoverImage = func() { - im, err := bp.ImageManager.GetFullSizeCoverArt(bp.coverArtID) - if err != nil { - log.Printf("error getting full size cover image: %s", err.Error()) - } else { - contr.ShowPopUpImage(im) - } + bp.NowPlaying.OnCoverTapped = func() { + contr.NavigateTo(controller.FullscreenRoute()) } bp.NowPlaying.OnSetFavorite = func(fav bool) { contr.SetTrackFavorites([]string{pm.NowPlaying().ID}, fav) diff --git a/ui/browsing/fullscreenpage.go b/ui/browsing/fullscreenpage.go new file mode 100644 index 0000000..668647e --- /dev/null +++ b/ui/browsing/fullscreenpage.go @@ -0,0 +1,78 @@ +package browsing + +import ( + "github.com/dweymouth/supersonic/backend" + "github.com/dweymouth/supersonic/backend/mediaprovider" + "github.com/dweymouth/supersonic/sharedutil" + "github.com/dweymouth/supersonic/ui/controller" + "github.com/dweymouth/supersonic/ui/util" + "github.com/dweymouth/supersonic/ui/widgets" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" +) + +type FullscreenPage struct { + widget.BaseWidget + + fullscreenPageState + + queue []*mediaprovider.Track + + card *widgets.LargeNowPlayingCard + nowPlayingID string +} + +type fullscreenPageState struct { + contr *controller.Controller + pool *util.WidgetPool + pm *backend.PlaybackManager + canRate bool +} + +func NewFullscreenPage( + contr *controller.Controller, + pool *util.WidgetPool, + pm *backend.PlaybackManager, + canRate bool, +) *FullscreenPage { + a := &FullscreenPage{fullscreenPageState: fullscreenPageState{ + contr: contr, pool: pool, pm: pm, canRate: canRate, + }} + a.ExtendBaseWidget(a) + + a.card = widgets.NewLargeNowPlayingCard() + + a.Reload() + return a +} + +func (a *FullscreenPage) CreateRenderer() fyne.WidgetRenderer { + container := container.NewPadded() + return widget.NewSimpleRenderer(container) +} + +func (a *FullscreenPage) Save() SavedPage { + nps := a.fullscreenPageState + return &nps +} + +func (a *FullscreenPage) Route() controller.Route { + return controller.NowPlayingRoute("") +} + +var _ CanShowNowPlaying = (*FullscreenPage)(nil) + +func (a *FullscreenPage) OnSongChange(song, lastScrobbledIfAny *mediaprovider.Track) { + a.nowPlayingID = sharedutil.TrackIDOrEmptyStr(song) + a.card.Update(song.Name, song.ArtistNames, song.ArtistIDs, song.Album) +} + +func (a *FullscreenPage) Reload() { + a.queue = a.pm.GetPlayQueue() +} + +func (s *fullscreenPageState) Restore() Page { + return NewFullscreenPage(s.contr, s.pool, s.pm, s.canRate) +} diff --git a/ui/browsing/router.go b/ui/browsing/router.go index 4c5b418..0a2a188 100644 --- a/ui/browsing/router.go +++ b/ui/browsing/router.go @@ -30,6 +30,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) 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) @@ -41,12 +42,13 @@ func (r Router) CreatePage(rte controller.Route) Page { return NewArtistsPage(r.Controller, r.widgetPool, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager) 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 NewFullscreenPage(r.Controller, r.widgetPool, r.App.PlaybackManager, canRate) 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: - _, canRate := r.App.ServerManager.Server.(mediaprovider.SupportsRating) return NewNowPlayingPage(rte.Arg, r.Controller, r.widgetPool, &r.App.Config.NowPlayingPage, r.App.PlaybackManager, canRate) case controller.Playlist: return NewPlaylistPage(rte.Arg, &r.App.Config.PlaylistPage, r.widgetPool, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager) diff --git a/ui/controller/routes.go b/ui/controller/routes.go index dc2255a..172175a 100644 --- a/ui/controller/routes.go +++ b/ui/controller/routes.go @@ -8,6 +8,7 @@ const ( Albums Artist Artists + Fullscreen Genre Genres Favorites @@ -38,6 +39,10 @@ func FavoritesRoute() Route { return Route{Page: Favorites} } +func FullscreenRoute() Route { + return Route{Page: Fullscreen} +} + func GenreRoute(genre string) Route { return Route{Page: Genre, Arg: genre} } diff --git a/ui/widgets/largenowplayingcard.go b/ui/widgets/largenowplayingcard.go new file mode 100644 index 0000000..3edf36e --- /dev/null +++ b/ui/widgets/largenowplayingcard.go @@ -0,0 +1,115 @@ +package widgets + +import ( + "image" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" + "github.com/dweymouth/supersonic/ui/theme" +) + +// Shows the current album art, track name, artist name, and album name +// for the currently playing track. Placed into the left side of the BottomPanel. +type LargeNowPlayingCard struct { + widget.BaseWidget + + DisableRating bool + + trackName *widget.Hyperlink + artistName *MultiHyperlink + albumName *widget.Hyperlink + cover *ImagePlaceholder + + OnTrackNameTapped func() + OnArtistNameTapped func(artistID string) + OnAlbumNameTapped func() + OnShowCoverImage func() + OnSetRating func(rating int) + OnSetFavorite func(favorite bool) + OnAddToPlaylist func() +} + +func NewLargeNowPlayingCard() *LargeNowPlayingCard { + n := &LargeNowPlayingCard{ + trackName: widget.NewHyperlink("", nil), + artistName: NewMultiHyperlink(), + albumName: widget.NewHyperlink("", nil), + } + n.ExtendBaseWidget(n) + n.cover = NewImagePlaceholder(theme.TracksIcon, 300) + n.trackName.Hidden = true + n.albumName.Hidden = true + n.albumName.Truncation = fyne.TextTruncateEllipsis + n.trackName.Truncation = fyne.TextTruncateEllipsis + n.trackName.TextStyle.Bold = true + n.albumName.OnTapped = n.onAlbumNameTapped + n.artistName.OnTapped = n.onArtistNameTapped + n.trackName.OnTapped = n.onTrackNameTapped + + return n +} + +func (n *LargeNowPlayingCard) MinSize() fyne.Size { + // prop up height for when cover image is hidden + return fyne.NewSize(n.BaseWidget.MinSize().Width, 85) +} + +func (n *LargeNowPlayingCard) onAlbumNameTapped() { + if n.OnAlbumNameTapped != nil { + n.OnAlbumNameTapped() + } +} + +func (n *LargeNowPlayingCard) onArtistNameTapped(artistID string) { + if n.OnArtistNameTapped != nil { + n.OnArtistNameTapped(artistID) + } +} + +func (n *LargeNowPlayingCard) onTrackNameTapped() { + if n.OnTrackNameTapped != nil { + n.OnTrackNameTapped() + } +} + +func (n *LargeNowPlayingCard) onShowCoverImage(*fyne.PointEvent) { + if n.OnShowCoverImage != nil { + n.OnShowCoverImage() + } +} + +func (n *LargeNowPlayingCard) onSetFavorite(fav bool) { + if n.OnSetFavorite != nil { + n.OnSetFavorite(fav) + } +} + +func (n *LargeNowPlayingCard) onSetRating(rating int) { + if n.OnSetRating != nil { + n.OnSetRating(rating) + } +} + +func (n *LargeNowPlayingCard) CreateRenderer() fyne.WidgetRenderer { + vbox := container.NewVBox( + n.trackName, + n.albumName, + n.artistName, + ) + c := container.NewBorder(nil, vbox, nil, nil, n.cover) + return widget.NewSimpleRenderer(c) +} + +func (n *LargeNowPlayingCard) Update(track string, artists, artistIDs []string, album string) { + n.trackName.SetText(track) + n.trackName.Hidden = track == "" + n.artistName.BuildSegments(artists, artistIDs) + n.albumName.SetText(album) + n.albumName.Hidden = album == "" + n.Refresh() +} + +func (n *LargeNowPlayingCard) SetCoverImage(im image.Image) { + n.cover.SetImage(im, false) +} diff --git a/ui/widgets/nowplayingcard.go b/ui/widgets/nowplayingcard.go index ec3634d..13f882e 100644 --- a/ui/widgets/nowplayingcard.go +++ b/ui/widgets/nowplayingcard.go @@ -30,7 +30,7 @@ type NowPlayingCard struct { OnTrackNameTapped func() OnArtistNameTapped func(artistID string) OnAlbumNameTapped func() - OnShowCoverImage func() + OnCoverTapped func() OnSetRating func(rating int) OnSetFavorite func(favorite bool) OnAddToPlaylist func() @@ -84,8 +84,8 @@ func (n *NowPlayingCard) onTrackNameTapped() { } func (n *NowPlayingCard) onShowCoverImage(*fyne.PointEvent) { - if n.OnShowCoverImage != nil { - n.OnShowCoverImage() + if n.OnCoverTapped != nil { + n.OnCoverTapped() } }