Merge pull request #162 from dweymouth/feature/albumviewfilter

Add album filters (excl. genre filter for now) to album grid views
This commit is contained in:
Drew Weymouth
2023-05-12 19:32:15 -07:00
committed by GitHub
16 changed files with 407 additions and 140 deletions
+26 -16
View File
@@ -27,7 +27,9 @@ type AlbumsPage struct {
grid *widgets.GridView
searchGrid *widgets.GridView
searcher *widgets.SearchEntry
filterBtn *widgets.AlbumFilterButton
searchText string
filter backend.AlbumFilter
titleDisp *widget.RichText
sortOrder *selectWidget
container *fyne.Container
@@ -71,16 +73,23 @@ func NewAlbumsPage(cfg *backend.AlbumsPageConfig, contr *controller.Controller,
cfg.SortOrder = string(backend.AlbumSortRecentlyAdded)
}
a.sortOrder.Selected = cfg.SortOrder
iter := lm.AlbumsIter(backend.AlbumSortOrder(a.sortOrder.Selected))
iter := lm.AlbumsIter(backend.AlbumSortOrder(a.sortOrder.Selected), a.filter)
a.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), im)
contr.ConnectAlbumGridActions(a.grid)
a.searcher = widgets.NewSearchEntry()
a.searcher.OnSearched = a.OnSearched
a.createSearchAndFilter()
a.createContainer(false)
return a
}
func (a *AlbumsPage) createSearchAndFilter() {
a.searcher = widgets.NewSearchEntry()
a.searcher.Text = a.searchText
a.searcher.OnSearched = a.OnSearched
a.filterBtn = widgets.NewAlbumFilterButton(&a.filter)
a.filterBtn.OnChanged = a.Reload
}
func (a *AlbumsPage) createContainer(searchgrid bool) {
searchVbox := container.NewVBox(layout.NewSpacer(), a.searcher, layout.NewSpacer())
sortVbox := container.NewVBox(layout.NewSpacer(), a.sortOrder, layout.NewSpacer())
@@ -89,7 +98,7 @@ func (a *AlbumsPage) createContainer(searchgrid bool) {
g = a.searchGrid
}
a.container = container.NewBorder(
container.NewHBox(util.NewHSpace(6), a.titleDisp, sortVbox, layout.NewSpacer(), searchVbox, util.NewHSpace(12)),
container.NewHBox(util.NewHSpace(6), a.titleDisp, sortVbox, layout.NewSpacer(), container.NewCenter(a.filterBtn), searchVbox, util.NewHSpace(12)),
nil,
nil,
nil,
@@ -99,11 +108,13 @@ func (a *AlbumsPage) createContainer(searchgrid bool) {
func restoreAlbumsPage(saved *savedAlbumsPage) *AlbumsPage {
a := &AlbumsPage{
cfg: saved.cfg,
contr: saved.contr,
pm: saved.pm,
lm: saved.lm,
im: saved.im,
cfg: saved.cfg,
contr: saved.contr,
pm: saved.pm,
lm: saved.lm,
im: saved.im,
searchText: saved.searchText,
filter: saved.filter,
}
a.ExtendBaseWidget(a)
@@ -115,13 +126,10 @@ func restoreAlbumsPage(saved *savedAlbumsPage) *AlbumsPage {
a.sortOrder.Selected = saved.sortOrder
a.sortOrder.OnChanged = a.onSortOrderChanged
a.grid = widgets.NewGridViewFromState(saved.gridState)
a.searcher = widgets.NewSearchEntry()
a.searcher.OnSearched = a.OnSearched
a.searcher.Entry.Text = saved.searchText
a.searchText = saved.searchText
if a.searchText != "" {
a.searchGrid = widgets.NewGridViewFromState(saved.searchGridState)
}
a.createSearchAndFilter()
a.createContainer(saved.searchText != "")
return a
@@ -154,7 +162,7 @@ func (a *AlbumsPage) Reload() {
if a.searchText != "" {
a.doSearch(a.searchText)
} else {
iter := a.lm.AlbumsIter(backend.AlbumSortOrder(a.sortOrder.Selected))
iter := a.lm.AlbumsIter(backend.AlbumSortOrder(a.sortOrder.Selected), a.filter)
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
a.grid.Refresh()
}
@@ -168,6 +176,7 @@ func (a *AlbumsPage) Save() SavedPage {
lm: a.lm,
im: a.im,
searchText: a.searchText,
filter: a.filter,
sortOrder: a.sortOrder.Selected,
gridState: a.grid.SaveToState(),
}
@@ -182,7 +191,7 @@ func (a *AlbumsPage) doSearch(query string) {
a.searchGrid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(a.lm.SearchIter(query)), a.im)
a.contr.ConnectAlbumGridActions(a.searchGrid)
} else {
a.searchGrid.Reset(widgets.NewGridViewAlbumIterator(a.lm.SearchIter(query)))
a.searchGrid.Reset(widgets.NewGridViewAlbumIterator(a.lm.SearchIterWithFilter(query, a.filter)))
}
a.container.Objects[0] = a.searchGrid
a.Refresh()
@@ -190,7 +199,7 @@ func (a *AlbumsPage) doSearch(query string) {
func (a *AlbumsPage) onSortOrderChanged(order string) {
a.cfg.SortOrder = a.sortOrder.Selected
iter := a.lm.AlbumsIter(backend.AlbumSortOrder(order))
iter := a.lm.AlbumsIter(backend.AlbumSortOrder(order), a.filter)
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
if a.searchText == "" {
a.container.Objects[0] = a.grid
@@ -205,6 +214,7 @@ func (a *AlbumsPage) CreateRenderer() fyne.WidgetRenderer {
type savedAlbumsPage struct {
searchText string
filter backend.AlbumFilter
cfg *backend.AlbumsPageConfig
contr *controller.Controller
pm *backend.PlaybackManager
+36 -24
View File
@@ -2,7 +2,6 @@ package browsing
import (
"log"
"time"
"github.com/dweymouth/supersonic/backend"
"github.com/dweymouth/supersonic/ui/controller"
@@ -30,6 +29,7 @@ type FavoritesPage struct {
sm *backend.ServerManager
lm *backend.LibraryManager
filter backend.AlbumFilter
searchText string
nowPlayingID string
pendingViewSwitch bool
@@ -39,6 +39,7 @@ type FavoritesPage struct {
artistListCtr *fyne.Container
tracklistCtr *fyne.Container
searcher *widgets.SearchEntry
filterBtn *widgets.AlbumFilterButton
titleDisp *widget.RichText
toggleBtns *widgets.ToggleButtonGroup
container *fyne.Container
@@ -46,16 +47,18 @@ type FavoritesPage struct {
func NewFavoritesPage(cfg *backend.FavoritesPageConfig, contr *controller.Controller, sm *backend.ServerManager, pm *backend.PlaybackManager, lm *backend.LibraryManager, im *backend.ImageManager) *FavoritesPage {
a := &FavoritesPage{
cfg: cfg,
contr: contr,
pm: pm,
lm: lm,
sm: sm,
im: im,
filter: backend.AlbumFilter{ExcludeUnfavorited: true},
cfg: cfg,
contr: contr,
pm: pm,
lm: lm,
sm: sm,
im: im,
}
a.ExtendBaseWidget(a)
a.createHeader(0, "")
a.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(lm.StarredIter()), a.im)
a.createHeader(0)
iter := lm.StarredIter(a.filter)
a.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), a.im)
a.contr.ConnectAlbumGridActions(a.grid)
if cfg.InitialView == "Artists" {
a.toggleBtns.SetActivatedButton(1)
@@ -69,7 +72,7 @@ func NewFavoritesPage(cfg *backend.FavoritesPageConfig, contr *controller.Contro
return a
}
func (a *FavoritesPage) createHeader(activeBtnIdx int, searchText string) {
func (a *FavoritesPage) createHeader(activeBtnIdx int) {
a.titleDisp = widget.NewRichTextWithText("Favorites")
a.titleDisp.Segments[0].(*widget.TextSegment).Style = widget.RichTextStyle{
SizeName: theme.SizeNameHeadingText,
@@ -80,27 +83,32 @@ func (a *FavoritesPage) createHeader(activeBtnIdx int, searchText string) {
widget.NewButtonWithIcon("", myTheme.TracksIcon, a.onShowFavoriteSongs))
a.searcher = widgets.NewSearchEntry()
a.searcher.OnSearched = a.OnSearched
a.searcher.Entry.Text = searchText
a.searcher.Entry.Text = a.searchText
a.filterBtn = widgets.NewAlbumFilterButton(&a.filter)
a.filterBtn.FavoriteDisabled = true
a.filterBtn.OnChanged = a.Reload
}
func (a *FavoritesPage) createContainer(initialView fyne.CanvasObject) {
searchVbox := container.NewVBox(layout.NewSpacer(), a.searcher, layout.NewSpacer())
a.container = container.NewBorder(
container.NewHBox(util.NewHSpace(9), a.titleDisp, container.NewCenter(a.toggleBtns), layout.NewSpacer(), searchVbox, util.NewHSpace(15)),
a.container = container.NewBorder(container.NewHBox(util.NewHSpace(9),
a.titleDisp, container.NewCenter(a.toggleBtns), layout.NewSpacer(), container.NewCenter(a.filterBtn), searchVbox, util.NewHSpace(15)),
nil, nil, nil, initialView)
}
func restoreFavoritesPage(saved *savedFavoritesPage) *FavoritesPage {
a := &FavoritesPage{
cfg: saved.cfg,
contr: saved.contr,
pm: saved.pm,
lm: saved.lm,
sm: saved.sm,
im: saved.im,
cfg: saved.cfg,
contr: saved.contr,
pm: saved.pm,
lm: saved.lm,
sm: saved.sm,
im: saved.im,
searchText: saved.searchText,
filter: saved.filter,
}
a.ExtendBaseWidget(a)
a.createHeader(saved.activeToggleBtn, saved.searchText)
a.createHeader(saved.activeToggleBtn)
a.grid = widgets.NewGridViewFromState(saved.gridState)
if saved.searchText != "" {
@@ -129,7 +137,8 @@ func (a *FavoritesPage) Reload() {
if a.searchText != "" {
a.doSearchAlbums(a.searchText)
} else {
a.grid.Reset(widgets.NewGridViewAlbumIterator(a.lm.StarredIter()))
iter := a.lm.StarredIter(a.filter)
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
}
if a.tracklistCtr != nil || a.artistListCtr != nil {
go func() {
@@ -169,6 +178,7 @@ func (a *FavoritesPage) Save() SavedPage {
sm: a.sm,
im: a.im,
lm: a.lm,
filter: a.filter,
searchText: a.searchText,
gridState: a.grid.SaveToState(),
activeToggleBtn: a.toggleBtns.ActivatedButtonIndex(),
@@ -219,9 +229,7 @@ func (a *FavoritesPage) SelectAll() {
}
func (a *FavoritesPage) doSearchAlbums(query string) {
iter := a.lm.SearchIterWithFilter(query, func(al *subsonic.AlbumID3) bool {
return al.Starred.After(time.Time{})
})
iter := a.lm.SearchIterWithFilter(query, a.filter)
if a.searchGrid == nil {
a.searchGrid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), a.im)
a.contr.ConnectAlbumGridActions(a.searchGrid)
@@ -235,6 +243,7 @@ func (a *FavoritesPage) doSearchAlbums(query string) {
func (a *FavoritesPage) onShowFavoriteAlbums() {
a.cfg.InitialView = "Albums" // save setting
a.searcher.Entry.Show()
a.filterBtn.Show()
if a.searchText == "" {
a.container.Objects[0] = a.grid
} else {
@@ -246,6 +255,7 @@ func (a *FavoritesPage) onShowFavoriteAlbums() {
func (a *FavoritesPage) onShowFavoriteArtists() {
a.cfg.InitialView = "Artists" // save setting
a.searcher.Entry.Hide() // disable search on artists for now
a.filterBtn.Hide()
if a.artistListCtr == nil {
if a.pendingViewSwitch {
return
@@ -294,6 +304,7 @@ func buildArtistListModel(artists []*subsonic.ArtistID3) []widgets.ArtistGenreLi
func (a *FavoritesPage) onShowFavoriteSongs() {
a.cfg.InitialView = "Songs" // save setting
a.searcher.Entry.Hide() // disable search on songs for now
a.filterBtn.Hide()
if a.tracklistCtr == nil {
if a.pendingViewSwitch {
return
@@ -343,6 +354,7 @@ type savedFavoritesPage struct {
lm *backend.LibraryManager
gridState widgets.GridViewState
searchGridState widgets.GridViewState
filter backend.AlbumFilter
searchText string
activeToggleBtn int
}
+35 -28
View File
@@ -12,8 +12,6 @@ import (
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/dweymouth/go-subsonic/subsonic"
)
// TODO: there is a lot of code duplication between this and albumspage. Refactor?
@@ -29,6 +27,8 @@ type GenrePage struct {
searchGrid *widgets.GridView
searcher *widgets.SearchEntry
searchText string
filter backend.AlbumFilter
filterBtn *widgets.AlbumFilterButton
titleDisp *widget.RichText
playRandom *widget.Button
@@ -39,11 +39,12 @@ type GenrePage struct {
func NewGenrePage(genre string, contr *controller.Controller, pm *backend.PlaybackManager, lm *backend.LibraryManager, im *backend.ImageManager) *GenrePage {
g := &GenrePage{
genre: genre,
contr: contr,
pm: pm,
lm: lm,
im: im,
genre: genre,
filter: backend.AlbumFilter{Genres: []string{genre}},
contr: contr,
pm: pm,
lm: lm,
im: im,
}
g.ExtendBaseWidget(g)
@@ -52,16 +53,24 @@ func NewGenrePage(genre string, contr *controller.Controller, pm *backend.Playba
SizeName: theme.SizeNameHeadingText,
}
g.playRandom = widget.NewButtonWithIcon(" Play random", myTheme.ShuffleIcon, g.playRandomSongs)
iter := g.lm.GenreIter(g.genre)
iter := g.lm.GenreIter(g.genre, g.filter)
g.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), g.im)
g.contr.ConnectAlbumGridActions(g.grid)
g.searcher = widgets.NewSearchEntry()
g.searcher.OnSearched = g.OnSearched
g.createSearchAndFilter()
g.createContainer(false)
return g
}
func (g *GenrePage) createSearchAndFilter() {
g.searcher = widgets.NewSearchEntry()
g.searcher.Text = g.searchText
g.searcher.OnSearched = g.OnSearched
g.filterBtn = widgets.NewAlbumFilterButton(&g.filter)
g.filterBtn.GenreDisabled = true
g.filterBtn.OnChanged = g.Reload
}
func (g *GenrePage) createContainer(searchGrid bool) {
searchVbox := container.NewVBox(layout.NewSpacer(), g.searcher, layout.NewSpacer())
gr := g.grid
@@ -70,21 +79,21 @@ func (g *GenrePage) createContainer(searchGrid bool) {
}
playRandomVbox := container.NewVBox(layout.NewSpacer(), g.playRandom, layout.NewSpacer())
g.container = container.NewBorder(
container.NewHBox(util.NewHSpace(6), g.titleDisp, playRandomVbox, layout.NewSpacer(), searchVbox, util.NewHSpace(15)),
nil,
nil,
nil,
gr,
container.NewHBox(util.NewHSpace(6),
g.titleDisp, playRandomVbox, layout.NewSpacer(), container.NewCenter(g.filterBtn), searchVbox, util.NewHSpace(15)),
nil, nil, nil, gr,
)
}
func restoreGenrePage(saved *savedGenrePage) *GenrePage {
g := &GenrePage{
genre: saved.genre,
contr: saved.contr,
pm: saved.pm,
lm: saved.lm,
im: saved.im,
genre: saved.genre,
contr: saved.contr,
pm: saved.pm,
lm: saved.lm,
im: saved.im,
searchText: saved.searchText,
filter: saved.filter,
}
g.ExtendBaseWidget(g)
@@ -94,10 +103,7 @@ func restoreGenrePage(saved *savedGenrePage) *GenrePage {
}
g.playRandom = widget.NewButtonWithIcon(" Play random", myTheme.ShuffleIcon, g.playRandomSongs)
g.grid = widgets.NewGridViewFromState(saved.gridState)
g.searcher = widgets.NewSearchEntry()
g.searcher.OnSearched = g.OnSearched
g.searcher.Entry.Text = saved.searchText
g.searchText = saved.searchText
g.createSearchAndFilter()
if g.searchText != "" {
g.searchGrid = widgets.NewGridViewFromState(saved.searchGridState)
}
@@ -118,7 +124,8 @@ func (g *GenrePage) Reload() {
if g.searchText != "" {
g.doSearch(g.searchText)
} else {
g.grid.Reset(widgets.NewGridViewAlbumIterator(g.lm.GenreIter(g.genre)))
iter := g.lm.GenreIter(g.genre, g.filter)
g.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
g.grid.Refresh()
}
}
@@ -126,6 +133,7 @@ func (g *GenrePage) Reload() {
func (g *GenrePage) Save() SavedPage {
sg := &savedGenrePage{
genre: g.genre,
filter: g.filter,
searchText: g.searchText,
contr: g.contr,
pm: g.pm,
@@ -159,9 +167,7 @@ func (g *GenrePage) OnSearched(query string) {
}
func (g *GenrePage) doSearch(query string) {
iter := g.lm.SearchIterWithFilter(query, func(al *subsonic.AlbumID3) bool {
return al.Genre == g.genre
})
iter := g.lm.SearchIterWithFilter(query, g.filter)
if g.searchGrid == nil {
g.searchGrid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), g.im)
g.contr.ConnectAlbumGridActions(g.searchGrid)
@@ -179,6 +185,7 @@ func (g *GenrePage) playRandomSongs() {
type savedGenrePage struct {
genre string
searchText string
filter backend.AlbumFilter
contr *controller.Controller
pm *backend.PlaybackManager
lm *backend.LibraryManager