ui refactoring (create controller pkg) + beginning of add to playlist
This commit is contained in:
+18
-17
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"supersonic/backend"
|
"supersonic/backend"
|
||||||
|
"supersonic/ui/controller"
|
||||||
"supersonic/ui/layouts"
|
"supersonic/ui/layouts"
|
||||||
"supersonic/ui/util"
|
"supersonic/ui/util"
|
||||||
"supersonic/ui/widgets"
|
"supersonic/ui/widgets"
|
||||||
@@ -30,13 +31,13 @@ type AlbumPage struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type albumPageState struct {
|
type albumPageState struct {
|
||||||
albumID string
|
albumID string
|
||||||
lm *backend.LibraryManager
|
lm *backend.LibraryManager
|
||||||
pm *backend.PlaybackManager
|
pm *backend.PlaybackManager
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
sm *backend.ServerManager
|
sm *backend.ServerManager
|
||||||
popUpProvider util.PopUpProvider
|
contr *controller.Controller
|
||||||
nav func(Route)
|
nav func(Route)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAlbumPage(
|
func NewAlbumPage(
|
||||||
@@ -45,18 +46,18 @@ func NewAlbumPage(
|
|||||||
pm *backend.PlaybackManager,
|
pm *backend.PlaybackManager,
|
||||||
lm *backend.LibraryManager,
|
lm *backend.LibraryManager,
|
||||||
im *backend.ImageManager,
|
im *backend.ImageManager,
|
||||||
popUpProvider util.PopUpProvider,
|
contr *controller.Controller,
|
||||||
nav func(Route),
|
nav func(Route),
|
||||||
) *AlbumPage {
|
) *AlbumPage {
|
||||||
a := &AlbumPage{
|
a := &AlbumPage{
|
||||||
albumPageState: albumPageState{
|
albumPageState: albumPageState{
|
||||||
albumID: albumID,
|
albumID: albumID,
|
||||||
sm: sm,
|
sm: sm,
|
||||||
pm: pm,
|
pm: pm,
|
||||||
lm: lm,
|
lm: lm,
|
||||||
im: im,
|
im: im,
|
||||||
nav: nav,
|
nav: nav,
|
||||||
popUpProvider: popUpProvider,
|
contr: contr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
@@ -241,7 +242,7 @@ func (a *AlbumPageHeader) showPopUpCover() {
|
|||||||
log.Printf("error getting full size album cover: %s", err.Error())
|
log.Printf("error getting full size album cover: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
util.ShowPopUpImage(cover, a.page.popUpProvider)
|
a.page.contr.ShowPopUpImage(cover)
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatMiscLabelStr(a *subsonic.AlbumID3) string {
|
func formatMiscLabelStr(a *subsonic.AlbumID3) string {
|
||||||
@@ -249,5 +250,5 @@ func formatMiscLabelStr(a *subsonic.AlbumID3) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *albumPageState) Restore() Page {
|
func (s *albumPageState) Restore() Page {
|
||||||
return NewAlbumPage(s.albumID, s.sm, s.pm, s.lm, s.im, s.popUpProvider, s.nav)
|
return NewAlbumPage(s.albumID, s.sm, s.pm, s.lm, s.im, s.contr, s.nav)
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-13
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"supersonic/backend"
|
"supersonic/backend"
|
||||||
"supersonic/res"
|
"supersonic/res"
|
||||||
|
"supersonic/ui/controller"
|
||||||
"supersonic/ui/layouts"
|
"supersonic/ui/layouts"
|
||||||
"supersonic/ui/util"
|
"supersonic/ui/util"
|
||||||
"supersonic/ui/widgets"
|
"supersonic/ui/widgets"
|
||||||
@@ -22,11 +23,11 @@ import (
|
|||||||
var _ fyne.Widget = (*ArtistPage)(nil)
|
var _ fyne.Widget = (*ArtistPage)(nil)
|
||||||
|
|
||||||
type artistPageState struct {
|
type artistPageState struct {
|
||||||
artistID string
|
artistID string
|
||||||
sm *backend.ServerManager
|
sm *backend.ServerManager
|
||||||
im *backend.ImageManager
|
im *backend.ImageManager
|
||||||
nav func(Route)
|
nav func(Route)
|
||||||
popUpProvider util.PopUpProvider
|
contr *controller.Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArtistPage struct {
|
type ArtistPage struct {
|
||||||
@@ -40,13 +41,13 @@ type ArtistPage struct {
|
|||||||
OnPlayAlbum func(string, int)
|
OnPlayAlbum func(string, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArtistPage(artistID string, sm *backend.ServerManager, im *backend.ImageManager, popUp util.PopUpProvider, nav func(Route)) *ArtistPage {
|
func NewArtistPage(artistID string, sm *backend.ServerManager, im *backend.ImageManager, contr *controller.Controller, nav func(Route)) *ArtistPage {
|
||||||
a := &ArtistPage{artistPageState: artistPageState{
|
a := &ArtistPage{artistPageState: artistPageState{
|
||||||
artistID: artistID,
|
artistID: artistID,
|
||||||
sm: sm,
|
sm: sm,
|
||||||
im: im,
|
im: im,
|
||||||
nav: nav,
|
nav: nav,
|
||||||
popUpProvider: popUp,
|
contr: contr,
|
||||||
}}
|
}}
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
a.header = NewArtistPageHeader(a, nav)
|
a.header = NewArtistPageHeader(a, nav)
|
||||||
@@ -111,7 +112,7 @@ func (a *ArtistPage) CreateRenderer() fyne.WidgetRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *artistPageState) Restore() Page {
|
func (s *artistPageState) Restore() Page {
|
||||||
return NewArtistPage(s.artistID, s.sm, s.im, s.popUpProvider, s.nav)
|
return NewArtistPage(s.artistID, s.sm, s.im, s.contr, s.nav)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArtistPageHeader struct {
|
type ArtistPageHeader struct {
|
||||||
@@ -190,7 +191,7 @@ func (a *ArtistPageHeader) UpdateInfo(info *subsonic.ArtistInfo2) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
a.artistImage.OnTapped = func() {
|
a.artistImage.OnTapped = func() {
|
||||||
util.ShowPopUpImage(im, a.artistPage.popUpProvider)
|
a.artistPage.contr.ShowPopUpImage(im)
|
||||||
}
|
}
|
||||||
a.artistImage.SetImage(im, true /*tappable*/)
|
a.artistImage.SetImage(im, true /*tappable*/)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-21
@@ -2,10 +2,8 @@ package browsing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"supersonic/backend"
|
"supersonic/backend"
|
||||||
|
"supersonic/ui/controller"
|
||||||
"supersonic/ui/util"
|
"supersonic/ui/util"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
|
||||||
"fyne.io/fyne/v2/widget"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PageName int
|
type PageName int
|
||||||
@@ -69,42 +67,29 @@ type NavigationHandler interface {
|
|||||||
|
|
||||||
type Router struct {
|
type Router struct {
|
||||||
App *backend.App
|
App *backend.App
|
||||||
MainWindow fyne.Window
|
Controller *controller.Controller
|
||||||
Nav NavigationHandler
|
Nav NavigationHandler
|
||||||
|
|
||||||
pop util.PopUpProvider
|
pop util.PopUpProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRouter(app *backend.App, mainWindow fyne.Window, nav NavigationHandler) Router {
|
func NewRouter(app *backend.App, controller *controller.Controller, nav NavigationHandler) Router {
|
||||||
r := Router{
|
r := Router{
|
||||||
App: app,
|
App: app,
|
||||||
MainWindow: mainWindow,
|
Controller: controller,
|
||||||
Nav: nav,
|
Nav: nav,
|
||||||
}
|
}
|
||||||
r.pop = &popUpProvider{window: r.MainWindow}
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
type popUpProvider struct {
|
|
||||||
window fyne.Window
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *popUpProvider) CreatePopUp(obj fyne.CanvasObject) *widget.PopUp {
|
|
||||||
return widget.NewPopUp(obj, p.window.Canvas())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *popUpProvider) WindowSize() fyne.Size {
|
|
||||||
return p.window.Canvas().Size()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r Router) CreatePage(rte Route) Page {
|
func (r Router) CreatePage(rte Route) Page {
|
||||||
switch rte.Page {
|
switch rte.Page {
|
||||||
case Album:
|
case Album:
|
||||||
return NewAlbumPage(rte.Arg, r.App.ServerManager, r.App.PlaybackManager, r.App.LibraryManager, r.App.ImageManager, r.pop, r.OpenRoute)
|
return NewAlbumPage(rte.Arg, r.App.ServerManager, r.App.PlaybackManager, r.App.LibraryManager, r.App.ImageManager, r.Controller, r.OpenRoute)
|
||||||
case Albums:
|
case Albums:
|
||||||
return NewAlbumsPage("Albums", rte.Arg, r.App.LibraryManager, r.App.ImageManager, r.OpenRoute)
|
return NewAlbumsPage("Albums", rte.Arg, r.App.LibraryManager, r.App.ImageManager, r.OpenRoute)
|
||||||
case Artist:
|
case Artist:
|
||||||
return NewArtistPage(rte.Arg, r.App.ServerManager, r.App.ImageManager, r.pop, r.OpenRoute)
|
return NewArtistPage(rte.Arg, r.App.ServerManager, r.App.ImageManager, r.Controller, r.OpenRoute)
|
||||||
case Artists:
|
case Artists:
|
||||||
return NewArtistsGenresPage(false, r.App.ServerManager, r.OpenRoute)
|
return NewArtistsGenresPage(false, r.App.ServerManager, r.OpenRoute)
|
||||||
case Favorites:
|
case Favorites:
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"log"
|
||||||
|
"supersonic/backend"
|
||||||
|
"supersonic/ui/dialogs"
|
||||||
|
"supersonic/ui/util"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"github.com/dweymouth/go-subsonic"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Controller struct {
|
||||||
|
MainWindow fyne.Window
|
||||||
|
App *backend.App
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Controller) ShowPopUpImage(img image.Image) {
|
||||||
|
im := canvas.NewImageFromImage(img)
|
||||||
|
im.FillMode = canvas.ImageFillContain
|
||||||
|
pop := widget.NewPopUp(im, m.MainWindow.Canvas())
|
||||||
|
s := m.MainWindow.Canvas().Size()
|
||||||
|
var popS fyne.Size
|
||||||
|
if asp := util.ImageAspect(img); s.Width/s.Height > asp {
|
||||||
|
// window height is limiting factor
|
||||||
|
h := s.Height * 0.8
|
||||||
|
popS = fyne.NewSize(h*asp, h)
|
||||||
|
} else {
|
||||||
|
w := s.Width * 0.8
|
||||||
|
popS = fyne.NewSize(w, w*(1/asp))
|
||||||
|
}
|
||||||
|
pop.Resize(popS)
|
||||||
|
pop.ShowAtPosition(fyne.NewPos(
|
||||||
|
(s.Width-popS.Width)/2,
|
||||||
|
(s.Height-popS.Height)/2,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show dialog to prompt for playlist.
|
||||||
|
// Depending on the results of that dialog, potentially create a new playlist
|
||||||
|
// Add tracks to the user-specified playlist
|
||||||
|
func (m *Controller) DoAddTracksToPlaylistWorkflow(tracks []*subsonic.Child) {
|
||||||
|
pls, err := m.App.LibraryManager.GetUserOwnedPlaylists()
|
||||||
|
if err != nil {
|
||||||
|
// TODO: surface this error to user
|
||||||
|
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())
|
||||||
|
dlg.OnCanceled = pop.Hide
|
||||||
|
dlg.OnSubmit = func(playlistChoice int, newPlaylistName string) {
|
||||||
|
pop.Hide()
|
||||||
|
// call server to add tracks to playlist
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-1
@@ -4,6 +4,7 @@ import (
|
|||||||
"supersonic/backend"
|
"supersonic/backend"
|
||||||
"supersonic/res"
|
"supersonic/res"
|
||||||
"supersonic/ui/browsing"
|
"supersonic/ui/browsing"
|
||||||
|
"supersonic/ui/controller"
|
||||||
"supersonic/ui/os"
|
"supersonic/ui/os"
|
||||||
"supersonic/ui/widgets"
|
"supersonic/ui/widgets"
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@ type MainWindow struct {
|
|||||||
|
|
||||||
App *backend.App
|
App *backend.App
|
||||||
Router browsing.Router
|
Router browsing.Router
|
||||||
|
Controller *controller.Controller
|
||||||
BrowsingPane *browsing.BrowsingPane
|
BrowsingPane *browsing.BrowsingPane
|
||||||
BottomPanel *BottomPanel
|
BottomPanel *BottomPanel
|
||||||
|
|
||||||
@@ -43,7 +45,11 @@ func NewMainWindow(fyneApp fyne.App, appName string, app *backend.App, size fyne
|
|||||||
BrowsingPane: browsing.NewBrowsingPane(app),
|
BrowsingPane: browsing.NewBrowsingPane(app),
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Router = browsing.NewRouter(app, m.Window, m.BrowsingPane)
|
m.Controller = &controller.Controller{
|
||||||
|
MainWindow: m.Window,
|
||||||
|
App: app,
|
||||||
|
}
|
||||||
|
m.Router = browsing.NewRouter(app, m.Controller, m.BrowsingPane)
|
||||||
m.BottomPanel = NewBottomPanel(app.Player, m.Router.OpenRoute)
|
m.BottomPanel = NewBottomPanel(app.Player, m.Router.OpenRoute)
|
||||||
m.BottomPanel.SetPlaybackManager(app.PlaybackManager)
|
m.BottomPanel.SetPlaybackManager(app.PlaybackManager)
|
||||||
m.BottomPanel.ImageManager = app.ImageManager
|
m.BottomPanel.ImageManager = app.ImageManager
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/canvas"
|
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
"golang.org/x/net/html"
|
"golang.org/x/net/html"
|
||||||
)
|
)
|
||||||
@@ -33,27 +32,6 @@ type PopUpProvider interface {
|
|||||||
WindowSize() fyne.Size
|
WindowSize() fyne.Size
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShowPopUpImage(img image.Image, popUpProvider PopUpProvider) {
|
|
||||||
im := canvas.NewImageFromImage(img)
|
|
||||||
im.FillMode = canvas.ImageFillContain
|
|
||||||
pop := popUpProvider.CreatePopUp(im)
|
|
||||||
s := popUpProvider.WindowSize()
|
|
||||||
var popS fyne.Size
|
|
||||||
if asp := ImageAspect(img); s.Width/s.Height > asp {
|
|
||||||
// window height is limiting factor
|
|
||||||
h := s.Height * 0.8
|
|
||||||
popS = fyne.NewSize(h*asp, h)
|
|
||||||
} else {
|
|
||||||
w := s.Width * 0.8
|
|
||||||
popS = fyne.NewSize(w, w*(1/asp))
|
|
||||||
}
|
|
||||||
pop.Resize(popS)
|
|
||||||
pop.ShowAtPosition(fyne.NewPos(
|
|
||||||
(s.Width-popS.Width)/2,
|
|
||||||
(s.Height-popS.Height)/2,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
func RichTextSegsFromHTMLString(s string) []widget.RichTextSegment {
|
func RichTextSegsFromHTMLString(s string) []widget.RichTextSegment {
|
||||||
tokr := html.NewTokenizer(strings.NewReader(s))
|
tokr := html.NewTokenizer(strings.NewReader(s))
|
||||||
var segs []widget.RichTextSegment
|
var segs []widget.RichTextSegment
|
||||||
|
|||||||
Reference in New Issue
Block a user