123 lines
2.8 KiB
Go
123 lines
2.8 KiB
Go
package ui
|
|
|
|
import (
|
|
"fmt"
|
|
"gomuse/backend"
|
|
"gomuse/player"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/layout"
|
|
"fyne.io/fyne/v2/theme"
|
|
"fyne.io/fyne/v2/widget"
|
|
)
|
|
|
|
// TrackPosSlider is a custom slider that doesn't trigger
|
|
// the seek action until drag end.
|
|
type TrackPosSlider struct {
|
|
widget.Slider
|
|
|
|
OnDragEnd func(float64)
|
|
|
|
isDragging bool
|
|
lastDraggedValue float64
|
|
}
|
|
|
|
func NewTrackPosSlider() *TrackPosSlider {
|
|
slider := &TrackPosSlider{
|
|
Slider: widget.Slider{
|
|
Value: 0,
|
|
Min: 0,
|
|
Max: 1,
|
|
Step: 0.002,
|
|
Orientation: widget.Horizontal,
|
|
},
|
|
}
|
|
slider.ExtendBaseWidget(slider)
|
|
return slider
|
|
}
|
|
|
|
func (t *TrackPosSlider) DragEnd() {
|
|
t.isDragging = false
|
|
t.Slider.DragEnd()
|
|
if t.OnDragEnd != nil {
|
|
t.OnDragEnd(t.lastDraggedValue)
|
|
}
|
|
}
|
|
|
|
func (t *TrackPosSlider) Dragged(e *fyne.DragEvent) {
|
|
t.isDragging = true
|
|
t.Slider.Dragged(e)
|
|
t.lastDraggedValue = t.Value
|
|
}
|
|
|
|
func (t *TrackPosSlider) IsDragging() bool {
|
|
return t.isDragging
|
|
}
|
|
|
|
// NewPlayerControls sets up the seek bar, and transport buttons, and returns the encompassing Container.
|
|
func NewPlayerControls(p *player.Player, pm *backend.PlaybackManager) *fyne.Container {
|
|
slider := NewTrackPosSlider()
|
|
curTimeLabel := widget.NewLabel("0:00")
|
|
totalTimeLabel := widget.NewLabel("0:00")
|
|
|
|
c := container.NewBorder(nil, nil, curTimeLabel, totalTimeLabel, slider)
|
|
|
|
slider.OnDragEnd = func(f float64) {
|
|
p.Seek(fmt.Sprintf("%d", int(f*100)), player.SeekAbsolutePercent)
|
|
}
|
|
|
|
prev := widget.NewButtonWithIcon("", theme.MediaSkipPreviousIcon(), func() {
|
|
p.SeekBackOrPrevious()
|
|
})
|
|
next := widget.NewButtonWithIcon("", theme.MediaSkipNextIcon(), func() {
|
|
p.SeekNext()
|
|
})
|
|
playpause := widget.NewButtonWithIcon("", theme.MediaPlayIcon(), func() {
|
|
p.PlayPause()
|
|
})
|
|
|
|
p.OnPaused(func() {
|
|
playpause.SetIcon(theme.MediaPlayIcon())
|
|
})
|
|
p.OnPlaying(func() {
|
|
playpause.SetIcon(theme.MediaPauseIcon())
|
|
})
|
|
p.OnStopped(func() {
|
|
playpause.SetIcon(theme.MediaPlayIcon())
|
|
})
|
|
|
|
buttons := container.NewHBox(prev, playpause, next)
|
|
b := container.New(layout.NewCenterLayout(), buttons)
|
|
content := container.NewVBox(c, b)
|
|
|
|
pm.OnPlayTimeUpdate(func(curTime float64, totalTime float64) {
|
|
if !pm.IsSeeking() {
|
|
v := 0.0
|
|
if totalTime > 0 {
|
|
v = curTime / totalTime
|
|
}
|
|
ct := SecondsToTimeString(curTime)
|
|
updated := false
|
|
if ct != curTimeLabel.Text {
|
|
curTimeLabel.SetText(ct)
|
|
updated = true
|
|
}
|
|
tt := SecondsToTimeString(totalTime)
|
|
if tt != totalTimeLabel.Text {
|
|
totalTimeLabel.SetText(tt)
|
|
updated = true
|
|
}
|
|
if !slider.IsDragging() {
|
|
if totalTime < 210 || updated {
|
|
// if current track is long, we only need to redraw the slider
|
|
// when the time label updates, to reduce screen redraws.
|
|
slider.SetValue(v)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
return content
|
|
}
|