Add compare view and drop-to-play only handler

This commit is contained in:
Stu 2025-12-04 06:12:02 -05:00
parent d5458f7050
commit 7fe4f78b94

163
main.go
View File

@ -178,6 +178,8 @@ type appState struct {
playerPaused bool playerPaused bool
playerPos float64 playerPos float64
playerLast time.Time playerLast time.Time
compareSess1 *playSession
compareSess2 *playSession
progressQuit chan struct{} progressQuit chan struct{}
convertCancel context.CancelFunc convertCancel context.CancelFunc
playerSurf *playerSurface playerSurf *playerSurface
@ -415,10 +417,144 @@ func (s *appState) showMainMenu() {
s.showPlayerView() s.showPlayerView()
} }
// showCompareView renders a simple side-by-side player for the first two loaded videos.
func (s *appState) showCompareView() {
s.stopPreview()
s.stopPlayer()
s.stopCompareSessions()
s.active = "compare"
header := widget.NewLabelWithStyle("Compare", fyne.TextAlignLeading, fyne.TextStyle{Bold: true})
backBtn := widget.NewButton("Back to Player", func() { s.showPlayerView() })
headerRow := container.NewHBox(header, layout.NewSpacer(), backBtn)
if len(s.loadedVideos) < 2 {
icon := canvas.NewText("⬆", utils.MustHex("#4CE870"))
icon.TextStyle = fyne.TextStyle{Monospace: true, Bold: true}
icon.TextSize = 28
msg := widget.NewLabel("Load at least two videos to compare.")
msg.Alignment = fyne.TextAlignCenter
s.setContent(container.NewBorder(container.NewPadded(headerRow), nil, nil, nil, container.NewCenter(container.NewVBox(container.NewCenter(icon), container.NewCenter(msg)))))
return
}
src1 := s.loadedVideos[0]
src2 := s.loadedVideos[1]
// Left player
left := s.buildComparePane(src1, func() { s.stopCompareSessions() }, func(ps *playSession) { s.compareSess1 = ps })
// Right player
right := s.buildComparePane(src2, func() { s.stopCompareSessions() }, func(ps *playSession) { s.compareSess2 = ps })
body := container.NewGridWithColumns(2, left, right)
s.setContent(container.NewBorder(container.NewPadded(headerRow), nil, nil, nil, container.NewPadded(body)))
}
// buildComparePane builds a simple player pane for compare view.
func (s *appState) buildComparePane(src *videoSource, onStop func(), setSess func(*playSession)) fyne.CanvasObject {
stageBG := canvas.NewRectangle(utils.MustHex("#0F1529"))
stageBG.SetMinSize(fyne.NewSize(640, 360))
videoImg := canvas.NewImageFromResource(nil)
videoImg.FillMode = canvas.ImageFillContain
stage := container.NewMax(stageBG, videoImg)
currentTime := widget.NewLabel("0:00")
totalTime := widget.NewLabel(src.DurationString())
totalTime.Alignment = fyne.TextAlignTrailing
slider := widget.NewSlider(0, math.Max(1, src.Duration))
slider.Step = 0.5
var updatingProgress bool
var sess *playSession
updateProgress := func(val float64) {
fyne.Do(func() {
updatingProgress = true
currentTime.SetText(formatClock(val))
slider.SetValue(val)
updatingProgress = false
})
}
ensureSession := func() *playSession {
if sess == nil {
ps := newPlaySession(src.Path, src.Width, src.Height, src.FrameRate, 640, 360, updateProgress, videoImg)
ps.SetVolume(100)
setSess(ps)
sess = ps
}
return sess
}
slider.OnChanged = func(val float64) {
if updatingProgress {
return
}
updateProgress(val)
if ps := ensureSession(); ps != nil {
ps.Seek(val)
}
}
playBtn := utils.MakeIconButton("▶/⏸", "Play/Pause", func() {
if ps := ensureSession(); ps != nil {
if ps.paused {
ps.Play()
ps.paused = false
} else {
ps.Pause()
ps.paused = true
}
}
})
var volIcon *widget.Button
volIcon = utils.MakeIconButton("🔊", "Mute/Unmute", func() {
if ps := ensureSession(); ps != nil {
if ps.muted || ps.volume <= 0 {
ps.SetVolume(50)
} else {
ps.SetVolume(0)
}
if ps.muted || ps.volume <= 0 {
volIcon.SetText("🔇")
} else {
volIcon.SetText("🔊")
}
}
})
volSlider := widget.NewSlider(0, 100)
volSlider.Step = 1
volSlider.Value = 100
volSlider.OnChanged = func(val float64) {
if ps := ensureSession(); ps != nil {
ps.SetVolume(val)
if ps.muted || ps.volume <= 0 {
volIcon.SetText("🔇")
} else {
volIcon.SetText("🔊")
}
}
}
progressBar := container.NewBorder(nil, nil, currentTime, totalTime, container.NewMax(slider))
controlRow := container.NewHBox(playBtn, layout.NewSpacer(), volIcon, container.NewMax(volSlider))
title := widget.NewLabelWithStyle(filepath.Base(src.Path), fyne.TextAlignLeading, fyne.TextStyle{Bold: true})
return container.NewVBox(
title,
container.NewPadded(stage),
container.NewPadded(progressBar),
container.NewPadded(controlRow),
)
}
// showPlayerView renders the player-focused UI with a lightweight playlist. // showPlayerView renders the player-focused UI with a lightweight playlist.
func (s *appState) showPlayerView() { func (s *appState) showPlayerView() {
s.stopPreview() s.stopPreview()
s.stopPlayer() s.stopPlayer()
s.stopCompareSessions()
s.active = "player" s.active = "player"
header := widget.NewLabelWithStyle("VT Player", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}) header := widget.NewLabelWithStyle("VT Player", fyne.TextAlignLeading, fyne.TextStyle{Bold: true})
@ -462,7 +598,19 @@ func (s *appState) showPlayerView() {
}) })
clearList.Importance = widget.LowImportance clearList.Importance = widget.LowImportance
controlsBar := container.NewHBox(openFile, addFolder, clearList, layout.NewSpacer()) var compareBtn *widget.Button
if len(s.loadedVideos) >= 2 {
compareBtn = widget.NewButton("Compare View", func() {
s.showCompareView()
})
}
barItems := []fyne.CanvasObject{openFile, addFolder, clearList}
if compareBtn != nil {
barItems = append(barItems, compareBtn)
}
barItems = append(barItems, layout.NewSpacer())
controlsBar := container.NewHBox(barItems...)
// Player area // Player area
var playerArea fyne.CanvasObject var playerArea fyne.CanvasObject
@ -675,6 +823,7 @@ func (s *appState) showPlayerView() {
func (s *appState) showQueue() { func (s *appState) showQueue() {
s.stopPreview() s.stopPreview()
s.stopPlayer() s.stopPlayer()
s.stopCompareSessions()
s.lastModule = s.active s.lastModule = s.active
s.active = "queue" s.active = "queue"
s.refreshQueueView() s.refreshQueueView()
@ -1587,6 +1736,7 @@ func (s *appState) shutdown() {
} }
s.stopPlayer() s.stopPlayer()
s.stopCompareSessions()
if s.player != nil { if s.player != nil {
s.player.Close() s.player.Close()
} }
@ -1605,6 +1755,17 @@ func (s *appState) stopPlayer() {
s.playerPaused = true s.playerPaused = true
} }
func (s *appState) stopCompareSessions() {
if s.compareSess1 != nil {
s.compareSess1.Stop()
s.compareSess1 = nil
}
if s.compareSess2 != nil {
s.compareSess2.Stop()
s.compareSess2 = nil
}
}
func main() { func main() {
logging.Init() logging.Init()
defer logging.Close() defer logging.Close()