Move timeline to separate component

This commit is contained in:
Nicolas Mowen 2024-03-26 09:30:07 -06:00
parent 985ee97e1c
commit 35996733a9

View File

@ -8,6 +8,7 @@ import DynamicVideoPlayer from "@/components/player/dynamic/DynamicVideoPlayer";
import MotionReviewTimeline from "@/components/timeline/MotionReviewTimeline"; import MotionReviewTimeline from "@/components/timeline/MotionReviewTimeline";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer"; import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { FrigateConfig } from "@/types/frigateConfig"; import { FrigateConfig } from "@/types/frigateConfig";
import { Preview } from "@/types/preview"; import { Preview } from "@/types/preview";
import { import {
@ -17,7 +18,14 @@ import {
ReviewSummary, ReviewSummary,
} from "@/types/review"; } from "@/types/review";
import { getChunkedTimeDay } from "@/utils/timelineUtil"; import { getChunkedTimeDay } from "@/utils/timelineUtil";
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import {
MutableRefObject,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { isDesktop, isMobile } from "react-device-detect"; import { isDesktop, isMobile } from "react-device-detect";
import { FaCircle, FaVideo } from "react-icons/fa"; import { FaCircle, FaVideo } from "react-icons/fa";
import { IoMdArrowRoundBack } from "react-icons/io"; import { IoMdArrowRoundBack } from "react-icons/io";
@ -25,6 +33,7 @@ import { useNavigate } from "react-router-dom";
import useSWR from "swr"; import useSWR from "swr";
const SEGMENT_DURATION = 30; const SEGMENT_DURATION = 30;
type TimelineType = "timeline" | "events";
type RecordingViewProps = { type RecordingViewProps = {
startCamera: string; startCamera: string;
@ -63,7 +72,9 @@ export function RecordingView({
[reviewItems, mainCamera], [reviewItems, mainCamera],
); );
// timeline time // timeline
const [timelineType, setTimelineType] = useState<TimelineType>("timeline");
const timeRange = useMemo(() => getChunkedTimeDay(startTime), [startTime]); const timeRange = useMemo(() => getChunkedTimeDay(startTime), [startTime]);
const [selectedRangeIdx, setSelectedRangeIdx] = useState( const [selectedRangeIdx, setSelectedRangeIdx] = useState(
@ -164,16 +175,6 @@ export function RecordingView({
// motion timeline data // motion timeline data
const { data: motionData } = useSWR<MotionData[]>([
"review/activity/motion",
{
before: timeRange.end,
after: timeRange.start,
scale: SEGMENT_DURATION / 2,
cameras: mainCamera,
},
]);
const mainCameraAspect = useMemo(() => { const mainCameraAspect = useMemo(() => {
if (!config) { if (!config) {
return "normal"; return "normal";
@ -209,7 +210,7 @@ export function RecordingView({
<IoMdArrowRoundBack className="size-5 mr-[10px]" /> <IoMdArrowRoundBack className="size-5 mr-[10px]" />
Back Back
</Button> </Button>
<div className="flex items-center justify-end"> <div className="flex items-center justify-end gap-2">
{isMobile && ( {isMobile && (
<Drawer> <Drawer>
<DrawerTrigger asChild> <DrawerTrigger asChild>
@ -247,6 +248,30 @@ export function RecordingView({
motionOnly={false} motionOnly={false}
setMotionOnly={() => {}} setMotionOnly={() => {}}
/> />
<ToggleGroup
className="*:px-3 *:py-4 *:rounded-md"
type="single"
size="sm"
value={timelineType}
onValueChange={(value: TimelineType) =>
value ? setTimelineType(value) : null
} // don't allow the severity to be unselected
>
<ToggleGroupItem
className={`${timelineType == "timeline" ? "" : "text-gray-500"}`}
value="timeline"
aria-label="Select timeline"
>
<div className="">Timeline</div>
</ToggleGroupItem>
<ToggleGroupItem
className={`${timelineType == "events" ? "" : "text-gray-500"}`}
value="events"
aria-label="Select events"
>
<div className="hidden md:block">Events</div>
</ToggleGroupItem>
</ToggleGroup>
</div> </div>
</div> </div>
@ -317,7 +342,53 @@ export function RecordingView({
)} )}
</div> </div>
</div> </div>
<Timeline
contentRef={contentRef}
mainCamera={mainCamera}
timelineType={timelineType}
timeRange={timeRange}
mainCameraReviewItems={mainCameraReviewItems}
currentTime={currentTime}
setCurrentTime={setCurrentTime}
setScrubbing={setScrubbing}
/>
</div>
</div>
);
}
type TimelineProps = {
contentRef: MutableRefObject<HTMLDivElement | null>;
mainCamera: string;
timelineType: TimelineType;
timeRange: { start: number; end: number };
mainCameraReviewItems: ReviewSegment[];
currentTime: number;
setCurrentTime: React.Dispatch<React.SetStateAction<number>>;
setScrubbing: React.Dispatch<React.SetStateAction<boolean>>;
};
function Timeline({
contentRef,
mainCamera,
timelineType,
timeRange,
mainCameraReviewItems,
currentTime,
setCurrentTime,
setScrubbing,
}: TimelineProps) {
const { data: motionData } = useSWR<MotionData[]>([
"review/activity/motion",
{
before: timeRange.end,
after: timeRange.start,
scale: SEGMENT_DURATION / 2,
cameras: mainCamera,
},
]);
if (timelineType == "timeline") {
return (
<div <div
className={ className={
isDesktop isDesktop
@ -341,7 +412,6 @@ export function RecordingView({
onHandlebarDraggingChange={(scrubbing) => setScrubbing(scrubbing)} onHandlebarDraggingChange={(scrubbing) => setScrubbing(scrubbing)}
/> />
</div> </div>
</div>
</div>
); );
} }
}