Add menu bar and center playback controls

UI improvements:
- Add menu bar at top with File, View, and Tools menus
- Move File operations (Open, Add Folder, Clear) to File menu
- Add Frame-Accurate Mode toggle in Tools menu
- Center playback controls (Prev, Play, Next) at bottom
- Move volume controls to left, playlist toggle to right
- Remove redundant top control bar for cleaner interface
- Add keyframingMode state to appState for feature toggle

Layout changes:
- Menu bar provides access to advanced features
- Main player area takes full space below menu
- Controls centered bottom like modern video players (Haruna/VLC)
- Cleaner interface suitable for basic playback or advanced editing

Prepares for:
- Frame-accurate navigation features (when keyframing enabled)
- Timeline with keyframe markers
- In/out point cutting tools
- Integration with VideoTools chapter support

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Stu Leak 2025-12-05 10:03:31 -05:00 committed by Stu
parent 5e2171a95e
commit c7d821e03a

71
main.go
View File

@ -197,6 +197,7 @@ type appState struct {
queueOffset fyne.Position queueOffset fyne.Position
compareFile1 *videoSource compareFile1 *videoSource
compareFile2 *videoSource compareFile2 *videoSource
keyframingMode bool // Toggle for frame-accurate editing features
} }
func (s *appState) stopPreview() { func (s *appState) stopPreview() {
@ -558,14 +559,14 @@ func (s *appState) showPlayerView() {
s.stopCompareSessions() s.stopCompareSessions()
s.active = "player" s.active = "player"
header := widget.NewLabelWithStyle("VT Player", fyne.TextAlignLeading, fyne.TextStyle{Bold: true})
// Helper to refresh the view after selection/loads. // Helper to refresh the view after selection/loads.
refresh := func() { refresh := func() {
s.showPlayerView() s.showPlayerView()
} }
openFile := widget.NewButton("Open File…", func() { // Create menu bar
fileMenu := fyne.NewMenu("File",
fyne.NewMenuItem("Open File…", func() {
dlg := dialog.NewFileOpen(func(r fyne.URIReadCloser, err error) { dlg := dialog.NewFileOpen(func(r fyne.URIReadCloser, err error) {
if err != nil || r == nil { if err != nil || r == nil {
return return
@ -576,9 +577,8 @@ func (s *appState) showPlayerView() {
}, s.window) }, s.window)
dlg.Resize(fyne.NewSize(700, 480)) dlg.Resize(fyne.NewSize(700, 480))
dlg.Show() dlg.Show()
}) }),
fyne.NewMenuItem("Open Folder…", func() {
addFolder := widget.NewButton("Add Folder…", func() {
dlg := dialog.NewFolderOpen(func(l fyne.ListableURI, err error) { dlg := dialog.NewFolderOpen(func(l fyne.ListableURI, err error) {
if err != nil || l == nil { if err != nil || l == nil {
return return
@ -591,27 +591,38 @@ func (s *appState) showPlayerView() {
}, s.window) }, s.window)
dlg.Resize(fyne.NewSize(700, 480)) dlg.Resize(fyne.NewSize(700, 480))
dlg.Show() dlg.Show()
}) }),
fyne.NewMenuItemSeparator(),
clearList := widget.NewButton("Clear Playlist", func() { fyne.NewMenuItem("Clear Playlist", func() {
s.clearVideo() s.clearVideo()
refresh() refresh()
}) }),
clearList.Importance = widget.LowImportance )
viewMenu := fyne.NewMenu("View",
fyne.NewMenuItem("Playlist", func() {
// Will be implemented with playlist toggle
}),
)
var compareBtn *widget.Button
if len(s.loadedVideos) >= 2 { if len(s.loadedVideos) >= 2 {
compareBtn = widget.NewButton("Compare View", func() { viewMenu.Items = append(viewMenu.Items, fyne.NewMenuItem("Compare Videos", func() {
s.showCompareView() s.showCompareView()
}) }))
} }
barItems := []fyne.CanvasObject{openFile, addFolder, clearList} toolsMenu := fyne.NewMenu("Tools")
if compareBtn != nil {
barItems = append(barItems, compareBtn) // Keyframing mode toggle
} keyframeModeItem := fyne.NewMenuItem("Frame-Accurate Mode", func() {
barItems = append(barItems, layout.NewSpacer()) s.keyframingMode = !s.keyframingMode
controlsBar := container.NewHBox(barItems...) refresh()
})
keyframeModeItem.Checked = s.keyframingMode
toolsMenu.Items = append(toolsMenu.Items, keyframeModeItem)
mainMenu := fyne.NewMainMenu(fileMenu, viewMenu, toolsMenu)
s.window.SetMainMenu(mainMenu)
// Player area // Player area
var playerArea fyne.CanvasObject var playerArea fyne.CanvasObject
@ -836,7 +847,17 @@ func (s *appState) showPlayerView() {
progressBar := container.NewBorder(nil, nil, currentTime, totalTime, container.NewMax(slider)) progressBar := container.NewBorder(nil, nil, currentTime, totalTime, container.NewMax(slider))
volContainer := container.NewHBox(volIcon, container.NewMax(volSlider)) volContainer := container.NewHBox(volIcon, container.NewMax(volSlider))
volContainer.Resize(fyne.NewSize(150, 32)) volContainer.Resize(fyne.NewSize(150, 32))
controlRow := container.NewHBox(prevBtn, playBtn, nextBtn, layout.NewSpacer(), playlistToggleBtn, volContainer)
// Center the playback controls
playbackControls := container.NewHBox(prevBtn, playBtn, nextBtn)
// Create control row with centered playback controls
controlRow := container.NewBorder(
nil, nil,
volContainer, // Volume on left
container.NewHBox(playlistToggleBtn), // Playlist toggle on right
container.NewCenter(playbackControls), // Playback controls centered
)
playerArea = container.NewBorder( playerArea = container.NewBorder(
nil, nil,
@ -847,13 +868,7 @@ func (s *appState) showPlayerView() {
) )
} }
mainPanel := container.NewBorder( mainPanel := playerArea
container.NewVBox(header, controlsBar, widget.NewSeparator()),
nil,
nil,
nil,
playerArea,
)
s.setContent(mainPanel) s.setContent(mainPanel)
} }