Add compare view and drop-to-play only handler
This commit is contained in:
parent
d5458f7050
commit
7fe4f78b94
163
main.go
163
main.go
|
|
@ -178,6 +178,8 @@ type appState struct {
|
|||
playerPaused bool
|
||||
playerPos float64
|
||||
playerLast time.Time
|
||||
compareSess1 *playSession
|
||||
compareSess2 *playSession
|
||||
progressQuit chan struct{}
|
||||
convertCancel context.CancelFunc
|
||||
playerSurf *playerSurface
|
||||
|
|
@ -415,10 +417,144 @@ func (s *appState) showMainMenu() {
|
|||
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.
|
||||
func (s *appState) showPlayerView() {
|
||||
s.stopPreview()
|
||||
s.stopPlayer()
|
||||
s.stopCompareSessions()
|
||||
s.active = "player"
|
||||
|
||||
header := widget.NewLabelWithStyle("VT Player", fyne.TextAlignLeading, fyne.TextStyle{Bold: true})
|
||||
|
|
@ -462,7 +598,19 @@ func (s *appState) showPlayerView() {
|
|||
})
|
||||
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
|
||||
var playerArea fyne.CanvasObject
|
||||
|
|
@ -675,6 +823,7 @@ func (s *appState) showPlayerView() {
|
|||
func (s *appState) showQueue() {
|
||||
s.stopPreview()
|
||||
s.stopPlayer()
|
||||
s.stopCompareSessions()
|
||||
s.lastModule = s.active
|
||||
s.active = "queue"
|
||||
s.refreshQueueView()
|
||||
|
|
@ -1587,6 +1736,7 @@ func (s *appState) shutdown() {
|
|||
}
|
||||
|
||||
s.stopPlayer()
|
||||
s.stopCompareSessions()
|
||||
if s.player != nil {
|
||||
s.player.Close()
|
||||
}
|
||||
|
|
@ -1605,6 +1755,17 @@ func (s *appState) stopPlayer() {
|
|||
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() {
|
||||
logging.Init()
|
||||
defer logging.Close()
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user