forked from Leak_Technologies/VideoTools
Add video interaction: double-click fullscreen and right-click play/pause
Implements intuitive video player interactions for enhanced user experience. Video Interaction Features: - Double-click video area to toggle fullscreen - Right-click video area to play/pause - Single-click does nothing (reserved for future use) - Transparent tappable overlay on video canvas Implementation: - Created TappableOverlay widget in internal/ui/tappable.go - Invisible widget captures tap, double-tap, and secondary-tap events - Extends widget.BaseWidget for Fyne compatibility - Added overlay to stage container after video image User Experience: - Double-click anywhere on video → instant fullscreen - Right-click anywhere on video → quick play/pause - Works alongside existing keyboard shortcuts (F11, Space, ESC) - Play button icon updates when using right-click Technical Details: - TappableOverlay has no visual representation - Implements Tapped(), DoubleTapped(), TappedSecondary() - Callbacks are configurable per instance - Positioned as top layer in container.NewMax() stack Usage: 1. Load a video 2. Double-click video to enter fullscreen 3. Right-click to pause/play 4. ESC or F11 to exit fullscreen Next Steps: - Consider adding single-click functionality - Add visual feedback for interactions - Implement mouse cursor auto-hide in fullscreen 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b73beb1fef
commit
e25f0c4284
64
internal/ui/tappable.go
Normal file
64
internal/ui/tappable.go
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
// TappableOverlay is an invisible widget that captures tap and double-tap events
|
||||
type TappableOverlay struct {
|
||||
widget.BaseWidget
|
||||
OnTapped func()
|
||||
OnDoubleTapped func()
|
||||
OnSecondaryTapped func()
|
||||
}
|
||||
|
||||
// NewTappableOverlay creates a new tappable overlay
|
||||
func NewTappableOverlay(onTapped, onDoubleTapped, onSecondaryTapped func()) *TappableOverlay {
|
||||
t := &TappableOverlay{
|
||||
OnTapped: onTapped,
|
||||
OnDoubleTapped: onDoubleTapped,
|
||||
OnSecondaryTapped: onSecondaryTapped,
|
||||
}
|
||||
t.ExtendBaseWidget(t)
|
||||
return t
|
||||
}
|
||||
|
||||
// Tapped handles single tap events
|
||||
func (t *TappableOverlay) Tapped(*fyne.PointEvent) {
|
||||
if t.OnTapped != nil {
|
||||
t.OnTapped()
|
||||
}
|
||||
}
|
||||
|
||||
// TappedSecondary handles right-click events
|
||||
func (t *TappableOverlay) TappedSecondary(*fyne.PointEvent) {
|
||||
if t.OnSecondaryTapped != nil {
|
||||
t.OnSecondaryTapped()
|
||||
}
|
||||
}
|
||||
|
||||
// DoubleTapped handles double-tap events
|
||||
func (t *TappableOverlay) DoubleTapped(*fyne.PointEvent) {
|
||||
if t.OnDoubleTapped != nil {
|
||||
t.OnDoubleTapped()
|
||||
}
|
||||
}
|
||||
|
||||
// CreateRenderer implements fyne.Widget
|
||||
func (t *TappableOverlay) CreateRenderer() fyne.WidgetRenderer {
|
||||
return &tappableRenderer{}
|
||||
}
|
||||
|
||||
// MinSize returns minimum size (should fill parent)
|
||||
func (t *TappableOverlay) MinSize() fyne.Size {
|
||||
return fyne.NewSize(1, 1)
|
||||
}
|
||||
|
||||
type tappableRenderer struct{}
|
||||
|
||||
func (r *tappableRenderer) Layout(size fyne.Size) {}
|
||||
func (r *tappableRenderer) MinSize() fyne.Size { return fyne.NewSize(1, 1) }
|
||||
func (r *tappableRenderer) Refresh() {}
|
||||
func (r *tappableRenderer) Objects() []fyne.CanvasObject { return nil }
|
||||
func (r *tappableRenderer) Destroy() {}
|
||||
28
main.go
28
main.go
|
|
@ -1068,6 +1068,34 @@ func (s *appState) showPlayerView() {
|
|||
})
|
||||
}
|
||||
|
||||
// Add tappable overlay to stage for video interactions
|
||||
// Double-click toggles fullscreen, right-click plays/pauses
|
||||
videoTapper := ui.NewTappableOverlay(
|
||||
nil, // Single tap does nothing for now
|
||||
func() {
|
||||
// Double-tap: toggle fullscreen
|
||||
s.toggleFullscreen()
|
||||
},
|
||||
func() {
|
||||
// Right-click: toggle play/pause
|
||||
if !ensureSession() {
|
||||
return
|
||||
}
|
||||
if s.playerPaused {
|
||||
s.playSess.Play()
|
||||
s.playerPaused = false
|
||||
playBtn.SetText(ui.IconPause)
|
||||
} else {
|
||||
s.playSess.Pause()
|
||||
s.playerPaused = true
|
||||
playBtn.SetText(ui.IconPlayArrow)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// Add tapper to stage
|
||||
stage.Objects = append(stage.Objects, videoTapper)
|
||||
|
||||
playerArea = container.NewBorder(
|
||||
nil,
|
||||
container.NewVBox(container.NewPadded(progressBar), container.NewPadded(controlRow)),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user