From 78050f8b43ab22f94b6e14da26e73e3506df2edf Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sat, 17 Dec 2022 18:12:37 -0800 Subject: [PATCH] fix race condition with async image fetches --- ui/albumcard.go | 9 ++++++++- ui/albumgrid.go | 33 ++++++++++++++++++++++++++------- ui/nowplayingcard.go | 2 +- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/ui/albumcard.go b/ui/albumcard.go index 65b8397..4609111 100644 --- a/ui/albumcard.go +++ b/ui/albumcard.go @@ -1,6 +1,7 @@ package ui import ( + "context" "image" "log" @@ -39,9 +40,15 @@ type AlbumCard struct { albumID string title *widget.Label artist *widget.Label - Cover *TappableImage container *fyne.Container + // updated by AlbumGrid + Cover *TappableImage + + // these fields are used by AlbumGrid to track async update tasks + PrevAlbumID string + ImgLoadCancel context.CancelFunc + OnTapped func() } diff --git a/ui/albumgrid.go b/ui/albumgrid.go index 3f11eb5..23cd7ec 100644 --- a/ui/albumgrid.go +++ b/ui/albumgrid.go @@ -1,6 +1,7 @@ package ui import ( + "context" "gomuse/backend" "fyne.io/fyne/v2" @@ -41,15 +42,33 @@ func NewAlbumGrid(iter backend.AlbumIterator, pm *backend.PlaybackManager, im *b // update func func(itemID int, obj fyne.CanvasObject) { ac := obj.(*AlbumCard) - ac.Update(ag.albums[itemID]) + album := ag.albums[itemID] + if ac.PrevAlbumID == album.ID { + // nothing to do + return + } + ac.Update(album) + ac.PrevAlbumID = album.ID // TODO: set image to a placeholder before spinning off async fetch - go func() { - i, err := im.GetAlbumThumbnail(ag.albums[itemID].ID) - if err == nil { - ac.Cover.SetImage(i) - ac.Refresh() + // cancel any previous image fetch + if ac.ImgLoadCancel != nil { + ac.ImgLoadCancel() + ac.ImgLoadCancel = nil + } + ctx, cancel := context.WithCancel(context.Background()) + go func(ctx context.Context) { + i, err := im.GetAlbumThumbnail(album.ID) + select { + case <-ctx.Done(): + return + default: + if err == nil { + ac.Cover.SetImage(i) + ac.Refresh() + } } - }() + }(ctx) + ac.ImgLoadCancel = cancel // TODO: remove magic number 10 if !ag.done && !ag.fetching && itemID > len(ag.albums)-10 { diff --git a/ui/nowplayingcard.go b/ui/nowplayingcard.go index 5e17d56..2d4d585 100644 --- a/ui/nowplayingcard.go +++ b/ui/nowplayingcard.go @@ -37,7 +37,7 @@ func NewNowPlayingCard() *NowPlayingCard { n.cover.SetMinSize(fyne.NewSize(100, 100)) n.cover.FillMode = canvas.ImageFillContain - n.c = container.NewBorder(nil, nil, n.cover, nil, container.New(&layout.VboxCustomPadding{-10}, n.trackName, n.artistName, n.albumName)) + n.c = container.NewBorder(nil, nil, n.cover, nil, container.New(&layout.VboxCustomPadding{ExtraPad: -10}, n.trackName, n.artistName, n.albumName)) return n }