Enhance video playback controls for better user experience
Implement play/pause, mute, and fullscreen toggles in the video modal, along with temporary control visibility. Includes improved error handling for fragment loading stats. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 11420304-80a9-4ef2-adff-cbdaa418ffa8 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/11420304-80a9-4ef2-adff-cbdaa418ffa8/Qpg7dKb
This commit is contained in:
parent
1bd4584dcc
commit
4ee20431aa
@ -59,6 +59,10 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps)
|
||||
const [showShareMenu, setShowShareMenu] = useState(false);
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
const [videoThumbnail, setVideoThumbnail] = useState<string | null>(null);
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [isMuted, setIsMuted] = useState(false);
|
||||
const [showControls, setShowControls] = useState(true);
|
||||
const [controlsTimeout, setControlsTimeout] = useState<NodeJS.Timeout | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleEscape = (e: KeyboardEvent) => {
|
||||
@ -163,12 +167,18 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps)
|
||||
console.log('Razlog preklopa: adaptivni algoritem na podlagi omrežne hitrosti');
|
||||
});
|
||||
|
||||
// Fragment loading stats
|
||||
// Fragment loading stats - fixed error handling
|
||||
hls.on(Hls.Events.FRAG_LOADED, (event, data) => {
|
||||
const stats = data.stats;
|
||||
const loadTime = stats.loading.end - stats.loading.start;
|
||||
const speed = (stats.total * 8) / loadTime; // bits per ms = kbps
|
||||
console.log(`Fragment naložen v ${loadTime}ms, hitrost: ${Math.round(speed)} kbps`);
|
||||
try {
|
||||
if (data.frag && data.frag.stats) {
|
||||
const stats = data.frag.stats;
|
||||
const loadTime = stats.loading.end - stats.loading.start;
|
||||
const speed = (stats.total * 8) / loadTime; // bits per ms = kbps
|
||||
console.log(`Fragment naložen v ${loadTime}ms, hitrost: ${Math.round(speed)} kbps`);
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore stats errors, they don't affect playback
|
||||
}
|
||||
});
|
||||
|
||||
// Buffer monitoring for dynamic adjustment
|
||||
@ -222,7 +232,7 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps)
|
||||
console.log('Using native video support for MP4');
|
||||
}
|
||||
|
||||
// Capture thumbnail when video loads
|
||||
// Video event listeners
|
||||
videoElement.addEventListener('loadeddata', () => {
|
||||
console.log('Video data loaded, capturing thumbnail');
|
||||
setTimeout(() => captureVideoThumbnail(), 1000);
|
||||
@ -232,6 +242,10 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps)
|
||||
console.log('Video can play, capturing thumbnail');
|
||||
captureVideoThumbnail();
|
||||
});
|
||||
|
||||
videoElement.addEventListener('play', () => setIsPlaying(true));
|
||||
videoElement.addEventListener('pause', () => setIsPlaying(false));
|
||||
videoElement.addEventListener('volumechange', () => setIsMuted(videoElement.muted));
|
||||
}
|
||||
|
||||
// Cleanup when modal closes
|
||||
@ -280,6 +294,52 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps)
|
||||
}
|
||||
};
|
||||
|
||||
const togglePlay = () => {
|
||||
if (videoRef.current) {
|
||||
if (isPlaying) {
|
||||
videoRef.current.pause();
|
||||
} else {
|
||||
videoRef.current.play();
|
||||
handleVideoPlay();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const toggleMute = () => {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.muted = !videoRef.current.muted;
|
||||
}
|
||||
};
|
||||
|
||||
const toggleFullscreen = () => {
|
||||
if (videoRef.current) {
|
||||
if (document.fullscreenElement) {
|
||||
document.exitFullscreen();
|
||||
} else {
|
||||
videoRef.current.requestFullscreen();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const showControlsTemporarily = () => {
|
||||
setShowControls(true);
|
||||
if (controlsTimeout) {
|
||||
clearTimeout(controlsTimeout);
|
||||
}
|
||||
const timeout = setTimeout(() => {
|
||||
setShowControls(false);
|
||||
}, 3000);
|
||||
setControlsTimeout(timeout);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (controlsTimeout) {
|
||||
clearTimeout(controlsTimeout);
|
||||
}
|
||||
};
|
||||
}, [controlsTimeout]);
|
||||
|
||||
const getShareUrl = () => {
|
||||
if (!video?.id) return window.location.origin;
|
||||
return `${window.location.origin}?video=${video.id}`;
|
||||
@ -339,15 +399,21 @@ export default function VideoModal({ video, isOpen, onClose }: VideoModalProps)
|
||||
</Button>
|
||||
|
||||
<div className="relative bg-black rounded-lg overflow-hidden">
|
||||
<video
|
||||
ref={videoRef}
|
||||
className="w-full h-auto max-h-[80vh]"
|
||||
controls
|
||||
preload="metadata"
|
||||
onPlay={handleVideoPlay}
|
||||
data-testid="video-player"
|
||||
crossOrigin="anonymous"
|
||||
<div
|
||||
className="relative flex items-center justify-center bg-black"
|
||||
onMouseMove={showControlsTemporarily}
|
||||
onMouseEnter={() => setShowControls(true)}
|
||||
onMouseLeave={() => setShowControls(false)}
|
||||
>
|
||||
<video
|
||||
ref={videoRef}
|
||||
className="w-full h-auto max-h-[80vh] cursor-pointer"
|
||||
preload="metadata"
|
||||
onPlay={handleVideoPlay}
|
||||
data-testid="video-player"
|
||||
crossOrigin="anonymous"
|
||||
onClick={togglePlay}
|
||||
>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user