make artist image displayable in pop-up
This commit is contained in:
@@ -28,22 +28,17 @@ type AlbumPage struct {
|
|||||||
tracklist *widgets.Tracklist
|
tracklist *widgets.Tracklist
|
||||||
nowPlayingID string
|
nowPlayingID string
|
||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
popUpProvider PopUpProvider
|
popUpProvider util.PopUpProvider
|
||||||
|
|
||||||
OnPlayAlbum func(string, int)
|
OnPlayAlbum func(string, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PopUpProvider interface {
|
|
||||||
CreatePopUp(fyne.CanvasObject) *widget.PopUp
|
|
||||||
WindowSize() fyne.Size
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAlbumPage(
|
func NewAlbumPage(
|
||||||
albumID string,
|
albumID string,
|
||||||
sm *backend.ServerManager,
|
sm *backend.ServerManager,
|
||||||
lm *backend.LibraryManager,
|
lm *backend.LibraryManager,
|
||||||
im *backend.ImageManager,
|
im *backend.ImageManager,
|
||||||
popUpProvider PopUpProvider,
|
popUpProvider util.PopUpProvider,
|
||||||
nav func(Route),
|
nav func(Route),
|
||||||
) *AlbumPage {
|
) *AlbumPage {
|
||||||
a := &AlbumPage{albumID: albumID, sm: sm, lm: lm, im: im, nav: nav, popUpProvider: popUpProvider}
|
a := &AlbumPage{albumID: albumID, sm: sm, lm: lm, im: im, nav: nav, popUpProvider: popUpProvider}
|
||||||
@@ -136,9 +131,8 @@ type AlbumPageHeader struct {
|
|||||||
func NewAlbumPageHeader(page *AlbumPage) *AlbumPageHeader {
|
func NewAlbumPageHeader(page *AlbumPage) *AlbumPageHeader {
|
||||||
a := &AlbumPageHeader{page: page}
|
a := &AlbumPageHeader{page: page}
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
a.cover = widgets.NewTappableImage()
|
a.cover = widgets.NewTappableImage(a.showPopUpCover)
|
||||||
a.cover.FillMode = canvas.ImageFillContain
|
a.cover.FillMode = canvas.ImageFillContain
|
||||||
a.cover.OnTapped = a.showPopUpCover
|
|
||||||
a.cover.SetMinSize(fyne.NewSize(225, 225))
|
a.cover.SetMinSize(fyne.NewSize(225, 225))
|
||||||
// due to cache warming we can probably immediately set the cover
|
// due to cache warming we can probably immediately set the cover
|
||||||
// and not have to set it asynchronously in the Update function
|
// and not have to set it asynchronously in the Update function
|
||||||
@@ -223,24 +217,7 @@ func (a *AlbumPageHeader) showPopUpCover() {
|
|||||||
log.Printf("error getting full size album cover: %s", err.Error())
|
log.Printf("error getting full size album cover: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
im := canvas.NewImageFromImage(cover)
|
util.ShowPopUpImage(cover, a.page.popUpProvider)
|
||||||
im.FillMode = canvas.ImageFillContain
|
|
||||||
pop := a.page.popUpProvider.CreatePopUp(im)
|
|
||||||
s := a.page.popUpProvider.WindowSize()
|
|
||||||
var popS fyne.Size
|
|
||||||
if asp := util.ImageAspect(cover); s.Width/s.Height > asp {
|
|
||||||
// window height is limiting factor
|
|
||||||
h := s.Height * 0.8
|
|
||||||
popS = fyne.NewSize(h*asp, h)
|
|
||||||
} else {
|
|
||||||
w := s.Width * 0.8
|
|
||||||
popS = fyne.NewSize(w, w*(1/asp))
|
|
||||||
}
|
|
||||||
pop.Resize(popS)
|
|
||||||
pop.ShowAtPosition(fyne.NewPos(
|
|
||||||
(s.Width-popS.Width)/2,
|
|
||||||
(s.Height-popS.Height)/2,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatMiscLabelStr(a *subsonic.AlbumID3) string {
|
func formatMiscLabelStr(a *subsonic.AlbumID3) string {
|
||||||
@@ -252,7 +229,7 @@ type savedAlbumPage struct {
|
|||||||
lm *backend.LibraryManager
|
lm *backend.LibraryManager
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
sm *backend.ServerManager
|
sm *backend.ServerManager
|
||||||
popUpProvider PopUpProvider
|
popUpProvider util.PopUpProvider
|
||||||
nav func(Route)
|
nav func(Route)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+31
-21
@@ -24,10 +24,12 @@ var _ fyne.Widget = (*ArtistPage)(nil)
|
|||||||
type ArtistPage struct {
|
type ArtistPage struct {
|
||||||
widget.BaseWidget
|
widget.BaseWidget
|
||||||
|
|
||||||
artistID string
|
artistID string
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
sm *backend.ServerManager
|
sm *backend.ServerManager
|
||||||
nav func(Route)
|
nav func(Route)
|
||||||
|
popUpProvider util.PopUpProvider
|
||||||
|
|
||||||
grid *widgets.AlbumGrid
|
grid *widgets.AlbumGrid
|
||||||
header *ArtistPageHeader
|
header *ArtistPageHeader
|
||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
@@ -35,15 +37,16 @@ type ArtistPage struct {
|
|||||||
OnPlayAlbum func(string, int)
|
OnPlayAlbum func(string, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArtistPage(artistID string, sm *backend.ServerManager, im *backend.ImageManager, nav func(Route)) *ArtistPage {
|
func NewArtistPage(artistID string, sm *backend.ServerManager, im *backend.ImageManager, popUp util.PopUpProvider, nav func(Route)) *ArtistPage {
|
||||||
a := &ArtistPage{
|
a := &ArtistPage{
|
||||||
artistID: artistID,
|
artistID: artistID,
|
||||||
sm: sm,
|
sm: sm,
|
||||||
im: im,
|
im: im,
|
||||||
nav: nav,
|
nav: nav,
|
||||||
|
popUpProvider: popUp,
|
||||||
}
|
}
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
a.header = NewArtistPageHeader(nav)
|
a.header = NewArtistPageHeader(a, nav)
|
||||||
a.container = container.NewBorder(
|
a.container = container.NewBorder(
|
||||||
container.New(&layouts.MaxPadLayout{PadLeft: 15, PadRight: 15, PadTop: 15, PadBottom: 10}, a.header),
|
container.New(&layouts.MaxPadLayout{PadLeft: 15, PadRight: 15, PadTop: 15, PadBottom: 10}, a.header),
|
||||||
nil, nil, nil, layout.NewSpacer())
|
nil, nil, nil, layout.NewSpacer())
|
||||||
@@ -65,10 +68,11 @@ func (a *ArtistPage) Reload() {
|
|||||||
|
|
||||||
func (a *ArtistPage) Save() SavedPage {
|
func (a *ArtistPage) Save() SavedPage {
|
||||||
return &savedArtistPage{
|
return &savedArtistPage{
|
||||||
artistID: a.artistID,
|
artistID: a.artistID,
|
||||||
sm: a.sm,
|
sm: a.sm,
|
||||||
im: a.im,
|
im: a.im,
|
||||||
nav: a.nav,
|
nav: a.nav,
|
||||||
|
popUpProvider: a.popUpProvider,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,14 +113,15 @@ func (a *ArtistPage) CreateRenderer() fyne.WidgetRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type savedArtistPage struct {
|
type savedArtistPage struct {
|
||||||
artistID string
|
artistID string
|
||||||
sm *backend.ServerManager
|
sm *backend.ServerManager
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
nav func(Route)
|
nav func(Route)
|
||||||
|
popUpProvider util.PopUpProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *savedArtistPage) Restore() Page {
|
func (s *savedArtistPage) Restore() Page {
|
||||||
return NewArtistPage(s.artistID, s.sm, s.im, s.nav)
|
return NewArtistPage(s.artistID, s.sm, s.im, s.popUpProvider, s.nav)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArtistPageHeader struct {
|
type ArtistPageHeader struct {
|
||||||
@@ -124,6 +129,7 @@ type ArtistPageHeader struct {
|
|||||||
|
|
||||||
nav func(Route)
|
nav func(Route)
|
||||||
artistID string
|
artistID string
|
||||||
|
artistPage *ArtistPage
|
||||||
artistImage *widgets.ImagePlaceholder
|
artistImage *widgets.ImagePlaceholder
|
||||||
titleDisp *widget.RichText
|
titleDisp *widget.RichText
|
||||||
biographyDisp *widget.RichText
|
biographyDisp *widget.RichText
|
||||||
@@ -131,9 +137,10 @@ type ArtistPageHeader struct {
|
|||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArtistPageHeader(nav func(Route)) *ArtistPageHeader {
|
func NewArtistPageHeader(page *ArtistPage, nav func(Route)) *ArtistPageHeader {
|
||||||
a := &ArtistPageHeader{
|
a := &ArtistPageHeader{
|
||||||
nav: nav,
|
nav: nav,
|
||||||
|
artistPage: page,
|
||||||
titleDisp: widget.NewRichTextWithText(""),
|
titleDisp: widget.NewRichTextWithText(""),
|
||||||
biographyDisp: widget.NewRichTextWithText("Artist biography not available."),
|
biographyDisp: widget.NewRichTextWithText("Artist biography not available."),
|
||||||
similarArtists: container.NewHBox(),
|
similarArtists: container.NewHBox(),
|
||||||
@@ -192,7 +199,10 @@ func (a *ArtistPageHeader) UpdateInfo(info *subsonic.ArtistInfo2) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
a.artistImage.SetImage(im)
|
a.artistImage.OnTapped = func() {
|
||||||
|
util.ShowPopUpImage(im, a.artistPage.popUpProvider)
|
||||||
|
}
|
||||||
|
a.artistImage.SetImage(im, true /*tappable*/)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-12
@@ -19,16 +19,15 @@ import (
|
|||||||
type PlaylistPage struct {
|
type PlaylistPage struct {
|
||||||
widget.BaseWidget
|
widget.BaseWidget
|
||||||
|
|
||||||
playlistID string
|
playlistID string
|
||||||
sm *backend.ServerManager
|
sm *backend.ServerManager
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
nav func(Route)
|
nav func(Route)
|
||||||
header *PlaylistPageHeader
|
header *PlaylistPageHeader
|
||||||
tracklist *widgets.Tracklist
|
tracklist *widgets.Tracklist
|
||||||
nowPlayingID string
|
nowPlayingID string
|
||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
popUpProvider PopUpProvider
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPlaylistPage(
|
func NewPlaylistPage(
|
||||||
@@ -160,13 +159,13 @@ func (a *PlaylistPageHeader) Update(playlist *subsonic.Playlist) {
|
|||||||
var haveCover bool
|
var haveCover bool
|
||||||
if playlist.CoverArt != "" {
|
if playlist.CoverArt != "" {
|
||||||
if im, err := a.page.im.GetAlbumThumbnail(playlist.CoverArt); err == nil && im != nil {
|
if im, err := a.page.im.GetAlbumThumbnail(playlist.CoverArt); err == nil && im != nil {
|
||||||
a.image.SetImage(im)
|
a.image.SetImage(im, false /*tappable*/)
|
||||||
haveCover = true
|
haveCover = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !haveCover {
|
if !haveCover {
|
||||||
if im, err := a.page.im.GetAlbumThumbnail(playlist.ID); err == nil && im != nil {
|
if im, err := a.page.im.GetAlbumThumbnail(playlist.ID); err == nil && im != nil {
|
||||||
a.image.SetImage(im)
|
a.image.SetImage(im, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
a.Refresh()
|
a.Refresh()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package browsing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"supersonic/backend"
|
"supersonic/backend"
|
||||||
|
"supersonic/ui/util"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
@@ -70,14 +71,18 @@ type Router struct {
|
|||||||
App *backend.App
|
App *backend.App
|
||||||
MainWindow fyne.Window
|
MainWindow fyne.Window
|
||||||
Nav NavigationHandler
|
Nav NavigationHandler
|
||||||
|
|
||||||
|
pop util.PopUpProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRouter(app *backend.App, mainWindow fyne.Window, nav NavigationHandler) Router {
|
func NewRouter(app *backend.App, mainWindow fyne.Window, nav NavigationHandler) Router {
|
||||||
return Router{
|
r := Router{
|
||||||
App: app,
|
App: app,
|
||||||
MainWindow: mainWindow,
|
MainWindow: mainWindow,
|
||||||
Nav: nav,
|
Nav: nav,
|
||||||
}
|
}
|
||||||
|
r.pop = &popUpProvider{window: r.MainWindow}
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
type popUpProvider struct {
|
type popUpProvider struct {
|
||||||
@@ -92,18 +97,14 @@ func (p *popUpProvider) WindowSize() fyne.Size {
|
|||||||
return p.window.Canvas().Size()
|
return p.window.Canvas().Size()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Router) pop() *popUpProvider {
|
|
||||||
return &popUpProvider{window: r.MainWindow}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r Router) CreatePage(rte Route) Page {
|
func (r Router) CreatePage(rte Route) Page {
|
||||||
switch rte.Page {
|
switch rte.Page {
|
||||||
case Album:
|
case Album:
|
||||||
return NewAlbumPage(rte.Arg, r.App.ServerManager, r.App.LibraryManager, r.App.ImageManager, r.pop(), r.OpenRoute)
|
return NewAlbumPage(rte.Arg, r.App.ServerManager, r.App.LibraryManager, r.App.ImageManager, r.pop, r.OpenRoute)
|
||||||
case Albums:
|
case Albums:
|
||||||
return NewAlbumsPage("Albums", rte.Arg, r.App.LibraryManager, r.App.ImageManager, r.OpenRoute)
|
return NewAlbumsPage("Albums", rte.Arg, r.App.LibraryManager, r.App.ImageManager, r.OpenRoute)
|
||||||
case Artist:
|
case Artist:
|
||||||
return NewArtistPage(rte.Arg, r.App.ServerManager, r.App.ImageManager, r.OpenRoute)
|
return NewArtistPage(rte.Arg, r.App.ServerManager, r.App.ImageManager, r.pop, r.OpenRoute)
|
||||||
case Artists:
|
case Artists:
|
||||||
return NewArtistsGenresPage(false, r.App.ServerManager, r.OpenRoute)
|
return NewArtistsGenresPage(false, r.App.ServerManager, r.OpenRoute)
|
||||||
case Favorites:
|
case Favorites:
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
"golang.org/x/net/html"
|
"golang.org/x/net/html"
|
||||||
)
|
)
|
||||||
@@ -26,6 +28,32 @@ func ImageAspect(im image.Image) float32 {
|
|||||||
return float32(b.Max.X-b.Min.X) / float32(b.Max.Y-b.Min.Y)
|
return float32(b.Max.X-b.Min.X) / float32(b.Max.Y-b.Min.Y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PopUpProvider interface {
|
||||||
|
CreatePopUp(fyne.CanvasObject) *widget.PopUp
|
||||||
|
WindowSize() fyne.Size
|
||||||
|
}
|
||||||
|
|
||||||
|
func ShowPopUpImage(img image.Image, popUpProvider PopUpProvider) {
|
||||||
|
im := canvas.NewImageFromImage(img)
|
||||||
|
im.FillMode = canvas.ImageFillContain
|
||||||
|
pop := popUpProvider.CreatePopUp(im)
|
||||||
|
s := popUpProvider.WindowSize()
|
||||||
|
var popS fyne.Size
|
||||||
|
if asp := ImageAspect(img); s.Width/s.Height > asp {
|
||||||
|
// window height is limiting factor
|
||||||
|
h := s.Height * 0.8
|
||||||
|
popS = fyne.NewSize(h*asp, h)
|
||||||
|
} else {
|
||||||
|
w := s.Width * 0.8
|
||||||
|
popS = fyne.NewSize(w, w*(1/asp))
|
||||||
|
}
|
||||||
|
pop.Resize(popS)
|
||||||
|
pop.ShowAtPosition(fyne.NewPos(
|
||||||
|
(s.Width-popS.Width)/2,
|
||||||
|
(s.Height-popS.Height)/2,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
func RichTextSegsFromHTMLString(s string) []widget.RichTextSegment {
|
func RichTextSegsFromHTMLString(s string) []widget.RichTextSegment {
|
||||||
tokr := html.NewTokenizer(strings.NewReader(s))
|
tokr := html.NewTokenizer(strings.NewReader(s))
|
||||||
var segs []widget.RichTextSegment
|
var segs []widget.RichTextSegment
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ type ImagePlaceholder struct {
|
|||||||
widget.BaseWidget
|
widget.BaseWidget
|
||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
minSize float32
|
minSize float32
|
||||||
|
|
||||||
|
OnTapped func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewImagePlaceholder(centerIcon fyne.Resource, minSize float32) *ImagePlaceholder {
|
func NewImagePlaceholder(centerIcon fyne.Resource, minSize float32) *ImagePlaceholder {
|
||||||
@@ -34,15 +36,36 @@ func NewImagePlaceholder(centerIcon fyne.Resource, minSize float32) *ImagePlaceh
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ImagePlaceholder) SetImage(img image.Image) {
|
type CanvasImage interface {
|
||||||
cImg := canvas.NewImageFromImage(img)
|
fyne.CanvasObject
|
||||||
cImg.FillMode = canvas.ImageFillContain
|
|
||||||
cImg.SetMinSize(fyne.NewSize(i.minSize, i.minSize))
|
SetMinSize(fyne.Size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ImagePlaceholder) SetImage(img image.Image, tappable bool) {
|
||||||
|
var cIm CanvasImage
|
||||||
|
if tappable {
|
||||||
|
cImg := NewTappableImage(i.onTapped)
|
||||||
|
cImg.Image.Image = img
|
||||||
|
cImg.FillMode = canvas.ImageFillContain
|
||||||
|
cIm = cImg
|
||||||
|
} else {
|
||||||
|
cImg := canvas.NewImageFromImage(img)
|
||||||
|
cImg.FillMode = canvas.ImageFillContain
|
||||||
|
cIm = cImg
|
||||||
|
}
|
||||||
|
cIm.SetMinSize(fyne.NewSize(i.minSize, i.minSize))
|
||||||
i.container.RemoveAll()
|
i.container.RemoveAll()
|
||||||
i.container.Add(cImg)
|
i.container.Add(cIm)
|
||||||
i.container.Refresh()
|
i.container.Refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *ImagePlaceholder) onTapped() {
|
||||||
|
if i.OnTapped != nil {
|
||||||
|
i.OnTapped()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (i *ImagePlaceholder) CreateRenderer() fyne.WidgetRenderer {
|
func (i *ImagePlaceholder) CreateRenderer() fyne.WidgetRenderer {
|
||||||
return widget.NewSimpleRenderer(i.container)
|
return widget.NewSimpleRenderer(i.container)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ type TappableImage struct {
|
|||||||
OnTapped func()
|
OnTapped func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTappableImage() *TappableImage {
|
func NewTappableImage(onTapped func()) *TappableImage {
|
||||||
t := &TappableImage{}
|
t := &TappableImage{OnTapped: onTapped}
|
||||||
t.ExtendBaseWidget(t)
|
t.ExtendBaseWidget(t)
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user