fix some bugs and restructure a bit more
This commit is contained in:
@@ -44,10 +44,12 @@ type MediaProvider interface {
|
|||||||
|
|
||||||
AlbumSortOrders() []string
|
AlbumSortOrders() []string
|
||||||
|
|
||||||
IterateAlbums(sortOrder string, searchQuery string, filter AlbumFilter) AlbumIterator
|
IterateAlbums(sortOrder string, filter AlbumFilter) AlbumIterator
|
||||||
|
|
||||||
IterateTracks(searchQuery string) TrackIterator
|
IterateTracks(searchQuery string) TrackIterator
|
||||||
|
|
||||||
|
SearchAlbums(searchQuery string, filter AlbumFilter) AlbumIterator
|
||||||
|
|
||||||
GetRandomTracks(genre string, count int) ([]*Track, error)
|
GetRandomTracks(genre string, count int) ([]*Track, error)
|
||||||
|
|
||||||
GetSimilarTracks(artistID string, count int) ([]*Track, error)
|
GetSimilarTracks(artistID string, count int) ([]*Track, error)
|
||||||
|
|||||||
@@ -10,6 +10,30 @@ import (
|
|||||||
"github.com/dweymouth/supersonic/sharedutil"
|
"github.com/dweymouth/supersonic/sharedutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AlbumSortRecentlyAdded string = "Recently Added"
|
||||||
|
AlbumSortRecentlyPlayed string = "Recently Played"
|
||||||
|
AlbumSortFrequentlyPlayed string = "Frequently Played"
|
||||||
|
AlbumSortRandom string = "Random"
|
||||||
|
AlbumSortTitleAZ string = "Title (A-Z)"
|
||||||
|
AlbumSortArtistAZ string = "Artist (A-Z)"
|
||||||
|
AlbumSortYearAscending string = "Year (ascending)"
|
||||||
|
AlbumSortYearDescending string = "Year (descending)"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *subsonicMediaProvider) AlbumSortOrders() []string {
|
||||||
|
return []string{
|
||||||
|
AlbumSortRecentlyAdded,
|
||||||
|
AlbumSortRecentlyPlayed,
|
||||||
|
AlbumSortFrequentlyPlayed,
|
||||||
|
AlbumSortRandom,
|
||||||
|
AlbumSortTitleAZ,
|
||||||
|
AlbumSortArtistAZ,
|
||||||
|
AlbumSortYearAscending,
|
||||||
|
AlbumSortYearDescending,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func filterMatches(f mediaprovider.AlbumFilter, album *subsonic.AlbumID3) bool {
|
func filterMatches(f mediaprovider.AlbumFilter, album *subsonic.AlbumID3) bool {
|
||||||
if album == nil {
|
if album == nil {
|
||||||
return false
|
return false
|
||||||
@@ -34,15 +58,7 @@ func filterMatches(f mediaprovider.AlbumFilter, album *subsonic.AlbumID3) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterIsEmpty(f mediaprovider.AlbumFilter) bool {
|
func (s *subsonicMediaProvider) IterateAlbums(sortOrder string, filter mediaprovider.AlbumFilter) mediaprovider.AlbumIterator {
|
||||||
return !f.ExcludeFavorited && !f.ExcludeUnfavorited &&
|
|
||||||
f.MinYear == 0 && f.MaxYear == 0 && len(f.Genres) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *subsonicMediaProvider) IterateAlbums(sortOrder, searchQuery string, filter mediaprovider.AlbumFilter) mediaprovider.AlbumIterator {
|
|
||||||
if searchQuery != "" {
|
|
||||||
return s.newSearchIter(searchQuery, filter)
|
|
||||||
}
|
|
||||||
if sortOrder == "" && len(filter.Genres) == 1 {
|
if sortOrder == "" && len(filter.Genres) == 1 {
|
||||||
return s.newBaseIter("byGenre", filter, map[string]string{"genre": filter.Genres[0]})
|
return s.newBaseIter("byGenre", filter, map[string]string{"genre": filter.Genres[0]})
|
||||||
}
|
}
|
||||||
@@ -72,6 +88,10 @@ func (s *subsonicMediaProvider) IterateAlbums(sortOrder, searchQuery string, fil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *subsonicMediaProvider) SearchAlbums(searchQuery string, filter mediaprovider.AlbumFilter) mediaprovider.AlbumIterator {
|
||||||
|
return s.newSearchIter(searchQuery, filter)
|
||||||
|
}
|
||||||
|
|
||||||
type baseIter struct {
|
type baseIter struct {
|
||||||
listType string
|
listType string
|
||||||
filter mediaprovider.AlbumFilter
|
filter mediaprovider.AlbumFilter
|
||||||
@@ -217,7 +237,7 @@ func (s *searchIter) addNewAlbums(al []*subsonic.AlbumID3) {
|
|||||||
if _, have := s.albumIDset[album.ID]; have {
|
if _, have := s.albumIDset[album.ID]; have {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if filterMatches(s.filter, album) {
|
if !filterMatches(s.filter, album) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s.prefetched = append(s.prefetched, album)
|
s.prefetched = append(s.prefetched, album)
|
||||||
@@ -326,27 +346,3 @@ func (r *randomIter) Next() *mediaprovider.Album {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
type BatchingIterator struct {
|
|
||||||
iter AlbumIterator
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBatchingIterator(iter AlbumIterator) *BatchingIterator {
|
|
||||||
return &BatchingIterator{iter}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BatchingIterator) NextN(n int) []*subsonic.AlbumID3 {
|
|
||||||
results := make([]*subsonic.AlbumID3, 0, n)
|
|
||||||
i := 0
|
|
||||||
for i < n {
|
|
||||||
album := b.iter.Next()
|
|
||||||
if album == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
results = append(results, album)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -12,17 +12,6 @@ import (
|
|||||||
"github.com/dweymouth/supersonic/sharedutil"
|
"github.com/dweymouth/supersonic/sharedutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
AlbumSortRecentlyAdded string = "Recently Added"
|
|
||||||
AlbumSortRecentlyPlayed string = "Recently Played"
|
|
||||||
AlbumSortFrequentlyPlayed string = "Frequently Played"
|
|
||||||
AlbumSortRandom string = "Random"
|
|
||||||
AlbumSortTitleAZ string = "Title (A-Z)"
|
|
||||||
AlbumSortArtistAZ string = "Artist (A-Z)"
|
|
||||||
AlbumSortYearAscending string = "Year (ascending)"
|
|
||||||
AlbumSortYearDescending string = "Year (descending)"
|
|
||||||
)
|
|
||||||
|
|
||||||
type subsonicMediaProvider struct {
|
type subsonicMediaProvider struct {
|
||||||
client *subsonic.Client
|
client *subsonic.Client
|
||||||
}
|
}
|
||||||
@@ -31,19 +20,6 @@ func SubsonicMediaProvider(subsonicClient *subsonic.Client) mediaprovider.MediaP
|
|||||||
return &subsonicMediaProvider{client: subsonicClient}
|
return &subsonicMediaProvider{client: subsonicClient}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *subsonicMediaProvider) AlbumSortOrders() []string {
|
|
||||||
return []string{
|
|
||||||
AlbumSortRecentlyAdded,
|
|
||||||
AlbumSortRecentlyPlayed,
|
|
||||||
AlbumSortFrequentlyPlayed,
|
|
||||||
AlbumSortRandom,
|
|
||||||
AlbumSortTitleAZ,
|
|
||||||
AlbumSortArtistAZ,
|
|
||||||
AlbumSortYearAscending,
|
|
||||||
AlbumSortYearDescending,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *subsonicMediaProvider) CreatePlaylist(name string, trackIDs []string) error {
|
func (s *subsonicMediaProvider) CreatePlaylist(name string, trackIDs []string) error {
|
||||||
return s.client.CreatePlaylistWithTracks(trackIDs, map[string]string{"name": name})
|
return s.client.CreatePlaylistWithTracks(trackIDs, map[string]string{"name": name})
|
||||||
}
|
}
|
||||||
@@ -69,21 +45,11 @@ func (s *subsonicMediaProvider) GetAlbum(albumID string) (*mediaprovider.AlbumWi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &mediaprovider.AlbumWithTracks{
|
album := &mediaprovider.AlbumWithTracks{
|
||||||
Album: mediaprovider.Album{
|
|
||||||
ID: al.ID,
|
|
||||||
Name: al.Name,
|
|
||||||
ArtistIDs: []string{al.ArtistID},
|
|
||||||
CoverArtID: al.CoverArt,
|
|
||||||
ArtistNames: []string{al.Artist},
|
|
||||||
Genres: []string{al.Genre},
|
|
||||||
Year: al.Year,
|
|
||||||
TrackCount: al.SongCount,
|
|
||||||
Favorite: !al.Starred.IsZero(),
|
|
||||||
Duration: al.Duration,
|
|
||||||
},
|
|
||||||
Tracks: sharedutil.MapSlice(al.Song, toTrack),
|
Tracks: sharedutil.MapSlice(al.Song, toTrack),
|
||||||
}, nil
|
}
|
||||||
|
fillAlbum(al, &album.Album)
|
||||||
|
return album, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *subsonicMediaProvider) GetArtist(artistID string) (*mediaprovider.ArtistWithAlbums, error) {
|
func (s *subsonicMediaProvider) GetArtist(artistID string) (*mediaprovider.ArtistWithAlbums, error) {
|
||||||
@@ -168,19 +134,11 @@ func (s *subsonicMediaProvider) GetPlaylist(playlistID string) (*mediaprovider.P
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &mediaprovider.PlaylistWithTracks{
|
playlist := &mediaprovider.PlaylistWithTracks{
|
||||||
Playlist: mediaprovider.Playlist{
|
|
||||||
ID: pl.ID,
|
|
||||||
CoverArtID: pl.CoverArt,
|
|
||||||
Name: pl.Name,
|
|
||||||
Description: pl.Comment,
|
|
||||||
TrackCount: pl.SongCount,
|
|
||||||
Public: pl.Public,
|
|
||||||
Owner: pl.Owner,
|
|
||||||
Duration: pl.Duration,
|
|
||||||
},
|
|
||||||
Tracks: sharedutil.MapSlice(pl.Entry, toTrack),
|
Tracks: sharedutil.MapSlice(pl.Entry, toTrack),
|
||||||
}, nil
|
}
|
||||||
|
fillPlaylist(pl, &playlist.Playlist)
|
||||||
|
return playlist, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *subsonicMediaProvider) GetPlaylists() ([]*mediaprovider.Playlist, error) {
|
func (s *subsonicMediaProvider) GetPlaylists() ([]*mediaprovider.Playlist, error) {
|
||||||
@@ -261,34 +219,24 @@ func (s *subsonicMediaProvider) SetRating(params mediaprovider.RatingFavoritePar
|
|||||||
var err error
|
var err error
|
||||||
batchSetRating := func(offs int, wg *sync.WaitGroup) {
|
batchSetRating := func(offs int, wg *sync.WaitGroup) {
|
||||||
for i := 0; i < batchSize && offs+i < len(params.TrackIDs); i++ {
|
for i := 0; i < batchSize && offs+i < len(params.TrackIDs); i++ {
|
||||||
if wg != nil {
|
wg.Add(1)
|
||||||
wg.Add(1)
|
|
||||||
}
|
|
||||||
go func(idx int) {
|
go func(idx int) {
|
||||||
newErr := s.client.SetRating(params.TrackIDs[idx], rating)
|
newErr := s.client.SetRating(params.TrackIDs[idx], rating)
|
||||||
if err == nil && newErr != nil {
|
if err == nil && newErr != nil {
|
||||||
err = newErr
|
err = newErr
|
||||||
}
|
}
|
||||||
if wg != nil {
|
wg.Done()
|
||||||
wg.Done()
|
|
||||||
}
|
|
||||||
}(offs + i)
|
}(offs + i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(params.TrackIDs) <= 5 {
|
numBatches := int(math.Ceil(float64(len(params.TrackIDs)) / float64(batchSize)))
|
||||||
// one batch only - no need to use wait group
|
for i := 0; i < numBatches; i++ {
|
||||||
batchSetRating(0, nil)
|
var wg sync.WaitGroup
|
||||||
} else {
|
batchSetRating(i*batchSize, &wg)
|
||||||
go func() {
|
wg.Wait()
|
||||||
numBatches := int(math.Ceil(float64(len(params.TrackIDs)) / float64(batchSize)))
|
|
||||||
for i := 0; i < numBatches; i++ {
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
batchSetRating(i*batchSize, &wg)
|
|
||||||
wg.Wait()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,6 +262,7 @@ func toTrack(ch *subsonic.Child) *mediaprovider.Track {
|
|||||||
Favorite: !ch.Starred.IsZero(),
|
Favorite: !ch.Starred.IsZero(),
|
||||||
PlayCount: int(ch.PlayCount),
|
PlayCount: int(ch.PlayCount),
|
||||||
FilePath: ch.Path,
|
FilePath: ch.Path,
|
||||||
|
Size: ch.Size,
|
||||||
BitRate: ch.BitRate,
|
BitRate: ch.BitRate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,18 +271,22 @@ func toAlbum(al *subsonic.AlbumID3) *mediaprovider.Album {
|
|||||||
if al == nil {
|
if al == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &mediaprovider.Album{
|
album := &mediaprovider.Album{}
|
||||||
ID: al.ID,
|
fillAlbum(al, album)
|
||||||
CoverArtID: al.CoverArt,
|
return album
|
||||||
Name: al.Name,
|
}
|
||||||
Duration: al.Duration,
|
|
||||||
ArtistIDs: []string{al.ArtistID},
|
func fillAlbum(subAlbum *subsonic.AlbumID3, album *mediaprovider.Album) {
|
||||||
ArtistNames: []string{al.Artist},
|
album.ID = subAlbum.ID
|
||||||
Year: al.Year,
|
album.CoverArtID = subAlbum.CoverArt
|
||||||
Genres: []string{al.Genre},
|
album.Name = subAlbum.Name
|
||||||
TrackCount: al.SongCount,
|
album.Duration = subAlbum.Duration
|
||||||
Favorite: !al.Starred.IsZero(),
|
album.ArtistIDs = []string{subAlbum.ArtistID}
|
||||||
}
|
album.ArtistNames = []string{subAlbum.Artist}
|
||||||
|
album.Year = subAlbum.Year
|
||||||
|
album.TrackCount = subAlbum.SongCount
|
||||||
|
album.Genres = []string{subAlbum.Genre}
|
||||||
|
album.Favorite = !subAlbum.Starred.IsZero()
|
||||||
}
|
}
|
||||||
|
|
||||||
func toArtist(ar *subsonic.Artist) *mediaprovider.Artist {
|
func toArtist(ar *subsonic.Artist) *mediaprovider.Artist {
|
||||||
@@ -360,14 +313,21 @@ func toArtistFromID3(ar *subsonic.ArtistID3) *mediaprovider.Artist {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func toPlaylist(pl *subsonic.Playlist) *mediaprovider.Playlist {
|
func toPlaylist(pl *subsonic.Playlist) *mediaprovider.Playlist {
|
||||||
return &mediaprovider.Playlist{
|
if pl == nil {
|
||||||
Name: pl.Name,
|
return nil
|
||||||
ID: pl.ID,
|
|
||||||
CoverArtID: pl.CoverArt,
|
|
||||||
Description: pl.Comment,
|
|
||||||
Owner: pl.Owner,
|
|
||||||
Public: pl.Public,
|
|
||||||
TrackCount: pl.SongCount,
|
|
||||||
Duration: pl.Duration,
|
|
||||||
}
|
}
|
||||||
|
playlist := &mediaprovider.Playlist{}
|
||||||
|
fillPlaylist(pl, playlist)
|
||||||
|
return playlist
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillPlaylist(pl *subsonic.Playlist, playlist *mediaprovider.Playlist) {
|
||||||
|
playlist.Name = pl.Name
|
||||||
|
playlist.ID = pl.ID
|
||||||
|
playlist.CoverArtID = pl.CoverArt
|
||||||
|
playlist.Description = pl.Comment
|
||||||
|
playlist.Owner = pl.Owner
|
||||||
|
playlist.Public = pl.Public
|
||||||
|
playlist.TrackCount = pl.SongCount
|
||||||
|
playlist.Duration = pl.Duration
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ func (s *subsonicMediaProvider) IterateTracks(searchQuery string) mediaprovider.
|
|||||||
if searchQuery == "" {
|
if searchQuery == "" {
|
||||||
return &allTracksIterator{
|
return &allTracksIterator{
|
||||||
s: s,
|
s: s,
|
||||||
albumIter: s.IterateAlbums(AlbumSortArtistAZ, "", mediaprovider.AlbumFilter{}),
|
albumIter: s.IterateAlbums(AlbumSortArtistAZ, mediaprovider.AlbumFilter{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &searchTracksIterator{
|
return &searchTracksIterator{
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func NewAlbumsPage(cfg *backend.AlbumsPageConfig, contr *controller.Controller,
|
|||||||
cfg.SortOrder = string(mp.AlbumSortOrders()[0])
|
cfg.SortOrder = string(mp.AlbumSortOrders()[0])
|
||||||
}
|
}
|
||||||
a.sortOrder.Selected = cfg.SortOrder
|
a.sortOrder.Selected = cfg.SortOrder
|
||||||
iter := mp.IterateAlbums(a.sortOrder.Selected, "", a.filter)
|
iter := mp.IterateAlbums(a.sortOrder.Selected, a.filter)
|
||||||
a.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), im)
|
a.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), im)
|
||||||
contr.ConnectAlbumGridActions(a.grid)
|
contr.ConnectAlbumGridActions(a.grid)
|
||||||
a.createSearchAndFilter()
|
a.createSearchAndFilter()
|
||||||
@@ -163,7 +163,7 @@ func (a *AlbumsPage) Reload() {
|
|||||||
if a.searchText != "" {
|
if a.searchText != "" {
|
||||||
a.doSearch(a.searchText)
|
a.doSearch(a.searchText)
|
||||||
} else {
|
} else {
|
||||||
iter := a.mp.IterateAlbums(a.sortOrder.Selected, "", a.filter)
|
iter := a.mp.IterateAlbums(a.sortOrder.Selected, a.filter)
|
||||||
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
|
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
|
||||||
a.grid.Refresh()
|
a.grid.Refresh()
|
||||||
}
|
}
|
||||||
@@ -188,7 +188,7 @@ func (a *AlbumsPage) Save() SavedPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *AlbumsPage) doSearch(query string) {
|
func (a *AlbumsPage) doSearch(query string) {
|
||||||
iter := widgets.NewGridViewAlbumIterator(a.mp.IterateAlbums("", query, a.filter))
|
iter := widgets.NewGridViewAlbumIterator(a.mp.SearchAlbums(query, a.filter))
|
||||||
if a.searchGrid == nil {
|
if a.searchGrid == nil {
|
||||||
a.searchGrid = widgets.NewGridView(iter, a.im)
|
a.searchGrid = widgets.NewGridView(iter, a.im)
|
||||||
a.contr.ConnectAlbumGridActions(a.searchGrid)
|
a.contr.ConnectAlbumGridActions(a.searchGrid)
|
||||||
@@ -201,7 +201,7 @@ func (a *AlbumsPage) doSearch(query string) {
|
|||||||
|
|
||||||
func (a *AlbumsPage) onSortOrderChanged(order string) {
|
func (a *AlbumsPage) onSortOrderChanged(order string) {
|
||||||
a.cfg.SortOrder = a.sortOrder.Selected
|
a.cfg.SortOrder = a.sortOrder.Selected
|
||||||
iter := a.mp.IterateAlbums(order, "", a.filter)
|
iter := a.mp.IterateAlbums(order, a.filter)
|
||||||
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
|
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
|
||||||
if a.searchText == "" {
|
if a.searchText == "" {
|
||||||
a.container.Objects[0] = a.grid
|
a.container.Objects[0] = a.grid
|
||||||
|
|||||||
+10
-10
@@ -30,7 +30,7 @@ type artistPageState struct {
|
|||||||
|
|
||||||
cfg *backend.ArtistPageConfig
|
cfg *backend.ArtistPageConfig
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
sm *backend.ServerManager
|
mp mediaprovider.MediaProvider
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
}
|
}
|
||||||
@@ -49,20 +49,20 @@ type ArtistPage struct {
|
|||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArtistPage(artistID string, cfg *backend.ArtistPageConfig, pm *backend.PlaybackManager, sm *backend.ServerManager, im *backend.ImageManager, contr *controller.Controller) *ArtistPage {
|
func NewArtistPage(artistID string, cfg *backend.ArtistPageConfig, 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, pm, sm, im, contr, activeView)
|
return newArtistPage(artistID, cfg, pm, mp, im, contr, activeView)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArtistPage(artistID string, cfg *backend.ArtistPageConfig, pm *backend.PlaybackManager, sm *backend.ServerManager, im *backend.ImageManager, contr *controller.Controller, activeView int) *ArtistPage {
|
func newArtistPage(artistID string, cfg *backend.ArtistPageConfig, pm *backend.PlaybackManager, mp mediaprovider.MediaProvider, im *backend.ImageManager, contr *controller.Controller, activeView int) *ArtistPage {
|
||||||
a := &ArtistPage{artistPageState: artistPageState{
|
a := &ArtistPage{artistPageState: artistPageState{
|
||||||
artistID: artistID,
|
artistID: artistID,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
pm: pm,
|
pm: pm,
|
||||||
sm: sm,
|
mp: mp,
|
||||||
im: im,
|
im: im,
|
||||||
contr: contr,
|
contr: contr,
|
||||||
activeView: activeView,
|
activeView: activeView,
|
||||||
@@ -141,7 +141,7 @@ func (a *ArtistPage) playArtistRadio() {
|
|||||||
|
|
||||||
// should be called asynchronously
|
// should be called asynchronously
|
||||||
func (a *ArtistPage) load() {
|
func (a *ArtistPage) load() {
|
||||||
artist, err := a.sm.Server.GetArtist(a.artistID)
|
artist, err := a.mp.GetArtist(a.artistID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to get artist: %s", err.Error())
|
log.Printf("Failed to get artist: %s", err.Error())
|
||||||
return
|
return
|
||||||
@@ -153,7 +153,7 @@ func (a *ArtistPage) load() {
|
|||||||
} else {
|
} else {
|
||||||
a.showTopTracks()
|
a.showTopTracks()
|
||||||
}
|
}
|
||||||
info, err := a.sm.Server.GetArtistInfo(a.artistID)
|
info, err := a.mp.GetArtistInfo(a.artistID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to get artist info: %s", err.Error())
|
log.Printf("Failed to get artist info: %s", err.Error())
|
||||||
}
|
}
|
||||||
@@ -189,7 +189,7 @@ func (a *ArtistPage) showTopTracks() {
|
|||||||
a.activeView = 1 // if page still loading, will show tracks view first
|
a.activeView = 1 // if page still loading, will show tracks view first
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ts, err := a.sm.Server.GetTopTracks(a.artistInfo.Artist, 20)
|
ts, err := a.mp.GetTopTracks(a.artistInfo.Artist, 20)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error getting top songs: %s", err.Error())
|
log.Printf("error getting top songs: %s", err.Error())
|
||||||
return
|
return
|
||||||
@@ -232,7 +232,7 @@ func (a *ArtistPage) CreateRenderer() fyne.WidgetRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *artistPageState) Restore() Page {
|
func (s *artistPageState) Restore() Page {
|
||||||
return newArtistPage(s.artistID, s.cfg, s.pm, s.sm, s.im, s.contr, s.activeView)
|
return newArtistPage(s.artistID, s.cfg, s.pm, s.mp, s.im, s.contr, s.activeView)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArtistPageHeader struct {
|
type ArtistPageHeader struct {
|
||||||
@@ -333,7 +333,7 @@ func (a *ArtistPageHeader) UpdateInfo(info *mediaprovider.ArtistInfo) {
|
|||||||
|
|
||||||
func (a *ArtistPageHeader) toggleFavorited() {
|
func (a *ArtistPageHeader) toggleFavorited() {
|
||||||
params := mediaprovider.RatingFavoriteParameters{ArtistIDs: []string{a.artistID}}
|
params := mediaprovider.RatingFavoriteParameters{ArtistIDs: []string{a.artistID}}
|
||||||
a.artistPage.sm.Server.SetFavorite(params, a.favoriteBtn.IsFavorited)
|
a.artistPage.mp.SetFavorite(params, a.favoriteBtn.IsFavorited)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ArtistPageHeader) createContainer() {
|
func (a *ArtistPageHeader) createContainer() {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/dweymouth/supersonic/backend"
|
|
||||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||||
"github.com/dweymouth/supersonic/sharedutil"
|
"github.com/dweymouth/supersonic/sharedutil"
|
||||||
"github.com/dweymouth/supersonic/ui/controller"
|
"github.com/dweymouth/supersonic/ui/controller"
|
||||||
@@ -25,7 +24,7 @@ type ArtistsGenresPage struct {
|
|||||||
|
|
||||||
isGenresPage bool
|
isGenresPage bool
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
sm *backend.ServerManager
|
mp mediaprovider.MediaProvider
|
||||||
model []widgets.ArtistGenreListItemModel
|
model []widgets.ArtistGenreListItemModel
|
||||||
list *widgets.ArtistGenreList
|
list *widgets.ArtistGenreList
|
||||||
|
|
||||||
@@ -34,11 +33,11 @@ type ArtistsGenresPage struct {
|
|||||||
searcher *widgets.SearchEntry
|
searcher *widgets.SearchEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArtistsGenresPage(isGenresPage bool, contr *controller.Controller, sm *backend.ServerManager) *ArtistsGenresPage {
|
func NewArtistsGenresPage(isGenresPage bool, contr *controller.Controller, mp mediaprovider.MediaProvider) *ArtistsGenresPage {
|
||||||
return newArtistsGenresPage(isGenresPage, contr, sm, "")
|
return newArtistsGenresPage(isGenresPage, contr, mp, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArtistsGenresPage(isGenresPage bool, contr *controller.Controller, sm *backend.ServerManager, searchText string) *ArtistsGenresPage {
|
func newArtistsGenresPage(isGenresPage bool, contr *controller.Controller, mp mediaprovider.MediaProvider, searchText string) *ArtistsGenresPage {
|
||||||
title := "Artists"
|
title := "Artists"
|
||||||
if isGenresPage {
|
if isGenresPage {
|
||||||
title = "Genres"
|
title = "Genres"
|
||||||
@@ -46,7 +45,7 @@ func newArtistsGenresPage(isGenresPage bool, contr *controller.Controller, sm *b
|
|||||||
a := &ArtistsGenresPage{
|
a := &ArtistsGenresPage{
|
||||||
isGenresPage: isGenresPage,
|
isGenresPage: isGenresPage,
|
||||||
contr: contr,
|
contr: contr,
|
||||||
sm: sm,
|
mp: mp,
|
||||||
titleDisp: widget.NewRichTextWithText(title),
|
titleDisp: widget.NewRichTextWithText(title),
|
||||||
}
|
}
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
@@ -72,13 +71,13 @@ func newArtistsGenresPage(isGenresPage bool, contr *controller.Controller, sm *b
|
|||||||
// should be called asynchronously
|
// should be called asynchronously
|
||||||
func (a *ArtistsGenresPage) load(searchOnLoad bool) {
|
func (a *ArtistsGenresPage) load(searchOnLoad bool) {
|
||||||
if a.isGenresPage {
|
if a.isGenresPage {
|
||||||
genres, err := a.sm.Server.GetGenres()
|
genres, err := a.mp.GetGenres()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error loading genres: %v", err.Error())
|
log.Printf("error loading genres: %v", err.Error())
|
||||||
}
|
}
|
||||||
a.model = a.buildGenresListModel(genres)
|
a.model = a.buildGenresListModel(genres)
|
||||||
} else {
|
} else {
|
||||||
artists, err := a.sm.Server.GetArtists()
|
artists, err := a.mp.GetArtists()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error loading artists: %v", err.Error())
|
log.Printf("error loading artists: %v", err.Error())
|
||||||
}
|
}
|
||||||
@@ -127,7 +126,7 @@ func (a *ArtistsGenresPage) Save() SavedPage {
|
|||||||
return &savedArtistsGenresPage{
|
return &savedArtistsGenresPage{
|
||||||
isGenresPage: a.isGenresPage,
|
isGenresPage: a.isGenresPage,
|
||||||
contr: a.contr,
|
contr: a.contr,
|
||||||
sm: a.sm,
|
mp: a.mp,
|
||||||
searchText: a.searcher.Entry.Text,
|
searchText: a.searcher.Entry.Text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,12 +134,12 @@ func (a *ArtistsGenresPage) Save() SavedPage {
|
|||||||
type savedArtistsGenresPage struct {
|
type savedArtistsGenresPage struct {
|
||||||
isGenresPage bool
|
isGenresPage bool
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
sm *backend.ServerManager
|
mp mediaprovider.MediaProvider
|
||||||
searchText string
|
searchText string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *savedArtistsGenresPage) Restore() Page {
|
func (s *savedArtistsGenresPage) Restore() Page {
|
||||||
return newArtistsGenresPage(s.isGenresPage, s.contr, s.sm, s.searchText)
|
return newArtistsGenresPage(s.isGenresPage, s.contr, s.mp, s.searchText)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ArtistsGenresPage) buildArtistListModel(artists []*mediaprovider.Artist) []widgets.ArtistGenreListItemModel {
|
func (a *ArtistsGenresPage) buildArtistListModel(artists []*mediaprovider.Artist) []widgets.ArtistGenreListItemModel {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ type FavoritesPage struct {
|
|||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
sm *backend.ServerManager
|
mp mediaprovider.MediaProvider
|
||||||
|
|
||||||
filter mediaprovider.AlbumFilter
|
filter mediaprovider.AlbumFilter
|
||||||
searchText string
|
searchText string
|
||||||
@@ -43,18 +43,18 @@ type FavoritesPage struct {
|
|||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFavoritesPage(cfg *backend.FavoritesPageConfig, contr *controller.Controller, sm *backend.ServerManager, pm *backend.PlaybackManager, im *backend.ImageManager) *FavoritesPage {
|
func NewFavoritesPage(cfg *backend.FavoritesPageConfig, 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,
|
||||||
contr: contr,
|
contr: contr,
|
||||||
pm: pm,
|
pm: pm,
|
||||||
sm: sm,
|
mp: mp,
|
||||||
im: im,
|
im: im,
|
||||||
}
|
}
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
a.createHeader(0)
|
a.createHeader(0)
|
||||||
iter := sm.Server.IterateAlbums("", "", a.filter)
|
iter := mp.IterateAlbums("", a.filter)
|
||||||
a.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), a.im)
|
a.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), a.im)
|
||||||
a.contr.ConnectAlbumGridActions(a.grid)
|
a.contr.ConnectAlbumGridActions(a.grid)
|
||||||
if cfg.InitialView == "Artists" {
|
if cfg.InitialView == "Artists" {
|
||||||
@@ -98,7 +98,7 @@ func restoreFavoritesPage(saved *savedFavoritesPage) *FavoritesPage {
|
|||||||
cfg: saved.cfg,
|
cfg: saved.cfg,
|
||||||
contr: saved.contr,
|
contr: saved.contr,
|
||||||
pm: saved.pm,
|
pm: saved.pm,
|
||||||
sm: saved.sm,
|
mp: saved.mp,
|
||||||
im: saved.im,
|
im: saved.im,
|
||||||
searchText: saved.searchText,
|
searchText: saved.searchText,
|
||||||
filter: saved.filter,
|
filter: saved.filter,
|
||||||
@@ -139,13 +139,13 @@ func (a *FavoritesPage) Reload() {
|
|||||||
if a.searchText != "" {
|
if a.searchText != "" {
|
||||||
a.doSearchAlbums(a.searchText)
|
a.doSearchAlbums(a.searchText)
|
||||||
} else {
|
} else {
|
||||||
iter := a.sm.Server.IterateAlbums("", "", a.filter)
|
iter := a.mp.IterateAlbums("", a.filter)
|
||||||
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
|
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
|
||||||
}
|
}
|
||||||
if a.tracklistCtr != nil || a.artistListCtr != nil {
|
if a.tracklistCtr != nil || a.artistListCtr != nil {
|
||||||
go func() {
|
go func() {
|
||||||
// re-fetch starred info from server
|
// re-fetch starred info from server
|
||||||
starred, err := a.sm.Server.GetFavorites()
|
starred, err := a.mp.GetFavorites()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error getting starred items: %s", err.Error())
|
log.Printf("error getting starred items: %s", err.Error())
|
||||||
return
|
return
|
||||||
@@ -177,7 +177,7 @@ func (a *FavoritesPage) Save() SavedPage {
|
|||||||
cfg: a.cfg,
|
cfg: a.cfg,
|
||||||
contr: a.contr,
|
contr: a.contr,
|
||||||
pm: a.pm,
|
pm: a.pm,
|
||||||
sm: a.sm,
|
mp: a.mp,
|
||||||
im: a.im,
|
im: a.im,
|
||||||
filter: a.filter,
|
filter: a.filter,
|
||||||
searchText: a.searchText,
|
searchText: a.searchText,
|
||||||
@@ -230,7 +230,7 @@ func (a *FavoritesPage) SelectAll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *FavoritesPage) doSearchAlbums(query string) {
|
func (a *FavoritesPage) doSearchAlbums(query string) {
|
||||||
iter := a.sm.Server.IterateAlbums("", query, a.filter)
|
iter := a.mp.SearchAlbums(query, a.filter)
|
||||||
if a.searchGrid == nil {
|
if a.searchGrid == nil {
|
||||||
a.searchGrid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), a.im)
|
a.searchGrid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), a.im)
|
||||||
a.contr.ConnectAlbumGridActions(a.searchGrid)
|
a.contr.ConnectAlbumGridActions(a.searchGrid)
|
||||||
@@ -266,7 +266,7 @@ func (a *FavoritesPage) onShowFavoriteArtists() {
|
|||||||
a.createContainer(layout.NewSpacer())
|
a.createContainer(layout.NewSpacer())
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
fav, err := a.sm.Server.GetFavorites()
|
fav, err := a.mp.GetFavorites()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error getting starred items: %s", err.Error())
|
log.Printf("error getting starred items: %s", err.Error())
|
||||||
return
|
return
|
||||||
@@ -315,7 +315,7 @@ func (a *FavoritesPage) onShowFavoriteSongs() {
|
|||||||
a.createContainer(layout.NewSpacer())
|
a.createContainer(layout.NewSpacer())
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
fav, err := a.sm.Server.GetFavorites()
|
fav, err := a.mp.GetFavorites()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error getting starred items: %s", err.Error())
|
log.Printf("error getting starred items: %s", err.Error())
|
||||||
return
|
return
|
||||||
@@ -350,7 +350,7 @@ type savedFavoritesPage struct {
|
|||||||
cfg *backend.FavoritesPageConfig
|
cfg *backend.FavoritesPageConfig
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
sm *backend.ServerManager
|
mp mediaprovider.MediaProvider
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
gridState widgets.GridViewState
|
gridState widgets.GridViewState
|
||||||
searchGridState widgets.GridViewState
|
searchGridState widgets.GridViewState
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func NewGenrePage(genre string, contr *controller.Controller, pm *backend.Playba
|
|||||||
SizeName: theme.SizeNameHeadingText,
|
SizeName: theme.SizeNameHeadingText,
|
||||||
}
|
}
|
||||||
g.playRandom = widget.NewButtonWithIcon(" Play random", myTheme.ShuffleIcon, g.playRandomSongs)
|
g.playRandom = widget.NewButtonWithIcon(" Play random", myTheme.ShuffleIcon, g.playRandomSongs)
|
||||||
iter := g.mp.IterateAlbums("", "", g.filter)
|
iter := g.mp.IterateAlbums("", g.filter)
|
||||||
g.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), g.im)
|
g.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), g.im)
|
||||||
g.contr.ConnectAlbumGridActions(g.grid)
|
g.contr.ConnectAlbumGridActions(g.grid)
|
||||||
g.createSearchAndFilter()
|
g.createSearchAndFilter()
|
||||||
@@ -125,7 +125,7 @@ func (g *GenrePage) Reload() {
|
|||||||
if g.searchText != "" {
|
if g.searchText != "" {
|
||||||
g.doSearch(g.searchText)
|
g.doSearch(g.searchText)
|
||||||
} else {
|
} else {
|
||||||
iter := g.mp.IterateAlbums("", "", g.filter)
|
iter := g.mp.IterateAlbums("", g.filter)
|
||||||
g.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
|
g.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
|
||||||
g.grid.Refresh()
|
g.grid.Refresh()
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ func (g *GenrePage) OnSearched(query string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GenrePage) doSearch(query string) {
|
func (g *GenrePage) doSearch(query string) {
|
||||||
iter := g.mp.IterateAlbums("", query, g.filter)
|
iter := g.mp.SearchAlbums(query, g.filter)
|
||||||
if g.searchGrid == nil {
|
if g.searchGrid == nil {
|
||||||
g.searchGrid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), g.im)
|
g.searchGrid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), g.im)
|
||||||
g.contr.ConnectAlbumGridActions(g.searchGrid)
|
g.contr.ConnectAlbumGridActions(g.searchGrid)
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ type NowPlayingPage struct {
|
|||||||
type nowPlayingPageState struct {
|
type nowPlayingPageState struct {
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
conf *backend.NowPlayingPageConfig
|
conf *backend.NowPlayingPageConfig
|
||||||
sm *backend.ServerManager
|
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,10 +34,9 @@ func NewNowPlayingPage(
|
|||||||
highlightedTrackID string,
|
highlightedTrackID string,
|
||||||
contr *controller.Controller,
|
contr *controller.Controller,
|
||||||
conf *backend.NowPlayingPageConfig,
|
conf *backend.NowPlayingPageConfig,
|
||||||
sm *backend.ServerManager,
|
|
||||||
pm *backend.PlaybackManager,
|
pm *backend.PlaybackManager,
|
||||||
) *NowPlayingPage {
|
) *NowPlayingPage {
|
||||||
a := &NowPlayingPage{nowPlayingPageState: nowPlayingPageState{contr: contr, conf: conf, sm: sm, pm: pm}}
|
a := &NowPlayingPage{nowPlayingPageState: nowPlayingPageState{contr: contr, conf: conf, pm: pm}}
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
a.tracklist = widgets.NewTracklist(nil)
|
a.tracklist = widgets.NewTracklist(nil)
|
||||||
a.tracklist.SetVisibleColumns(conf.TracklistColumns)
|
a.tracklist.SetVisibleColumns(conf.TracklistColumns)
|
||||||
@@ -117,5 +115,5 @@ func (a *NowPlayingPage) load(highlightedTrackID string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *nowPlayingPageState) Restore() Page {
|
func (s *nowPlayingPageState) Restore() Page {
|
||||||
return NewNowPlayingPage("", s.contr, s.conf, s.sm, s.pm)
|
return NewNowPlayingPage("", s.contr, s.conf, s.pm)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type PlaylistsPage struct {
|
|||||||
|
|
||||||
cfg *backend.PlaylistsPageConfig
|
cfg *backend.PlaylistsPageConfig
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
sm *backend.ServerManager
|
mp mediaprovider.MediaProvider
|
||||||
playlists []*mediaprovider.Playlist
|
playlists []*mediaprovider.Playlist
|
||||||
searchedPlaylists []*mediaprovider.Playlist
|
searchedPlaylists []*mediaprovider.Playlist
|
||||||
|
|
||||||
@@ -38,18 +38,18 @@ type PlaylistsPage struct {
|
|||||||
gridView *widgets.GridView
|
gridView *widgets.GridView
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPlaylistsPage(contr *controller.Controller, cfg *backend.PlaylistsPageConfig, sm *backend.ServerManager) *PlaylistsPage {
|
func NewPlaylistsPage(contr *controller.Controller, cfg *backend.PlaylistsPageConfig, mp mediaprovider.MediaProvider) *PlaylistsPage {
|
||||||
activeView := 0
|
activeView := 0
|
||||||
if cfg.InitialView == "Grid" {
|
if cfg.InitialView == "Grid" {
|
||||||
activeView = 1
|
activeView = 1
|
||||||
}
|
}
|
||||||
return newPlaylistsPage(contr, cfg, sm, "", activeView)
|
return newPlaylistsPage(contr, cfg, mp, "", activeView)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPlaylistsPage(contr *controller.Controller, cfg *backend.PlaylistsPageConfig, sm *backend.ServerManager, searchText string, activeView int) *PlaylistsPage {
|
func newPlaylistsPage(contr *controller.Controller, cfg *backend.PlaylistsPageConfig, mp mediaprovider.MediaProvider, searchText string, activeView int) *PlaylistsPage {
|
||||||
a := &PlaylistsPage{
|
a := &PlaylistsPage{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
sm: sm,
|
mp: mp,
|
||||||
contr: contr,
|
contr: contr,
|
||||||
titleDisp: widget.NewRichTextWithText("Playlists"),
|
titleDisp: widget.NewRichTextWithText("Playlists"),
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ func newPlaylistsPage(contr *controller.Controller, cfg *backend.PlaylistsPageCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *PlaylistsPage) load(searchOnLoad bool) {
|
func (a *PlaylistsPage) load(searchOnLoad bool) {
|
||||||
playlists, err := a.sm.Server.GetPlaylists()
|
playlists, err := a.mp.GetPlaylists()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error loading playlists: %v", err.Error())
|
log.Printf("error loading playlists: %v", err.Error())
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,7 @@ func (a *PlaylistsPage) Save() SavedPage {
|
|||||||
return &savedPlaylistsPage{
|
return &savedPlaylistsPage{
|
||||||
contr: a.contr,
|
contr: a.contr,
|
||||||
cfg: a.cfg,
|
cfg: a.cfg,
|
||||||
sm: a.sm,
|
mp: a.mp,
|
||||||
searchText: a.searcher.Entry.Text,
|
searchText: a.searcher.Entry.Text,
|
||||||
activeView: a.viewToggle.ActivatedButtonIndex(),
|
activeView: a.viewToggle.ActivatedButtonIndex(),
|
||||||
}
|
}
|
||||||
@@ -222,13 +222,13 @@ func (a *PlaylistsPage) Save() SavedPage {
|
|||||||
type savedPlaylistsPage struct {
|
type savedPlaylistsPage struct {
|
||||||
contr *controller.Controller
|
contr *controller.Controller
|
||||||
cfg *backend.PlaylistsPageConfig
|
cfg *backend.PlaylistsPageConfig
|
||||||
sm *backend.ServerManager
|
mp mediaprovider.MediaProvider
|
||||||
searchText string
|
searchText string
|
||||||
activeView int
|
activeView int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *savedPlaylistsPage) Restore() Page {
|
func (s *savedPlaylistsPage) Restore() Page {
|
||||||
return newPlaylistsPage(s.contr, s.cfg, s.sm, s.searchText, s.activeView)
|
return newPlaylistsPage(s.contr, s.cfg, s.mp, s.searchText, s.activeView)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *PlaylistsPage) buildContainer(initialView fyne.CanvasObject) {
|
func (a *PlaylistsPage) buildContainer(initialView fyne.CanvasObject) {
|
||||||
|
|||||||
@@ -32,21 +32,21 @@ func (r Router) CreatePage(rte controller.Route) Page {
|
|||||||
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.App.PlaybackManager, r.App.ServerManager, r.App.ImageManager, r.Controller)
|
return NewArtistPage(rte.Arg, &r.App.Config.ArtistPage, r.App.PlaybackManager, r.App.ServerManager.Server, r.App.ImageManager, r.Controller)
|
||||||
case controller.Artists:
|
case controller.Artists:
|
||||||
return NewArtistsGenresPage(false, r.Controller, r.App.ServerManager)
|
return NewArtistsGenresPage(false, r.Controller, r.App.ServerManager.Server)
|
||||||
case controller.Favorites:
|
case controller.Favorites:
|
||||||
return NewFavoritesPage(&r.App.Config.FavoritesPage, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager)
|
return NewFavoritesPage(&r.App.Config.FavoritesPage, 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 NewArtistsGenresPage(true, r.Controller, r.App.ServerManager)
|
return NewArtistsGenresPage(true, r.Controller, r.App.ServerManager.Server)
|
||||||
case controller.NowPlaying:
|
case controller.NowPlaying:
|
||||||
return NewNowPlayingPage(rte.Arg, r.Controller, &r.App.Config.NowPlayingPage, r.App.ServerManager, r.App.PlaybackManager)
|
return NewNowPlayingPage(rte.Arg, r.Controller, &r.App.Config.NowPlayingPage, r.App.PlaybackManager)
|
||||||
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.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)
|
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.App.ServerManager.Server)
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-37
@@ -128,12 +128,14 @@ func (m *Controller) ConnectAlbumGridActions(grid *widgets.GridView) {
|
|||||||
m.NavigateTo(ArtistRoute(artistID))
|
m.NavigateTo(ArtistRoute(artistID))
|
||||||
}
|
}
|
||||||
grid.OnAddToPlaylist = func(albumID string) {
|
grid.OnAddToPlaylist = func(albumID string) {
|
||||||
album, err := m.App.ServerManager.Server.GetAlbum(albumID)
|
go func() {
|
||||||
if err != nil {
|
album, err := m.App.ServerManager.Server.GetAlbum(albumID)
|
||||||
log.Printf("error loading album: %s", err.Error())
|
if err != nil {
|
||||||
return
|
log.Printf("error loading album: %s", err.Error())
|
||||||
}
|
return
|
||||||
m.DoAddTracksToPlaylistWorkflow(sharedutil.TracksToIDs(album.Tracks))
|
}
|
||||||
|
m.DoAddTracksToPlaylistWorkflow(sharedutil.TracksToIDs(album.Tracks))
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,36 +171,38 @@ func (m *Controller) PromptForFirstServer() {
|
|||||||
// Depending on the results of that dialog, potentially create a new playlist
|
// Depending on the results of that dialog, potentially create a new playlist
|
||||||
// Add tracks to the user-specified playlist
|
// Add tracks to the user-specified playlist
|
||||||
func (m *Controller) DoAddTracksToPlaylistWorkflow(trackIDs []string) {
|
func (m *Controller) DoAddTracksToPlaylistWorkflow(trackIDs []string) {
|
||||||
pls, err := m.App.ServerManager.Server.GetPlaylists()
|
go func() {
|
||||||
pls = sharedutil.FilterSlice(pls, func(pl *mediaprovider.Playlist) bool {
|
pls, err := m.App.ServerManager.Server.GetPlaylists()
|
||||||
return pl.Owner == m.App.ServerManager.LoggedInUser
|
pls = sharedutil.FilterSlice(pls, func(pl *mediaprovider.Playlist) bool {
|
||||||
})
|
return pl.Owner == m.App.ServerManager.LoggedInUser
|
||||||
if err != nil {
|
})
|
||||||
// TODO: surface this error to user
|
if err != nil {
|
||||||
log.Printf("error getting user-owned playlists: %s", err.Error())
|
// TODO: surface this error to user
|
||||||
return
|
log.Printf("error getting user-owned playlists: %s", err.Error())
|
||||||
}
|
return
|
||||||
plNames := make([]string, 0, len(pls))
|
|
||||||
for _, pl := range pls {
|
|
||||||
plNames = append(plNames, pl.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
dlg := dialogs.NewAddToPlaylistDialog("Add to Playlist", plNames)
|
|
||||||
pop := widget.NewModalPopUp(dlg, m.MainWindow.Canvas())
|
|
||||||
m.ClosePopUpOnEscape(pop)
|
|
||||||
dlg.OnCanceled = pop.Hide
|
|
||||||
dlg.OnSubmit = func(playlistChoice int, newPlaylistName string) {
|
|
||||||
pop.Hide()
|
|
||||||
m.doModalClosed()
|
|
||||||
if playlistChoice < 0 {
|
|
||||||
m.App.ServerManager.Server.CreatePlaylist(newPlaylistName, trackIDs)
|
|
||||||
} else {
|
|
||||||
m.App.ServerManager.Server.EditPlaylistTracks(
|
|
||||||
pls[playlistChoice].ID, trackIDs, nil /*tracksToRemove*/)
|
|
||||||
}
|
}
|
||||||
}
|
plNames := make([]string, 0, len(pls))
|
||||||
m.haveModal = true
|
for _, pl := range pls {
|
||||||
pop.Show()
|
plNames = append(plNames, pl.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
dlg := dialogs.NewAddToPlaylistDialog("Add to Playlist", plNames)
|
||||||
|
pop := widget.NewModalPopUp(dlg, m.MainWindow.Canvas())
|
||||||
|
m.ClosePopUpOnEscape(pop)
|
||||||
|
dlg.OnCanceled = pop.Hide
|
||||||
|
dlg.OnSubmit = func(playlistChoice int, newPlaylistName string) {
|
||||||
|
pop.Hide()
|
||||||
|
m.doModalClosed()
|
||||||
|
if playlistChoice < 0 {
|
||||||
|
go m.App.ServerManager.Server.CreatePlaylist(newPlaylistName, trackIDs)
|
||||||
|
} else {
|
||||||
|
go m.App.ServerManager.Server.EditPlaylistTracks(
|
||||||
|
pls[playlistChoice].ID, trackIDs, nil /*tracksToRemove*/)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.haveModal = true
|
||||||
|
pop.Show()
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Controller) DoEditPlaylistWorkflow(playlist *mediaprovider.Playlist) {
|
func (m *Controller) DoEditPlaylistWorkflow(playlist *mediaprovider.Playlist) {
|
||||||
@@ -399,7 +403,7 @@ func (c *Controller) doModalClosed() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) SetTrackFavorites(trackIDs []string, favorite bool) {
|
func (c *Controller) SetTrackFavorites(trackIDs []string, favorite bool) {
|
||||||
c.App.ServerManager.Server.SetFavorite(mediaprovider.RatingFavoriteParameters{
|
go c.App.ServerManager.Server.SetFavorite(mediaprovider.RatingFavoriteParameters{
|
||||||
TrackIDs: trackIDs,
|
TrackIDs: trackIDs,
|
||||||
}, favorite)
|
}, favorite)
|
||||||
|
|
||||||
@@ -409,7 +413,7 @@ func (c *Controller) SetTrackFavorites(trackIDs []string, favorite bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) SetTrackRatings(trackIDs []string, rating int) {
|
func (c *Controller) SetTrackRatings(trackIDs []string, rating int) {
|
||||||
c.App.ServerManager.Server.SetRating(mediaprovider.RatingFavoriteParameters{
|
go c.App.ServerManager.Server.SetRating(mediaprovider.RatingFavoriteParameters{
|
||||||
TrackIDs: trackIDs,
|
TrackIDs: trackIDs,
|
||||||
}, rating)
|
}, rating)
|
||||||
|
|
||||||
|
|||||||
@@ -608,11 +608,11 @@ func (t *TrackRow) Update(tr *mediaprovider.Track, rowNum int) {
|
|||||||
|
|
||||||
// Render favorite column
|
// Render favorite column
|
||||||
if tr.Favorite {
|
if tr.Favorite {
|
||||||
t.isFavorite = false
|
|
||||||
t.favorite.Objects[0].(*TappableIcon).Resource = myTheme.NotFavoriteIcon
|
|
||||||
} else {
|
|
||||||
t.isFavorite = true
|
t.isFavorite = true
|
||||||
t.favorite.Objects[0].(*TappableIcon).Resource = myTheme.FavoriteIcon
|
t.favorite.Objects[0].(*TappableIcon).Resource = myTheme.FavoriteIcon
|
||||||
|
} else {
|
||||||
|
t.isFavorite = false
|
||||||
|
t.favorite.Objects[0].(*TappableIcon).Resource = myTheme.NotFavoriteIcon
|
||||||
}
|
}
|
||||||
|
|
||||||
t.rating.Rating = tr.Rating
|
t.rating.Rating = tr.Rating
|
||||||
|
|||||||
Reference in New Issue
Block a user