From b7af1e716c7ab99bb966d970d5e6ef6e3c42a28f Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sat, 1 Jun 2024 17:42:40 -0700 Subject: [PATCH] use radio icon for image placeholder for radio stations --- backend/imagemanager.go | 9 --------- res/bundled.go | 2 +- res/icons/remix_design/broadcast.svg | 2 +- ui/bottompanel.go | 30 ++++++++++------------------ ui/dialogs/searchdialog.go | 2 +- ui/mainwindow.go | 3 +-- ui/widgets/gridview.go | 2 +- ui/widgets/imageplaceholder.go | 8 ++++---- ui/widgets/largenowplayingcard.go | 2 ++ ui/widgets/nowplayingcard.go | 24 ++++++++++++---------- ui/widgets/playqueuelist.go | 5 +++++ 11 files changed, 40 insertions(+), 49 deletions(-) diff --git a/backend/imagemanager.go b/backend/imagemanager.go index f8102ee..e9050ce 100644 --- a/backend/imagemanager.go +++ b/backend/imagemanager.go @@ -120,15 +120,6 @@ func (i *ImageManager) GetCoverThumbnail(coverID string) (image.Image, error) { return i.fetchAndCacheCoverFromDiskOrServer(context.Background(), coverID, i.thumbnailCache.DefaultTTL, nil) } -// GetCoverThumbnailWithTTL fetches the cover for the given coverID and updates the TTL -// in the in-memory image cache. It blocks until the image fetch is complete. -func (i *ImageManager) GetCoverThumbnailWithTTL(coverID string, ttl time.Duration) (image.Image, error) { - if img, err := i.thumbnailCache.GetWithNewTTL(coverID, ttl); err == nil { - return img, nil - } - return i.fetchAndCacheCoverFromDiskOrServer(context.Background(), coverID, ttl, nil) -} - // GetFullSizeCoverArt fetches the full size cover image for the given coverID. // It blocks until the fetch is complete. func (i *ImageManager) GetFullSizeCoverArt(coverID string) (image.Image, error) { diff --git a/res/bundled.go b/res/bundled.go index 5852714..3e1b5d0 100644 --- a/res/bundled.go +++ b/res/bundled.go @@ -88,7 +88,7 @@ var ResFilterSvg = &fyne.StaticResource{ var ResBroadcastSvg = &fyne.StaticResource{ StaticName: "broadcast.svg", StaticContent: []byte( - "\n\n \n"), + "\n\n \n"), } var ResRepeatSvg = &fyne.StaticResource{ StaticName: "repeat.svg", diff --git a/res/icons/remix_design/broadcast.svg b/res/icons/remix_design/broadcast.svg index 724c40b..ab4b918 100644 --- a/res/icons/remix_design/broadcast.svg +++ b/res/icons/remix_design/broadcast.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/ui/bottompanel.go b/ui/bottompanel.go index a99de31..58387eb 100644 --- a/ui/bottompanel.go +++ b/ui/bottompanel.go @@ -1,13 +1,11 @@ package ui import ( - "image" - "time" - "github.com/dweymouth/supersonic/backend" "github.com/dweymouth/supersonic/backend/mediaprovider" "github.com/dweymouth/supersonic/ui/controller" "github.com/dweymouth/supersonic/ui/layouts" + "github.com/dweymouth/supersonic/ui/util" "github.com/dweymouth/supersonic/ui/widgets" "fyne.io/fyne/v2" @@ -18,19 +16,18 @@ import ( type BottomPanel struct { widget.BaseWidget - ImageManager *backend.ImageManager + imageLoader util.ThumbnailLoader NowPlaying *widgets.NowPlayingCard Controls *widgets.PlayerControls AuxControls *widgets.AuxControls - coverArtID string - container *fyne.Container + container *fyne.Container } var _ fyne.Widget = (*BottomPanel)(nil) -func NewBottomPanel(pm *backend.PlaybackManager, contr *controller.Controller) *BottomPanel { +func NewBottomPanel(pm *backend.PlaybackManager, im *backend.ImageManager, contr *controller.Controller) *BottomPanel { bp := &BottomPanel{} bp.ExtendBaseWidget(bp) @@ -105,6 +102,8 @@ func NewBottomPanel(pm *backend.PlaybackManager, contr *controller.Controller) * pm.SetNextLoopMode() }) + bp.imageLoader = util.NewThumbnailLoader(im, bp.NowPlaying.SetImage) + bp.container = container.New(layouts.NewLeftMiddleRightLayout(500), bp.NowPlaying, bp.Controls, bp.AuxControls) return bp @@ -112,20 +111,11 @@ func NewBottomPanel(pm *backend.PlaybackManager, contr *controller.Controller) * func (bp *BottomPanel) onSongChange(song mediaprovider.MediaItem, _ *mediaprovider.Track) { if song == nil { - bp.NowPlaying.Update(nil, nil) + bp.NowPlaying.Update(nil) + bp.imageLoader.Load("") } else { - meta := song.Metadata() - bp.coverArtID = meta.CoverArtID - var im image.Image - if bp.ImageManager != nil { - // set image to expire not long after the length of the song - // if song is played through without much pausing, image will still - // be in cache for the next song if it's from the same album, or - // if the user navigates to the album page for the track - imgTTLSec := meta.Duration + 30 - im, _ = bp.ImageManager.GetCoverThumbnailWithTTL(meta.CoverArtID, time.Duration(imgTTLSec)*time.Second) - } - bp.NowPlaying.Update(song, im) + bp.NowPlaying.Update(song) + bp.imageLoader.Load(song.Metadata().CoverArtID) } } diff --git a/ui/dialogs/searchdialog.go b/ui/dialogs/searchdialog.go index 6e140d6..8e24b5e 100644 --- a/ui/dialogs/searchdialog.go +++ b/ui/dialogs/searchdialog.go @@ -264,7 +264,7 @@ func (s *searchResult) Update(result *mediaprovider.SearchResult) { } s.id = result.ID s.contentType = result.Type - s.image.CenterIcon = placeholderIconForContentType(result.Type) + s.image.PlaceholderIcon = placeholderIconForContentType(result.Type) s.imageLoader.Load(result.CoverID) s.title.SetText(result.Name) diff --git a/ui/mainwindow.go b/ui/mainwindow.go index 7a896d5..dbc3440 100644 --- a/ui/mainwindow.go +++ b/ui/mainwindow.go @@ -84,8 +84,7 @@ func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, m.Controller.ReloadFunc = m.BrowsingPane.Reload m.Controller.CurPageFunc = m.BrowsingPane.CurrentPage - m.BottomPanel = NewBottomPanel(app.PlaybackManager, m.Controller) - m.BottomPanel.ImageManager = app.ImageManager + m.BottomPanel = NewBottomPanel(app.PlaybackManager, app.ImageManager, m.Controller) m.container = container.NewBorder(nil, m.BottomPanel, nil, nil, m.BrowsingPane) m.Window.SetContent(m.container) m.Window.Resize(size) diff --git a/ui/widgets/gridview.go b/ui/widgets/gridview.go index 8d9c8dd..5776413 100644 --- a/ui/widgets/gridview.go +++ b/ui/widgets/gridview.go @@ -321,7 +321,7 @@ func (g *GridView) doUpdateItemCard(itemIdx int, card *GridViewItem) { } card.ItemIndex = itemIdx g.itemForIndex[itemIdx] = card - card.Cover.Im.CenterIcon = g.Placeholder + card.Cover.Im.PlaceholderIcon = g.Placeholder if !card.NeedsUpdate(item) && card.ItemIndex == itemIdx { // nothing to do g.stateMutex.Unlock() diff --git a/ui/widgets/imageplaceholder.go b/ui/widgets/imageplaceholder.go index de552ae..b7bf6c0 100644 --- a/ui/widgets/imageplaceholder.go +++ b/ui/widgets/imageplaceholder.go @@ -15,8 +15,8 @@ import ( // a placeholder with a rectangular border frame // and an icon positioned in the center of the frame. type ImagePlaceholder struct { - ScaleMode canvas.ImageScale - CenterIcon fyne.Resource + ScaleMode canvas.ImageScale + PlaceholderIcon fyne.Resource widget.BaseWidget content *fyne.Container @@ -31,7 +31,7 @@ type ImagePlaceholder struct { } func NewImagePlaceholder(centerIcon fyne.Resource, minSize float32) *ImagePlaceholder { - i := &ImagePlaceholder{minSize: minSize, CenterIcon: centerIcon} + i := &ImagePlaceholder{minSize: minSize, PlaceholderIcon: centerIcon} i.ExtendBaseWidget(i) i.iconImage = canvas.NewImageFromResource(centerIcon) i.iconImage.FillMode = canvas.ImageFillContain @@ -94,7 +94,7 @@ func (i *ImagePlaceholder) MinSize() fyne.Size { func (i *ImagePlaceholder) Refresh() { i.border.Hidden = i.HaveImage() - i.iconImage.Resource = i.CenterIcon + i.iconImage.Resource = i.PlaceholderIcon i.iconImage.Hidden = i.HaveImage() i.imageDisp.Hidden = !i.HaveImage() i.imageDisp.ScaleMode = i.ScaleMode diff --git a/ui/widgets/largenowplayingcard.go b/ui/widgets/largenowplayingcard.go index 8bb304b..e558ae4 100644 --- a/ui/widgets/largenowplayingcard.go +++ b/ui/widgets/largenowplayingcard.go @@ -125,9 +125,11 @@ func (n *LargeNowPlayingCard) Update(item mediaprovider.MediaItem) { if tr, ok := item.(*mediaprovider.Track); ok { n.rating.Rating = tr.Rating n.favorite.Favorite = tr.Favorite + n.cover.PlaceholderIcon = myTheme.TracksIcon } else { n.rating.Rating = 0 n.favorite.Favorite = false + n.cover.PlaceholderIcon = myTheme.RadioIcon } n.Refresh() diff --git a/ui/widgets/nowplayingcard.go b/ui/widgets/nowplayingcard.go index e5ae046..9cf2b2b 100644 --- a/ui/widgets/nowplayingcard.go +++ b/ui/widgets/nowplayingcard.go @@ -25,7 +25,7 @@ type NowPlayingCard struct { trackName *widget.Hyperlink artistName *MultiHyperlink albumName *widget.Hyperlink - cover *TappableImage + cover *ImagePlaceholder menu *widget.PopUpMenu ratingMenu *fyne.MenuItem @@ -45,17 +45,16 @@ func NewNowPlayingCard() *NowPlayingCard { albumName: widget.NewHyperlink("", nil), } n.ExtendBaseWidget(n) - n.cover = NewTappableImage(n.onShowCoverImage) + n.cover = NewImagePlaceholder(myTheme.TracksIcon, 85) + n.cover.OnTapped = n.onShowCoverImage n.cover.OnTappedSecondary = n.showMenu + n.cover.ScaleMode = canvas.ImageScaleFastest + n.cover.Hidden = true n.trackName.Hidden = true n.albumName.Hidden = true n.albumName.Truncation = fyne.TextTruncateEllipsis n.trackName.Truncation = fyne.TextTruncateEllipsis n.trackName.TextStyle.Bold = true - n.cover.SetMinSize(fyne.NewSquareSize(85)) - n.cover.FillMode = canvas.ImageFillContain - n.cover.ScaleMode = canvas.ImageScaleFastest - n.cover.Hidden = true n.albumName.OnTapped = n.onAlbumNameTapped n.artistName.OnTapped = n.onArtistNameTapped n.trackName.OnTapped = n.onTrackNameTapped @@ -119,30 +118,35 @@ func (n *NowPlayingCard) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(c) } -func (n *NowPlayingCard) Update(track mediaprovider.MediaItem, cover image.Image) { +func (n *NowPlayingCard) Update(track mediaprovider.MediaItem) { if track == nil { n.trackName.SetText("") n.artistName.BuildSegments([]string{}, []string{}) n.albumName.SetText("") - + n.cover.Hidden = true } else { + n.cover.Hidden = false n.trackName.SetText(track.Metadata().Name) if tr, ok := track.(*mediaprovider.Track); ok { n.artistName.BuildSegments(tr.ArtistNames, tr.ArtistIDs) n.albumName.SetText(tr.Album) + n.cover.PlaceholderIcon = myTheme.TracksIcon } else { n.artistName.BuildSegments([]string{}, []string{}) n.albumName.SetText("") + n.cover.PlaceholderIcon = myTheme.RadioIcon } } n.trackName.Hidden = n.trackName.Text == "" n.artistName.Hidden = len(n.artistName.Segments) == 0 n.albumName.Hidden = n.albumName.Text == "" - n.cover.Image.Image = cover - n.cover.Hidden = cover == nil n.Refresh() } +func (n *NowPlayingCard) SetImage(cover image.Image) { + n.cover.SetImage(cover, true) +} + func (n *NowPlayingCard) showMenu(e *fyne.PointEvent) { if n.menu == nil { n.ratingMenu = util.NewRatingSubmenu(n.onSetRating) diff --git a/ui/widgets/playqueuelist.go b/ui/widgets/playqueuelist.go index a99ff4a..c2adde0 100644 --- a/ui/widgets/playqueuelist.go +++ b/ui/widgets/playqueuelist.go @@ -372,6 +372,11 @@ func (p *PlayQueueListRow) Update(tm *util.TrackListModel, rowNum int) { // a new track (*mediaprovider.Track) meta := tm.Item.Metadata() if meta.ID != p.trackID { + if meta.Type == mediaprovider.MediaItemTypeRadioStation { + p.cover.PlaceholderIcon = myTheme.RadioIcon + } else { + p.cover.PlaceholderIcon = myTheme.TracksIcon + } p.imageLoader.Load(meta.CoverArtID) p.EnsureUnfocused() p.trackID = meta.ID