From 1da934e63c1f4af941461c9f99397f45aa15e3b4 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Mon, 19 Aug 2024 15:01:21 -0600 Subject: [PATCH] Dynamically detect if full screen is supported (#13197) --- web/src/components/player/HlsVideoPlayer.tsx | 6 ++-- .../player/dynamic/DynamicVideoPlayer.tsx | 3 ++ web/src/hooks/use-fullscreen.ts | 30 +++++++++++++++++-- web/src/pages/Live.tsx | 5 +++- web/src/views/events/RecordingView.tsx | 4 ++- web/src/views/live/LiveBirdseyeView.tsx | 20 ++++++++----- web/src/views/live/LiveCameraView.tsx | 4 ++- 7 files changed, 57 insertions(+), 15 deletions(-) diff --git a/web/src/components/player/HlsVideoPlayer.tsx b/web/src/components/player/HlsVideoPlayer.tsx index 5f499ade7..7f49a6cad 100644 --- a/web/src/components/player/HlsVideoPlayer.tsx +++ b/web/src/components/player/HlsVideoPlayer.tsx @@ -6,7 +6,7 @@ import { useState, } from "react"; import Hls from "hls.js"; -import { isAndroid, isDesktop, isIOS, isMobile } from "react-device-detect"; +import { isAndroid, isDesktop, isMobile } from "react-device-detect"; import { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch"; import VideoControls from "./VideoControls"; import { VideoResolutionType } from "@/types/live"; @@ -33,6 +33,7 @@ type HlsVideoPlayerProps = { visible: boolean; currentSource: string; hotKeys: boolean; + supportsFullscreen: boolean; fullscreen: boolean; onClipEnded?: () => void; onPlayerLoaded?: () => void; @@ -49,6 +50,7 @@ export default function HlsVideoPlayer({ visible, currentSource, hotKeys, + supportsFullscreen, fullscreen, onClipEnded, onPlayerLoaded, @@ -180,7 +182,7 @@ export default function HlsVideoPlayer({ seek: true, playbackRate: true, plusUpload: config?.plus?.enabled == true, - fullscreen: !isIOS, + fullscreen: supportsFullscreen, }} setControlsOpen={setControlsOpen} setMuted={(muted) => setMuted(muted, true)} diff --git a/web/src/components/player/dynamic/DynamicVideoPlayer.tsx b/web/src/components/player/dynamic/DynamicVideoPlayer.tsx index caa709430..6c4e28e27 100644 --- a/web/src/components/player/dynamic/DynamicVideoPlayer.tsx +++ b/web/src/components/player/dynamic/DynamicVideoPlayer.tsx @@ -24,6 +24,7 @@ type DynamicVideoPlayerProps = { startTimestamp?: number; isScrubbing: boolean; hotKeys: boolean; + supportsFullscreen: boolean; fullscreen: boolean; onControllerReady: (controller: DynamicVideoController) => void; onTimestampUpdate?: (timestamp: number) => void; @@ -40,6 +41,7 @@ export default function DynamicVideoPlayer({ startTimestamp, isScrubbing, hotKeys, + supportsFullscreen, fullscreen, onControllerReady, onTimestampUpdate, @@ -201,6 +203,7 @@ export default function DynamicVideoPlayer({ visible={!(isScrubbing || isLoading)} currentSource={source} hotKeys={hotKeys} + supportsFullscreen={supportsFullscreen} fullscreen={fullscreen} onTimeUpdate={onTimeUpdate} onPlayerLoaded={onPlayerLoaded} diff --git a/web/src/hooks/use-fullscreen.ts b/web/src/hooks/use-fullscreen.ts index a0f0a1e56..c7082ab5c 100644 --- a/web/src/hooks/use-fullscreen.ts +++ b/web/src/hooks/use-fullscreen.ts @@ -1,4 +1,4 @@ -import { RefObject, useCallback, useEffect, useState } from "react"; +import { RefObject, useCallback, useEffect, useMemo, useState } from "react"; import nosleep from "nosleep.js"; const NoSleep = new nosleep(); @@ -147,5 +147,31 @@ export function useFullscreen( } }, [elementRef, handleFullscreenChange, handleFullscreenError]); - return { fullscreen, toggleFullscreen, error, clearError }; + // compatibility + + const supportsFullScreen = useMemo(() => { + // @ts-expect-error we need to check that fullscreen exists + if (document.exitFullscreen) return true; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if ((document as any).msExitFullscreen) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return true; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if ((document as any).webkitExitFullscreen) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return true; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if ((document as any).mozCancelFullScreen) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return true; + return false; + }, []); + + return { + fullscreen, + toggleFullscreen, + supportsFullScreen, + error, + clearError, + }; } diff --git a/web/src/pages/Live.tsx b/web/src/pages/Live.tsx index cd8cc6b0a..c088a5b04 100644 --- a/web/src/pages/Live.tsx +++ b/web/src/pages/Live.tsx @@ -36,7 +36,8 @@ function Live() { const mainRef = useRef(null); - const { fullscreen, toggleFullscreen } = useFullscreen(mainRef); + const { fullscreen, toggleFullscreen, supportsFullScreen } = + useFullscreen(mainRef); // document title @@ -100,6 +101,7 @@ function Live() {
{selectedCameraName === "birdseye" ? ( @@ -107,6 +109,7 @@ function Live() { diff --git a/web/src/views/events/RecordingView.tsx b/web/src/views/events/RecordingView.tsx index 1de3a690f..f01da9578 100644 --- a/web/src/views/events/RecordingView.tsx +++ b/web/src/views/events/RecordingView.tsx @@ -257,7 +257,8 @@ export function RecordingView({ // fullscreen - const { fullscreen, toggleFullscreen } = useFullscreen(mainLayoutRef); + const { fullscreen, toggleFullscreen, supportsFullScreen } = + useFullscreen(mainLayoutRef); // layout @@ -549,6 +550,7 @@ export function RecordingView({ mainControllerRef.current = controller; }} isScrubbing={scrubbing || exportMode == "timeline"} + supportsFullscreen={supportsFullScreen} setFullResolution={setFullResolution} toggleFullscreen={toggleFullscreen} containerRef={mainLayoutRef} diff --git a/web/src/views/live/LiveBirdseyeView.tsx b/web/src/views/live/LiveBirdseyeView.tsx index 70e20e77a..be69b43c8 100644 --- a/web/src/views/live/LiveBirdseyeView.tsx +++ b/web/src/views/live/LiveBirdseyeView.tsx @@ -22,11 +22,13 @@ import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch"; import useSWR from "swr"; type LiveBirdseyeViewProps = { + supportsFullscreen: boolean; fullscreen: boolean; toggleFullscreen: () => void; }; export default function LiveBirdseyeView({ + supportsFullscreen, fullscreen, toggleFullscreen, }: LiveBirdseyeViewProps) { @@ -155,14 +157,16 @@ export default function LiveBirdseyeView({
- + {supportsFullscreen && ( + + )} {!isIOS && !isFirefox && config.birdseye.restream && ( void; }; export default function LiveCameraView({ config, camera, + supportsFullscreen, fullscreen, toggleFullscreen, }: LiveCameraViewProps) { @@ -376,7 +378,7 @@ export default function LiveCameraView({ )} )} - {!isIOS && ( + {supportsFullscreen && (