refactor UI for better separation

This commit is contained in:
Drew Weymouth
2022-12-24 16:47:00 -08:00
parent 5c644faeaf
commit cefb25133e
8 changed files with 99 additions and 79 deletions
+2 -1
View File
@@ -9,6 +9,7 @@ import (
"supersonic/backend" "supersonic/backend"
"supersonic/player" "supersonic/player"
"supersonic/ui" "supersonic/ui"
"supersonic/ui/widgets"
"fyne.io/fyne/v2/app" "fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
@@ -50,7 +51,7 @@ func main() {
mainWindow := ui.NewMainWindow(myApp, appname, p) mainWindow := ui.NewMainWindow(myApp, appname, p)
if server == nil { if server == nil {
d := ui.NewAddServerDialog("Connect to Server") d := widgets.NewAddServerForm("Connect to Server")
pop := widget.NewModalPopUp(d, mainWindow.Canvas()) pop := widget.NewModalPopUp(d, mainWindow.Canvas())
d.OnSubmit = func() { d.OnSubmit = func() {
pop.Hide() pop.Hide()
+4 -3
View File
@@ -3,6 +3,7 @@ package ui
import ( import (
"context" "context"
"supersonic/backend" "supersonic/backend"
"supersonic/ui/widgets"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/widget" "fyne.io/fyne/v2/widget"
@@ -35,7 +36,7 @@ func NewAlbumGrid(iter backend.AlbumIterator, pm *backend.PlaybackManager, im *b
}, },
// create func // create func
func() fyne.CanvasObject { func() fyne.CanvasObject {
ac := NewAlbumCard() ac := widgets.NewAlbumCard()
ac.OnPlay = func() { ac.OnPlay = func() {
pm.PlayAlbum(ac.AlbumID()) pm.PlayAlbum(ac.AlbumID())
} }
@@ -43,7 +44,7 @@ func NewAlbumGrid(iter backend.AlbumIterator, pm *backend.PlaybackManager, im *b
}, },
// update func // update func
func(itemID int, obj fyne.CanvasObject) { func(itemID int, obj fyne.CanvasObject) {
ac := obj.(*AlbumCard) ac := obj.(*widgets.AlbumCard)
ag.doUpdateAlbumCard(itemID, ac) ag.doUpdateAlbumCard(itemID, ac)
}, },
) )
@@ -54,7 +55,7 @@ func NewAlbumGrid(iter backend.AlbumIterator, pm *backend.PlaybackManager, im *b
return ag return ag
} }
func (ag *AlbumGrid) doUpdateAlbumCard(albumIdx int, ac *AlbumCard) { func (ag *AlbumGrid) doUpdateAlbumCard(albumIdx int, ac *widgets.AlbumCard) {
album := ag.albums[albumIdx] album := ag.albums[albumIdx]
if ac.PrevAlbumID == album.ID { if ac.PrevAlbumID == album.ID {
// nothing to do // nothing to do
+32 -7
View File
@@ -1,9 +1,11 @@
package ui package ui
import ( import (
"fmt"
"image" "image"
"supersonic/backend" "supersonic/backend"
"supersonic/player" "supersonic/player"
"supersonic/ui/widgets"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
@@ -57,8 +59,8 @@ type BottomPanel struct {
playbackManager *backend.PlaybackManager playbackManager *backend.PlaybackManager
nowPlaying *NowPlayingCard nowPlaying *widgets.NowPlayingCard
controls *PlayerControls controls *widgets.PlayerControls
container *fyne.Container container *fyne.Container
} }
@@ -67,9 +69,30 @@ var _ fyne.Widget = (*BottomPanel)(nil)
func NewBottomPanel(p *player.Player) *BottomPanel { func NewBottomPanel(p *player.Player) *BottomPanel {
bp := &BottomPanel{} bp := &BottomPanel{}
bp.ExtendBaseWidget(bp) bp.ExtendBaseWidget(bp)
p.OnPaused(func() {
bp.controls.SetPlaying(false)
})
p.OnPlaying(func() {
bp.controls.SetPlaying(true)
})
p.OnStopped(func() {
bp.controls.SetPlaying(false)
})
bp.nowPlaying = NewNowPlayingCard() bp.nowPlaying = widgets.NewNowPlayingCard()
bp.controls = NewPlayerControls(p) bp.controls = widgets.NewPlayerControls()
bp.controls.OnPlayPause(func() {
p.PlayPause()
})
bp.controls.OnSeekNext(func() {
p.SeekNext()
})
bp.controls.OnSeekPrevious(func() {
p.SeekBackOrPrevious()
})
bp.controls.OnSeek(func(f float64) {
p.Seek(fmt.Sprintf("%d", int(f*100)), player.SeekAbsolutePercent)
})
bp.container = container.New(newBottomPanelLayout(500, bp.nowPlaying, bp.controls, nil), bp.nowPlaying, bp.controls) bp.container = container.New(newBottomPanelLayout(500, bp.nowPlaying, bp.controls, nil), bp.nowPlaying, bp.controls)
return bp return bp
@@ -77,9 +100,11 @@ func NewBottomPanel(p *player.Player) *BottomPanel {
func (bp *BottomPanel) SetPlaybackManager(pm *backend.PlaybackManager) { func (bp *BottomPanel) SetPlaybackManager(pm *backend.PlaybackManager) {
bp.playbackManager = pm bp.playbackManager = pm
bp.controls.SetPlaybackManager(pm) pm.OnSongChange(bp.onSongChange)
pm.OnSongChange(func(song *subsonic.Child) { pm.OnPlayTimeUpdate(func(cur, total float64) {
bp.onSongChange(song) if !pm.IsSeeking() {
bp.controls.UpdatePlayTime(cur, total)
}
}) })
} }
+1 -1
View File
@@ -1,4 +1,4 @@
package ui package util
import ( import (
"fmt" "fmt"
@@ -1,4 +1,4 @@
package ui package widgets
import ( import (
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
@@ -8,7 +8,7 @@ import (
"fyne.io/fyne/v2/widget" "fyne.io/fyne/v2/widget"
) )
type AddServerDialog struct { type AddServerForm struct {
widget.BaseWidget widget.BaseWidget
Nickname string Nickname string
@@ -20,10 +20,10 @@ type AddServerDialog struct {
container *fyne.Container container *fyne.Container
} }
var _ fyne.Widget = (*AddServerDialog)(nil) var _ fyne.Widget = (*AddServerForm)(nil)
func NewAddServerDialog(title string) *AddServerDialog { func NewAddServerForm(title string) *AddServerForm {
a := &AddServerDialog{} a := &AddServerForm{}
a.ExtendBaseWidget(a) a.ExtendBaseWidget(a)
titleLabel := widget.NewLabel(title) titleLabel := widget.NewLabel(title)
titleLabel.TextStyle.Bold = true titleLabel.TextStyle.Bold = true
@@ -59,11 +59,11 @@ func NewAddServerDialog(title string) *AddServerDialog {
return a return a
} }
func (a *AddServerDialog) MinSize() fyne.Size { func (a *AddServerForm) MinSize() fyne.Size {
a.ExtendBaseWidget(a) a.ExtendBaseWidget(a)
return fyne.NewSize(300, a.container.MinSize().Height) return fyne.NewSize(300, a.container.MinSize().Height)
} }
func (a *AddServerDialog) CreateRenderer() fyne.WidgetRenderer { func (a *AddServerForm) CreateRenderer() fyne.WidgetRenderer {
return widget.NewSimpleRenderer(a.container) return widget.NewSimpleRenderer(a.container)
} }
+2 -1
View File
@@ -1,4 +1,4 @@
package ui package widgets
import ( import (
"context" "context"
@@ -11,6 +11,7 @@ import (
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/driver/desktop" "fyne.io/fyne/v2/driver/desktop"
"fyne.io/fyne/v2/widget" "fyne.io/fyne/v2/widget"
"github.com/dweymouth/go-subsonic" "github.com/dweymouth/go-subsonic"
) )
@@ -1,4 +1,4 @@
package ui package widgets
import ( import (
"image" "image"
@@ -1,9 +1,7 @@
package ui package widgets
import ( import (
"fmt" "supersonic/ui/util"
"supersonic/backend"
"supersonic/player"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
@@ -67,48 +65,27 @@ type PlayerControls struct {
container *fyne.Container container *fyne.Container
totalTime float64 totalTime float64
player *player.Player
playbackManager *backend.PlaybackManager
} }
var _ fyne.Widget = (*PlayerControls)(nil) var _ fyne.Widget = (*PlayerControls)(nil)
// NewPlayerControls sets up the seek bar, and transport buttons, and returns the encompassing Container. // NewPlayerControls sets up the seek bar, and transport buttons.
func NewPlayerControls(p *player.Player) *PlayerControls { func NewPlayerControls() *PlayerControls {
pc := &PlayerControls{player: p} pc := &PlayerControls{}
pc.ExtendBaseWidget(pc) pc.ExtendBaseWidget(pc)
pc.slider = NewTrackPosSlider() pc.slider = NewTrackPosSlider()
pc.curTimeLabel = widget.NewLabel("0:00") pc.curTimeLabel = widget.NewLabel("0:00")
pc.totalTimeLabel = widget.NewLabel("0:00") pc.totalTimeLabel = widget.NewLabel("0:00")
pc.slider.OnDragEnd = func(f float64) {
p.Seek(fmt.Sprintf("%d", int(f*100)), player.SeekAbsolutePercent)
}
pc.slider.OnChanged = func(f float64) { pc.slider.OnChanged = func(f float64) {
time := f * pc.totalTime time := f * pc.totalTime
pc.curTimeLabel.SetText(SecondsToTimeString(time)) pc.curTimeLabel.SetText(util.SecondsToTimeString(time))
} }
pc.prev = widget.NewButtonWithIcon("", theme.MediaSkipPreviousIcon(), func() { pc.prev = widget.NewButtonWithIcon("", theme.MediaSkipPreviousIcon(), func() {})
p.SeekBackOrPrevious() pc.next = widget.NewButtonWithIcon("", theme.MediaSkipNextIcon(), func() {})
}) pc.playpause = widget.NewButtonWithIcon("", theme.MediaPlayIcon(), func() {})
pc.next = widget.NewButtonWithIcon("", theme.MediaSkipNextIcon(), func() {
p.SeekNext()
})
pc.playpause = widget.NewButtonWithIcon("", theme.MediaPlayIcon(), func() {
p.PlayPause()
})
p.OnPaused(func() {
pc.playpause.SetIcon(theme.MediaPlayIcon())
})
p.OnPlaying(func() {
pc.playpause.SetIcon(theme.MediaPauseIcon())
})
p.OnStopped(func() {
pc.playpause.SetIcon(theme.MediaPlayIcon())
})
buttons := container.NewHBox(pc.prev, pc.playpause, pc.next) buttons := container.NewHBox(pc.prev, pc.playpause, pc.next)
b := container.New(layout.NewCenterLayout(), buttons) b := container.New(layout.NewCenterLayout(), buttons)
@@ -119,31 +96,47 @@ func NewPlayerControls(p *player.Player) *PlayerControls {
return pc return pc
} }
func (pc *PlayerControls) SetPlaybackManager(pm *backend.PlaybackManager) { func (pc *PlayerControls) OnSeek(f func(float64)) {
pc.playbackManager = pm pc.slider.OnDragEnd = f
pm.OnPlayTimeUpdate(func(curTime float64, totalTime float64) {
pc.doPlayTimeUpdate(curTime, totalTime)
})
} }
func (pc *PlayerControls) doPlayTimeUpdate(curTime, totalTime float64) { func (pc *PlayerControls) OnSeekPrevious(f func()) {
pc.prev.OnTapped = f
}
func (pc *PlayerControls) OnSeekNext(f func()) {
pc.next.OnTapped = f
}
func (pc *PlayerControls) OnPlayPause(f func()) {
pc.playpause.OnTapped = f
}
func (pc *PlayerControls) SetPlaying(playing bool) {
if playing {
pc.playpause.SetIcon(theme.MediaPauseIcon())
} else {
pc.playpause.SetIcon(theme.MediaPlayIcon())
}
}
func (pc *PlayerControls) UpdatePlayTime(curTime, totalTime float64) {
// TODO: there is a bug with very long tracks (~20min) where the // TODO: there is a bug with very long tracks (~20min) where the
// curtime label will bounce back and forth +- 1sec (rounding issue?) // curtime label will bounce back and forth +- 1sec (rounding issue?)
pc.totalTime = totalTime pc.totalTime = totalTime
if !pc.playbackManager.IsSeeking() {
v := 0.0 v := 0.0
if totalTime > 0 { if totalTime > 0 {
v = curTime / totalTime v = curTime / totalTime
} }
updated := false updated := false
tt := SecondsToTimeString(totalTime) tt := util.SecondsToTimeString(totalTime)
if tt != pc.totalTimeLabel.Text { if tt != pc.totalTimeLabel.Text {
pc.totalTimeLabel.SetText(tt) pc.totalTimeLabel.SetText(tt)
updated = true updated = true
} }
if !pc.slider.IsDragging() { if !pc.slider.IsDragging() {
ct := SecondsToTimeString(curTime) ct := util.SecondsToTimeString(curTime)
if ct != pc.curTimeLabel.Text { if ct != pc.curTimeLabel.Text {
pc.curTimeLabel.SetText(ct) pc.curTimeLabel.SetText(ct)
updated = true updated = true
@@ -153,7 +146,6 @@ func (pc *PlayerControls) doPlayTimeUpdate(curTime, totalTime float64) {
pc.slider.SetValue(v) pc.slider.SetValue(v)
} }
} }
}
} }
func (p *PlayerControls) CreateRenderer() fyne.WidgetRenderer { func (p *PlayerControls) CreateRenderer() fyne.WidgetRenderer {