mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-12-19 19:06:16 +01:00
Dynamically detect if full screen is supported (#13197)
This commit is contained in:
parent
65ceadda2b
commit
4974defe6f
@ -6,7 +6,7 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import Hls from "hls.js";
|
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 { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch";
|
||||||
import VideoControls from "./VideoControls";
|
import VideoControls from "./VideoControls";
|
||||||
import { VideoResolutionType } from "@/types/live";
|
import { VideoResolutionType } from "@/types/live";
|
||||||
@ -33,6 +33,7 @@ type HlsVideoPlayerProps = {
|
|||||||
visible: boolean;
|
visible: boolean;
|
||||||
currentSource: string;
|
currentSource: string;
|
||||||
hotKeys: boolean;
|
hotKeys: boolean;
|
||||||
|
supportsFullscreen: boolean;
|
||||||
fullscreen: boolean;
|
fullscreen: boolean;
|
||||||
onClipEnded?: () => void;
|
onClipEnded?: () => void;
|
||||||
onPlayerLoaded?: () => void;
|
onPlayerLoaded?: () => void;
|
||||||
@ -49,6 +50,7 @@ export default function HlsVideoPlayer({
|
|||||||
visible,
|
visible,
|
||||||
currentSource,
|
currentSource,
|
||||||
hotKeys,
|
hotKeys,
|
||||||
|
supportsFullscreen,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
onClipEnded,
|
onClipEnded,
|
||||||
onPlayerLoaded,
|
onPlayerLoaded,
|
||||||
@ -180,7 +182,7 @@ export default function HlsVideoPlayer({
|
|||||||
seek: true,
|
seek: true,
|
||||||
playbackRate: true,
|
playbackRate: true,
|
||||||
plusUpload: config?.plus?.enabled == true,
|
plusUpload: config?.plus?.enabled == true,
|
||||||
fullscreen: !isIOS,
|
fullscreen: supportsFullscreen,
|
||||||
}}
|
}}
|
||||||
setControlsOpen={setControlsOpen}
|
setControlsOpen={setControlsOpen}
|
||||||
setMuted={(muted) => setMuted(muted, true)}
|
setMuted={(muted) => setMuted(muted, true)}
|
||||||
|
@ -24,6 +24,7 @@ type DynamicVideoPlayerProps = {
|
|||||||
startTimestamp?: number;
|
startTimestamp?: number;
|
||||||
isScrubbing: boolean;
|
isScrubbing: boolean;
|
||||||
hotKeys: boolean;
|
hotKeys: boolean;
|
||||||
|
supportsFullscreen: boolean;
|
||||||
fullscreen: boolean;
|
fullscreen: boolean;
|
||||||
onControllerReady: (controller: DynamicVideoController) => void;
|
onControllerReady: (controller: DynamicVideoController) => void;
|
||||||
onTimestampUpdate?: (timestamp: number) => void;
|
onTimestampUpdate?: (timestamp: number) => void;
|
||||||
@ -40,6 +41,7 @@ export default function DynamicVideoPlayer({
|
|||||||
startTimestamp,
|
startTimestamp,
|
||||||
isScrubbing,
|
isScrubbing,
|
||||||
hotKeys,
|
hotKeys,
|
||||||
|
supportsFullscreen,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
onControllerReady,
|
onControllerReady,
|
||||||
onTimestampUpdate,
|
onTimestampUpdate,
|
||||||
@ -201,6 +203,7 @@ export default function DynamicVideoPlayer({
|
|||||||
visible={!(isScrubbing || isLoading)}
|
visible={!(isScrubbing || isLoading)}
|
||||||
currentSource={source}
|
currentSource={source}
|
||||||
hotKeys={hotKeys}
|
hotKeys={hotKeys}
|
||||||
|
supportsFullscreen={supportsFullscreen}
|
||||||
fullscreen={fullscreen}
|
fullscreen={fullscreen}
|
||||||
onTimeUpdate={onTimeUpdate}
|
onTimeUpdate={onTimeUpdate}
|
||||||
onPlayerLoaded={onPlayerLoaded}
|
onPlayerLoaded={onPlayerLoaded}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { RefObject, useCallback, useEffect, useState } from "react";
|
import { RefObject, useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import nosleep from "nosleep.js";
|
import nosleep from "nosleep.js";
|
||||||
|
|
||||||
const NoSleep = new nosleep();
|
const NoSleep = new nosleep();
|
||||||
@ -147,5 +147,31 @@ export function useFullscreen<T extends HTMLElement = HTMLElement>(
|
|||||||
}
|
}
|
||||||
}, [elementRef, handleFullscreenChange, handleFullscreenError]);
|
}, [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,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,8 @@ function Live() {
|
|||||||
|
|
||||||
const mainRef = useRef<HTMLDivElement | null>(null);
|
const mainRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const { fullscreen, toggleFullscreen } = useFullscreen(mainRef);
|
const { fullscreen, toggleFullscreen, supportsFullScreen } =
|
||||||
|
useFullscreen(mainRef);
|
||||||
|
|
||||||
// document title
|
// document title
|
||||||
|
|
||||||
@ -100,6 +101,7 @@ function Live() {
|
|||||||
<div className="size-full" ref={mainRef}>
|
<div className="size-full" ref={mainRef}>
|
||||||
{selectedCameraName === "birdseye" ? (
|
{selectedCameraName === "birdseye" ? (
|
||||||
<LiveBirdseyeView
|
<LiveBirdseyeView
|
||||||
|
supportsFullscreen={supportsFullScreen}
|
||||||
fullscreen={fullscreen}
|
fullscreen={fullscreen}
|
||||||
toggleFullscreen={toggleFullscreen}
|
toggleFullscreen={toggleFullscreen}
|
||||||
/>
|
/>
|
||||||
@ -107,6 +109,7 @@ function Live() {
|
|||||||
<LiveCameraView
|
<LiveCameraView
|
||||||
config={config}
|
config={config}
|
||||||
camera={selectedCamera}
|
camera={selectedCamera}
|
||||||
|
supportsFullscreen={supportsFullScreen}
|
||||||
fullscreen={fullscreen}
|
fullscreen={fullscreen}
|
||||||
toggleFullscreen={toggleFullscreen}
|
toggleFullscreen={toggleFullscreen}
|
||||||
/>
|
/>
|
||||||
|
@ -257,7 +257,8 @@ export function RecordingView({
|
|||||||
|
|
||||||
// fullscreen
|
// fullscreen
|
||||||
|
|
||||||
const { fullscreen, toggleFullscreen } = useFullscreen(mainLayoutRef);
|
const { fullscreen, toggleFullscreen, supportsFullScreen } =
|
||||||
|
useFullscreen(mainLayoutRef);
|
||||||
|
|
||||||
// layout
|
// layout
|
||||||
|
|
||||||
@ -549,6 +550,7 @@ export function RecordingView({
|
|||||||
mainControllerRef.current = controller;
|
mainControllerRef.current = controller;
|
||||||
}}
|
}}
|
||||||
isScrubbing={scrubbing || exportMode == "timeline"}
|
isScrubbing={scrubbing || exportMode == "timeline"}
|
||||||
|
supportsFullscreen={supportsFullScreen}
|
||||||
setFullResolution={setFullResolution}
|
setFullResolution={setFullResolution}
|
||||||
toggleFullscreen={toggleFullscreen}
|
toggleFullscreen={toggleFullscreen}
|
||||||
containerRef={mainLayoutRef}
|
containerRef={mainLayoutRef}
|
||||||
|
@ -22,11 +22,13 @@ import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
type LiveBirdseyeViewProps = {
|
type LiveBirdseyeViewProps = {
|
||||||
|
supportsFullscreen: boolean;
|
||||||
fullscreen: boolean;
|
fullscreen: boolean;
|
||||||
toggleFullscreen: () => void;
|
toggleFullscreen: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function LiveBirdseyeView({
|
export default function LiveBirdseyeView({
|
||||||
|
supportsFullscreen,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
toggleFullscreen,
|
toggleFullscreen,
|
||||||
}: LiveBirdseyeViewProps) {
|
}: LiveBirdseyeViewProps) {
|
||||||
@ -155,6 +157,7 @@ export default function LiveBirdseyeView({
|
|||||||
<div
|
<div
|
||||||
className={`mr-1 flex flex-row items-center gap-2 *:rounded-lg ${isMobile ? "landscape:flex-col" : ""}`}
|
className={`mr-1 flex flex-row items-center gap-2 *:rounded-lg ${isMobile ? "landscape:flex-col" : ""}`}
|
||||||
>
|
>
|
||||||
|
{supportsFullscreen && (
|
||||||
<CameraFeatureToggle
|
<CameraFeatureToggle
|
||||||
className="p-2 md:p-0"
|
className="p-2 md:p-0"
|
||||||
variant={fullscreen ? "overlay" : "primary"}
|
variant={fullscreen ? "overlay" : "primary"}
|
||||||
@ -163,6 +166,7 @@ export default function LiveBirdseyeView({
|
|||||||
title={fullscreen ? "Close" : "Fullscreen"}
|
title={fullscreen ? "Close" : "Fullscreen"}
|
||||||
onClick={toggleFullscreen}
|
onClick={toggleFullscreen}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
{!isIOS && !isFirefox && config.birdseye.restream && (
|
{!isIOS && !isFirefox && config.birdseye.restream && (
|
||||||
<CameraFeatureToggle
|
<CameraFeatureToggle
|
||||||
className="p-2 md:p-0"
|
className="p-2 md:p-0"
|
||||||
|
@ -83,12 +83,14 @@ import { useSessionPersistence } from "@/hooks/use-session-persistence";
|
|||||||
type LiveCameraViewProps = {
|
type LiveCameraViewProps = {
|
||||||
config?: FrigateConfig;
|
config?: FrigateConfig;
|
||||||
camera: CameraConfig;
|
camera: CameraConfig;
|
||||||
|
supportsFullscreen: boolean;
|
||||||
fullscreen: boolean;
|
fullscreen: boolean;
|
||||||
toggleFullscreen: () => void;
|
toggleFullscreen: () => void;
|
||||||
};
|
};
|
||||||
export default function LiveCameraView({
|
export default function LiveCameraView({
|
||||||
config,
|
config,
|
||||||
camera,
|
camera,
|
||||||
|
supportsFullscreen,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
toggleFullscreen,
|
toggleFullscreen,
|
||||||
}: LiveCameraViewProps) {
|
}: LiveCameraViewProps) {
|
||||||
@ -376,7 +378,7 @@ export default function LiveCameraView({
|
|||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{!isIOS && (
|
{supportsFullscreen && (
|
||||||
<CameraFeatureToggle
|
<CameraFeatureToggle
|
||||||
className="p-2 md:p-0"
|
className="p-2 md:p-0"
|
||||||
variant={fullscreen ? "overlay" : "primary"}
|
variant={fullscreen ? "overlay" : "primary"}
|
||||||
|
Loading…
Reference in New Issue
Block a user