Implement scrubbing

This commit is contained in:
Nicolas Mowen 2024-02-22 14:49:14 -07:00
parent 34115d0a60
commit c9189b5d5b
3 changed files with 52 additions and 9 deletions

View File

@ -25,6 +25,7 @@ export type EventReviewTimelineProps = {
events: ReviewSegment[]; events: ReviewSegment[];
severityType: ReviewSeverity; severityType: ReviewSeverity;
contentRef: RefObject<HTMLDivElement>; contentRef: RefObject<HTMLDivElement>;
onHandlebarDraggingChange?: (isDragging: boolean) => void;
}; };
export function EventReviewTimeline({ export function EventReviewTimeline({
@ -41,6 +42,7 @@ export function EventReviewTimeline({
events, events,
severityType, severityType,
contentRef, contentRef,
onHandlebarDraggingChange,
}: EventReviewTimelineProps) { }: EventReviewTimelineProps) {
const [isDragging, setIsDragging] = useState(false); const [isDragging, setIsDragging] = useState(false);
const [currentTimeSegment, setCurrentTimeSegment] = useState<number>(0); const [currentTimeSegment, setCurrentTimeSegment] = useState<number>(0);
@ -152,6 +154,12 @@ export function EventReviewTimeline({
} }
}, [currentTimeSegment, showHandlebar]); }, [currentTimeSegment, showHandlebar]);
useEffect(() => {
if (onHandlebarDraggingChange) {
onHandlebarDraggingChange(isDragging);
}
}, [isDragging, onHandlebarDraggingChange]);
useEffect(() => { useEffect(() => {
if (timelineRef.current && handlebarTime && showHandlebar) { if (timelineRef.current && handlebarTime && showHandlebar) {
const { scrollHeight: timelineHeight } = timelineRef.current; const { scrollHeight: timelineHeight } = timelineRef.current;

View File

@ -139,7 +139,7 @@ export default function Events() {
// selected items // selected items
const selectedReviews = useMemo(() => { const selectedData = useMemo(() => {
if (!selectedReviewId) { if (!selectedReviewId) {
return undefined; return undefined;
} }
@ -159,18 +159,21 @@ export default function Events() {
return { return {
selected: selectedReview, selected: selectedReview,
cameraReviews: allReviews.filter( cameraSegments: allReviews.filter(
(seg) => seg.camera == selectedReview?.camera (seg) => seg.camera == selectedReview.camera
),
cameraPreviews: allPreviews?.filter(
(seg) => seg.camera == selectedReview.camera
), ),
}; };
}, [selectedReviewId, reviewPages]); }, [selectedReviewId, reviewPages]);
if (selectedReviews) { if (selectedData) {
return ( return (
<DesktopRecordingView <DesktopRecordingView
reviewItems={selectedReviews.cameraReviews} reviewItems={selectedData.cameraSegments}
selectedReview={selectedReviews.selected} selectedReview={selectedData.selected}
relevantPreviews={allPreviews} relevantPreviews={selectedData.cameraPreviews}
/> />
); );
} else { } else {

View File

@ -5,7 +5,7 @@ import EventReviewTimeline from "@/components/timeline/EventReviewTimeline";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { ReviewSegment } from "@/types/review"; import { ReviewSegment } from "@/types/review";
import { getChunkedTimeRange } from "@/utils/timelineUtil"; import { getChunkedTimeRange } from "@/utils/timelineUtil";
import { useMemo, useRef, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { IoMdArrowRoundBack } from "react-icons/io"; import { IoMdArrowRoundBack } from "react-icons/io";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@ -24,6 +24,7 @@ export default function DesktopRecordingView({
const contentRef = useRef<HTMLDivElement | null>(null); const contentRef = useRef<HTMLDivElement | null>(null);
// timeline time // timeline time
const timeRange = useMemo( const timeRange = useMemo(
() => getChunkedTimeRange(selectedReview.start_time), () => getChunkedTimeRange(selectedReview.start_time),
[] []
@ -37,10 +38,40 @@ export default function DesktopRecordingView({
}) })
); );
// move to next clip
useEffect(() => {
if (!controllerRef.current) {
return;
}
console.log("current index and moving to ");
if (selectedRangeIdx < timeRange.ranges.length - 1) {
controllerRef.current.onClipEndedEvent(() => {
setSelectedRangeIdx(selectedRangeIdx + 1);
});
}
}, [controllerRef, selectedRangeIdx]);
// scrubbing and timeline state
const [scrubbing, setScrubbing] = useState(false);
const [currentTime, setCurrentTime] = useState<number>( const [currentTime, setCurrentTime] = useState<number>(
selectedReview?.start_time || Date.now() / 1000 selectedReview?.start_time || Date.now() / 1000
); );
useEffect(() => {
if (scrubbing) {
controllerRef.current?.scrubToTimestamp(currentTime);
}
}, [controllerRef, currentTime, scrubbing]);
useEffect(() => {
if (!scrubbing) {
controllerRef.current?.seekToTimestamp(currentTime, true);
}
}, [controllerRef, scrubbing]);
return ( return (
<div ref={contentRef} className="relative w-full h-full"> <div ref={contentRef} className="relative w-full h-full">
<Button <Button
@ -72,7 +103,7 @@ export default function DesktopRecordingView({
<div className="absolute top-0 right-0 bottom-0"> <div className="absolute top-0 right-0 bottom-0">
<EventReviewTimeline <EventReviewTimeline
segmentDuration={60} segmentDuration={30}
timestampSpread={15} timestampSpread={15}
timelineStart={timeRange.end} timelineStart={timeRange.end}
timelineEnd={timeRange.start} timelineEnd={timeRange.start}
@ -82,6 +113,7 @@ export default function DesktopRecordingView({
events={reviewItems} events={reviewItems}
severityType={selectedReview.severity} severityType={selectedReview.severity}
contentRef={contentRef} contentRef={contentRef}
onHandlebarDraggingChange={(scrubbing) => setScrubbing(scrubbing)}
/> />
</div> </div>
</div> </div>