Add pop up plqy queue button to lower right
This commit is contained in:
@@ -55,6 +55,11 @@ var ResPlaylistSvg = &fyne.StaticResource{
|
|||||||
StaticContent: []byte(
|
StaticContent: []byte(
|
||||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->\n<svg fill=\"#000000\" width=\"800px\" height=\"800px\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M16 17a3 3 0 0 1-3 3h-2a3 3 0 0 1 0-6h2a3 3 0 0 1 1 .17V1l6-1v4l-4 .67V17zM0 3h12v2H0V3zm0 4h12v2H0V7zm0 4h12v2H0v-2zm0 4h6v2H0v-2z\"/></svg>"),
|
"<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->\n<svg fill=\"#000000\" width=\"800px\" height=\"800px\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M16 17a3 3 0 0 1-3 3h-2a3 3 0 0 1 0-6h2a3 3 0 0 1 1 .17V1l6-1v4l-4 .67V17zM0 3h12v2H0V3zm0 4h12v2H0V7zm0 4h12v2H0v-2zm0 4h6v2H0v-2z\"/></svg>"),
|
||||||
}
|
}
|
||||||
|
var ResPlayqueueSvg = &fyne.StaticResource{
|
||||||
|
StaticName: "playqueue.svg",
|
||||||
|
StaticContent: []byte(
|
||||||
|
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->\n<svg fill=\"#000000\" width=\"800px\" height=\"800px\" viewBox=\"0 0 32 32\" style=\"fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;\" version=\"1.1\" xml:space=\"preserve\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:serif=\"http://www.serif.com/\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" stroke=\"#000000\" stroke-width=\"0.48\">\n\r<g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"/>\n\r<g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n\r<g id=\"SVGRepo_iconCarrier\">\n\r<path d=\"M5.011,19l21.989,-0c0.552,0 1,-0.448 1,-1c0,-0.552 -0.448,-1 -1,-1l-21.989,0c-0.552,0 -1,0.448 -1,1c-0,0.552 0.448,1 1,1Z\"/>\n\r<path d=\"M5.019,28l21.981,-0c0.552,0 1,-0.448 1,-1c0,-0.552 -0.448,-1 -1,-1l-21.981,0c-0.552,0 -1,0.448 -1,1c0,0.552 0.448,1 1,1Z\"/>\n\r<path d=\"M15.994,10l11.006,0c0.552,-0 1,-0.448 1,-1c-0,-0.552 -0.448,-1 -1,-1l-11.006,0c-0.552,-0 -1,0.448 -1,1c-0,0.552 0.448,1 1,1Z\"/>\n\r<path d=\"M12.496,9.868c0.312,-0.178 0.504,-0.509 0.504,-0.868c-0,-0.359 -0.192,-0.69 -0.504,-0.868l-7,-4c-0.309,-0.177 -0.69,-0.176 -0.998,0.003c-0.308,0.179 -0.498,0.509 -0.498,0.865l-0,8c-0,0.356 0.19,0.686 0.498,0.865c0.308,0.179 0.689,0.18 0.998,0.003l7,-4Z\"/>\n\r</g>\n\r</svg>"),
|
||||||
|
}
|
||||||
var ResStarOutlineSvg = &fyne.StaticResource{
|
var ResStarOutlineSvg = &fyne.StaticResource{
|
||||||
StaticName: "star-outline.svg",
|
StaticName: "star-outline.svg",
|
||||||
StaticContent: []byte(
|
StaticContent: []byte(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ fyne bundle -append -prefix Res icons/publicdomain/heart-outline.svg >> bundled.
|
|||||||
fyne bundle -append -prefix Res icons/publicdomain/musicnotes.svg >> bundled.go
|
fyne bundle -append -prefix Res icons/publicdomain/musicnotes.svg >> bundled.go
|
||||||
fyne bundle -append -prefix Res icons/publicdomain/people.svg >> bundled.go
|
fyne bundle -append -prefix Res icons/publicdomain/people.svg >> bundled.go
|
||||||
fyne bundle -append -prefix Res icons/publicdomain/playlist.svg >> bundled.go
|
fyne bundle -append -prefix Res icons/publicdomain/playlist.svg >> bundled.go
|
||||||
|
fyne bundle -append -prefix Res icons/publicdomain/playqueue.svg >> bundled.go
|
||||||
fyne bundle -append -prefix Res icons/publicdomain/star-outline.svg >> bundled.go
|
fyne bundle -append -prefix Res icons/publicdomain/star-outline.svg >> bundled.go
|
||||||
fyne bundle -append -prefix Res icons/publicdomain/star-filled.svg >> bundled.go
|
fyne bundle -append -prefix Res icons/publicdomain/star-filled.svg >> bundled.go
|
||||||
fyne bundle -append -prefix Res icons/publicdomain/theatermasks.svg >> bundled.go
|
fyne bundle -append -prefix Res icons/publicdomain/theatermasks.svg >> bundled.go
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" version="1.1" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:serif="http://www.serif.com/" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="#000000" stroke-width="0.48">
|
||||||
|
␍<g id="SVGRepo_bgCarrier" stroke-width="0"/>
|
||||||
|
␍<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
␍<g id="SVGRepo_iconCarrier">
|
||||||
|
␍<path d="M5.011,19l21.989,-0c0.552,0 1,-0.448 1,-1c0,-0.552 -0.448,-1 -1,-1l-21.989,0c-0.552,0 -1,0.448 -1,1c-0,0.552 0.448,1 1,1Z"/>
|
||||||
|
␍<path d="M5.019,28l21.981,-0c0.552,0 1,-0.448 1,-1c0,-0.552 -0.448,-1 -1,-1l-21.981,0c-0.552,0 -1,0.448 -1,1c0,0.552 0.448,1 1,1Z"/>
|
||||||
|
␍<path d="M15.994,10l11.006,0c0.552,-0 1,-0.448 1,-1c-0,-0.552 -0.448,-1 -1,-1l-11.006,0c-0.552,-0 -1,0.448 -1,1c-0,0.552 0.448,1 1,1Z"/>
|
||||||
|
␍<path d="M12.496,9.868c0.312,-0.178 0.504,-0.509 0.504,-0.868c-0,-0.359 -0.192,-0.69 -0.504,-0.868l-7,-4c-0.309,-0.177 -0.69,-0.176 -0.998,0.003c-0.308,0.179 -0.498,0.509 -0.498,0.865l-0,8c-0,0.356 0.19,0.686 0.498,0.865c0.308,0.179 0.689,0.18 0.998,0.003l7,-4Z"/>
|
||||||
|
␍</g>
|
||||||
|
␍</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -106,6 +106,7 @@ func NewBottomPanel(pm *backend.PlaybackManager, im *backend.ImageManager, contr
|
|||||||
bp.AuxControls.OnChangeLoopMode(func() {
|
bp.AuxControls.OnChangeLoopMode(func() {
|
||||||
pm.SetNextLoopMode()
|
pm.SetNextLoopMode()
|
||||||
})
|
})
|
||||||
|
bp.AuxControls.OnShowPlayQueue(contr.ShowPopUpPlayQueue)
|
||||||
|
|
||||||
bp.imageLoader = util.NewThumbnailLoader(im, bp.NowPlaying.SetImage)
|
bp.imageLoader = util.NewThumbnailLoader(im, bp.NowPlaying.SetImage)
|
||||||
|
|
||||||
|
|||||||
@@ -131,24 +131,10 @@ func NewNowPlayingPage(
|
|||||||
a.queueList = widgets.NewPlayQueueList(a.im, false)
|
a.queueList = widgets.NewPlayQueueList(a.im, false)
|
||||||
a.relatedList = widgets.NewPlayQueueList(a.im, true)
|
a.relatedList = widgets.NewPlayQueueList(a.im, true)
|
||||||
a.queueList.Reorderable = true
|
a.queueList.Reorderable = true
|
||||||
a.queueList.OnReorderItems = a.doSetNewTrackOrder
|
|
||||||
a.queueList.OnDownload = contr.ShowDownloadDialog
|
a.contr.ConnectPlayQueuelistActions(a.queueList)
|
||||||
a.queueList.OnShare = func(tracks []*mediaprovider.Track) {
|
// override OnSetRating and Favorite so we can also update the
|
||||||
if len(tracks) > 0 {
|
// LargeNowPlayingCard's displayed rating and favorite
|
||||||
a.contr.ShowShareDialog(tracks[0].ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a.queueList.OnAddToPlaylist = contr.DoAddTracksToPlaylistWorkflow
|
|
||||||
a.queueList.OnPlayItemAt = func(tracknum int) {
|
|
||||||
_ = a.pm.PlayTrackAt(tracknum)
|
|
||||||
}
|
|
||||||
a.queueList.OnShowArtistPage = func(artistID string) {
|
|
||||||
a.contr.NavigateTo(controller.ArtistRoute(artistID))
|
|
||||||
}
|
|
||||||
a.queueList.OnRemoveFromQueue = func(idxs []int) {
|
|
||||||
a.queueList.UnselectAll()
|
|
||||||
a.pm.RemoveTracksFromQueue(idxs)
|
|
||||||
}
|
|
||||||
a.queueList.OnSetRating = func(trackIDs []string, rating int) {
|
a.queueList.OnSetRating = func(trackIDs []string, rating int) {
|
||||||
contr.SetTrackRatings(trackIDs, rating)
|
contr.SetTrackRatings(trackIDs, rating)
|
||||||
if slices.Contains(trackIDs, a.nowPlayingID) {
|
if slices.Contains(trackIDs, a.nowPlayingID) {
|
||||||
@@ -161,6 +147,7 @@ func NewNowPlayingPage(
|
|||||||
a.card.SetDisplayedFavorite(fav)
|
a.card.SetDisplayedFavorite(fav)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a.relatedList.OnDownload = a.queueList.OnDownload
|
a.relatedList.OnDownload = a.queueList.OnDownload
|
||||||
a.relatedList.OnShare = a.queueList.OnShare
|
a.relatedList.OnShare = a.queueList.OnShare
|
||||||
a.relatedList.OnAddToPlaylist = a.queueList.OnAddToPlaylist
|
a.relatedList.OnAddToPlaylist = a.queueList.OnAddToPlaylist
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/dweymouth/supersonic/backend"
|
||||||
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||||
|
"github.com/dweymouth/supersonic/backend/player"
|
||||||
|
"github.com/dweymouth/supersonic/sharedutil"
|
||||||
|
"github.com/dweymouth/supersonic/ui/widgets"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *Controller) ConnectTracklistActionsWithReplayGainAlbum(tracklist *widgets.Tracklist) {
|
||||||
|
m.connectTracklistActionsWithReplayGainMode(tracklist, player.ReplayGainAlbum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Controller) ConnectTracklistActions(tracklist *widgets.Tracklist) {
|
||||||
|
m.connectTracklistActionsWithReplayGainMode(tracklist, player.ReplayGainTrack)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Controller) connectTracklistActionsWithReplayGainMode(tracklist *widgets.Tracklist, mode player.ReplayGainMode) {
|
||||||
|
tracklist.OnAddToPlaylist = m.DoAddTracksToPlaylistWorkflow
|
||||||
|
tracklist.OnPlaySelectionNext = func(tracks []*mediaprovider.Track) {
|
||||||
|
m.App.PlaybackManager.LoadTracks(tracks, backend.InsertNext, false)
|
||||||
|
}
|
||||||
|
tracklist.OnAddToQueue = func(tracks []*mediaprovider.Track) {
|
||||||
|
m.App.PlaybackManager.LoadTracks(tracks, backend.Append, false)
|
||||||
|
}
|
||||||
|
tracklist.OnPlayTrackAt = func(idx int) {
|
||||||
|
m.App.PlaybackManager.LoadTracks(tracklist.GetTracks(), backend.Replace, false)
|
||||||
|
if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto {
|
||||||
|
m.App.PlaybackManager.SetReplayGainMode(mode)
|
||||||
|
}
|
||||||
|
m.App.PlaybackManager.PlayTrackAt(idx)
|
||||||
|
}
|
||||||
|
tracklist.OnPlaySelection = func(tracks []*mediaprovider.Track, shuffle bool) {
|
||||||
|
m.App.PlaybackManager.LoadTracks(tracks, backend.Replace, shuffle)
|
||||||
|
if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto {
|
||||||
|
m.App.PlaybackManager.SetReplayGainMode(mode)
|
||||||
|
}
|
||||||
|
m.App.PlaybackManager.PlayFromBeginning()
|
||||||
|
}
|
||||||
|
tracklist.OnSetFavorite = m.SetTrackFavorites
|
||||||
|
tracklist.OnSetRating = m.SetTrackRatings
|
||||||
|
tracklist.OnShowAlbumPage = func(albumID string) {
|
||||||
|
m.NavigateTo(AlbumRoute(albumID))
|
||||||
|
}
|
||||||
|
tracklist.OnShowArtistPage = func(artistID string) {
|
||||||
|
m.NavigateTo(ArtistRoute(artistID))
|
||||||
|
}
|
||||||
|
tracklist.OnColumnVisibilityMenuShown = func(pop *widget.PopUp) {
|
||||||
|
m.ClosePopUpOnEscape(pop)
|
||||||
|
}
|
||||||
|
tracklist.OnDownload = m.ShowDownloadDialog
|
||||||
|
tracklist.OnShare = func(trackID string) {
|
||||||
|
go m.ShowShareDialog(trackID)
|
||||||
|
}
|
||||||
|
tracklist.OnShowTrackInfo = m.ShowTrackInfoDialog
|
||||||
|
tracklist.OnPlaySongRadio = func(track *mediaprovider.Track) {
|
||||||
|
go func() {
|
||||||
|
tracks, err := m.GetSongRadioTracks(track)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error getting song radio: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.App.PlaybackManager.LoadTracks(tracks, backend.Replace, false)
|
||||||
|
if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto {
|
||||||
|
m.App.PlaybackManager.SetReplayGainMode(mode)
|
||||||
|
}
|
||||||
|
m.App.PlaybackManager.PlayFromBeginning()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Controller) ConnectAlbumGridActions(grid *widgets.GridView) {
|
||||||
|
grid.OnAddToQueue = func(albumID string) {
|
||||||
|
go m.App.PlaybackManager.LoadAlbum(albumID, backend.Append, false)
|
||||||
|
}
|
||||||
|
grid.OnPlayNext = func(albumID string) {
|
||||||
|
go m.App.PlaybackManager.LoadAlbum(albumID, backend.InsertNext, false)
|
||||||
|
}
|
||||||
|
grid.OnPlay = func(albumID string, shuffle bool) {
|
||||||
|
go m.App.PlaybackManager.PlayAlbum(albumID, 0, shuffle)
|
||||||
|
}
|
||||||
|
grid.OnShowItemPage = func(albumID string) {
|
||||||
|
m.NavigateTo(AlbumRoute(albumID))
|
||||||
|
}
|
||||||
|
grid.OnShowSecondaryPage = func(artistID string) {
|
||||||
|
m.NavigateTo(ArtistRoute(artistID))
|
||||||
|
}
|
||||||
|
grid.OnAddToPlaylist = func(albumID string) {
|
||||||
|
go func() {
|
||||||
|
album, err := m.App.ServerManager.Server.GetAlbum(albumID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error loading bum: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.DoAddTracksToPlaylistWorkflow(sharedutil.TracksToIDs(album.Tracks))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
grid.OnDownload = func(albumID string) {
|
||||||
|
go func() {
|
||||||
|
album, err := m.App.ServerManager.Server.GetAlbum(albumID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error loading bum: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.ShowDownloadDialog(album.Tracks, album.Name)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
grid.OnShare = func(albumID string) {
|
||||||
|
go m.ShowShareDialog(albumID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Controller) ConnectArtistGridActions(grid *widgets.GridView) {
|
||||||
|
grid.OnShowItemPage = func(id string) { m.NavigateTo(ArtistRoute(id)) }
|
||||||
|
grid.OnPlayNext = func(artistID string) {
|
||||||
|
go m.App.PlaybackManager.LoadTracks(m.GetArtistTracks(artistID), backend.InsertNext, false)
|
||||||
|
}
|
||||||
|
grid.OnPlay = func(artistID string, shuffle bool) { go m.App.PlaybackManager.PlayArtistDiscography(artistID, shuffle) }
|
||||||
|
grid.OnAddToQueue = func(artistID string) {
|
||||||
|
go m.App.PlaybackManager.LoadTracks(m.GetArtistTracks(artistID), backend.Append, false)
|
||||||
|
}
|
||||||
|
grid.OnAddToPlaylist = func(artistID string) {
|
||||||
|
go m.DoAddTracksToPlaylistWorkflow(
|
||||||
|
sharedutil.TracksToIDs(m.GetArtistTracks(artistID)))
|
||||||
|
}
|
||||||
|
grid.OnDownload = func(artistID string) {
|
||||||
|
go func() {
|
||||||
|
tracks := m.GetArtistTracks(artistID)
|
||||||
|
tist, err := m.App.ServerManager.Server.GetArtist(artistID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error getting tist: %v", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.ShowDownloadDialog(tracks, tist.Name)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
grid.OnShare = func(artistID string) {
|
||||||
|
go m.ShowShareDialog(artistID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) ConnectPlayQueuelistActions(list *widgets.PlayQueueList) {
|
||||||
|
list.OnReorderItems = func(idxs []int, insertPos int) {
|
||||||
|
newTracks := sharedutil.ReorderItems(list.Items(), idxs, insertPos)
|
||||||
|
c.App.PlaybackManager.UpdatePlayQueue(newTracks)
|
||||||
|
}
|
||||||
|
list.OnDownload = c.ShowDownloadDialog
|
||||||
|
list.OnShare = func(tracks []*mediaprovider.Track) {
|
||||||
|
if len(tracks) > 0 {
|
||||||
|
c.ShowShareDialog(tracks[0].ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.OnAddToPlaylist = c.DoAddTracksToPlaylistWorkflow
|
||||||
|
list.OnPlayItemAt = func(tracknum int) {
|
||||||
|
_ = c.App.PlaybackManager.PlayTrackAt(tracknum)
|
||||||
|
}
|
||||||
|
list.OnShowArtistPage = func(artistID string) {
|
||||||
|
c.NavigateTo(ArtistRoute(artistID))
|
||||||
|
}
|
||||||
|
list.OnRemoveFromQueue = func(idxs []int) {
|
||||||
|
list.UnselectAll()
|
||||||
|
c.App.PlaybackManager.RemoveTracksFromQueue(idxs)
|
||||||
|
}
|
||||||
|
list.OnSetRating = c.SetTrackRatings
|
||||||
|
list.OnSetFavorite = c.SetTrackFavorites
|
||||||
|
}
|
||||||
+58
-132
@@ -45,11 +45,37 @@ type Controller struct {
|
|||||||
ReloadFunc func()
|
ReloadFunc func()
|
||||||
RefreshPageFunc func()
|
RefreshPageFunc func()
|
||||||
|
|
||||||
|
popUpQueue *widgets.PlayQueueList
|
||||||
escapablePopUp *widget.PopUp
|
escapablePopUp *widget.PopUp
|
||||||
haveModal bool
|
haveModal bool
|
||||||
runOnModalClosed func()
|
runOnModalClosed func()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func New(app *backend.App, appVersion string, mainWindow fyne.Window) *Controller {
|
||||||
|
c := &Controller{
|
||||||
|
AppVersion: appVersion,
|
||||||
|
MainWindow: mainWindow,
|
||||||
|
App: app,
|
||||||
|
}
|
||||||
|
c.initVisualizations()
|
||||||
|
c.App.PlaybackManager.OnQueueChange(func() {
|
||||||
|
if c.popUpQueue != nil {
|
||||||
|
c.popUpQueue.SetItems(c.App.PlaybackManager.GetPlayQueue())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
c.App.PlaybackManager.OnSongChange(func(track mediaprovider.MediaItem, _ *mediaprovider.Track) {
|
||||||
|
if c.popUpQueue == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if track == nil {
|
||||||
|
c.popUpQueue.SetNowPlaying("")
|
||||||
|
} else {
|
||||||
|
c.popUpQueue.SetNowPlaying(track.Metadata().ID)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Controller) NavigateTo(route Route) {
|
func (m *Controller) NavigateTo(route Route) {
|
||||||
m.NavHandler(route)
|
m.NavHandler(route)
|
||||||
}
|
}
|
||||||
@@ -81,6 +107,38 @@ func (m *Controller) HaveModal() bool {
|
|||||||
return m.haveModal
|
return m.haveModal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Controller) ShowPopUpPlayQueue() {
|
||||||
|
if m.popUpQueue == nil {
|
||||||
|
m.popUpQueue = widgets.NewPlayQueueList(m.App.ImageManager, false)
|
||||||
|
m.popUpQueue.Reorderable = true
|
||||||
|
m.popUpQueue.SetItems(m.App.PlaybackManager.GetPlayQueue())
|
||||||
|
m.ConnectPlayQueuelistActions(m.popUpQueue)
|
||||||
|
}
|
||||||
|
m.popUpQueue.SetNowPlaying(m.App.PlaybackManager.NowPlaying().Metadata().ID)
|
||||||
|
m.popUpQueue.UnselectAll()
|
||||||
|
m.popUpQueue.ScrollToNowPlaying()
|
||||||
|
|
||||||
|
title := widget.NewRichTextWithText(lang.L("Play Queue"))
|
||||||
|
title.Segments[0].(*widget.TextSegment).Style.Alignment = fyne.TextAlignCenter
|
||||||
|
title.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = true
|
||||||
|
container := container.NewBorder(title, nil, nil, nil,
|
||||||
|
container.NewPadded(m.popUpQueue),
|
||||||
|
)
|
||||||
|
pop := widget.NewPopUp(container, m.MainWindow.Canvas())
|
||||||
|
m.ClosePopUpOnEscape(pop)
|
||||||
|
minSize := fyne.NewSize(300, 400)
|
||||||
|
maxSize := fyne.NewSize(800, 1000)
|
||||||
|
canvasSize := m.MainWindow.Canvas().Size()
|
||||||
|
size := minSize.Max(maxSize.Min(
|
||||||
|
fyne.NewSize(canvasSize.Width*0.4, canvasSize.Height*0.5),
|
||||||
|
))
|
||||||
|
pop.Resize(size)
|
||||||
|
pop.ShowAtPosition(fyne.NewPos(
|
||||||
|
canvasSize.Width-size.Width-10,
|
||||||
|
canvasSize.Height-size.Height-100,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Controller) ShowPopUpImage(img image.Image) {
|
func (m *Controller) ShowPopUpImage(img image.Image) {
|
||||||
im := canvas.NewImageFromImage(img)
|
im := canvas.NewImageFromImage(img)
|
||||||
im.FillMode = canvas.ImageFillContain
|
im.FillMode = canvas.ImageFillContain
|
||||||
@@ -103,138 +161,6 @@ func (m *Controller) ShowPopUpImage(img image.Image) {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Controller) ConnectTracklistActionsWithReplayGainAlbum(tracklist *widgets.Tracklist) {
|
|
||||||
m.connectTracklistActionsWithReplayGainMode(tracklist, player.ReplayGainAlbum)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Controller) ConnectTracklistActions(tracklist *widgets.Tracklist) {
|
|
||||||
m.connectTracklistActionsWithReplayGainMode(tracklist, player.ReplayGainTrack)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Controller) connectTracklistActionsWithReplayGainMode(tracklist *widgets.Tracklist, mode player.ReplayGainMode) {
|
|
||||||
tracklist.OnAddToPlaylist = m.DoAddTracksToPlaylistWorkflow
|
|
||||||
tracklist.OnPlaySelectionNext = func(tracks []*mediaprovider.Track) {
|
|
||||||
m.App.PlaybackManager.LoadTracks(tracks, backend.InsertNext, false)
|
|
||||||
}
|
|
||||||
tracklist.OnAddToQueue = func(tracks []*mediaprovider.Track) {
|
|
||||||
m.App.PlaybackManager.LoadTracks(tracks, backend.Append, false)
|
|
||||||
}
|
|
||||||
tracklist.OnPlayTrackAt = func(idx int) {
|
|
||||||
m.App.PlaybackManager.LoadTracks(tracklist.GetTracks(), backend.Replace, false)
|
|
||||||
if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto {
|
|
||||||
m.App.PlaybackManager.SetReplayGainMode(mode)
|
|
||||||
}
|
|
||||||
m.App.PlaybackManager.PlayTrackAt(idx)
|
|
||||||
}
|
|
||||||
tracklist.OnPlaySelection = func(tracks []*mediaprovider.Track, shuffle bool) {
|
|
||||||
m.App.PlaybackManager.LoadTracks(tracks, backend.Replace, shuffle)
|
|
||||||
if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto {
|
|
||||||
m.App.PlaybackManager.SetReplayGainMode(mode)
|
|
||||||
}
|
|
||||||
m.App.PlaybackManager.PlayFromBeginning()
|
|
||||||
}
|
|
||||||
tracklist.OnSetFavorite = m.SetTrackFavorites
|
|
||||||
tracklist.OnSetRating = m.SetTrackRatings
|
|
||||||
tracklist.OnShowAlbumPage = func(albumID string) {
|
|
||||||
m.NavigateTo(AlbumRoute(albumID))
|
|
||||||
}
|
|
||||||
tracklist.OnShowArtistPage = func(artistID string) {
|
|
||||||
m.NavigateTo(ArtistRoute(artistID))
|
|
||||||
}
|
|
||||||
tracklist.OnColumnVisibilityMenuShown = func(pop *widget.PopUp) {
|
|
||||||
m.ClosePopUpOnEscape(pop)
|
|
||||||
}
|
|
||||||
tracklist.OnDownload = m.ShowDownloadDialog
|
|
||||||
tracklist.OnShare = func(trackID string) {
|
|
||||||
go m.ShowShareDialog(trackID)
|
|
||||||
}
|
|
||||||
tracklist.OnShowTrackInfo = m.ShowTrackInfoDialog
|
|
||||||
tracklist.OnPlaySongRadio = func(track *mediaprovider.Track) {
|
|
||||||
go func() {
|
|
||||||
tracks, err := m.GetSongRadioTracks(track)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error getting song radio: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.App.PlaybackManager.LoadTracks(tracks, backend.Replace, false)
|
|
||||||
if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto {
|
|
||||||
m.App.PlaybackManager.SetReplayGainMode(mode)
|
|
||||||
}
|
|
||||||
m.App.PlaybackManager.PlayFromBeginning()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Controller) ConnectAlbumGridActions(grid *widgets.GridView) {
|
|
||||||
grid.OnAddToQueue = func(albumID string) {
|
|
||||||
go m.App.PlaybackManager.LoadAlbum(albumID, backend.Append, false)
|
|
||||||
}
|
|
||||||
grid.OnPlayNext = func(albumID string) {
|
|
||||||
go m.App.PlaybackManager.LoadAlbum(albumID, backend.InsertNext, false)
|
|
||||||
}
|
|
||||||
grid.OnPlay = func(albumID string, shuffle bool) {
|
|
||||||
go m.App.PlaybackManager.PlayAlbum(albumID, 0, shuffle)
|
|
||||||
}
|
|
||||||
grid.OnShowItemPage = func(albumID string) {
|
|
||||||
m.NavigateTo(AlbumRoute(albumID))
|
|
||||||
}
|
|
||||||
grid.OnShowSecondaryPage = func(artistID string) {
|
|
||||||
m.NavigateTo(ArtistRoute(artistID))
|
|
||||||
}
|
|
||||||
grid.OnAddToPlaylist = func(albumID string) {
|
|
||||||
go func() {
|
|
||||||
album, err := m.App.ServerManager.Server.GetAlbum(albumID)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error loading album: %s", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.DoAddTracksToPlaylistWorkflow(sharedutil.TracksToIDs(album.Tracks))
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
grid.OnDownload = func(albumID string) {
|
|
||||||
go func() {
|
|
||||||
album, err := m.App.ServerManager.Server.GetAlbum(albumID)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error loading album: %s", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.ShowDownloadDialog(album.Tracks, album.Name)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
grid.OnShare = func(albumID string) {
|
|
||||||
go m.ShowShareDialog(albumID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Controller) ConnectArtistGridActions(grid *widgets.GridView) {
|
|
||||||
grid.OnShowItemPage = func(id string) { m.NavigateTo(ArtistRoute(id)) }
|
|
||||||
grid.OnPlayNext = func(artistID string) {
|
|
||||||
go m.App.PlaybackManager.LoadTracks(m.GetArtistTracks(artistID), backend.InsertNext, false)
|
|
||||||
}
|
|
||||||
grid.OnPlay = func(artistID string, shuffle bool) { go m.App.PlaybackManager.PlayArtistDiscography(artistID, shuffle) }
|
|
||||||
grid.OnAddToQueue = func(artistID string) {
|
|
||||||
go m.App.PlaybackManager.LoadTracks(m.GetArtistTracks(artistID), backend.Append, false)
|
|
||||||
}
|
|
||||||
grid.OnAddToPlaylist = func(artistID string) {
|
|
||||||
go m.DoAddTracksToPlaylistWorkflow(
|
|
||||||
sharedutil.TracksToIDs(m.GetArtistTracks(artistID)))
|
|
||||||
}
|
|
||||||
grid.OnDownload = func(artistID string) {
|
|
||||||
go func() {
|
|
||||||
tracks := m.GetArtistTracks(artistID)
|
|
||||||
artist, err := m.App.ServerManager.Server.GetArtist(artistID)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error getting artist: %v", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.ShowDownloadDialog(tracks, artist.Name)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
grid.OnShare = func(artistID string) {
|
|
||||||
go m.ShowShareDialog(artistID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Controller) GetArtistTracks(artistID string) []*mediaprovider.Track {
|
func (m *Controller) GetArtistTracks(artistID string) []*mediaprovider.Track {
|
||||||
if mp := m.App.ServerManager.Server; mp != nil {
|
if mp := m.App.ServerManager.Server; mp != nil {
|
||||||
if tr, err := mp.GetArtistTracks(artistID); err != nil {
|
if tr, err := mp.GetArtistTracks(artistID); err != nil {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ type visualizationData struct {
|
|||||||
visualizationAnim *fyne.Animation
|
visualizationAnim *fyne.Animation
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) InitVisualizations() {
|
func (c *Controller) initVisualizations() {
|
||||||
c.App.LocalPlayer.OnStopped(c.stopVisualizationAnim)
|
c.App.LocalPlayer.OnStopped(c.stopVisualizationAnim)
|
||||||
c.App.LocalPlayer.OnPaused(c.stopVisualizationAnim)
|
c.App.LocalPlayer.OnPaused(c.stopVisualizationAnim)
|
||||||
c.App.LocalPlayer.OnPlaying(func() {
|
c.App.LocalPlayer.OnPlaying(func() {
|
||||||
|
|||||||
+1
-6
@@ -76,12 +76,7 @@ func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string,
|
|||||||
if app.Config.Application.EnableSystemTray {
|
if app.Config.Application.EnableSystemTray {
|
||||||
m.SetupSystemTrayMenu(displayAppName, fyneApp)
|
m.SetupSystemTrayMenu(displayAppName, fyneApp)
|
||||||
}
|
}
|
||||||
m.Controller = &controller.Controller{
|
m.Controller = controller.New(app, appVersion, m.Window)
|
||||||
AppVersion: appVersion,
|
|
||||||
MainWindow: m.Window,
|
|
||||||
App: app,
|
|
||||||
}
|
|
||||||
m.Controller.InitVisualizations()
|
|
||||||
m.BrowsingPane = browsing.NewBrowsingPane(app, m.Controller, func() { m.Router.NavigateTo(m.StartupPage()) })
|
m.BrowsingPane = browsing.NewBrowsingPane(app, m.Controller, func() { m.Router.NavigateTo(m.StartupPage()) })
|
||||||
m.Router = browsing.NewRouter(app, m.Controller, m.BrowsingPane)
|
m.Router = browsing.NewRouter(app, m.Controller, m.BrowsingPane)
|
||||||
// inject controller dependencies
|
// inject controller dependencies
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ var (
|
|||||||
NowPlayingIcon fyne.Resource = theme.NewThemedResource(res.ResHeadphonesSvg)
|
NowPlayingIcon fyne.Resource = theme.NewThemedResource(res.ResHeadphonesSvg)
|
||||||
PlaylistIcon fyne.Resource = theme.NewThemedResource(res.ResPlaylistSvg)
|
PlaylistIcon fyne.Resource = theme.NewThemedResource(res.ResPlaylistSvg)
|
||||||
PlayNextIcon fyne.Resource = theme.NewThemedResource(res.ResPlaylistAddNextSvg)
|
PlayNextIcon fyne.Resource = theme.NewThemedResource(res.ResPlaylistAddNextSvg)
|
||||||
|
PlayQueueIcon fyne.Resource = theme.NewThemedResource(res.ResPlayqueueSvg)
|
||||||
ShareIcon fyne.Resource = theme.NewThemedResource(res.ResShareSvg)
|
ShareIcon fyne.Resource = theme.NewThemedResource(res.ResShareSvg)
|
||||||
ShuffleIcon fyne.Resource = theme.NewThemedResource(res.ResShuffleSvg)
|
ShuffleIcon fyne.Resource = theme.NewThemedResource(res.ResShuffleSvg)
|
||||||
TracksIcon fyne.Resource = theme.NewThemedResource(res.ResMusicnotesSvg)
|
TracksIcon fyne.Resource = theme.NewThemedResource(res.ResMusicnotesSvg)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ type AuxControls struct {
|
|||||||
|
|
||||||
VolumeControl *VolumeControl
|
VolumeControl *VolumeControl
|
||||||
loop *IconButton
|
loop *IconButton
|
||||||
|
showQueue *IconButton
|
||||||
|
|
||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
}
|
}
|
||||||
@@ -27,14 +28,18 @@ func NewAuxControls(initialVolume int) *AuxControls {
|
|||||||
a := &AuxControls{
|
a := &AuxControls{
|
||||||
VolumeControl: NewVolumeControl(initialVolume),
|
VolumeControl: NewVolumeControl(initialVolume),
|
||||||
loop: NewIconButton(myTheme.RepeatIcon, nil),
|
loop: NewIconButton(myTheme.RepeatIcon, nil),
|
||||||
|
showQueue: NewIconButton(myTheme.PlayQueueIcon, nil),
|
||||||
}
|
}
|
||||||
a.loop.IconSize = IconButtonSizeSmaller
|
a.loop.IconSize = IconButtonSizeSmaller
|
||||||
|
a.showQueue.IconSize = IconButtonSizeSmaller
|
||||||
a.container = container.NewHBox(
|
a.container = container.NewHBox(
|
||||||
layout.NewSpacer(),
|
layout.NewSpacer(),
|
||||||
container.NewVBox(
|
container.NewVBox(
|
||||||
layout.NewSpacer(),
|
layout.NewSpacer(),
|
||||||
a.VolumeControl,
|
a.VolumeControl,
|
||||||
container.NewHBox(layout.NewSpacer(), a.loop, util.NewHSpace(5)),
|
container.New(
|
||||||
|
layout.NewCustomPaddedHBoxLayout(theme.Padding()*1.5),
|
||||||
|
layout.NewSpacer(), a.loop, a.showQueue, util.NewHSpace(5)),
|
||||||
layout.NewSpacer(),
|
layout.NewSpacer(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -64,6 +69,10 @@ func (a *AuxControls) SetLoopMode(mode backend.LoopMode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AuxControls) OnShowPlayQueue(f func()) {
|
||||||
|
a.showQueue.OnTapped = f
|
||||||
|
}
|
||||||
|
|
||||||
type volumeSlider struct {
|
type volumeSlider struct {
|
||||||
widget.Slider
|
widget.Slider
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package widgets
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -134,6 +135,12 @@ func (p *PlayQueueList) SetItems(items []mediaprovider.MediaItem) {
|
|||||||
p.Refresh()
|
p.Refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PlayQueueList) Items() []mediaprovider.MediaItem {
|
||||||
|
return sharedutil.MapSlice(p.items, func(item *util.TrackListModel) mediaprovider.MediaItem {
|
||||||
|
return item.Item
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Sets the currently playing item ID and updates the list rendering
|
// Sets the currently playing item ID and updates the list rendering
|
||||||
func (p *PlayQueueList) SetNowPlaying(itemID string) {
|
func (p *PlayQueueList) SetNowPlaying(itemID string) {
|
||||||
prevNowPlaying := p.nowPlayingID
|
prevNowPlaying := p.nowPlayingID
|
||||||
@@ -168,6 +175,15 @@ func (p *PlayQueueList) Scroll(amount float32) {
|
|||||||
p.list.ScrollToOffset(p.list.GetScrollOffset() + amount)
|
p.list.ScrollToOffset(p.list.GetScrollOffset() + amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PlayQueueList) ScrollToNowPlaying() {
|
||||||
|
idx := slices.IndexFunc(p.items, func(item *util.TrackListModel) bool {
|
||||||
|
return item.Item.Metadata().ID == p.nowPlayingID
|
||||||
|
})
|
||||||
|
if idx > 0 {
|
||||||
|
p.list.ScrollTo(idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (p *PlayQueueList) Refresh() {
|
func (p *PlayQueueList) Refresh() {
|
||||||
p.list.EnableDragging = p.Reorderable
|
p.list.EnableDragging = p.Reorderable
|
||||||
p.BaseWidget.Refresh()
|
p.BaseWidget.Refresh()
|
||||||
|
|||||||
Reference in New Issue
Block a user