Fix control visibility and stabilize HLS loading

This commit is contained in:
Mert Uyanık
2025-10-29 07:58:50 +03:00
parent b57b24d051
commit 400bf899aa
3 changed files with 95 additions and 35 deletions
+3
View File
@@ -14,6 +14,9 @@
.controls-layer.hidden.playing {
opacity: 0;
}
.controls-layer.fullscreen.hidden.playing {
cursor: none;
}
+88 -31
View File
@@ -28,60 +28,116 @@ export const ControlsLayer: React.FC<ControlsLayerProps> = ({
subtitles = [],
audioTracks = [],
}) => {
const { videoState, uiState, togglePlay, toggleFullscreen, showControls, hideControls } = usePlayerContext()
const [mouseMoving, setMouseMoving] = useState(false)
const { videoState, uiState, togglePlay, toggleFullscreen, showControls, hideControls } =
usePlayerContext()
const [isPointerOver, setIsPointerOver] = useState(false)
const [lastInteraction, setLastInteraction] = useState<number>(0)
const hideTimeoutRef = useRef<number>()
const containerRef = useRef<HTMLDivElement>(null)
const lastClickTimeRef = useRef<number>(0)
const isMenuOpen =
uiState.settingsOpen ||
uiState.volumeControlOpen ||
uiState.qualityMenuOpen ||
uiState.subtitleMenuOpen
const autoHideEnabled = videoState.fullscreen && videoState.playing && !isMenuOpen
// Auto-hide controls after inactivity
useEffect(() => {
if (videoState.playing) {
// Show controls on mouse movement
if (mouseMoving) {
showControls()
}
// Clear existing timeout
const clearHideTimeout = useCallback(() => {
if (hideTimeoutRef.current) {
window.clearTimeout(hideTimeoutRef.current)
hideTimeoutRef.current = undefined
}
}, [])
const scheduleHide = useCallback(() => {
if (!autoHideEnabled) {
clearHideTimeout()
return
}
// Hide controls after inactivity (3 seconds in all modes)
if (mouseMoving) {
const hideDelay = 3000
clearHideTimeout()
hideTimeoutRef.current = window.setTimeout(() => {
hideControls()
setMouseMoving(false)
}, hideDelay)
}
} else {
// Always show controls when paused
}, 3000)
}, [autoHideEnabled, clearHideTimeout, hideControls])
// Keep controls visible when not playing or when any menu is open
useEffect(() => {
if (!videoState.playing || isMenuOpen) {
clearHideTimeout()
showControls()
}
}, [videoState.playing, isMenuOpen, showControls, clearHideTimeout])
// Manage controls visibility when leaving fullscreen
useEffect(() => {
if (!videoState.fullscreen) {
clearHideTimeout()
if (!videoState.playing || isPointerOver) {
showControls()
}
}
}, [videoState.fullscreen, videoState.playing, isPointerOver, showControls, clearHideTimeout])
// Re-schedule auto hide when interaction changes
useEffect(() => {
if (autoHideEnabled && lastInteraction > 0) {
scheduleHide()
}
return () => {
if (hideTimeoutRef.current) {
window.clearTimeout(hideTimeoutRef.current)
if (autoHideEnabled) {
clearHideTimeout()
}
}
}, [mouseMoving, videoState.playing, videoState.fullscreen, showControls, hideControls])
}, [autoHideEnabled, lastInteraction, scheduleHide, clearHideTimeout])
const handleMouseEnter = useCallback(() => {
setIsPointerOver(true)
showControls()
if (autoHideEnabled) {
setLastInteraction(Date.now())
}
}, [autoHideEnabled, showControls])
// Handle mouse movement
const handleMouseMove = useCallback(() => {
if (!mouseMoving) {
setMouseMoving(true)
setIsPointerOver(true)
showControls()
if (autoHideEnabled) {
setLastInteraction(Date.now())
}
}, [mouseMoving])
}, [autoHideEnabled, showControls])
const handleMouseLeave = useCallback(() => {
// Only hide controls on mouse leave when in fullscreen mode
// When player is small, controls should stay visible
setMouseMoving(false)
if (videoState.playing && videoState.fullscreen) {
setIsPointerOver(false)
clearHideTimeout()
if (videoState.fullscreen) {
if (videoState.playing) {
hideControls()
} else {
showControls()
}
} else if (videoState.playing) {
hideControls()
}
}, [videoState.playing, videoState.fullscreen, hideControls])
}, [clearHideTimeout, videoState.fullscreen, videoState.playing, hideControls, showControls])
useEffect(() => {
return () => {
clearHideTimeout()
}
}, [clearHideTimeout])
const previousAutoHide = useRef(autoHideEnabled)
useEffect(() => {
if (autoHideEnabled && !previousAutoHide.current) {
showControls()
setLastInteraction(Date.now())
}
previousAutoHide.current = autoHideEnabled
}, [autoHideEnabled, showControls])
// Keyboard shortcuts
useKeyboardShortcuts(keyboardShortcuts)
@@ -132,12 +188,13 @@ export const ControlsLayer: React.FC<ControlsLayerProps> = ({
const controlsClassName = `controls-layer ${uiState.controlsVisible ? 'visible' : 'hidden'} ${
videoState.playing ? 'playing' : 'paused'
}`
} ${videoState.fullscreen ? 'fullscreen' : 'windowed'}`
return (
<div
ref={containerRef}
className={controlsClassName}
onMouseEnter={handleMouseEnter}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
onClick={handleClick}
+1 -1
View File
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import React, { useEffect, useState, useCallback } from 'react'
import { PlayerProvider } from '../contexts/PlayerContext'
import { VideoElement } from './VideoElement'
import { ControlsLayer } from './ControlsLayer'