clicking album thumbnail on album page shows full size cover popup

This commit is contained in:
Drew Weymouth
2023-01-22 13:21:25 -08:00
parent c1aaed4b3e
commit c9bd3b5079
5 changed files with 146 additions and 33 deletions
+16
View File
@@ -18,6 +18,9 @@ type ImageManager struct {
s *ServerManager
baseCacheDir string
thumbnailCache gcache.Cache
cachedFullSizeCover image.Image
cachedFullSizeCoverID string
}
func NewImageManager(s *ServerManager, baseCacheDir string) *ImageManager {
@@ -66,6 +69,19 @@ func (i *ImageManager) GetAlbumThumbnail(albumID string) (image.Image, error) {
return i.fetchAndCacheCoverFromServer(albumID)
}
func (i *ImageManager) GetFullSizeAlbumCover(albumID string) (image.Image, error) {
if i.cachedFullSizeCoverID == albumID {
return i.cachedFullSizeCover, nil
}
im, err := i.s.Server.GetCoverArt(albumID, nil)
if err != nil {
return nil, err
}
i.cachedFullSizeCover = im
i.cachedFullSizeCoverID = albumID
return im, nil
}
func (i *ImageManager) ensureCoverCacheDir() string {
path := path.Join(i.baseCacheDir, i.s.ServerID.String(), "covers")
configdir.MakePath(path)
+57 -26
View File
@@ -19,21 +19,34 @@ import (
type AlbumPage struct {
widget.BaseWidget
albumID string
sm *backend.ServerManager
im *backend.ImageManager
lm *backend.LibraryManager
nav func(Route)
header *AlbumPageHeader
tracklist *widgets.Tracklist
nowPlayingID string
container *fyne.Container
albumID string
sm *backend.ServerManager
im *backend.ImageManager
lm *backend.LibraryManager
nav func(Route)
header *AlbumPageHeader
tracklist *widgets.Tracklist
nowPlayingID string
container *fyne.Container
popUpProvider PopUpProvider
OnPlayAlbum func(string, int)
}
func NewAlbumPage(albumID string, sm *backend.ServerManager, lm *backend.LibraryManager, im *backend.ImageManager, nav func(Route)) *AlbumPage {
a := &AlbumPage{albumID: albumID, sm: sm, lm: lm, im: im, nav: nav}
type PopUpProvider interface {
CreatePopUp(fyne.CanvasObject) *widget.PopUp
WindowSize() fyne.Size
}
func NewAlbumPage(
albumID string,
sm *backend.ServerManager,
lm *backend.LibraryManager,
im *backend.ImageManager,
popUpProvider PopUpProvider,
nav func(Route),
) *AlbumPage {
a := &AlbumPage{albumID: albumID, sm: sm, lm: lm, im: im, nav: nav, popUpProvider: popUpProvider}
a.ExtendBaseWidget(a)
a.header = NewAlbumPageHeader(a)
a.tracklist = widgets.NewTracklist(nil)
@@ -55,10 +68,11 @@ func (a *AlbumPage) SetPlayAlbumCallback(cb func(string, int)) {
func (a *AlbumPage) Save() SavedPage {
return &savedAlbumPage{
albumID: a.albumID,
lm: a.lm,
im: a.im,
nav: a.nav,
albumID: a.albumID,
lm: a.lm,
im: a.im,
nav: a.nav,
popUpProvider: a.popUpProvider,
}
}
@@ -107,7 +121,7 @@ type AlbumPageHeader struct {
page *AlbumPage
cover *canvas.Image
cover *widgets.TappableImage
titleLabel *widget.RichText
artistLabel *widgets.CustomHyperlink
genreLabel *widgets.CustomHyperlink
@@ -122,12 +136,14 @@ type AlbumPageHeader struct {
func NewAlbumPageHeader(page *AlbumPage) *AlbumPageHeader {
a := &AlbumPageHeader{page: page}
a.ExtendBaseWidget(a)
a.cover = &canvas.Image{FillMode: canvas.ImageFillContain}
a.cover = widgets.NewTappableImage()
a.cover.FillMode = canvas.ImageFillContain
a.cover.OnTapped = a.showPopUpCover
a.cover.SetMinSize(fyne.NewSize(225, 225))
// due to cache warming we can probably immediately set the cover
// and not have to set it asynchronously in the Update function
if im, ok := page.im.GetAlbumThumbnailFromCache(page.albumID); ok {
a.cover.Image = im
a.cover.Image.Image = im
}
a.titleLabel = widget.NewRichTextWithText("")
a.titleLabel.Wrapping = fyne.TextTruncate
@@ -180,12 +196,12 @@ func (a *AlbumPageHeader) Update(album *subsonic.AlbumID3, im *backend.ImageMana
a.Refresh()
// cover image was already loaded from cache in consructor
if a.albumID == album.ID && a.cover.Image != nil {
if a.albumID == album.ID && a.cover.Image.Image != nil {
return
}
go func() {
if cover, err := im.GetAlbumThumbnail(album.ID); err == nil {
a.cover.Image = cover
a.cover.Image.Image = cover
a.cover.Refresh()
} else {
log.Printf("error fetching cover: %v", err)
@@ -201,18 +217,33 @@ func (a *AlbumPageHeader) toggleFavorited() {
}
}
func (a *AlbumPageHeader) showPopUpCover() {
cover, err := a.page.im.GetFullSizeAlbumCover(a.albumID)
if err != nil {
log.Printf("error getting full size album cover: %s", err.Error())
return
}
im := canvas.NewImageFromImage(cover)
im.FillMode = canvas.ImageFillContain
pop := a.page.popUpProvider.CreatePopUp(im)
s := a.page.popUpProvider.WindowSize()
pop.Resize(fyne.NewSize(s.Width*0.8, s.Height*0.8))
pop.ShowAtPosition(fyne.NewPos(0.1*s.Width, 0.1*s.Height))
}
func formatMiscLabelStr(a *subsonic.AlbumID3) string {
return fmt.Sprintf("%d · %d tracks · %s", a.Year, a.SongCount, util.SecondsToTimeString(float64(a.Duration)))
}
type savedAlbumPage struct {
albumID string
lm *backend.LibraryManager
im *backend.ImageManager
sm *backend.ServerManager
nav func(Route)
albumID string
lm *backend.LibraryManager
im *backend.ImageManager
sm *backend.ServerManager
popUpProvider PopUpProvider
nav func(Route)
}
func (s *savedAlbumPage) Restore() Page {
return NewAlbumPage(s.albumID, s.sm, s.lm, s.im, s.nav)
return NewAlbumPage(s.albumID, s.sm, s.lm, s.im, s.popUpProvider, s.nav)
}
+27 -6
View File
@@ -2,6 +2,9 @@ package browsing
import (
"supersonic/backend"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/widget"
)
type PageName int
@@ -57,21 +60,39 @@ type NavigationHandler interface {
}
type Router struct {
App *backend.App
Nav NavigationHandler
App *backend.App
MainWindow fyne.Window
Nav NavigationHandler
}
func NewRouter(app *backend.App, nav NavigationHandler) Router {
func NewRouter(app *backend.App, mainWindow fyne.Window, nav NavigationHandler) Router {
return Router{
App: app,
Nav: nav,
App: app,
MainWindow: mainWindow,
Nav: nav,
}
}
type popUpProvider struct {
window fyne.Window
}
func (p *popUpProvider) CreatePopUp(obj fyne.CanvasObject) *widget.PopUp {
return widget.NewPopUp(obj, p.window.Canvas())
}
func (p *popUpProvider) WindowSize() fyne.Size {
return p.window.Canvas().Size()
}
func (r Router) pop() *popUpProvider {
return &popUpProvider{window: r.MainWindow}
}
func (r Router) CreatePage(rte Route) Page {
switch rte.Page {
case Album:
return NewAlbumPage(rte.Arg, r.App.ServerManager, r.App.LibraryManager, r.App.ImageManager, r.OpenRoute)
return NewAlbumPage(rte.Arg, r.App.ServerManager, r.App.LibraryManager, r.App.ImageManager, r.pop(), r.OpenRoute)
case Albums:
return NewAlbumsPage("Albums", rte.Arg, r.App.LibraryManager, r.App.ImageManager, r.OpenRoute)
case Artist:
+1 -1
View File
@@ -42,7 +42,7 @@ func NewMainWindow(fyneApp fyne.App, appName string, app *backend.App) MainWindo
BrowsingPane: browsing.NewBrowsingPane(app),
}
m.Router = browsing.NewRouter(app, m.BrowsingPane)
m.Router = browsing.NewRouter(app, m.Window, m.BrowsingPane)
m.BottomPanel = NewBottomPanel(app.Player, m.Router.OpenRoute)
m.BottomPanel.SetPlaybackManager(app.PlaybackManager)
m.BottomPanel.ImageManager = app.ImageManager
+45
View File
@@ -0,0 +1,45 @@
package widgets
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/driver/desktop"
"fyne.io/fyne/v2/widget"
)
type TappableImage struct {
widget.BaseWidget
canvas.Image
OnTapped func()
}
func NewTappableImage() *TappableImage {
t := &TappableImage{}
t.ExtendBaseWidget(t)
return t
}
func (t *TappableImage) Cursor() desktop.Cursor {
return desktop.PointerCursor
}
func (t *TappableImage) Tapped(e *fyne.PointEvent) {
if t.OnTapped != nil {
t.OnTapped()
}
}
func (t *TappableImage) Refresh() {
t.Image.Refresh()
t.BaseWidget.Refresh()
}
func (t *TappableImage) Resize(size fyne.Size) {
t.Image.Resize(size)
t.BaseWidget.Resize(size)
}
func (t *TappableImage) CreateRenderer() fyne.WidgetRenderer {
return widget.NewSimpleRenderer(&t.Image)
}