diff --git a/web/src/components/overlay/detail/SearchDetailDialog.tsx b/web/src/components/overlay/detail/SearchDetailDialog.tsx index f27023f025..843f2de597 100644 --- a/web/src/components/overlay/detail/SearchDetailDialog.tsx +++ b/web/src/components/overlay/detail/SearchDetailDialog.tsx @@ -25,7 +25,6 @@ import HlsVideoPlayer from "@/components/player/HlsVideoPlayer"; import { baseUrl } from "@/api/baseUrl"; import { cn } from "@/lib/utils"; import ActivityIndicator from "@/components/indicators/activity-indicator"; -import { ASPECT_VERTICAL_LAYOUT, ASPECT_WIDE_LAYOUT } from "@/types/record"; import { FaCheckCircle, FaChevronDown, @@ -63,6 +62,8 @@ import { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch"; import { Card, CardContent } from "@/components/ui/card"; import useImageLoaded from "@/hooks/use-image-loaded"; import ImageLoadingIndicator from "@/components/indicators/ImageLoadingIndicator"; +import { useResizeObserver } from "@/hooks/resize-observer"; +import { VideoResolutionType } from "@/types/live"; const SEARCH_TABS = [ "details", @@ -225,7 +226,7 @@ export default function SearchDetailDialog({ }} /> )} - {page == "video" && } + {page == "video" && } {page == "object lifecycle" && ( (null); @@ -608,61 +608,48 @@ function VideoTab({ search, config }: VideoTabProps) { `review/event/${search.id}`, ]); - const mainCameraAspect = useMemo(() => { - const camera = config?.cameras?.[search.camera]; + const containerRef = useRef(null); - if (!camera) { - return "normal"; - } + const [{ width: containerWidth, height: containerHeight }] = + useResizeObserver(containerRef); + const [videoResolution, setVideoResolution] = useState({ + width: 0, + height: 0, + }); - const aspectRatio = camera.detect.width / camera.detect.height; + const videoAspectRatio = useMemo(() => { + return videoResolution.width / videoResolution.height || 16 / 9; + }, [videoResolution]); - if (!aspectRatio) { - return "normal"; - } else if (aspectRatio > ASPECT_WIDE_LAYOUT) { - return "wide"; - } else if (aspectRatio < ASPECT_VERTICAL_LAYOUT) { - return "tall"; - } else { - return "normal"; - } - }, [config, search]); + const containerAspectRatio = useMemo(() => { + return containerWidth / containerHeight || 16 / 9; + }, [containerWidth, containerHeight]); - const containerClassName = useMemo(() => { - if (mainCameraAspect == "wide") { - return "flex justify-center items-center"; - } else if (mainCameraAspect == "tall") { - if (isDesktop) { - return "size-full flex flex-col justify-center items-center"; - } else { - return "size-full"; - } - } else { - return ""; - } - }, [mainCameraAspect]); - - const videoClassName = useMemo(() => { - if (mainCameraAspect == "wide") { - return "w-full aspect-wide"; - } else if (mainCameraAspect == "tall") { - if (isDesktop) { - return "w-[50%] aspect-tall flex justify-center"; - } else { - return "size-full"; - } + const videoDimensions = useMemo(() => { + if (!containerWidth || !containerHeight) + return { width: "100%", height: "100%" }; + + if (containerAspectRatio > videoAspectRatio) { + const height = containerHeight; + const width = height * videoAspectRatio; + return { width: `${width}px`, height: `${height}px` }; } else { - return "w-full aspect-video"; + const width = containerWidth; + const height = width / videoAspectRatio; + return { width: `${width}px`, height: `${height}px` }; } - }, [mainCameraAspect]); + }, [containerWidth, containerHeight, videoAspectRatio, containerAspectRatio]); return ( -
-
+
+
{(isLoading || !reviewItem) && ( - + )} -
+
setIsLoading(false)} + setFullResolution={setVideoResolution} /> -
-
- {!isLoading && reviewItem && ( -
+ + + { + if (reviewItem?.id) { + const params = new URLSearchParams({ + id: reviewItem.id, + }).toString(); + navigate(`/review?${params}`); + } + }} + > + + + + View in History + +
)} - > - - - { - if (reviewItem?.id) { - const params = new URLSearchParams({ - id: reviewItem.id, - }).toString(); - navigate(`/review?${params}`); - } - }} - > - - - - View in History -
- )} +
); }