mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-10 21:25:24 +03:00
Move timeline to separate component
This commit is contained in:
parent
985ee97e1c
commit
35996733a9
@ -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>
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user