From 38d7628c685e2a377e56ee16e417b97f816f649c Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Sat, 2 Mar 2024 09:27:05 -0700 Subject: [PATCH] Add support for full screen mode --- web/src/views/live/LiveCameraView.tsx | 91 ++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 15 deletions(-) diff --git a/web/src/views/live/LiveCameraView.tsx b/web/src/views/live/LiveCameraView.tsx index dff75fc78..b59fd0f4e 100644 --- a/web/src/views/live/LiveCameraView.tsx +++ b/web/src/views/live/LiveCameraView.tsx @@ -18,7 +18,13 @@ import { TooltipProvider } from "@/components/ui/tooltip"; import useKeyboardListener from "@/hooks/use-keyboard-listener"; import { CameraConfig } from "@/types/frigateConfig"; import { CameraPtzInfo } from "@/types/ptz"; -import React, { useCallback, useMemo, useState } from "react"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; import { isDesktop, isMobile, @@ -31,6 +37,7 @@ import { FaAngleLeft, FaAngleRight, FaAngleUp, + FaExpand, } from "react-icons/fa"; import { GiSpeaker, GiSpeakerOff } from "react-icons/gi"; import { IoMdArrowBack } from "react-icons/io"; @@ -52,6 +59,7 @@ type LiveCameraViewProps = { export default function LiveCameraView({ camera }: LiveCameraViewProps) { const navigate = useNavigate(); const { isPortrait } = useMobileOrientation(); + const mainRef = useRef(null); // camera features @@ -66,43 +74,97 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) { ); const { payload: audioState, send: sendAudio } = useAudioState(camera.name); + // fullscreen state + + useEffect(() => { + if (mainRef.current == null) { + return; + } + + const listener = () => { + setFullscreen(document.fullscreenElement != null); + }; + document.addEventListener("fullscreenchange", listener); + + return () => { + document.removeEventListener("fullscreenchange", listener); + }; + }, [mainRef]); + // playback state const [audio, setAudio] = useState(false); + const [fullscreen, setFullscreen] = useState(false); const growClassName = useMemo(() => { + const aspect = camera.detect.width / camera.detect.height; + + if (fullscreen) { + if (aspect > 16 / 9) { + return "absolute inset-x-0 top-[50%] -translate-y-[50%]"; + } else { + return "absolute inset-y-0 left-[50%] -translate-x-[50%]"; + } + } + if (isMobile) { if (isPortrait) { return "absolute left-2 right-2 top-[50%] -translate-y-[50%]"; } else { return "absolute top-2 bottom-2 left-[50%] -translate-x-[50%]"; } - } else if (camera.detect.width / camera.detect.height > 2) { + } else if (aspect > 2) { return "absolute left-2 right-2 top-[50%] -translate-y-[50%]"; } else { return "absolute top-2 bottom-2 left-[50%] -translate-x-[50%]"; } - }, [camera, isPortrait]); + }, [camera, fullscreen, isPortrait]); return (
- + {!fullscreen ? ( + + ) : ( +
+ )}
+ { + if (fullscreen) { + document.exitFullscreen(); + } else { + mainRef.current?.requestFullscreen(); + } + }} + />
-