more pooling of widgets, rename and rework a few things
This commit is contained in:
+38
-23
@@ -25,6 +25,7 @@ type AlbumPage struct {
|
|||||||
|
|
||||||
albumPageState
|
albumPageState
|
||||||
|
|
||||||
|
disposed bool
|
||||||
header *AlbumPageHeader
|
header *AlbumPageHeader
|
||||||
tracks []*mediaprovider.Track
|
tracks []*mediaprovider.Track
|
||||||
tracklist *widgets.Tracklist
|
tracklist *widgets.Tracklist
|
||||||
@@ -33,32 +34,32 @@ type AlbumPage struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type albumPageState struct {
|
type albumPageState struct {
|
||||||
albumID string
|
albumID string
|
||||||
sort widgets.TracklistSort
|
sort widgets.TracklistSort
|
||||||
cfg *backend.AlbumPageConfig
|
cfg *backend.AlbumPageConfig
|
||||||
widgetCache *util.WidgetCache
|
pool *util.WidgetPool
|
||||||
mp mediaprovider.MediaProvider
|
mp mediaprovider.MediaProvider
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAlbumPage(
|
func NewAlbumPage(
|
||||||
albumID string,
|
albumID string,
|
||||||
cfg *backend.AlbumPageConfig,
|
cfg *backend.AlbumPageConfig,
|
||||||
cache *util.WidgetCache,
|
pool *util.WidgetPool,
|
||||||
pm *backend.PlaybackManager,
|
pm *backend.PlaybackManager,
|
||||||
mp mediaprovider.MediaProvider,
|
mp mediaprovider.MediaProvider,
|
||||||
im *backend.ImageManager,
|
im *backend.ImageManager,
|
||||||
contr *controller.Controller,
|
contr *controller.Controller,
|
||||||
) *AlbumPage {
|
) *AlbumPage {
|
||||||
return newAlbumPage(albumID, cfg, cache, pm, mp, im, contr, widgets.TracklistSort{})
|
return newAlbumPage(albumID, cfg, pool, pm, mp, im, contr, widgets.TracklistSort{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAlbumPage(
|
func newAlbumPage(
|
||||||
albumID string,
|
albumID string,
|
||||||
cfg *backend.AlbumPageConfig,
|
cfg *backend.AlbumPageConfig,
|
||||||
cache *util.WidgetCache,
|
pool *util.WidgetPool,
|
||||||
pm *backend.PlaybackManager,
|
pm *backend.PlaybackManager,
|
||||||
mp mediaprovider.MediaProvider,
|
mp mediaprovider.MediaProvider,
|
||||||
im *backend.ImageManager,
|
im *backend.ImageManager,
|
||||||
@@ -67,24 +68,29 @@ func newAlbumPage(
|
|||||||
) *AlbumPage {
|
) *AlbumPage {
|
||||||
a := &AlbumPage{
|
a := &AlbumPage{
|
||||||
albumPageState: albumPageState{
|
albumPageState: albumPageState{
|
||||||
albumID: albumID,
|
albumID: albumID,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
widgetCache: cache,
|
pool: pool,
|
||||||
pm: pm,
|
pm: pm,
|
||||||
mp: mp,
|
mp: mp,
|
||||||
im: im,
|
im: im,
|
||||||
contr: contr,
|
contr: contr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
if h := a.widgetCache.Obtain(util.WidgetTypeAlbumPageHeader); h != nil {
|
if h := a.pool.Obtain(util.WidgetTypeAlbumPageHeader); h != nil {
|
||||||
a.header = h.(*AlbumPageHeader)
|
a.header = h.(*AlbumPageHeader)
|
||||||
a.header.Clear()
|
a.header.Clear()
|
||||||
} else {
|
} else {
|
||||||
a.header = NewAlbumPageHeader(a)
|
a.header = NewAlbumPageHeader(a)
|
||||||
}
|
}
|
||||||
a.header.page = a
|
a.header.page = a
|
||||||
a.tracklist = widgets.NewTracklist(nil)
|
if t := a.pool.Obtain(util.WidgetTypeTracklist); t != nil {
|
||||||
|
a.tracklist = t.(*widgets.Tracklist)
|
||||||
|
a.tracklist.Reset()
|
||||||
|
} else {
|
||||||
|
a.tracklist = widgets.NewTracklist(nil)
|
||||||
|
}
|
||||||
a.tracklist.SetVisibleColumns(a.cfg.TracklistColumns)
|
a.tracklist.SetVisibleColumns(a.cfg.TracklistColumns)
|
||||||
a.tracklist.SetSorting(sort)
|
a.tracklist.SetSorting(sort)
|
||||||
a.tracklist.OnVisibleColumnsChanged = func(cols []string) {
|
a.tracklist.OnVisibleColumnsChanged = func(cols []string) {
|
||||||
@@ -105,9 +111,12 @@ func (a *AlbumPage) CreateRenderer() fyne.WidgetRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *AlbumPage) Save() SavedPage {
|
func (a *AlbumPage) Save() SavedPage {
|
||||||
|
a.disposed = true
|
||||||
s := a.albumPageState
|
s := a.albumPageState
|
||||||
s.sort = a.tracklist.Sorting()
|
s.sort = a.tracklist.Sorting()
|
||||||
a.widgetCache.Release(util.WidgetTypeAlbumPageHeader, a.header)
|
a.header.page = nil
|
||||||
|
a.pool.Release(util.WidgetTypeAlbumPageHeader, a.header)
|
||||||
|
a.pool.Release(util.WidgetTypeTracklist, a.tracklist)
|
||||||
return &s
|
return &s
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +153,9 @@ func (a *AlbumPage) load() {
|
|||||||
log.Printf("Failed to get album: %s", err.Error())
|
log.Printf("Failed to get album: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if a.disposed {
|
||||||
|
return
|
||||||
|
}
|
||||||
a.header.Update(album, a.im)
|
a.header.Update(album, a.im)
|
||||||
a.tracklist.Options = widgets.TracklistOptions{
|
a.tracklist.Options = widgets.TracklistOptions{
|
||||||
ShowDiscNumber: album.Tracks[0].DiscNumber != album.Tracks[len(album.Tracks)-1].DiscNumber,
|
ShowDiscNumber: album.Tracks[0].DiscNumber != album.Tracks[len(album.Tracks)-1].DiscNumber,
|
||||||
@@ -279,6 +291,7 @@ func (a *AlbumPageHeader) Clear() {
|
|||||||
a.miscLabel.SetText("")
|
a.miscLabel.SetText("")
|
||||||
a.toggleFavButton.IsFavorited = false
|
a.toggleFavButton.IsFavorited = false
|
||||||
a.cover.Image.Image = nil
|
a.cover.Image.Image = nil
|
||||||
|
a.cover.Refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AlbumPageHeader) toggleFavorited() {
|
func (a *AlbumPageHeader) toggleFavorited() {
|
||||||
@@ -292,7 +305,9 @@ 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
|
||||||
}
|
}
|
||||||
a.page.contr.ShowPopUpImage(cover)
|
if a.page != nil {
|
||||||
|
a.page.contr.ShowPopUpImage(cover)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatMiscLabelStr(a *mediaprovider.AlbumWithTracks) string {
|
func formatMiscLabelStr(a *mediaprovider.AlbumWithTracks) string {
|
||||||
@@ -308,5 +323,5 @@ func formatMiscLabelStr(a *mediaprovider.AlbumWithTracks) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *albumPageState) Restore() Page {
|
func (s *albumPageState) Restore() Page {
|
||||||
return newAlbumPage(s.albumID, s.cfg, s.widgetCache, s.pm, s.mp, s.im, s.contr, s.sort)
|
return newAlbumPage(s.albumID, s.cfg, s.pool, s.pm, s.mp, s.im, s.contr, s.sort)
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-24
@@ -28,18 +28,19 @@ type artistPageState struct {
|
|||||||
activeView int
|
activeView int
|
||||||
trackSort widgets.TracklistSort
|
trackSort widgets.TracklistSort
|
||||||
|
|
||||||
widgetCache *util.WidgetCache
|
pool *util.WidgetPool
|
||||||
cfg *backend.ArtistPageConfig
|
cfg *backend.ArtistPageConfig
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
mp mediaprovider.MediaProvider
|
mp mediaprovider.MediaProvider
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArtistPage struct {
|
type ArtistPage struct {
|
||||||
widget.BaseWidget
|
widget.BaseWidget
|
||||||
|
|
||||||
artistPageState
|
artistPageState
|
||||||
|
disposed bool
|
||||||
|
|
||||||
artistInfo *mediaprovider.ArtistWithAlbums
|
artistInfo *mediaprovider.ArtistWithAlbums
|
||||||
|
|
||||||
@@ -50,34 +51,34 @@ type ArtistPage struct {
|
|||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArtistPage(artistID string, cfg *backend.ArtistPageConfig, cache *util.WidgetCache, pm *backend.PlaybackManager, mp mediaprovider.MediaProvider, im *backend.ImageManager, contr *controller.Controller) *ArtistPage {
|
func NewArtistPage(artistID string, cfg *backend.ArtistPageConfig, pool *util.WidgetPool, pm *backend.PlaybackManager, mp mediaprovider.MediaProvider, im *backend.ImageManager, contr *controller.Controller) *ArtistPage {
|
||||||
activeView := 0
|
activeView := 0
|
||||||
if cfg.InitialView == "Top Tracks" {
|
if cfg.InitialView == "Top Tracks" {
|
||||||
activeView = 1
|
activeView = 1
|
||||||
}
|
}
|
||||||
return newArtistPage(artistID, cfg, cache, pm, mp, im, contr, activeView, widgets.TracklistSort{})
|
return newArtistPage(artistID, cfg, pool, pm, mp, im, contr, activeView, widgets.TracklistSort{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArtistPage(artistID string, cfg *backend.ArtistPageConfig, cache *util.WidgetCache, pm *backend.PlaybackManager, mp mediaprovider.MediaProvider, im *backend.ImageManager, contr *controller.Controller, activeView int, sort widgets.TracklistSort) *ArtistPage {
|
func newArtistPage(artistID string, cfg *backend.ArtistPageConfig, pool *util.WidgetPool, pm *backend.PlaybackManager, mp mediaprovider.MediaProvider, im *backend.ImageManager, contr *controller.Controller, activeView int, sort widgets.TracklistSort) *ArtistPage {
|
||||||
a := &ArtistPage{artistPageState: artistPageState{
|
a := &ArtistPage{artistPageState: artistPageState{
|
||||||
artistID: artistID,
|
artistID: artistID,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
widgetCache: cache,
|
pool: pool,
|
||||||
pm: pm,
|
pm: pm,
|
||||||
mp: mp,
|
mp: mp,
|
||||||
im: im,
|
im: im,
|
||||||
contr: contr,
|
contr: contr,
|
||||||
activeView: activeView,
|
activeView: activeView,
|
||||||
trackSort: sort,
|
trackSort: sort,
|
||||||
}}
|
}}
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
if h := a.widgetCache.Obtain(util.WidgetTypeArtistPageHeader); h != nil {
|
if h := a.pool.Obtain(util.WidgetTypeArtistPageHeader); h != nil {
|
||||||
a.header = h.(*ArtistPageHeader)
|
a.header = h.(*ArtistPageHeader)
|
||||||
|
a.header.Clear()
|
||||||
} else {
|
} else {
|
||||||
a.header = NewArtistPageHeader(a)
|
a.header = NewArtistPageHeader(a)
|
||||||
}
|
}
|
||||||
a.header.artistPage = a
|
a.header.artistPage = a
|
||||||
a.header.Clear()
|
|
||||||
if img, ok := im.GetCachedArtistImage(artistID); ok {
|
if img, ok := im.GetCachedArtistImage(artistID); ok {
|
||||||
a.header.artistImage.SetImage(img, true /*tappable*/)
|
a.header.artistImage.SetImage(img, true /*tappable*/)
|
||||||
}
|
}
|
||||||
@@ -120,11 +121,14 @@ func (a *ArtistPage) Reload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *ArtistPage) Save() SavedPage {
|
func (a *ArtistPage) Save() SavedPage {
|
||||||
|
a.disposed = true
|
||||||
s := a.artistPageState
|
s := a.artistPageState
|
||||||
if a.tracklistCtr != nil {
|
if a.tracklistCtr != nil {
|
||||||
s.trackSort = a.tracklistCtr.Objects[0].(*widgets.Tracklist).Sorting()
|
tl := a.tracklistCtr.Objects[0].(*widgets.Tracklist)
|
||||||
|
s.trackSort = tl.Sorting()
|
||||||
|
a.pool.Release(util.WidgetTypeTracklist, tl)
|
||||||
}
|
}
|
||||||
a.widgetCache.Release(util.WidgetTypeArtistPageHeader, a.header)
|
a.pool.Release(util.WidgetTypeArtistPageHeader, a.header)
|
||||||
return &s
|
return &s
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +154,9 @@ func (a *ArtistPage) load() {
|
|||||||
log.Printf("Failed to get artist: %s", err.Error())
|
log.Printf("Failed to get artist: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if a.disposed {
|
||||||
|
return
|
||||||
|
}
|
||||||
a.artistInfo = artist
|
a.artistInfo = artist
|
||||||
a.header.Update(artist)
|
a.header.Update(artist)
|
||||||
if a.activeView == 0 {
|
if a.activeView == 0 {
|
||||||
@@ -198,7 +205,17 @@ func (a *ArtistPage) showTopTracks() {
|
|||||||
log.Printf("error getting top songs: %s", err.Error())
|
log.Printf("error getting top songs: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tl := widgets.NewTracklist(ts)
|
if a.disposed {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var tl *widgets.Tracklist
|
||||||
|
if t := a.pool.Obtain(util.WidgetTypeTracklist); t != nil {
|
||||||
|
tl = t.(*widgets.Tracklist)
|
||||||
|
tl.Reset()
|
||||||
|
tl.SetTracks(ts)
|
||||||
|
} else {
|
||||||
|
tl = widgets.NewTracklist(ts)
|
||||||
|
}
|
||||||
tl.Options = widgets.TracklistOptions{AutoNumber: true}
|
tl.Options = widgets.TracklistOptions{AutoNumber: true}
|
||||||
tl.SetVisibleColumns(a.cfg.TracklistColumns)
|
tl.SetVisibleColumns(a.cfg.TracklistColumns)
|
||||||
tl.SetSorting(a.trackSort)
|
tl.SetSorting(a.trackSort)
|
||||||
@@ -237,7 +254,7 @@ func (a *ArtistPage) CreateRenderer() fyne.WidgetRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *artistPageState) Restore() Page {
|
func (s *artistPageState) Restore() Page {
|
||||||
return newArtistPage(s.artistID, s.cfg, s.widgetCache, s.pm, s.mp, s.im, s.contr, s.activeView, s.trackSort)
|
return newArtistPage(s.artistID, s.cfg, s.pool, s.pm, s.mp, s.im, s.contr, s.activeView, s.trackSort)
|
||||||
}
|
}
|
||||||
|
|
||||||
const artistBioNotAvailableStr = "Artist biography not available."
|
const artistBioNotAvailableStr = "Artist biography not available."
|
||||||
|
|||||||
@@ -23,11 +23,13 @@ type FavoritesPage struct {
|
|||||||
widget.BaseWidget
|
widget.BaseWidget
|
||||||
|
|
||||||
cfg *backend.FavoritesPageConfig
|
cfg *backend.FavoritesPageConfig
|
||||||
|
pool *util.WidgetPool
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
mp mediaprovider.MediaProvider
|
mp mediaprovider.MediaProvider
|
||||||
|
|
||||||
|
disposed bool
|
||||||
trackSort widgets.TracklistSort
|
trackSort widgets.TracklistSort
|
||||||
filter mediaprovider.AlbumFilter
|
filter mediaprovider.AlbumFilter
|
||||||
searchText string
|
searchText string
|
||||||
@@ -45,10 +47,11 @@ type FavoritesPage struct {
|
|||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFavoritesPage(cfg *backend.FavoritesPageConfig, contr *controller.Controller, mp mediaprovider.MediaProvider, pm *backend.PlaybackManager, im *backend.ImageManager) *FavoritesPage {
|
func NewFavoritesPage(cfg *backend.FavoritesPageConfig, pool *util.WidgetPool, contr *controller.Controller, mp mediaprovider.MediaProvider, pm *backend.PlaybackManager, im *backend.ImageManager) *FavoritesPage {
|
||||||
a := &FavoritesPage{
|
a := &FavoritesPage{
|
||||||
filter: mediaprovider.AlbumFilter{ExcludeUnfavorited: true},
|
filter: mediaprovider.AlbumFilter{ExcludeUnfavorited: true},
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
pool: pool,
|
||||||
contr: contr,
|
contr: contr,
|
||||||
pm: pm,
|
pm: pm,
|
||||||
mp: mp,
|
mp: mp,
|
||||||
@@ -99,6 +102,7 @@ func restoreFavoritesPage(saved *savedFavoritesPage) *FavoritesPage {
|
|||||||
a := &FavoritesPage{
|
a := &FavoritesPage{
|
||||||
cfg: saved.cfg,
|
cfg: saved.cfg,
|
||||||
contr: saved.contr,
|
contr: saved.contr,
|
||||||
|
pool: saved.pool,
|
||||||
pm: saved.pm,
|
pm: saved.pm,
|
||||||
mp: saved.mp,
|
mp: saved.mp,
|
||||||
im: saved.im,
|
im: saved.im,
|
||||||
@@ -154,6 +158,9 @@ func (a *FavoritesPage) Reload() {
|
|||||||
log.Printf("error getting starred items: %s", err.Error())
|
log.Printf("error getting starred items: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if a.disposed {
|
||||||
|
return
|
||||||
|
}
|
||||||
if a.tracklistCtr != nil {
|
if a.tracklistCtr != nil {
|
||||||
// refresh favorite songs view
|
// refresh favorite songs view
|
||||||
tr := a.tracklistCtr.Objects[0].(*widgets.Tracklist)
|
tr := a.tracklistCtr.Objects[0].(*widgets.Tracklist)
|
||||||
@@ -176,9 +183,11 @@ func (a *FavoritesPage) Reload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *FavoritesPage) Save() SavedPage {
|
func (a *FavoritesPage) Save() SavedPage {
|
||||||
|
a.disposed = true
|
||||||
sf := &savedFavoritesPage{
|
sf := &savedFavoritesPage{
|
||||||
cfg: a.cfg,
|
cfg: a.cfg,
|
||||||
contr: a.contr,
|
contr: a.contr,
|
||||||
|
pool: a.pool,
|
||||||
pm: a.pm,
|
pm: a.pm,
|
||||||
mp: a.mp,
|
mp: a.mp,
|
||||||
im: a.im,
|
im: a.im,
|
||||||
@@ -191,7 +200,9 @@ func (a *FavoritesPage) Save() SavedPage {
|
|||||||
sf.searchGridState = a.searchGrid.SaveToState()
|
sf.searchGridState = a.searchGrid.SaveToState()
|
||||||
}
|
}
|
||||||
if a.tracklistCtr != nil {
|
if a.tracklistCtr != nil {
|
||||||
sf.trackSort = a.tracklistCtr.Objects[0].(*widgets.Tracklist).Sorting()
|
tl := a.tracklistCtr.Objects[0].(*widgets.Tracklist)
|
||||||
|
sf.trackSort = tl.Sorting()
|
||||||
|
a.pool.Release(util.WidgetTypeTracklist, tl)
|
||||||
}
|
}
|
||||||
return sf
|
return sf
|
||||||
}
|
}
|
||||||
@@ -277,6 +288,9 @@ func (a *FavoritesPage) onShowFavoriteArtists() {
|
|||||||
log.Printf("error getting starred items: %s", err.Error())
|
log.Printf("error getting starred items: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if a.disposed {
|
||||||
|
return
|
||||||
|
}
|
||||||
model := buildArtistGridViewModel(fav.Artists)
|
model := buildArtistGridViewModel(fav.Artists)
|
||||||
a.artistGrid = widgets.NewFixedGridView(model, a.im, myTheme.ArtistIcon)
|
a.artistGrid = widgets.NewFixedGridView(model, a.im, myTheme.ArtistIcon)
|
||||||
a.contr.ConnectArtistGridActions(a.artistGrid)
|
a.contr.ConnectArtistGridActions(a.artistGrid)
|
||||||
@@ -325,7 +339,17 @@ func (a *FavoritesPage) onShowFavoriteSongs() {
|
|||||||
log.Printf("error getting starred items: %s", err.Error())
|
log.Printf("error getting starred items: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tracklist := widgets.NewTracklist(fav.Tracks)
|
if a.disposed {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var tracklist *widgets.Tracklist
|
||||||
|
if tl := a.pool.Obtain(util.WidgetTypeTracklist); tl != nil {
|
||||||
|
tracklist = tl.(*widgets.Tracklist)
|
||||||
|
tracklist.Reset()
|
||||||
|
tracklist.SetTracks(fav.Tracks)
|
||||||
|
} else {
|
||||||
|
tracklist = widgets.NewTracklist(fav.Tracks)
|
||||||
|
}
|
||||||
tracklist.Options = widgets.TracklistOptions{AutoNumber: true}
|
tracklist.Options = widgets.TracklistOptions{AutoNumber: true}
|
||||||
tracklist.SetVisibleColumns(a.cfg.TracklistColumns)
|
tracklist.SetVisibleColumns(a.cfg.TracklistColumns)
|
||||||
tracklist.SetSorting(a.trackSort)
|
tracklist.SetSorting(a.trackSort)
|
||||||
@@ -355,6 +379,7 @@ func (a *FavoritesPage) CreateRenderer() fyne.WidgetRenderer {
|
|||||||
type savedFavoritesPage struct {
|
type savedFavoritesPage struct {
|
||||||
cfg *backend.FavoritesPageConfig
|
cfg *backend.FavoritesPageConfig
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
|
pool *util.WidgetPool
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
mp mediaprovider.MediaProvider
|
mp mediaprovider.MediaProvider
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ type NowPlayingPage struct {
|
|||||||
|
|
||||||
type nowPlayingPageState struct {
|
type nowPlayingPageState struct {
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
|
pool *util.WidgetPool
|
||||||
conf *backend.NowPlayingPageConfig
|
conf *backend.NowPlayingPageConfig
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
p *player.Player
|
p *player.Player
|
||||||
@@ -46,18 +47,26 @@ type nowPlayingPageState struct {
|
|||||||
func NewNowPlayingPage(
|
func NewNowPlayingPage(
|
||||||
highlightedTrackID string,
|
highlightedTrackID string,
|
||||||
contr *controller.Controller,
|
contr *controller.Controller,
|
||||||
|
pool *util.WidgetPool,
|
||||||
conf *backend.NowPlayingPageConfig,
|
conf *backend.NowPlayingPageConfig,
|
||||||
pm *backend.PlaybackManager,
|
pm *backend.PlaybackManager,
|
||||||
p *player.Player, // TODO: once other player backends are supported (eg uPnP), refactor
|
p *player.Player, // TODO: once other player backends are supported (eg uPnP), refactor
|
||||||
) *NowPlayingPage {
|
) *NowPlayingPage {
|
||||||
a := &NowPlayingPage{nowPlayingPageState: nowPlayingPageState{contr: contr, conf: conf, pm: pm, p: p}}
|
a := &NowPlayingPage{nowPlayingPageState: nowPlayingPageState{
|
||||||
|
contr: contr, pool: pool, conf: conf, pm: pm, p: p,
|
||||||
|
}}
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
|
|
||||||
p.OnPaused(a.formatStatusLine)
|
p.OnPaused(a.formatStatusLine)
|
||||||
p.OnPlaying(a.formatStatusLine)
|
p.OnPlaying(a.formatStatusLine)
|
||||||
p.OnStopped(a.formatStatusLine)
|
p.OnStopped(a.formatStatusLine)
|
||||||
|
|
||||||
a.tracklist = widgets.NewTracklist(nil)
|
if t := a.pool.Obtain(util.WidgetTypeTracklist); t != nil {
|
||||||
|
a.tracklist = t.(*widgets.Tracklist)
|
||||||
|
a.tracklist.Reset()
|
||||||
|
} else {
|
||||||
|
a.tracklist = widgets.NewTracklist(nil)
|
||||||
|
}
|
||||||
a.tracklist.SetVisibleColumns(conf.TracklistColumns)
|
a.tracklist.SetVisibleColumns(conf.TracklistColumns)
|
||||||
a.tracklist.OnVisibleColumnsChanged = func(cols []string) {
|
a.tracklist.OnVisibleColumnsChanged = func(cols []string) {
|
||||||
a.conf.TracklistColumns = cols
|
a.conf.TracklistColumns = cols
|
||||||
@@ -90,6 +99,7 @@ func (a *NowPlayingPage) CreateRenderer() fyne.WidgetRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *NowPlayingPage) Save() SavedPage {
|
func (a *NowPlayingPage) Save() SavedPage {
|
||||||
|
a.pool.Release(util.WidgetTypeTracklist, a.tracklist)
|
||||||
nps := a.nowPlayingPageState
|
nps := a.nowPlayingPageState
|
||||||
return &nps
|
return &nps
|
||||||
}
|
}
|
||||||
@@ -207,5 +217,5 @@ func (a *NowPlayingPage) load(highlightedTrackID string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *nowPlayingPageState) Restore() Page {
|
func (s *nowPlayingPageState) Restore() Page {
|
||||||
return NewNowPlayingPage("", s.contr, s.conf, s.pm, s.p)
|
return NewNowPlayingPage("", s.contr, s.pool, s.conf, s.pm, s.p)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ type PlaylistPage struct {
|
|||||||
|
|
||||||
playlistPageState
|
playlistPageState
|
||||||
|
|
||||||
|
disposed bool
|
||||||
header *PlaylistPageHeader
|
header *PlaylistPageHeader
|
||||||
tracklist *widgets.Tracklist
|
tracklist *widgets.Tracklist
|
||||||
tracks []*mediaprovider.Track
|
tracks []*mediaprovider.Track
|
||||||
@@ -35,6 +36,7 @@ type playlistPageState struct {
|
|||||||
playlistID string
|
playlistID string
|
||||||
conf *backend.PlaylistPageConfig
|
conf *backend.PlaylistPageConfig
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
|
widgetPool *util.WidgetPool
|
||||||
sm *backend.ServerManager
|
sm *backend.ServerManager
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
@@ -44,27 +46,40 @@ type playlistPageState struct {
|
|||||||
func NewPlaylistPage(
|
func NewPlaylistPage(
|
||||||
playlistID string,
|
playlistID string,
|
||||||
conf *backend.PlaylistPageConfig,
|
conf *backend.PlaylistPageConfig,
|
||||||
|
pool *util.WidgetPool,
|
||||||
contr *controller.Controller,
|
contr *controller.Controller,
|
||||||
sm *backend.ServerManager,
|
sm *backend.ServerManager,
|
||||||
pm *backend.PlaybackManager,
|
pm *backend.PlaybackManager,
|
||||||
im *backend.ImageManager,
|
im *backend.ImageManager,
|
||||||
) *PlaylistPage {
|
) *PlaylistPage {
|
||||||
return newPlaylistPage(playlistID, conf, contr, sm, pm, im, widgets.TracklistSort{})
|
return newPlaylistPage(playlistID, conf, contr, pool, sm, pm, im, widgets.TracklistSort{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPlaylistPage(
|
func newPlaylistPage(
|
||||||
playlistID string,
|
playlistID string,
|
||||||
conf *backend.PlaylistPageConfig,
|
conf *backend.PlaylistPageConfig,
|
||||||
contr *controller.Controller,
|
contr *controller.Controller,
|
||||||
|
pool *util.WidgetPool,
|
||||||
sm *backend.ServerManager,
|
sm *backend.ServerManager,
|
||||||
pm *backend.PlaybackManager,
|
pm *backend.PlaybackManager,
|
||||||
im *backend.ImageManager,
|
im *backend.ImageManager,
|
||||||
trackSort widgets.TracklistSort,
|
trackSort widgets.TracklistSort,
|
||||||
) *PlaylistPage {
|
) *PlaylistPage {
|
||||||
a := &PlaylistPage{playlistPageState: playlistPageState{playlistID: playlistID, conf: conf, contr: contr, sm: sm, pm: pm, im: im}}
|
a := &PlaylistPage{playlistPageState: playlistPageState{playlistID: playlistID, conf: conf, contr: contr, widgetPool: pool, sm: sm, pm: pm, im: im}}
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
a.header = NewPlaylistPageHeader(a)
|
if h := a.widgetPool.Obtain(util.WidgetTypePlaylistPageHeader); h != nil {
|
||||||
a.tracklist = widgets.NewTracklist(nil)
|
a.header = h.(*PlaylistPageHeader)
|
||||||
|
a.header.Clear()
|
||||||
|
} else {
|
||||||
|
a.header = NewPlaylistPageHeader(a)
|
||||||
|
}
|
||||||
|
a.header.page = a
|
||||||
|
if tl := a.widgetPool.Obtain(util.WidgetTypeTracklist); tl != nil {
|
||||||
|
a.tracklist = tl.(*widgets.Tracklist)
|
||||||
|
a.tracklist.Reset()
|
||||||
|
} else {
|
||||||
|
a.tracklist = widgets.NewTracklist(nil)
|
||||||
|
}
|
||||||
a.tracklist.SetVisibleColumns(conf.TracklistColumns)
|
a.tracklist.SetVisibleColumns(conf.TracklistColumns)
|
||||||
a.tracklist.SetSorting(trackSort)
|
a.tracklist.SetSorting(trackSort)
|
||||||
a.tracklist.OnVisibleColumnsChanged = func(cols []string) {
|
a.tracklist.OnVisibleColumnsChanged = func(cols []string) {
|
||||||
@@ -96,8 +111,11 @@ func (a *PlaylistPage) CreateRenderer() fyne.WidgetRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *PlaylistPage) Save() SavedPage {
|
func (a *PlaylistPage) Save() SavedPage {
|
||||||
|
a.disposed = true
|
||||||
p := a.playlistPageState
|
p := a.playlistPageState
|
||||||
p.trackSort = a.tracklist.Sorting()
|
p.trackSort = a.tracklist.Sorting()
|
||||||
|
p.widgetPool.Release(util.WidgetTypePlaylistPageHeader, a.header)
|
||||||
|
p.widgetPool.Release(util.WidgetTypeTracklist, a.tracklist)
|
||||||
return &p
|
return &p
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +152,9 @@ func (a *PlaylistPage) load() {
|
|||||||
log.Printf("Failed to get playlist: %s", err.Error())
|
log.Printf("Failed to get playlist: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if a.disposed {
|
||||||
|
return
|
||||||
|
}
|
||||||
renumberTracks(playlist.Tracks)
|
renumberTracks(playlist.Tracks)
|
||||||
a.tracks = playlist.Tracks
|
a.tracks = playlist.Tracks
|
||||||
a.tracklist.SetTracks(playlist.Tracks)
|
a.tracklist.SetTracks(playlist.Tracks)
|
||||||
@@ -202,7 +223,7 @@ func (a *PlaylistPage) onRemoveSelectedFromPlaylist() {
|
|||||||
}
|
}
|
||||||
a.sm.Server.EditPlaylistTracks(a.playlistID, nil, idxs)
|
a.sm.Server.EditPlaylistTracks(a.playlistID, nil, idxs)
|
||||||
a.tracklist.UnselectAll()
|
a.tracklist.UnselectAll()
|
||||||
go a.Reload()
|
a.Reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlaylistPageHeader struct {
|
type PlaylistPageHeader struct {
|
||||||
@@ -282,6 +303,14 @@ func NewPlaylistPageHeader(page *PlaylistPage) *PlaylistPageHeader {
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *PlaylistPageHeader) Clear() {
|
||||||
|
a.titleLabel.Segments[0].(*widget.TextSegment).Text = ""
|
||||||
|
a.createdAtLabel.Text = ""
|
||||||
|
a.descriptionLabel.Text = ""
|
||||||
|
a.ownerLabel.Text = ""
|
||||||
|
a.image.SetImage(nil, false)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *PlaylistPageHeader) CreateRenderer() fyne.WidgetRenderer {
|
func (a *PlaylistPageHeader) CreateRenderer() fyne.WidgetRenderer {
|
||||||
return widget.NewSimpleRenderer(a.container)
|
return widget.NewSimpleRenderer(a.container)
|
||||||
}
|
}
|
||||||
@@ -327,5 +356,5 @@ func (a *PlaylistPageHeader) formatPlaylistTrackTimeStr(p *mediaprovider.Playlis
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *playlistPageState) Restore() Page {
|
func (s *playlistPageState) Restore() Page {
|
||||||
return newPlaylistPage(s.playlistID, s.conf, s.contr, s.sm, s.pm, s.im, s.trackSort)
|
return newPlaylistPage(s.playlistID, s.conf, s.contr, s.widgetPool, s.sm, s.pm, s.im, s.trackSort)
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-14
@@ -12,18 +12,18 @@ type NavigationHandler interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Router struct {
|
type Router struct {
|
||||||
App *backend.App
|
App *backend.App
|
||||||
Controller *controller.Controller
|
Controller *controller.Controller
|
||||||
Nav NavigationHandler
|
Nav NavigationHandler
|
||||||
widgetCache util.WidgetCache
|
widgetPool util.WidgetPool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRouter(app *backend.App, controller *controller.Controller, nav NavigationHandler) Router {
|
func NewRouter(app *backend.App, controller *controller.Controller, nav NavigationHandler) Router {
|
||||||
r := Router{
|
r := Router{
|
||||||
App: app,
|
App: app,
|
||||||
Controller: controller,
|
Controller: controller,
|
||||||
Nav: nav,
|
Nav: nav,
|
||||||
widgetCache: util.NewWidgetCache(),
|
widgetPool: util.NewWidgetPool(),
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
@@ -31,27 +31,27 @@ func NewRouter(app *backend.App, controller *controller.Controller, nav Navigati
|
|||||||
func (r Router) CreatePage(rte controller.Route) Page {
|
func (r Router) CreatePage(rte controller.Route) Page {
|
||||||
switch rte.Page {
|
switch rte.Page {
|
||||||
case controller.Album:
|
case controller.Album:
|
||||||
return NewAlbumPage(rte.Arg, &r.App.Config.AlbumPage, &r.widgetCache, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager, r.Controller)
|
return NewAlbumPage(rte.Arg, &r.App.Config.AlbumPage, &r.widgetPool, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager, r.Controller)
|
||||||
case controller.Albums:
|
case controller.Albums:
|
||||||
return NewAlbumsPage(&r.App.Config.AlbumsPage, r.Controller, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager)
|
return NewAlbumsPage(&r.App.Config.AlbumsPage, r.Controller, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager)
|
||||||
case controller.Artist:
|
case controller.Artist:
|
||||||
return NewArtistPage(rte.Arg, &r.App.Config.ArtistPage, &r.widgetCache, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager, r.Controller)
|
return NewArtistPage(rte.Arg, &r.App.Config.ArtistPage, &r.widgetPool, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager, r.Controller)
|
||||||
case controller.Artists:
|
case controller.Artists:
|
||||||
return NewArtistsPage(r.Controller, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager)
|
return NewArtistsPage(r.Controller, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager)
|
||||||
case controller.Favorites:
|
case controller.Favorites:
|
||||||
return NewFavoritesPage(&r.App.Config.FavoritesPage, r.Controller, r.App.ServerManager.Server, r.App.PlaybackManager, r.App.ImageManager)
|
return NewFavoritesPage(&r.App.Config.FavoritesPage, &r.widgetPool, r.Controller, r.App.ServerManager.Server, r.App.PlaybackManager, r.App.ImageManager)
|
||||||
case controller.Genre:
|
case controller.Genre:
|
||||||
return NewGenrePage(rte.Arg, r.Controller, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager)
|
return NewGenrePage(rte.Arg, r.Controller, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager)
|
||||||
case controller.Genres:
|
case controller.Genres:
|
||||||
return NewGenresPage(r.Controller, r.App.ServerManager.Server)
|
return NewGenresPage(r.Controller, r.App.ServerManager.Server)
|
||||||
case controller.NowPlaying:
|
case controller.NowPlaying:
|
||||||
return NewNowPlayingPage(rte.Arg, r.Controller, &r.App.Config.NowPlayingPage, r.App.PlaybackManager, r.App.Player)
|
return NewNowPlayingPage(rte.Arg, r.Controller, &r.widgetPool, &r.App.Config.NowPlayingPage, r.App.PlaybackManager, r.App.Player)
|
||||||
case controller.Playlist:
|
case controller.Playlist:
|
||||||
return NewPlaylistPage(rte.Arg, &r.App.Config.PlaylistPage, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager)
|
return NewPlaylistPage(rte.Arg, &r.App.Config.PlaylistPage, &r.widgetPool, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager)
|
||||||
case controller.Playlists:
|
case controller.Playlists:
|
||||||
return NewPlaylistsPage(r.Controller, &r.App.Config.PlaylistsPage, r.App.ServerManager.Server)
|
return NewPlaylistsPage(r.Controller, &r.App.Config.PlaylistsPage, r.App.ServerManager.Server)
|
||||||
case controller.Tracks:
|
case controller.Tracks:
|
||||||
return NewTracksPage(r.Controller, &r.App.Config.TracksPage, r.App.ServerManager.Server)
|
return NewTracksPage(r.Controller, &r.App.Config.TracksPage, &r.widgetPool, r.App.ServerManager.Server)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/dweymouth/supersonic/ui/controller"
|
"github.com/dweymouth/supersonic/ui/controller"
|
||||||
"github.com/dweymouth/supersonic/ui/layouts"
|
"github.com/dweymouth/supersonic/ui/layouts"
|
||||||
"github.com/dweymouth/supersonic/ui/theme"
|
"github.com/dweymouth/supersonic/ui/theme"
|
||||||
|
"github.com/dweymouth/supersonic/ui/util"
|
||||||
"github.com/dweymouth/supersonic/ui/widgets"
|
"github.com/dweymouth/supersonic/ui/widgets"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
@@ -34,16 +35,22 @@ type TracksPage struct {
|
|||||||
|
|
||||||
type tracksPageState struct {
|
type tracksPageState struct {
|
||||||
searchText string
|
searchText string
|
||||||
|
widgetPool *util.WidgetPool
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
conf *backend.TracksPageConfig
|
conf *backend.TracksPageConfig
|
||||||
mp mediaprovider.MediaProvider
|
mp mediaprovider.MediaProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTracksPage(contr *controller.Controller, conf *backend.TracksPageConfig, mp mediaprovider.MediaProvider) *TracksPage {
|
func NewTracksPage(contr *controller.Controller, conf *backend.TracksPageConfig, pool *util.WidgetPool, mp mediaprovider.MediaProvider) *TracksPage {
|
||||||
t := &TracksPage{tracksPageState: tracksPageState{contr: contr, conf: conf, mp: mp}}
|
t := &TracksPage{tracksPageState: tracksPageState{contr: contr, conf: conf, widgetPool: pool, mp: mp}}
|
||||||
t.ExtendBaseWidget(t)
|
t.ExtendBaseWidget(t)
|
||||||
|
|
||||||
t.tracklist = widgets.NewTracklist(nil)
|
if tl := t.widgetPool.Obtain(util.WidgetTypeTracklist); tl != nil {
|
||||||
|
t.tracklist = tl.(*widgets.Tracklist)
|
||||||
|
t.tracklist.Reset()
|
||||||
|
} else {
|
||||||
|
t.tracklist = widgets.NewTracklist(nil)
|
||||||
|
}
|
||||||
t.tracklist.Options = widgets.TracklistOptions{
|
t.tracklist.Options = widgets.TracklistOptions{
|
||||||
DisableSorting: true,
|
DisableSorting: true,
|
||||||
AutoNumber: true,
|
AutoNumber: true,
|
||||||
@@ -143,12 +150,14 @@ func (t *TracksPage) CreateRenderer() fyne.WidgetRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TracksPage) Save() SavedPage {
|
func (t *TracksPage) Save() SavedPage {
|
||||||
|
t.loader.Dispose()
|
||||||
|
t.widgetPool.Release(util.WidgetTypeTracklist, t.tracklist)
|
||||||
state := t.tracksPageState
|
state := t.tracksPageState
|
||||||
return &state
|
return &state
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *tracksPageState) Restore() Page {
|
func (s *tracksPageState) Restore() Page {
|
||||||
t := NewTracksPage(s.contr, s.conf, s.mp)
|
t := NewTracksPage(s.contr, s.conf, s.widgetPool, s.mp)
|
||||||
t.searchText = s.searchText
|
t.searchText = s.searchText
|
||||||
if t.searchText != "" {
|
if t.searchText != "" {
|
||||||
t.searcher.Entry.Text = t.searchText
|
t.searcher.Entry.Text = t.searchText
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
type WidgetType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
WidgetTypeAlbumPageHeader WidgetType = "AlbumPageHeader"
|
|
||||||
WidgetTypeArtistPageHeader WidgetType = "ArtistPageHeader"
|
|
||||||
)
|
|
||||||
|
|
||||||
type WidgetCache struct {
|
|
||||||
cache map[WidgetType][]cachedWidget
|
|
||||||
}
|
|
||||||
|
|
||||||
type cachedWidget struct {
|
|
||||||
widget fyne.CanvasObject
|
|
||||||
releasedAt int64 // unixMillis
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewWidgetCache() WidgetCache {
|
|
||||||
return WidgetCache{
|
|
||||||
cache: make(map[WidgetType][]cachedWidget),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WidgetCache) Obtain(typ WidgetType) fyne.CanvasObject {
|
|
||||||
var widget fyne.CanvasObject
|
|
||||||
if ws, ok := w.cache[typ]; ok && len(ws) > 0 {
|
|
||||||
i := len(ws) - 1
|
|
||||||
widget = ws[i].widget
|
|
||||||
ws[i].widget = nil
|
|
||||||
w.cache[typ] = ws[:i]
|
|
||||||
}
|
|
||||||
return widget
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WidgetCache) Release(typ WidgetType, wid fyne.CanvasObject) {
|
|
||||||
if _, ok := w.cache[typ]; !ok {
|
|
||||||
w.cache[typ] = make([]cachedWidget, 0)
|
|
||||||
}
|
|
||||||
w.cache[typ] = append(w.cache[typ], cachedWidget{
|
|
||||||
widget: wid,
|
|
||||||
releasedAt: time.Now().UnixMilli(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WidgetType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
WidgetTypeAlbumPageHeader WidgetType = iota
|
||||||
|
WidgetTypeArtistPageHeader
|
||||||
|
WidgetTypePlaylistPageHeader
|
||||||
|
WidgetTypeTracklist
|
||||||
|
)
|
||||||
|
|
||||||
|
// A pool to share commonly-used widgets across pages to reduce
|
||||||
|
// creation of new widgets and memory allocations.
|
||||||
|
// It is not thread-safe, which is fine for its current use.
|
||||||
|
type WidgetPool struct {
|
||||||
|
cache map[WidgetType][]cachedWidget
|
||||||
|
}
|
||||||
|
|
||||||
|
type cachedWidget struct {
|
||||||
|
widget fyne.CanvasObject
|
||||||
|
releasedAt int64 // unixMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWidgetPool() WidgetPool {
|
||||||
|
return WidgetPool{
|
||||||
|
cache: make(map[WidgetType][]cachedWidget),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtain obtains a widget of the given type from the pool, if one exists.
|
||||||
|
// Returns nil if there is no available widget.
|
||||||
|
func (w *WidgetPool) Obtain(typ WidgetType) fyne.CanvasObject {
|
||||||
|
var widget fyne.CanvasObject
|
||||||
|
if ws, ok := w.cache[typ]; ok && len(ws) > 0 {
|
||||||
|
i := len(ws) - 1
|
||||||
|
widget = ws[i].widget
|
||||||
|
ws[i].widget = nil
|
||||||
|
w.cache[typ] = ws[:i]
|
||||||
|
}
|
||||||
|
return widget
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release releases a widget into the pool.
|
||||||
|
// The widget must not be modified by the releaser after release,
|
||||||
|
// since it may be Obtained for a new use at any time.
|
||||||
|
func (w *WidgetPool) Release(typ WidgetType, wid fyne.CanvasObject) {
|
||||||
|
if _, ok := w.cache[typ]; !ok {
|
||||||
|
w.cache[typ] = make([]cachedWidget, 0)
|
||||||
|
}
|
||||||
|
w.cache[typ] = append(w.cache[typ], cachedWidget{
|
||||||
|
widget: wid,
|
||||||
|
releasedAt: time.Now().UnixMilli(),
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
// Component that manages lazily loading more tracks into a Tracklist
|
// Component that manages lazily loading more tracks into a Tracklist
|
||||||
// as the user scrolls near the bottom.
|
// as the user scrolls near the bottom.
|
||||||
type TracklistLoader struct {
|
type TracklistLoader struct {
|
||||||
|
disposed bool
|
||||||
|
|
||||||
tracklist *Tracklist
|
tracklist *Tracklist
|
||||||
iter mediaprovider.TrackIterator
|
iter mediaprovider.TrackIterator
|
||||||
|
|
||||||
@@ -28,11 +30,17 @@ func NewTracklistLoader(tracklist *Tracklist, iter mediaprovider.TrackIterator)
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancels all asynchronous loads so that they will no longer modify the tracklist.
|
||||||
|
func (t *TracklistLoader) Dispose() {
|
||||||
|
t.disposed = true
|
||||||
|
t.tracklist.OnTrackShown = nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *TracklistLoader) onTrackShown(tracknum int) {
|
func (t *TracklistLoader) onTrackShown(tracknum int) {
|
||||||
if tracknum > t.highestShown {
|
if tracknum > t.highestShown {
|
||||||
t.highestShown = tracknum
|
t.highestShown = tracknum
|
||||||
}
|
}
|
||||||
if t.highestShown >= t.len-25 && !t.fetching && !t.done {
|
if t.highestShown >= t.len-25 && !t.fetching && !t.done && !t.disposed {
|
||||||
t.fetching = true
|
t.fetching = true
|
||||||
go t.loadMoreTracks(25)
|
go t.loadMoreTracks(25)
|
||||||
}
|
}
|
||||||
@@ -52,6 +60,12 @@ func (t *TracklistLoader) loadMoreTracks(num int) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
t.trackBuffer = append(t.trackBuffer, tr)
|
t.trackBuffer = append(t.trackBuffer, tr)
|
||||||
|
if t.disposed {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if t.disposed {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
t.tracklist.AppendTracks(t.trackBuffer)
|
t.tracklist.AppendTracks(t.trackBuffer)
|
||||||
t.tracklist.Refresh()
|
t.tracklist.Refresh()
|
||||||
|
|||||||
Reference in New Issue
Block a user