From 675ea1e55b286106711e73ae924ee60f9f28bbdb Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Mon, 25 Mar 2024 14:34:11 -0600 Subject: [PATCH] Only show live cameras that are currently visible --- web/src/components/player/LivePlayer.tsx | 16 ++++--- web/src/views/live/LiveDashboardView.tsx | 54 +++++++++++++++++++++++- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/web/src/components/player/LivePlayer.tsx b/web/src/components/player/LivePlayer.tsx index 8be3f71b9..1c71230e2 100644 --- a/web/src/components/player/LivePlayer.tsx +++ b/web/src/components/player/LivePlayer.tsx @@ -14,6 +14,7 @@ import { isDesktop } from "react-device-detect"; import CameraActivityIndicator from "../indicators/CameraActivityIndicator"; type LivePlayerProps = { + cameraRef?: (ref: HTMLDivElement | null) => void; className?: string; cameraConfig: CameraConfig; preferredLiveMode?: LivePlayerMode; @@ -26,6 +27,7 @@ type LivePlayerProps = { }; export default function LivePlayer({ + cameraRef = undefined, className, cameraConfig, preferredLiveMode, @@ -140,6 +142,8 @@ export default function LivePlayer({ return (
- {isDesktop && ( -
- {recording == "ON" && ( - - )} -
- )} +
+ {recording == "ON" && ( + + )} +
); } diff --git a/web/src/views/live/LiveDashboardView.tsx b/web/src/views/live/LiveDashboardView.tsx index d5a7401c5..649e102b5 100644 --- a/web/src/views/live/LiveDashboardView.tsx +++ b/web/src/views/live/LiveDashboardView.tsx @@ -11,7 +11,7 @@ import { TooltipProvider } from "@/components/ui/tooltip"; import { usePersistence } from "@/hooks/use-persistence"; import { CameraConfig, FrigateConfig } from "@/types/frigateConfig"; import { ReviewSegment } from "@/types/review"; -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { isDesktop, isMobile, isSafari } from "react-device-detect"; import useSWR from "swr"; @@ -79,6 +79,53 @@ export default function LiveDashboardView({ }; }, [visibilityListener]); + const [visibleCameras, setVisibleCameras] = useState([]); + const visibleCameraObserver = useRef(null); + useEffect(() => { + const visibleCameras = new Set(); + visibleCameraObserver.current = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + const camera = (entry.target as HTMLElement).dataset.camera; + + if (!camera) { + return; + } + + if (entry.isIntersecting) { + visibleCameras.add(camera); + } else { + visibleCameras.delete(camera); + } + + setVisibleCameras([...visibleCameras]); + }); + }, + { threshold: 0.5 }, + ); + + return () => { + visibleCameraObserver.current?.disconnect(); + }; + }, []); + + const cameraRef = useCallback( + (node: HTMLElement | null) => { + if (!visibleCameraObserver.current) { + return; + } + + try { + if (node) visibleCameraObserver.current.observe(node); + } catch (e) { + // no op + } + }, + // we need to listen on the value of the ref + // eslint-disable-next-line react-hooks/exhaustive-deps + [visibleCameraObserver.current], + ); + const birdseyeConfig = useMemo(() => config?.birdseye, [config]); return ( @@ -149,9 +196,12 @@ export default function LiveDashboardView({ } return ( onSelectCamera(camera.name)}