add Related tab to Now Playing page

This commit is contained in:
Drew Weymouth
2024-05-25 11:57:17 -07:00
parent 8caab9bd43
commit e55a13fbdd
2 changed files with 89 additions and 18 deletions
+79 -8
View File
@@ -32,21 +32,32 @@ type NowPlayingPage struct {
nowPlayingPageState nowPlayingPageState
// volatile state
nowPlaying *mediaprovider.Track nowPlaying *mediaprovider.Track
nowPlayingID string nowPlayingID string
curLyricsID string curLyricsID string // id of track currently shown in lyrics
curRelatedID string // id of track currrently used to populate related list
totalTime float64
lastPlayPos float64
queue []*mediaprovider.Track queue []*mediaprovider.Track
queueList *widgets.PlayQueueList related []*mediaprovider.Track
lyricLock sync.Mutex lyricLock sync.Mutex
relatedLock sync.Mutex
// widgets for render
queueList *widgets.PlayQueueList
relatedList *widgets.PlayQueueList
lyricsViewer *widgets.LyricsViewer lyricsViewer *widgets.LyricsViewer
lyricFetchCancel context.CancelFunc
imageLoadCancel context.CancelFunc
card *widgets.LargeNowPlayingCard card *widgets.LargeNowPlayingCard
statusLabel *widget.Label statusLabel *widget.Label
tabs *container.AppTabs tabs *container.AppTabs
totalTime float64
lastPlayPos float64
container *fyne.Container container *fyne.Container
// cancel funcs for background fetch tasks
lyricFetchCancel context.CancelFunc
imageLoadCancel context.CancelFunc
relatedFetchCancel context.CancelFunc
} }
type nowPlayingPageState struct { type nowPlayingPageState struct {
@@ -56,6 +67,7 @@ type nowPlayingPageState struct {
sm *backend.ServerManager sm *backend.ServerManager
pm *backend.PlaybackManager pm *backend.PlaybackManager
im *backend.ImageManager im *backend.ImageManager
mp mediaprovider.MediaProvider
canRate bool canRate bool
canShare bool canShare bool
} }
@@ -67,11 +79,12 @@ func NewNowPlayingPage(
sm *backend.ServerManager, sm *backend.ServerManager,
im *backend.ImageManager, im *backend.ImageManager,
pm *backend.PlaybackManager, pm *backend.PlaybackManager,
mp mediaprovider.MediaProvider,
canRate bool, canRate bool,
canShare bool, canShare bool,
) *NowPlayingPage { ) *NowPlayingPage {
a := &NowPlayingPage{nowPlayingPageState: nowPlayingPageState{ a := &NowPlayingPage{nowPlayingPageState: nowPlayingPageState{
conf: conf, contr: contr, pool: pool, sm: sm, im: im, pm: pm, canRate: canRate, canShare: canShare, conf: conf, contr: contr, pool: pool, sm: sm, im: im, pm: pm, mp: mp, canRate: canRate, canShare: canShare,
}} }}
a.ExtendBaseWidget(a) a.ExtendBaseWidget(a)
@@ -95,6 +108,7 @@ func NewNowPlayingPage(
} }
a.queueList = widgets.NewPlayQueueList(a.im) a.queueList = widgets.NewPlayQueueList(a.im)
a.relatedList = widgets.NewPlayQueueList(a.im)
a.queueList.DisableRating = !canRate a.queueList.DisableRating = !canRate
a.queueList.DisableSharing = !canShare a.queueList.DisableSharing = !canShare
a.queueList.OnReorderTracks = a.doSetNewTrackOrder a.queueList.OnReorderTracks = a.doSetNewTrackOrder
@@ -127,6 +141,17 @@ func NewNowPlayingPage(
a.card.SetDisplayedFavorite(fav) a.card.SetDisplayedFavorite(fav)
} }
} }
a.relatedList.OnDownload = a.queueList.OnDownload
a.relatedList.OnShare = a.queueList.OnShare
a.relatedList.OnAddToPlaylist = a.queueList.OnAddToPlaylist
a.relatedList.OnShowArtistPage = a.queueList.OnShowArtistPage
a.relatedList.OnRemoveFromQueue = a.queueList.OnRemoveFromQueue
a.relatedList.OnSetRating = a.queueList.OnSetRating
a.relatedList.OnSetFavorite = a.queueList.OnSetFavorite
a.relatedList.OnPlayTrackAt = func(idx int) {
a.pm.LoadTracks(a.related, backend.Replace, false)
a.pm.PlayTrackAt(idx)
}
a.lyricsViewer = widgets.NewLyricsViewer() a.lyricsViewer = widgets.NewLyricsViewer()
a.statusLabel = widget.NewLabel("Stopped") a.statusLabel = widget.NewLabel("Stopped")
@@ -140,6 +165,8 @@ func (a *NowPlayingPage) CreateRenderer() fyne.WidgetRenderer {
initialTab := 0 initialTab := 0
if a.conf.InitialView == "Lyrics" { if a.conf.InitialView == "Lyrics" {
initialTab = 1 initialTab = 1
} else if a.conf.InitialView == "Related" {
initialTab = 2
} }
_ = initialTab _ = initialTab
paddedLayout := &layouts.PercentPadLayout{ paddedLayout := &layouts.PercentPadLayout{
@@ -150,6 +177,7 @@ func (a *NowPlayingPage) CreateRenderer() fyne.WidgetRenderer {
container.NewTabItem("Play Queue", container.NewTabItem("Play Queue",
container.NewBorder(layout.NewSpacer(), nil, nil, nil, a.queueList)), container.NewBorder(layout.NewSpacer(), nil, nil, nil, a.queueList)),
container.NewTabItem("Lyrics", a.lyricsViewer), container.NewTabItem("Lyrics", a.lyricsViewer),
container.NewTabItem("Related", a.relatedList),
) )
a.tabs.SelectIndex(initialTab) a.tabs.SelectIndex(initialTab)
a.tabs.OnSelected = func(*container.TabItem) { a.tabs.OnSelected = func(*container.TabItem) {
@@ -157,10 +185,14 @@ func (a *NowPlayingPage) CreateRenderer() fyne.WidgetRenderer {
a.saveSelectedTab(idx) a.saveSelectedTab(idx)
if idx == 1 /*lyrics*/ { if idx == 1 /*lyrics*/ {
a.updateLyrics() a.updateLyrics()
} else if idx == 2 /*related*/ {
a.updateRelatedList()
} }
} }
if initialTab == 1 /*lyrics*/ { if initialTab == 1 /*lyrics*/ {
a.updateLyrics() a.updateLyrics()
} else if initialTab == 2 /*related*/ {
a.updateRelatedList()
} }
mainContent := container.NewGridWithColumns(2, mainContent := container.NewGridWithColumns(2,
container.New(paddedLayout, a.card), container.New(paddedLayout, a.card),
@@ -201,6 +233,7 @@ func (a *NowPlayingPage) OnSongChange(song, _ *mediaprovider.Track) {
} }
a.nowPlayingID = sharedutil.TrackIDOrEmptyStr(song) a.nowPlayingID = sharedutil.TrackIDOrEmptyStr(song)
a.queueList.SetNowPlaying(a.nowPlayingID) a.queueList.SetNowPlaying(a.nowPlayingID)
a.relatedList.SetNowPlaying(a.nowPlayingID)
a.card.Update(song) a.card.Update(song)
if song == nil { if song == nil {
@@ -217,6 +250,8 @@ func (a *NowPlayingPage) OnSongChange(song, _ *mediaprovider.Track) {
if a.tabs != nil && a.tabs.SelectedIndex() == 1 /*lyrics*/ { if a.tabs != nil && a.tabs.SelectedIndex() == 1 /*lyrics*/ {
a.updateLyrics() a.updateLyrics()
} else if a.tabs != nil && a.tabs.SelectedIndex() == 2 /*related*/ {
a.updateRelatedList()
} }
} }
@@ -264,6 +299,40 @@ func (a *NowPlayingPage) updateLyrics() {
} }
} }
func (a *NowPlayingPage) updateRelatedList() {
a.relatedLock.Lock()
defer a.relatedLock.Unlock()
if a.relatedFetchCancel != nil {
a.relatedFetchCancel()
}
if a.curRelatedID == a.nowPlayingID {
return
}
a.curRelatedID = a.nowPlayingID
if a.nowPlayingID == "" {
a.relatedList.SetTracks(nil)
}
ctx, cancel := context.WithCancel(context.Background())
a.relatedFetchCancel = cancel
go func(ctx context.Context) {
related, err := a.mp.GetSongRadio(a.nowPlayingID, 50)
if err != nil {
log.Println("failed to get similar tracks: %s", err.Error())
}
select {
case <-ctx.Done():
return
default:
a.relatedLock.Lock()
a.related = related
a.relatedList.SetTracks(a.related)
a.relatedLock.Unlock()
}
}(ctx)
}
func (a *NowPlayingPage) OnPlayQueueChange() { func (a *NowPlayingPage) OnPlayQueueChange() {
a.Reload() a.Reload()
} }
@@ -283,7 +352,7 @@ func (s *nowPlayingPageState) Restore() Page {
page.Reload() page.Reload()
return page return page
} }
return NewNowPlayingPage(s.conf, s.contr, s.pool, s.sm, s.im, s.pm, s.canRate, s.canShare) return NewNowPlayingPage(s.conf, s.contr, s.pool, s.sm, s.im, s.pm, s.mp, s.canRate, s.canShare)
} }
var _ CanShowPlayTime = (*NowPlayingPage)(nil) var _ CanShowPlayTime = (*NowPlayingPage)(nil)
@@ -334,6 +403,8 @@ func (a *NowPlayingPage) saveSelectedTab(tabNum int) {
tabName = "Play Queue" tabName = "Play Queue"
case 1: case 1:
tabName = "Lyrics" tabName = "Lyrics"
case 2:
tabName = "Related"
} }
a.conf.InitialView = tabName a.conf.InitialView = tabName
} }
+1 -1
View File
@@ -48,7 +48,7 @@ func (r Router) CreatePage(rte controller.Route) Page {
case controller.Genres: case controller.Genres:
return NewGenresPage(r.Controller, r.App.ServerManager.Server) return NewGenresPage(r.Controller, r.App.ServerManager.Server)
case controller.NowPlaying: case controller.NowPlaying:
return NewNowPlayingPage(&r.App.Config.NowPlayingConfig, r.Controller, r.widgetPool, r.App.ServerManager, r.App.ImageManager, r.App.PlaybackManager, canRate, canShare) return NewNowPlayingPage(&r.App.Config.NowPlayingConfig, r.Controller, r.widgetPool, r.App.ServerManager, r.App.ImageManager, r.App.PlaybackManager, r.App.ServerManager.Server, canRate, canShare)
case controller.Playlist: case controller.Playlist:
return NewPlaylistPage(rte.Arg, &r.App.Config.PlaylistPage, r.widgetPool, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager) return NewPlaylistPage(rte.Arg, &r.App.Config.PlaylistPage, r.widgetPool, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager)
case controller.Playlists: case controller.Playlists: