diff --git a/k-tv-frontend/app/(main)/tv/page.tsx b/k-tv-frontend/app/(main)/tv/page.tsx index a561d29..37a76da 100644 --- a/k-tv-frontend/app/(main)/tv/page.tsx +++ b/k-tv-frontend/app/(main)/tv/page.tsx @@ -98,6 +98,21 @@ function TvPageContent() { return () => document.removeEventListener("fullscreenchange", handler); }, []); + // iOS Safari: track fullscreen state via webkit video element events. + // Re-run when streamUrl changes so we catch the video element after it mounts. + useEffect(() => { + const video = videoRef.current; + if (!video) return; + const onBegin = () => setIsFullscreen(true); + const onEnd = () => setIsFullscreen(false); + video.addEventListener("webkitbeginfullscreen", onBegin); + video.addEventListener("webkitendfullscreen", onEnd); + return () => { + video.removeEventListener("webkitbeginfullscreen", onBegin); + video.removeEventListener("webkitendfullscreen", onEnd); + }; + }, [streamUrl]); + // Hide the shared nav bar in fullscreen; reveal it when overlays are shown // (mouse move / key press). Classes are cleaned up on unmount. useEffect(() => { @@ -105,11 +120,29 @@ function TvPageContent() { document.body.classList.toggle("tv-overlays", isFullscreen && showOverlays); return () => document.body.classList.remove("tv-fullscreen", "tv-overlays"); }, [isFullscreen, showOverlays]); + const toggleFullscreen = useCallback(() => { - if (!document.fullscreenElement) { - document.documentElement.requestFullscreen().catch(() => {}); + // Standard Fullscreen API (Chrome, Firefox, Safari desktop) + if (document.fullscreenEnabled) { + if (!document.fullscreenElement) { + document.documentElement.requestFullscreen().catch(() => {}); + } else { + document.exitFullscreen().catch(() => {}); + } + return; + } + // iOS Safari: requestFullscreen is not supported. Fall back to the video + // element's proprietary webkit API instead. + const video = videoRef.current as HTMLVideoElement & { + webkitEnterFullscreen?: () => void; + webkitExitFullscreen?: () => void; + webkitDisplayingFullscreen?: boolean; + }; + if (!video?.webkitEnterFullscreen) return; + if (video.webkitDisplayingFullscreen) { + video.webkitExitFullscreen?.(); } else { - document.exitFullscreen().catch(() => {}); + video.webkitEnterFullscreen(); } }, []);