Major improvements to UnifiedPlayer: 1. GetFrameImage() now works when paused for responsive UI updates 2. Play() method properly starts FFmpeg process 3. Frame display loop runs continuously for smooth video display 4. Disabled audio temporarily to fix video playback fundamentals 5. Simplified FFmpeg command to focus on video stream only Player now: - Generates video frames correctly - Shows video when paused - Has responsive progress tracking - Starts playback properly Next steps: Re-enable audio playback once video is stable
178 lines
3.5 KiB
Go
178 lines
3.5 KiB
Go
package widget
|
|
|
|
import (
|
|
"image/color"
|
|
"time"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/canvas"
|
|
"fyne.io/fyne/v2/theme"
|
|
)
|
|
|
|
var _ fyne.Widget = (*Activity)(nil)
|
|
|
|
// Activity is used to indicate that something is happening that should be waited for,
|
|
// or is in the background (depending on usage).
|
|
//
|
|
// Since: 2.5
|
|
type Activity struct {
|
|
BaseWidget
|
|
|
|
started bool
|
|
}
|
|
|
|
// NewActivity returns a widget for indicating activity
|
|
//
|
|
// Since: 2.5
|
|
func NewActivity() *Activity {
|
|
a := &Activity{}
|
|
a.ExtendBaseWidget(a)
|
|
return a
|
|
}
|
|
|
|
func (a *Activity) MinSize() fyne.Size {
|
|
a.ExtendBaseWidget(a)
|
|
return a.BaseWidget.MinSize()
|
|
}
|
|
|
|
// Start the activity indicator animation
|
|
func (a *Activity) Start() {
|
|
if a.started {
|
|
return // already started
|
|
}
|
|
|
|
a.started = true
|
|
|
|
a.Refresh()
|
|
}
|
|
|
|
// Stop the activity indicator animation
|
|
func (a *Activity) Stop() {
|
|
if !a.started {
|
|
return // already stopped
|
|
}
|
|
|
|
a.started = false
|
|
|
|
a.Refresh()
|
|
}
|
|
|
|
func (a *Activity) CreateRenderer() fyne.WidgetRenderer {
|
|
dots := make([]fyne.CanvasObject, 3)
|
|
v := fyne.CurrentApp().Settings().ThemeVariant()
|
|
for i := range dots {
|
|
dots[i] = canvas.NewCircle(a.Theme().Color(theme.ColorNameForeground, v))
|
|
}
|
|
r := &activityRenderer{dots: dots, parent: a}
|
|
r.anim = &fyne.Animation{
|
|
Duration: time.Second * 2,
|
|
RepeatCount: fyne.AnimationRepeatForever,
|
|
Tick: r.animate,
|
|
}
|
|
r.updateColor()
|
|
|
|
if a.started {
|
|
r.start()
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
var _ fyne.WidgetRenderer = (*activityRenderer)(nil)
|
|
|
|
type activityRenderer struct {
|
|
anim *fyne.Animation
|
|
dots []fyne.CanvasObject
|
|
parent *Activity
|
|
|
|
bound fyne.Size
|
|
maxCol color.NRGBA
|
|
maxRad float32
|
|
wasStarted bool
|
|
}
|
|
|
|
func (a *activityRenderer) Destroy() {
|
|
a.parent.started = false
|
|
a.stop()
|
|
}
|
|
|
|
func (a *activityRenderer) Layout(size fyne.Size) {
|
|
a.maxRad = fyne.Min(size.Width, size.Height) / 2
|
|
a.bound = size
|
|
}
|
|
|
|
func (a *activityRenderer) MinSize() fyne.Size {
|
|
return fyne.NewSquareSize(a.parent.Theme().Size(theme.SizeNameInlineIcon))
|
|
}
|
|
|
|
func (a *activityRenderer) Objects() []fyne.CanvasObject {
|
|
return a.dots
|
|
}
|
|
|
|
func (a *activityRenderer) Refresh() {
|
|
if a.parent.started {
|
|
if !a.wasStarted {
|
|
a.start()
|
|
}
|
|
} else if a.wasStarted {
|
|
a.stop()
|
|
}
|
|
|
|
a.updateColor()
|
|
}
|
|
|
|
func (a *activityRenderer) animate(done float32) {
|
|
off := done * 2
|
|
if off > 1 {
|
|
off = 2 - off
|
|
}
|
|
|
|
off1 := (done + 0.25) * 2
|
|
if done >= 0.75 {
|
|
off1 = (done - 0.75) * 2
|
|
}
|
|
if off1 > 1 {
|
|
off1 = 2 - off1
|
|
}
|
|
|
|
off2 := (done + 0.75) * 2
|
|
if done >= 0.25 {
|
|
off2 = (done - 0.25) * 2
|
|
}
|
|
if off2 > 1 {
|
|
off2 = 2 - off2
|
|
}
|
|
|
|
a.scaleDot(a.dots[0].(*canvas.Circle), off)
|
|
a.scaleDot(a.dots[1].(*canvas.Circle), off1)
|
|
a.scaleDot(a.dots[2].(*canvas.Circle), off2)
|
|
}
|
|
|
|
func (a *activityRenderer) scaleDot(dot *canvas.Circle, off float32) {
|
|
rad := a.maxRad - a.maxRad*off/1.2
|
|
mid := fyne.NewPos(a.bound.Width/2, a.bound.Height/2)
|
|
|
|
dot.Move(mid.Subtract(fyne.NewSquareOffsetPos(rad)))
|
|
dot.Resize(fyne.NewSquareSize(rad * 2))
|
|
|
|
alpha := uint8(0 + int(float32(a.maxCol.A)*off))
|
|
dot.FillColor = color.NRGBA{R: a.maxCol.R, G: a.maxCol.G, B: a.maxCol.B, A: alpha}
|
|
dot.Refresh()
|
|
}
|
|
|
|
func (a *activityRenderer) start() {
|
|
a.wasStarted = true
|
|
a.anim.Start()
|
|
}
|
|
|
|
func (a *activityRenderer) stop() {
|
|
a.wasStarted = false
|
|
a.anim.Stop()
|
|
}
|
|
|
|
func (a *activityRenderer) updateColor() {
|
|
v := fyne.CurrentApp().Settings().ThemeVariant()
|
|
rr, gg, bb, aa := a.parent.Theme().Color(theme.ColorNameForeground, v).RGBA()
|
|
a.maxCol = color.NRGBA{R: uint8(rr >> 8), G: uint8(gg >> 8), B: uint8(bb >> 8), A: uint8(aa >> 8)}
|
|
}
|