add Related tab to Now Playing page
This commit is contained in:
@@ -32,21 +32,32 @@ type NowPlayingPage struct {
|
|||||||
|
|
||||||
nowPlayingPageState
|
nowPlayingPageState
|
||||||
|
|
||||||
nowPlaying *mediaprovider.Track
|
// volatile state
|
||||||
nowPlayingID string
|
nowPlaying *mediaprovider.Track
|
||||||
curLyricsID string
|
nowPlayingID string
|
||||||
queue []*mediaprovider.Track
|
curLyricsID string // id of track currently shown in lyrics
|
||||||
queueList *widgets.PlayQueueList
|
curRelatedID string // id of track currrently used to populate related list
|
||||||
lyricLock sync.Mutex
|
totalTime float64
|
||||||
lyricsViewer *widgets.LyricsViewer
|
lastPlayPos float64
|
||||||
lyricFetchCancel context.CancelFunc
|
queue []*mediaprovider.Track
|
||||||
imageLoadCancel context.CancelFunc
|
related []*mediaprovider.Track
|
||||||
card *widgets.LargeNowPlayingCard
|
|
||||||
statusLabel *widget.Label
|
lyricLock sync.Mutex
|
||||||
tabs *container.AppTabs
|
relatedLock sync.Mutex
|
||||||
totalTime float64
|
|
||||||
lastPlayPos float64
|
// widgets for render
|
||||||
container *fyne.Container
|
queueList *widgets.PlayQueueList
|
||||||
|
relatedList *widgets.PlayQueueList
|
||||||
|
lyricsViewer *widgets.LyricsViewer
|
||||||
|
card *widgets.LargeNowPlayingCard
|
||||||
|
statusLabel *widget.Label
|
||||||
|
tabs *container.AppTabs
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user