more pooling of widgets, rename and rework a few things

This commit is contained in:
Drew Weymouth
2023-07-07 17:11:03 -07:00
parent c6c33ecfed
commit d76fc41230
10 changed files with 257 additions and 128 deletions
+38 -23
View File
@@ -25,6 +25,7 @@ type AlbumPage struct {
albumPageState
disposed bool
header *AlbumPageHeader
tracks []*mediaprovider.Track
tracklist *widgets.Tracklist
@@ -33,32 +34,32 @@ type AlbumPage struct {
}
type albumPageState struct {
albumID string
sort widgets.TracklistSort
cfg *backend.AlbumPageConfig
widgetCache *util.WidgetCache
mp mediaprovider.MediaProvider
pm *backend.PlaybackManager
im *backend.ImageManager
contr *controller.Controller
albumID string
sort widgets.TracklistSort
cfg *backend.AlbumPageConfig
pool *util.WidgetPool
mp mediaprovider.MediaProvider
pm *backend.PlaybackManager
im *backend.ImageManager
contr *controller.Controller
}
func NewAlbumPage(
albumID string,
cfg *backend.AlbumPageConfig,
cache *util.WidgetCache,
pool *util.WidgetPool,
pm *backend.PlaybackManager,
mp mediaprovider.MediaProvider,
im *backend.ImageManager,
contr *controller.Controller,
) *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(
albumID string,
cfg *backend.AlbumPageConfig,
cache *util.WidgetCache,
pool *util.WidgetPool,
pm *backend.PlaybackManager,
mp mediaprovider.MediaProvider,
im *backend.ImageManager,
@@ -67,24 +68,29 @@ func newAlbumPage(
) *AlbumPage {
a := &AlbumPage{
albumPageState: albumPageState{
albumID: albumID,
cfg: cfg,
widgetCache: cache,
pm: pm,
mp: mp,
im: im,
contr: contr,
albumID: albumID,
cfg: cfg,
pool: pool,
pm: pm,
mp: mp,
im: im,
contr: contr,
},
}
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.Clear()
} else {
a.header = NewAlbumPageHeader(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.SetSorting(sort)
a.tracklist.OnVisibleColumnsChanged = func(cols []string) {
@@ -105,9 +111,12 @@ func (a *AlbumPage) CreateRenderer() fyne.WidgetRenderer {
}
func (a *AlbumPage) Save() SavedPage {
a.disposed = true
s := a.albumPageState
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
}
@@ -144,6 +153,9 @@ func (a *AlbumPage) load() {
log.Printf("Failed to get album: %s", err.Error())
return
}
if a.disposed {
return
}
a.header.Update(album, a.im)
a.tracklist.Options = widgets.TracklistOptions{
ShowDiscNumber: album.Tracks[0].DiscNumber != album.Tracks[len(album.Tracks)-1].DiscNumber,
@@ -279,6 +291,7 @@ func (a *AlbumPageHeader) Clear() {
a.miscLabel.SetText("")
a.toggleFavButton.IsFavorited = false
a.cover.Image.Image = nil
a.cover.Refresh()
}
func (a *AlbumPageHeader) toggleFavorited() {
@@ -292,7 +305,9 @@ func (a *AlbumPageHeader) showPopUpCover() {
log.Printf("error getting full size album cover: %s", err.Error())
return
}
a.page.contr.ShowPopUpImage(cover)
if a.page != nil {
a.page.contr.ShowPopUpImage(cover)
}
}
func formatMiscLabelStr(a *mediaprovider.AlbumWithTracks) string {
@@ -308,5 +323,5 @@ func formatMiscLabelStr(a *mediaprovider.AlbumWithTracks) string {
}
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
View File
@@ -28,18 +28,19 @@ type artistPageState struct {
activeView int
trackSort widgets.TracklistSort
widgetCache *util.WidgetCache
cfg *backend.ArtistPageConfig
pm *backend.PlaybackManager
mp mediaprovider.MediaProvider
im *backend.ImageManager
contr *controller.Controller
pool *util.WidgetPool
cfg *backend.ArtistPageConfig
pm *backend.PlaybackManager
mp mediaprovider.MediaProvider
im *backend.ImageManager
contr *controller.Controller
}
type ArtistPage struct {
widget.BaseWidget
artistPageState
disposed bool
artistInfo *mediaprovider.ArtistWithAlbums
@@ -50,34 +51,34 @@ type ArtistPage struct {
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
if cfg.InitialView == "Top Tracks" {
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{
artistID: artistID,
cfg: cfg,
widgetCache: cache,
pm: pm,
mp: mp,
im: im,
contr: contr,
activeView: activeView,
trackSort: sort,
artistID: artistID,
cfg: cfg,
pool: pool,
pm: pm,
mp: mp,
im: im,
contr: contr,
activeView: activeView,
trackSort: sort,
}}
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.Clear()
} else {
a.header = NewArtistPageHeader(a)
}
a.header.artistPage = a
a.header.Clear()
if img, ok := im.GetCachedArtistImage(artistID); ok {
a.header.artistImage.SetImage(img, true /*tappable*/)
}
@@ -120,11 +121,14 @@ func (a *ArtistPage) Reload() {
}
func (a *ArtistPage) Save() SavedPage {
a.disposed = true
s := a.artistPageState
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
}
@@ -150,6 +154,9 @@ func (a *ArtistPage) load() {
log.Printf("Failed to get artist: %s", err.Error())
return
}
if a.disposed {
return
}
a.artistInfo = artist
a.header.Update(artist)
if a.activeView == 0 {
@@ -198,7 +205,17 @@ func (a *ArtistPage) showTopTracks() {
log.Printf("error getting top songs: %s", err.Error())
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.SetVisibleColumns(a.cfg.TracklistColumns)
tl.SetSorting(a.trackSort)
@@ -237,7 +254,7 @@ func (a *ArtistPage) CreateRenderer() fyne.WidgetRenderer {
}
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."
+28 -3
View File
@@ -23,11 +23,13 @@ type FavoritesPage struct {
widget.BaseWidget
cfg *backend.FavoritesPageConfig
pool *util.WidgetPool
contr *controller.Controller
pm *backend.PlaybackManager
im *backend.ImageManager
mp mediaprovider.MediaProvider
disposed bool
trackSort widgets.TracklistSort
filter mediaprovider.AlbumFilter
searchText string
@@ -45,10 +47,11 @@ type FavoritesPage struct {
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{
filter: mediaprovider.AlbumFilter{ExcludeUnfavorited: true},
cfg: cfg,
pool: pool,
contr: contr,
pm: pm,
mp: mp,
@@ -99,6 +102,7 @@ func restoreFavoritesPage(saved *savedFavoritesPage) *FavoritesPage {
a := &FavoritesPage{
cfg: saved.cfg,
contr: saved.contr,
pool: saved.pool,
pm: saved.pm,
mp: saved.mp,
im: saved.im,
@@ -154,6 +158,9 @@ func (a *FavoritesPage) Reload() {
log.Printf("error getting starred items: %s", err.Error())
return
}
if a.disposed {
return
}
if a.tracklistCtr != nil {
// refresh favorite songs view
tr := a.tracklistCtr.Objects[0].(*widgets.Tracklist)
@@ -176,9 +183,11 @@ func (a *FavoritesPage) Reload() {
}
func (a *FavoritesPage) Save() SavedPage {
a.disposed = true
sf := &savedFavoritesPage{
cfg: a.cfg,
contr: a.contr,
pool: a.pool,
pm: a.pm,
mp: a.mp,
im: a.im,
@@ -191,7 +200,9 @@ func (a *FavoritesPage) Save() SavedPage {
sf.searchGridState = a.searchGrid.SaveToState()
}
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
}
@@ -277,6 +288,9 @@ func (a *FavoritesPage) onShowFavoriteArtists() {
log.Printf("error getting starred items: %s", err.Error())
return
}
if a.disposed {
return
}
model := buildArtistGridViewModel(fav.Artists)
a.artistGrid = widgets.NewFixedGridView(model, a.im, myTheme.ArtistIcon)
a.contr.ConnectArtistGridActions(a.artistGrid)
@@ -325,7 +339,17 @@ func (a *FavoritesPage) onShowFavoriteSongs() {
log.Printf("error getting starred items: %s", err.Error())
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.SetVisibleColumns(a.cfg.TracklistColumns)
tracklist.SetSorting(a.trackSort)
@@ -355,6 +379,7 @@ func (a *FavoritesPage) CreateRenderer() fyne.WidgetRenderer {
type savedFavoritesPage struct {
cfg *backend.FavoritesPageConfig
contr *controller.Controller
pool *util.WidgetPool
pm *backend.PlaybackManager
mp mediaprovider.MediaProvider
im *backend.ImageManager
+13 -3
View File
@@ -38,6 +38,7 @@ type NowPlayingPage struct {
type nowPlayingPageState struct {
contr *controller.Controller
pool *util.WidgetPool
conf *backend.NowPlayingPageConfig
pm *backend.PlaybackManager
p *player.Player
@@ -46,18 +47,26 @@ type nowPlayingPageState struct {
func NewNowPlayingPage(
highlightedTrackID string,
contr *controller.Controller,
pool *util.WidgetPool,
conf *backend.NowPlayingPageConfig,
pm *backend.PlaybackManager,
p *player.Player, // TODO: once other player backends are supported (eg uPnP), refactor
) *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)
p.OnPaused(a.formatStatusLine)
p.OnPlaying(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.OnVisibleColumnsChanged = func(cols []string) {
a.conf.TracklistColumns = cols
@@ -90,6 +99,7 @@ func (a *NowPlayingPage) CreateRenderer() fyne.WidgetRenderer {
}
func (a *NowPlayingPage) Save() SavedPage {
a.pool.Release(util.WidgetTypeTracklist, a.tracklist)
nps := a.nowPlayingPageState
return &nps
}
@@ -207,5 +217,5 @@ func (a *NowPlayingPage) load(highlightedTrackID string) {
}
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)
}
+35 -6
View File
@@ -24,6 +24,7 @@ type PlaylistPage struct {
playlistPageState
disposed bool
header *PlaylistPageHeader
tracklist *widgets.Tracklist
tracks []*mediaprovider.Track
@@ -35,6 +36,7 @@ type playlistPageState struct {
playlistID string
conf *backend.PlaylistPageConfig
contr *controller.Controller
widgetPool *util.WidgetPool
sm *backend.ServerManager
pm *backend.PlaybackManager
im *backend.ImageManager
@@ -44,27 +46,40 @@ type playlistPageState struct {
func NewPlaylistPage(
playlistID string,
conf *backend.PlaylistPageConfig,
pool *util.WidgetPool,
contr *controller.Controller,
sm *backend.ServerManager,
pm *backend.PlaybackManager,
im *backend.ImageManager,
) *PlaylistPage {
return newPlaylistPage(playlistID, conf, contr, sm, pm, im, widgets.TracklistSort{})
return newPlaylistPage(playlistID, conf, contr, pool, sm, pm, im, widgets.TracklistSort{})
}
func newPlaylistPage(
playlistID string,
conf *backend.PlaylistPageConfig,
contr *controller.Controller,
pool *util.WidgetPool,
sm *backend.ServerManager,
pm *backend.PlaybackManager,
im *backend.ImageManager,
trackSort widgets.TracklistSort,
) *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.header = NewPlaylistPageHeader(a)
a.tracklist = widgets.NewTracklist(nil)
if h := a.widgetPool.Obtain(util.WidgetTypePlaylistPageHeader); h != 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.SetSorting(trackSort)
a.tracklist.OnVisibleColumnsChanged = func(cols []string) {
@@ -96,8 +111,11 @@ func (a *PlaylistPage) CreateRenderer() fyne.WidgetRenderer {
}
func (a *PlaylistPage) Save() SavedPage {
a.disposed = true
p := a.playlistPageState
p.trackSort = a.tracklist.Sorting()
p.widgetPool.Release(util.WidgetTypePlaylistPageHeader, a.header)
p.widgetPool.Release(util.WidgetTypeTracklist, a.tracklist)
return &p
}
@@ -134,6 +152,9 @@ func (a *PlaylistPage) load() {
log.Printf("Failed to get playlist: %s", err.Error())
return
}
if a.disposed {
return
}
renumberTracks(playlist.Tracks)
a.tracks = playlist.Tracks
a.tracklist.SetTracks(playlist.Tracks)
@@ -202,7 +223,7 @@ func (a *PlaylistPage) onRemoveSelectedFromPlaylist() {
}
a.sm.Server.EditPlaylistTracks(a.playlistID, nil, idxs)
a.tracklist.UnselectAll()
go a.Reload()
a.Reload()
}
type PlaylistPageHeader struct {
@@ -282,6 +303,14 @@ func NewPlaylistPageHeader(page *PlaylistPage) *PlaylistPageHeader {
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 {
return widget.NewSimpleRenderer(a.container)
}
@@ -327,5 +356,5 @@ func (a *PlaylistPageHeader) formatPlaylistTrackTimeStr(p *mediaprovider.Playlis
}
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
View File
@@ -12,18 +12,18 @@ type NavigationHandler interface {
}
type Router struct {
App *backend.App
Controller *controller.Controller
Nav NavigationHandler
widgetCache util.WidgetCache
App *backend.App
Controller *controller.Controller
Nav NavigationHandler
widgetPool util.WidgetPool
}
func NewRouter(app *backend.App, controller *controller.Controller, nav NavigationHandler) Router {
r := Router{
App: app,
Controller: controller,
Nav: nav,
widgetCache: util.NewWidgetCache(),
App: app,
Controller: controller,
Nav: nav,
widgetPool: util.NewWidgetPool(),
}
return r
}
@@ -31,27 +31,27 @@ func NewRouter(app *backend.App, controller *controller.Controller, nav Navigati
func (r Router) CreatePage(rte controller.Route) Page {
switch rte.Page {
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:
return NewAlbumsPage(&r.App.Config.AlbumsPage, r.Controller, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager)
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:
return NewArtistsPage(r.Controller, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager)
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:
return NewGenrePage(rte.Arg, r.Controller, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager)
case controller.Genres:
return NewGenresPage(r.Controller, r.App.ServerManager.Server)
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:
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:
return NewPlaylistsPage(r.Controller, &r.App.Config.PlaylistsPage, r.App.ServerManager.Server)
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
}
+13 -4
View File
@@ -7,6 +7,7 @@ import (
"github.com/dweymouth/supersonic/ui/controller"
"github.com/dweymouth/supersonic/ui/layouts"
"github.com/dweymouth/supersonic/ui/theme"
"github.com/dweymouth/supersonic/ui/util"
"github.com/dweymouth/supersonic/ui/widgets"
"fyne.io/fyne/v2"
@@ -34,16 +35,22 @@ type TracksPage struct {
type tracksPageState struct {
searchText string
widgetPool *util.WidgetPool
contr *controller.Controller
conf *backend.TracksPageConfig
mp mediaprovider.MediaProvider
}
func NewTracksPage(contr *controller.Controller, conf *backend.TracksPageConfig, mp mediaprovider.MediaProvider) *TracksPage {
t := &TracksPage{tracksPageState: tracksPageState{contr: contr, conf: conf, mp: mp}}
func NewTracksPage(contr *controller.Controller, conf *backend.TracksPageConfig, pool *util.WidgetPool, mp mediaprovider.MediaProvider) *TracksPage {
t := &TracksPage{tracksPageState: tracksPageState{contr: contr, conf: conf, widgetPool: pool, mp: mp}}
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{
DisableSorting: true,
AutoNumber: true,
@@ -143,12 +150,14 @@ func (t *TracksPage) CreateRenderer() fyne.WidgetRenderer {
}
func (t *TracksPage) Save() SavedPage {
t.loader.Dispose()
t.widgetPool.Release(util.WidgetTypeTracklist, t.tracklist)
state := t.tracksPageState
return &state
}
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
if t.searchText != "" {
t.searcher.Entry.Text = t.searchText
-50
View File
@@ -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(),
})
}
+60
View File
@@ -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(),
})
}
+15 -1
View File
@@ -7,6 +7,8 @@ import (
// Component that manages lazily loading more tracks into a Tracklist
// as the user scrolls near the bottom.
type TracklistLoader struct {
disposed bool
tracklist *Tracklist
iter mediaprovider.TrackIterator
@@ -28,11 +30,17 @@ func NewTracklistLoader(tracklist *Tracklist, iter mediaprovider.TrackIterator)
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) {
if tracknum > t.highestShown {
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
go t.loadMoreTracks(25)
}
@@ -52,6 +60,12 @@ func (t *TracklistLoader) loadMoreTracks(num int) {
break
}
t.trackBuffer = append(t.trackBuffer, tr)
if t.disposed {
break
}
}
if t.disposed {
return
}
t.tracklist.AppendTracks(t.trackBuffer)
t.tracklist.Refresh()