forked from Leak_Technologies/VideoTools
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
|
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()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user