Fix #665: Add option to play albums in order on Albums page
This commit is contained in:
+2
-1
@@ -70,7 +70,8 @@ type AlbumPageConfig struct {
|
|||||||
type AlbumsPageConfig struct {
|
type AlbumsPageConfig struct {
|
||||||
SortOrder string // only relevant for Albums page
|
SortOrder string // only relevant for Albums page
|
||||||
ShowYears bool
|
ShowYears bool
|
||||||
ShuffleMode string // only relevant for genre page
|
ShuffleMode string // only relevant for Genre page
|
||||||
|
PlayInOrder bool // only relevant for Albums page
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArtistPageConfig struct {
|
type ArtistPageConfig struct {
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
"Home Page": "Home Page",
|
"Home Page": "Home Page",
|
||||||
"hr": "hr",
|
"hr": "hr",
|
||||||
"hrs": "hrs",
|
"hrs": "hrs",
|
||||||
|
"In order": "In order",
|
||||||
"Internet Radio Stations": "Internet Radio Stations",
|
"Internet Radio Stations": "Internet Radio Stations",
|
||||||
"Interview": "Interview",
|
"Interview": "Interview",
|
||||||
"Is favorite": "Is favorite",
|
"Is favorite": "Is favorite",
|
||||||
@@ -202,6 +203,7 @@
|
|||||||
"Show play queue": "Show play queue",
|
"Show play queue": "Show play queue",
|
||||||
"Show year in album grid cards": "Show year in album grid cards",
|
"Show year in album grid cards": "Show year in album grid cards",
|
||||||
"Shuffle": "Shuffle",
|
"Shuffle": "Shuffle",
|
||||||
|
"Shuffled": "Shuffled",
|
||||||
"Shuffle albums": "Shuffle albums",
|
"Shuffle albums": "Shuffle albums",
|
||||||
"Shuffle tracks": "Shuffle tracks",
|
"Shuffle tracks": "Shuffle tracks",
|
||||||
"Similar artists": "Similar artists",
|
"Similar artists": "Similar artists",
|
||||||
@@ -240,6 +242,7 @@
|
|||||||
"tracks": "tracks",
|
"tracks": "tracks",
|
||||||
"Transcode to": "Transcode to",
|
"Transcode to": "Transcode to",
|
||||||
"UI Scaling": "UI Scaling",
|
"UI Scaling": "UI Scaling",
|
||||||
|
"Unable to play albums": "Unable to play albums",
|
||||||
"Unable to play artist radio": "Unable to play artist radio",
|
"Unable to play artist radio": "Unable to play artist radio",
|
||||||
"Unable to play random tracks": "Unable to play random tracks",
|
"Unable to play random tracks": "Unable to play random tracks",
|
||||||
"URL": "URL",
|
"URL": "URL",
|
||||||
@@ -263,6 +266,7 @@
|
|||||||
"Set favorite": "Set favorite",
|
"Set favorite": "Set favorite",
|
||||||
"Unset favorite": "Unset favorite",
|
"Unset favorite": "Unset favorite",
|
||||||
"Remove from queue": "Remove from queue",
|
"Remove from queue": "Remove from queue",
|
||||||
|
"Play albums": "Play albums",
|
||||||
"Play song radio": "Play song radio",
|
"Play song radio": "Play song radio",
|
||||||
"to": "to",
|
"to": "to",
|
||||||
"by": "by",
|
"by": "by",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/lang"
|
"fyne.io/fyne/v2/lang"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/theme"
|
||||||
"github.com/dweymouth/supersonic/backend"
|
"github.com/dweymouth/supersonic/backend"
|
||||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||||
"github.com/dweymouth/supersonic/ui/controller"
|
"github.com/dweymouth/supersonic/ui/controller"
|
||||||
@@ -22,6 +22,9 @@ type albumsPageAdapter struct {
|
|||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
filter mediaprovider.AlbumFilter
|
filter mediaprovider.AlbumFilter
|
||||||
filterBtn *widgets.AlbumFilterButton
|
filterBtn *widgets.AlbumFilterButton
|
||||||
|
|
||||||
|
// dependency injected from the GridViewPage
|
||||||
|
itemsFn func() []widgets.GridViewItemModel
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAlbumsPage(cfg *backend.AlbumsPageConfig, pool *util.WidgetPool, contr *controller.Controller, pm *backend.PlaybackManager, mp mediaprovider.MediaProvider, im *backend.ImageManager) Page {
|
func NewAlbumsPage(cfg *backend.AlbumsPageConfig, pool *util.WidgetPool, contr *controller.Controller, pm *backend.PlaybackManager, mp mediaprovider.MediaProvider, im *backend.ImageManager) Page {
|
||||||
@@ -29,6 +32,12 @@ func NewAlbumsPage(cfg *backend.AlbumsPageConfig, pool *util.WidgetPool, contr *
|
|||||||
return NewGridViewPage(adapter, pool, mp, im)
|
return NewGridViewPage(adapter, pool, mp, im)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ GridViewPageAdapterGetItems = (*albumsPageAdapter)(nil)
|
||||||
|
|
||||||
|
func (a *albumsPageAdapter) SetItemsFunc(f func() []widgets.GridViewItemModel) {
|
||||||
|
a.itemsFn = f
|
||||||
|
}
|
||||||
|
|
||||||
func (a *albumsPageAdapter) Title() string { return lang.L("Albums") }
|
func (a *albumsPageAdapter) Title() string { return lang.L("Albums") }
|
||||||
|
|
||||||
func (a *albumsPageAdapter) Filter() mediaprovider.AlbumFilter {
|
func (a *albumsPageAdapter) Filter() mediaprovider.AlbumFilter {
|
||||||
@@ -66,7 +75,7 @@ func (a *albumsPageAdapter) SaveSortOrder(orderIdx int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *albumsPageAdapter) ActionButton() fyne.CanvasObject {
|
func (a *albumsPageAdapter) ActionButton() fyne.CanvasObject {
|
||||||
fn := func() {
|
shuffleAlbumsFn := func() {
|
||||||
go func() {
|
go func() {
|
||||||
if err := a.pm.PlayRandomAlbums(""); err != nil {
|
if err := a.pm.PlayRandomAlbums(""); err != nil {
|
||||||
log.Printf("error playing random albums: %v", err)
|
log.Printf("error playing random albums: %v", err)
|
||||||
@@ -77,7 +86,66 @@ func (a *albumsPageAdapter) ActionButton() fyne.CanvasObject {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
return widget.NewButtonWithIcon(lang.L("Play random"), myTheme.ShuffleIcon, fn)
|
playAlbumsFn := func() {
|
||||||
|
if a.itemsFn == nil {
|
||||||
|
a.contr.ToastProvider.ShowErrorToast(lang.L("Unable to play albums"))
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i, item := range a.itemsFn() {
|
||||||
|
if i >= 20 {
|
||||||
|
break // don't load more than first 20 albums
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
a.pm.LoadAlbum(item.ID, backend.Replace, false)
|
||||||
|
a.pm.PlayFromBeginning()
|
||||||
|
} else {
|
||||||
|
a.pm.LoadAlbum(item.ID, backend.Append, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
var btn *widgets.OptionButton
|
||||||
|
var inOrder, shuffled *fyne.MenuItem
|
||||||
|
inOrder = fyne.NewMenuItem(lang.L("In order"), func() {
|
||||||
|
shuffled.Checked = false
|
||||||
|
inOrder.Checked = true
|
||||||
|
a.cfg.PlayInOrder = true
|
||||||
|
btn.Text = lang.L("Play albums")
|
||||||
|
btn.Icon = theme.MediaPlayIcon()
|
||||||
|
btn.Refresh()
|
||||||
|
})
|
||||||
|
inOrder.Icon = myTheme.AlbumIcon
|
||||||
|
shuffled = fyne.NewMenuItem(lang.L("Shuffled"), func() {
|
||||||
|
inOrder.Checked = false
|
||||||
|
shuffled.Checked = true
|
||||||
|
a.cfg.PlayInOrder = false
|
||||||
|
btn.Text = lang.L("Shuffle albums")
|
||||||
|
btn.Icon = myTheme.ShuffleIcon
|
||||||
|
btn.Refresh()
|
||||||
|
})
|
||||||
|
shuffled.Icon = myTheme.ShuffleIcon
|
||||||
|
shuffled.Checked = !a.cfg.PlayInOrder
|
||||||
|
inOrder.Checked = a.cfg.PlayInOrder
|
||||||
|
|
||||||
|
menu := fyne.NewMenu("", inOrder, shuffled)
|
||||||
|
icon := myTheme.ShuffleIcon
|
||||||
|
textKey := "Shuffle albums"
|
||||||
|
if a.cfg.PlayInOrder {
|
||||||
|
textKey = "Play albums"
|
||||||
|
icon = theme.MediaPlayIcon()
|
||||||
|
}
|
||||||
|
btn = widgets.NewOptionButton(lang.L(textKey), menu, func() {
|
||||||
|
if a.cfg.PlayInOrder {
|
||||||
|
playAlbumsFn()
|
||||||
|
} else {
|
||||||
|
shuffleAlbumsFn()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
btn.Icon = icon
|
||||||
|
|
||||||
|
return btn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *albumsPageAdapter) Iter(sortOrderIdx int, filter mediaprovider.AlbumFilter) widgets.GridViewIterator {
|
func (a *albumsPageAdapter) Iter(sortOrderIdx int, filter mediaprovider.AlbumFilter) widgets.GridViewIterator {
|
||||||
|
|||||||
@@ -76,6 +76,13 @@ type GridViewPageAdapter[M, F any] interface {
|
|||||||
RefreshGrid(*widgets.GridView)
|
RefreshGrid(*widgets.GridView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GridViewPageAdapterGetItems interface {
|
||||||
|
// Optionally allows the GridViewPage to inject a function that
|
||||||
|
// can be used to retrieve the GridViewItemModels for the
|
||||||
|
// items currently loaded into the GridView.
|
||||||
|
SetItemsFunc(func() []widgets.GridViewItemModel)
|
||||||
|
}
|
||||||
|
|
||||||
type SortableGridViewPageAdapter interface {
|
type SortableGridViewPageAdapter interface {
|
||||||
// Returns the list of sort orders
|
// Returns the list of sort orders
|
||||||
// and the index of the initially selected sort order
|
// and the index of the initially selected sort order
|
||||||
@@ -113,6 +120,12 @@ func NewGridViewPage[M, F any](
|
|||||||
}
|
}
|
||||||
gp.grid.DisableSharing = !canShare
|
gp.grid.DisableSharing = !canShare
|
||||||
adapter.InitGrid(gp.grid)
|
adapter.InitGrid(gp.grid)
|
||||||
|
|
||||||
|
// If adapter supports SetItemsFunc, call it to inject the items dependency
|
||||||
|
if plfSetter, ok := adapter.(GridViewPageAdapterGetItems); ok {
|
||||||
|
plfSetter.SetItemsFunc(gp.grid.Items)
|
||||||
|
}
|
||||||
|
|
||||||
gp.createSearchAndFilter()
|
gp.createSearchAndFilter()
|
||||||
gp.createContainer()
|
gp.createContainer()
|
||||||
return gp
|
return gp
|
||||||
|
|||||||
@@ -198,6 +198,16 @@ func NewGridView(iter GridViewIterator, fetch util.ImageFetcher, placeholder fyn
|
|||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Items returns the items that are currently loaded into the GridView state.
|
||||||
|
func (g *GridView) Items() []GridViewItemModel {
|
||||||
|
g.stateMutex.Lock()
|
||||||
|
defer g.stateMutex.Unlock()
|
||||||
|
|
||||||
|
items := make([]GridViewItemModel, len(g.items))
|
||||||
|
copy(items, g.items)
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
func (g *GridView) SaveToState() *GridViewState {
|
func (g *GridView) SaveToState() *GridViewState {
|
||||||
g.stateMutex.RLock()
|
g.stateMutex.RLock()
|
||||||
s := g.GridViewState
|
s := g.GridViewState
|
||||||
|
|||||||
Reference in New Issue
Block a user