diff --git a/web/src/components/player/PreviewPlayer.tsx b/web/src/components/player/PreviewPlayer.tsx index 2a831fc6b..ca06e499c 100644 --- a/web/src/components/player/PreviewPlayer.tsx +++ b/web/src/components/player/PreviewPlayer.tsx @@ -33,6 +33,7 @@ type PreviewPlayerProps = { isScrubbing: boolean; forceAspect?: number; isVisible?: boolean; + rotate?: boolean; onControllerReady: (controller: PreviewController) => void; onClick?: () => void; }; @@ -45,6 +46,7 @@ export default function PreviewPlayer({ startTime, isScrubbing, isVisible = true, + rotate, onControllerReady, onClick, }: PreviewPlayerProps) { @@ -69,6 +71,7 @@ export default function PreviewPlayer({ isScrubbing={isScrubbing} isVisible={isVisible} currentHourFrame={currentHourFrame} + rotate={rotate} onControllerReady={onControllerReady} onClick={onClick} setCurrentHourFrame={setCurrentHourFrame} @@ -83,6 +86,7 @@ export default function PreviewPlayer({ camera={camera} timeRange={timeRange} startTime={startTime} + rotate={rotate} onControllerReady={onControllerReady} onClick={onClick} setCurrentHourFrame={setCurrentHourFrame} @@ -127,6 +131,7 @@ type PreviewVideoPlayerProps = { isScrubbing: boolean; isVisible: boolean; currentHourFrame?: string; + rotate?: boolean; onControllerReady: (controller: PreviewVideoController) => void; onClick?: () => void; setCurrentHourFrame: (src: string | undefined) => void; @@ -142,6 +147,7 @@ function PreviewVideoPlayer({ isScrubbing, isVisible, currentHourFrame, + rotate, onControllerReady, onClick, setCurrentHourFrame, @@ -183,6 +189,33 @@ function PreviewVideoPlayer({ controller.scrubbing = isScrubbing; }, [controller, isScrubbing]); + // rotation support + const rotateContainerRef = useRef(null); + const [rotateContainerSize, setRotateContainerSize] = useState({ + width: 0, + height: 0, + }); + + useEffect(() => { + if (!rotate) return; + + const container = rotateContainerRef.current; + if (!container) return; + + const updateSize = () => { + setRotateContainerSize({ + width: container.clientWidth, + height: container.clientHeight, + }); + }; + + updateSize(); + const resizeObserver = new ResizeObserver(updateSize); + resizeObserver.observe(container); + + return () => resizeObserver.disconnect(); + }, [rotate]); + // initial state const [firstLoad, setFirstLoad] = useState(true); @@ -282,67 +315,103 @@ function PreviewVideoPlayer({ ref={visibilityRef} className={cn( "relative flex w-full justify-center overflow-hidden rounded-lg bg-black md:rounded-2xl", + rotate && "h-full", onClick && "cursor-pointer", className, )} data-camera={camera} onClick={onClick} > - { - if (changeoverTimeout) { - clearTimeout(changeoverTimeout); - setChangeoverTimeout(undefined); +
+
- {isVisible && ( - - )} +
+
{cameraPreviews && !currentPreview && (
{t("noPreviewFoundFor", { camera: cameraName })} @@ -452,6 +521,7 @@ type PreviewFramesPlayerProps = { camera: string; timeRange: TimeRange; startTime?: number; + rotate?: boolean; onControllerReady: (controller: PreviewController) => void; onClick?: () => void; setCurrentHourFrame: (src: string) => void; @@ -461,6 +531,7 @@ function PreviewFramesPlayer({ camera, timeRange, startTime, + rotate, setCurrentHourFrame, onControllerReady, onClick, @@ -504,6 +575,33 @@ function PreviewFramesPlayer({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [imgRef, frameTimes, imgRef.current]); + // rotation support + const rotateContainerRef = useRef(null); + const [rotateContainerSize, setRotateContainerSize] = useState({ + width: 0, + height: 0, + }); + + useEffect(() => { + if (!rotate) return; + + const container = rotateContainerRef.current; + if (!container) return; + + const updateSize = () => { + setRotateContainerSize({ + width: container.clientWidth, + height: container.clientHeight, + }); + }; + + updateSize(); + const resizeObserver = new ResizeObserver(updateSize); + resizeObserver.observe(container); + + return () => resizeObserver.disconnect(); + }, [rotate]); + // initial state const [firstLoad, setFirstLoad] = useState(true); @@ -555,17 +653,48 @@ function PreviewFramesPlayer({
- +
+
+ +
+
{previewFrames?.length === 0 && (
{t("noPreviewFoundFor", { cameraName: cameraName })} diff --git a/web/src/components/player/dynamic/DynamicVideoPlayer.tsx b/web/src/components/player/dynamic/DynamicVideoPlayer.tsx index e77897ee8..140503155 100644 --- a/web/src/components/player/dynamic/DynamicVideoPlayer.tsx +++ b/web/src/components/player/dynamic/DynamicVideoPlayer.tsx @@ -337,6 +337,7 @@ export default function DynamicVideoPlayer({ cameraPreviews={cameraPreviews} startTime={startTimestamp} isScrubbing={isScrubbing} + rotate={rotate} onControllerReady={(previewController) => setPreviewController(previewController) }