Dynamically detect if full screen is supported (#13197)

This commit is contained in:
Nicolas Mowen 2024-08-19 15:01:21 -06:00
parent 65ceadda2b
commit 4974defe6f
7 changed files with 57 additions and 15 deletions

View File

@ -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)}

View File

@ -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}

View File

@ -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<T extends HTMLElement = HTMLElement>(
}
}, [elementRef, handleFullscreenChange, handleFullscreenError]);
return { fullscreen, toggleFullscreen, error, clearError };
// compatibility
const supportsFullScreen = useMemo<boolean>(() => {
// @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,
};
}

View File

@ -36,7 +36,8 @@ function Live() {
const mainRef = useRef<HTMLDivElement | null>(null);
const { fullscreen, toggleFullscreen } = useFullscreen(mainRef);
const { fullscreen, toggleFullscreen, supportsFullScreen } =
useFullscreen(mainRef);
// document title
@ -100,6 +101,7 @@ function Live() {
<div className="size-full" ref={mainRef}>
{selectedCameraName === "birdseye" ? (
<LiveBirdseyeView
supportsFullscreen={supportsFullScreen}
fullscreen={fullscreen}
toggleFullscreen={toggleFullscreen}
/>
@ -107,6 +109,7 @@ function Live() {
<LiveCameraView
config={config}
camera={selectedCamera}
supportsFullscreen={supportsFullScreen}
fullscreen={fullscreen}
toggleFullscreen={toggleFullscreen}
/>

View File

@ -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}

View File

@ -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,6 +157,7 @@ export default function LiveBirdseyeView({
<div
className={`mr-1 flex flex-row items-center gap-2 *:rounded-lg ${isMobile ? "landscape:flex-col" : ""}`}
>
{supportsFullscreen && (
<CameraFeatureToggle
className="p-2 md:p-0"
variant={fullscreen ? "overlay" : "primary"}
@ -163,6 +166,7 @@ export default function LiveBirdseyeView({
title={fullscreen ? "Close" : "Fullscreen"}
onClick={toggleFullscreen}
/>
)}
{!isIOS && !isFirefox && config.birdseye.restream && (
<CameraFeatureToggle
className="p-2 md:p-0"

View File

@ -83,12 +83,14 @@ import { useSessionPersistence } from "@/hooks/use-session-persistence";
type LiveCameraViewProps = {
config?: FrigateConfig;
camera: CameraConfig;
supportsFullscreen: boolean;
fullscreen: boolean;
toggleFullscreen: () => void;
};
export default function LiveCameraView({
config,
camera,
supportsFullscreen,
fullscreen,
toggleFullscreen,
}: LiveCameraViewProps) {
@ -376,7 +378,7 @@ export default function LiveCameraView({
)}
</Button>
)}
{!isIOS && (
{supportsFullscreen && (
<CameraFeatureToggle
className="p-2 md:p-0"
variant={fullscreen ? "overlay" : "primary"}