add Now Playing page to show play queue
This commit is contained in:
@@ -161,6 +161,20 @@ func (p *PlaybackManager) PlayFromBeginning() error {
|
|||||||
return p.player.PlayFromBeginning()
|
return p.player.PlayFromBeginning()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PlaybackManager) PlayTrackAt(idx int) error {
|
||||||
|
return p.player.PlayTrackAt(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PlaybackManager) GetPlayQueue() []*subsonic.Child {
|
||||||
|
pq := make([]*subsonic.Child, len(p.playQueue))
|
||||||
|
copy(pq, p.playQueue)
|
||||||
|
return pq
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PlaybackManager) RemoveTracksFromQueue(trackIdxs []int) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
func (p *PlaybackManager) checkScrobble(playDur time.Duration) {
|
func (p *PlaybackManager) checkScrobble(playDur time.Duration) {
|
||||||
if playDur.Seconds() < 0.1 || p.curTrackTime < 0.1 {
|
if playDur.Seconds() < 0.1 || p.curTrackTime < 0.1 {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package browsing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"supersonic/backend"
|
||||||
|
"supersonic/ui/controller"
|
||||||
|
"supersonic/ui/layouts"
|
||||||
|
"supersonic/ui/widgets"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"github.com/dweymouth/go-subsonic/subsonic"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NowPlayingPage struct {
|
||||||
|
widget.BaseWidget
|
||||||
|
|
||||||
|
nowPlayingPageState
|
||||||
|
|
||||||
|
title *widget.RichText
|
||||||
|
tracklist *widgets.Tracklist
|
||||||
|
nowPlayingID string
|
||||||
|
container *fyne.Container
|
||||||
|
}
|
||||||
|
|
||||||
|
type nowPlayingPageState struct {
|
||||||
|
contr controller.Controller
|
||||||
|
sm *backend.ServerManager
|
||||||
|
pm *backend.PlaybackManager
|
||||||
|
nav func(Route)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNowPlayingPage(
|
||||||
|
contr controller.Controller,
|
||||||
|
sm *backend.ServerManager,
|
||||||
|
pm *backend.PlaybackManager,
|
||||||
|
nav func(Route),
|
||||||
|
) *NowPlayingPage {
|
||||||
|
a := &NowPlayingPage{nowPlayingPageState: nowPlayingPageState{contr: contr, sm: sm, pm: pm, nav: nav}}
|
||||||
|
a.ExtendBaseWidget(a)
|
||||||
|
a.tracklist = widgets.NewTracklist(nil)
|
||||||
|
a.tracklist.AutoNumber = true
|
||||||
|
a.tracklist.DisablePlaybackMenu = true
|
||||||
|
a.tracklist.OnPlayTrackAt = a.onPlayTrackAt
|
||||||
|
a.tracklist.OnAddToPlaylist = a.contr.DoAddTracksToPlaylistWorkflow
|
||||||
|
a.title = widget.NewRichTextWithText("Now Playing")
|
||||||
|
a.title.Segments[0].(*widget.TextSegment).Style.SizeName = widget.RichTextStyleHeading.SizeName
|
||||||
|
a.container = container.New(&layouts.MaxPadLayout{PadLeft: 15, PadRight: 15, PadTop: 5, PadBottom: 15},
|
||||||
|
container.NewBorder(a.title, nil, nil, nil, a.tracklist))
|
||||||
|
a.loadAsync()
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *NowPlayingPage) CreateRenderer() fyne.WidgetRenderer {
|
||||||
|
return widget.NewSimpleRenderer(a.container)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *NowPlayingPage) Save() SavedPage {
|
||||||
|
nps := a.nowPlayingPageState
|
||||||
|
return &nps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *NowPlayingPage) Route() Route {
|
||||||
|
return NowPlayingRoute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *NowPlayingPage) Tapped(*fyne.PointEvent) {
|
||||||
|
a.tracklist.UnselectAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *NowPlayingPage) SelectAll() {
|
||||||
|
a.tracklist.SelectAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *NowPlayingPage) OnSongChange(song *subsonic.Child) {
|
||||||
|
if song == nil {
|
||||||
|
a.nowPlayingID = ""
|
||||||
|
} else {
|
||||||
|
a.nowPlayingID = song.ID
|
||||||
|
}
|
||||||
|
a.tracklist.SetNowPlaying(a.nowPlayingID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *NowPlayingPage) Reload() {
|
||||||
|
a.loadAsync()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *NowPlayingPage) onPlayTrackAt(tracknum int) {
|
||||||
|
_ = a.pm.PlayTrackAt(tracknum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *NowPlayingPage) loadAsync() {
|
||||||
|
go func() {
|
||||||
|
queue := a.pm.GetPlayQueue()
|
||||||
|
a.tracklist.Tracks = queue
|
||||||
|
a.tracklist.SetNowPlaying(a.nowPlayingID)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *nowPlayingPageState) Restore() Page {
|
||||||
|
return NewNowPlayingPage(s.contr, s.sm, s.pm, s.nav)
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ package browsing
|
|||||||
import (
|
import (
|
||||||
"supersonic/backend"
|
"supersonic/backend"
|
||||||
"supersonic/ui/controller"
|
"supersonic/ui/controller"
|
||||||
"supersonic/ui/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PageName int
|
type PageName int
|
||||||
@@ -17,6 +16,7 @@ const (
|
|||||||
Genre
|
Genre
|
||||||
Genres
|
Genres
|
||||||
Favorites
|
Favorites
|
||||||
|
NowPlaying
|
||||||
Playlist
|
Playlist
|
||||||
Playlists
|
Playlists
|
||||||
)
|
)
|
||||||
@@ -61,6 +61,10 @@ func ArtistsRoute() Route {
|
|||||||
return Route{Page: Artists}
|
return Route{Page: Artists}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NowPlayingRoute() Route {
|
||||||
|
return Route{Page: NowPlaying}
|
||||||
|
}
|
||||||
|
|
||||||
type NavigationHandler interface {
|
type NavigationHandler interface {
|
||||||
SetPage(Page)
|
SetPage(Page)
|
||||||
}
|
}
|
||||||
@@ -69,8 +73,6 @@ type Router struct {
|
|||||||
App *backend.App
|
App *backend.App
|
||||||
Controller controller.Controller
|
Controller controller.Controller
|
||||||
Nav NavigationHandler
|
Nav NavigationHandler
|
||||||
|
|
||||||
pop util.PopUpProvider
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRouter(app *backend.App, controller controller.Controller, nav NavigationHandler) Router {
|
func NewRouter(app *backend.App, controller controller.Controller, nav NavigationHandler) Router {
|
||||||
@@ -98,6 +100,8 @@ func (r Router) CreatePage(rte Route) Page {
|
|||||||
return NewGenrePage(rte.Arg, r.App.LibraryManager, r.App.ImageManager, r.OpenRoute)
|
return NewGenrePage(rte.Arg, r.App.LibraryManager, r.App.ImageManager, r.OpenRoute)
|
||||||
case Genres:
|
case Genres:
|
||||||
return NewArtistsGenresPage(true, r.App.ServerManager, r.OpenRoute)
|
return NewArtistsGenresPage(true, r.App.ServerManager, r.OpenRoute)
|
||||||
|
case NowPlaying:
|
||||||
|
return NewNowPlayingPage(r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.OpenRoute)
|
||||||
case Playlist:
|
case Playlist:
|
||||||
return NewPlaylistPage(rte.Arg, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager, r.OpenRoute)
|
return NewPlaylistPage(rte.Arg, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager, r.OpenRoute)
|
||||||
case Playlists:
|
case Playlists:
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ func (m *MainWindow) PromptForFirstServer(cb func(string, string, string, string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MainWindow) addNavigationButtons() {
|
func (m *MainWindow) addNavigationButtons() {
|
||||||
|
m.BrowsingPane.AddNavigationButton(res.ResHeadphonesInvertPng, func() {
|
||||||
|
m.Router.OpenRoute(browsing.NowPlayingRoute())
|
||||||
|
})
|
||||||
m.BrowsingPane.AddNavigationButton(res.ResHeartFilledInvertPng, func() {
|
m.BrowsingPane.AddNavigationButton(res.ResHeartFilledInvertPng, func() {
|
||||||
m.Router.OpenRoute(browsing.FavoritesRoute())
|
m.Router.OpenRoute(browsing.FavoritesRoute())
|
||||||
})
|
})
|
||||||
|
|||||||
+19
-14
@@ -119,7 +119,8 @@ type Tracklist struct {
|
|||||||
Tracks []*subsonic.Child
|
Tracks []*subsonic.Child
|
||||||
AutoNumber bool
|
AutoNumber bool
|
||||||
// must be set before the context menu is shown for the first time
|
// must be set before the context menu is shown for the first time
|
||||||
AuxiliaryMenuItems []*fyne.MenuItem
|
AuxiliaryMenuItems []*fyne.MenuItem
|
||||||
|
DisablePlaybackMenu bool
|
||||||
|
|
||||||
// user action callbacks
|
// user action callbacks
|
||||||
OnPlayTrackAt func(int)
|
OnPlayTrackAt func(int)
|
||||||
@@ -216,23 +217,27 @@ func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
|
|||||||
t.selectionMgr.Select(trackIdx)
|
t.selectionMgr.Select(trackIdx)
|
||||||
t.Refresh()
|
t.Refresh()
|
||||||
if t.ctxMenu == nil {
|
if t.ctxMenu == nil {
|
||||||
t.ctxMenu = fyne.NewMenu("",
|
t.ctxMenu = fyne.NewMenu("")
|
||||||
fyne.NewMenuItem("Play", func() {
|
if !t.DisablePlaybackMenu {
|
||||||
if t.OnPlaySelection != nil {
|
t.ctxMenu.Items = append(t.ctxMenu.Items,
|
||||||
t.OnPlaySelection(t.selectedTracks())
|
fyne.NewMenuItem("Play", func() {
|
||||||
}
|
if t.OnPlaySelection != nil {
|
||||||
}),
|
t.OnPlaySelection(t.selectedTracks())
|
||||||
fyne.NewMenuItem("Add to queue", func() {
|
}
|
||||||
if t.OnPlaySelection != nil {
|
}))
|
||||||
t.OnAddToQueue(t.selectedTracks())
|
t.ctxMenu.Items = append(t.ctxMenu.Items,
|
||||||
}
|
fyne.NewMenuItem("Add to queue", func() {
|
||||||
}),
|
if t.OnPlaySelection != nil {
|
||||||
|
t.OnAddToQueue(t.selectedTracks())
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
t.ctxMenu.Items = append(t.ctxMenu.Items,
|
||||||
fyne.NewMenuItem("Add to playlist...", func() {
|
fyne.NewMenuItem("Add to playlist...", func() {
|
||||||
if t.OnAddToPlaylist != nil {
|
if t.OnAddToPlaylist != nil {
|
||||||
t.OnAddToPlaylist(t.selectedTrackIDs())
|
t.OnAddToPlaylist(t.selectedTrackIDs())
|
||||||
}
|
}
|
||||||
}),
|
}))
|
||||||
)
|
|
||||||
if len(t.AuxiliaryMenuItems) > 0 {
|
if len(t.AuxiliaryMenuItems) > 0 {
|
||||||
t.ctxMenu.Items = append(t.ctxMenu.Items, fyne.NewMenuItemSeparator())
|
t.ctxMenu.Items = append(t.ctxMenu.Items, fyne.NewMenuItemSeparator())
|
||||||
t.ctxMenu.Items = append(t.ctxMenu.Items, t.AuxiliaryMenuItems...)
|
t.ctxMenu.Items = append(t.ctxMenu.Items, t.AuxiliaryMenuItems...)
|
||||||
|
|||||||
Reference in New Issue
Block a user