memoize initial time range and check for window visibility

This commit is contained in:
Josh Hawkins 2024-05-15 10:27:00 -05:00
parent 1757f4cb04
commit 1ece0e7021
2 changed files with 56 additions and 13 deletions

View File

@ -1,6 +1,6 @@
import TimeAgo from "../dynamic/TimeAgo"; import TimeAgo from "../dynamic/TimeAgo";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip"; import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
import { useCallback, useMemo } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import useSWR from "swr"; import useSWR from "swr";
import { FrigateConfig } from "@/types/frigateConfig"; import { FrigateConfig } from "@/types/frigateConfig";
import { REVIEW_PADDING, ReviewSegment } from "@/types/review"; import { REVIEW_PADDING, ReviewSegment } from "@/types/review";
@ -22,18 +22,34 @@ export function AnimatedEventCard({ event }: AnimatedEventCardProps) {
const currentHour = useMemo(() => isCurrentHour(event.start_time), [event]); const currentHour = useMemo(() => isCurrentHour(event.start_time), [event]);
// preview const initialTimeRange = useMemo(() => {
return {
const previews = useCameraPreviews(
{
after: Math.round(event.start_time), after: Math.round(event.start_time),
before: Math.round(event.end_time || event.start_time + 20), before: Math.round(event.end_time || event.start_time + 20),
}, };
{ }, [event]);
// preview
const previews = useCameraPreviews(initialTimeRange, {
camera: event.camera, camera: event.camera,
fetchPreviews: !currentHour, fetchPreviews: !currentHour,
}, });
);
// visibility
const [windowVisible, setWindowVisible] = useState(true);
const visibilityListener = useCallback(() => {
setWindowVisible(document.visibilityState == "visible");
}, []);
useEffect(() => {
addEventListener("visibilitychange", visibilityListener);
return () => {
removeEventListener("visibilitychange", visibilityListener);
};
}, [visibilityListener]);
// interaction // interaction
@ -86,6 +102,7 @@ export function AnimatedEventCard({ event }: AnimatedEventCardProps) {
setReviewed={() => {}} setReviewed={() => {}}
setIgnoreClick={() => {}} setIgnoreClick={() => {}}
isPlayingBack={() => {}} isPlayingBack={() => {}}
windowVisible={windowVisible}
/> />
) : ( ) : (
<InProgressPreview <InProgressPreview
@ -99,6 +116,7 @@ export function AnimatedEventCard({ event }: AnimatedEventCardProps) {
setReviewed={() => {}} setReviewed={() => {}}
setIgnoreClick={() => {}} setIgnoreClick={() => {}}
isPlayingBack={() => {}} isPlayingBack={() => {}}
windowVisible={windowVisible}
/> />
)} )}
</div> </div>

View File

@ -311,6 +311,21 @@ function PreviewContent({
isPlayingBack, isPlayingBack,
onTimeUpdate, onTimeUpdate,
}: PreviewContentProps) { }: PreviewContentProps) {
// visibility
const [windowVisible, setWindowVisible] = useState(true);
const visibilityListener = useCallback(() => {
setWindowVisible(document.visibilityState == "visible");
}, []);
useEffect(() => {
addEventListener("visibilitychange", visibilityListener);
return () => {
removeEventListener("visibilitychange", visibilityListener);
};
}, [visibilityListener]);
// preview // preview
if (relevantPreview) { if (relevantPreview) {
@ -323,6 +338,7 @@ function PreviewContent({
setIgnoreClick={setIgnoreClick} setIgnoreClick={setIgnoreClick}
isPlayingBack={isPlayingBack} isPlayingBack={isPlayingBack}
onTimeUpdate={onTimeUpdate} onTimeUpdate={onTimeUpdate}
windowVisible={windowVisible}
/> />
); );
} else if (isCurrentHour(review.start_time)) { } else if (isCurrentHour(review.start_time)) {
@ -334,6 +350,7 @@ function PreviewContent({
setIgnoreClick={setIgnoreClick} setIgnoreClick={setIgnoreClick}
isPlayingBack={isPlayingBack} isPlayingBack={isPlayingBack}
onTimeUpdate={onTimeUpdate} onTimeUpdate={onTimeUpdate}
windowVisible={windowVisible}
/> />
); );
} }
@ -349,6 +366,7 @@ type VideoPreviewProps = {
setIgnoreClick: (ignore: boolean) => void; setIgnoreClick: (ignore: boolean) => void;
isPlayingBack: (ended: boolean) => void; isPlayingBack: (ended: boolean) => void;
onTimeUpdate?: (time: number | undefined) => void; onTimeUpdate?: (time: number | undefined) => void;
windowVisible: boolean;
}; };
export function VideoPreview({ export function VideoPreview({
relevantPreview, relevantPreview,
@ -360,6 +378,7 @@ export function VideoPreview({
setIgnoreClick, setIgnoreClick,
isPlayingBack, isPlayingBack,
onTimeUpdate, onTimeUpdate,
windowVisible,
}: VideoPreviewProps) { }: VideoPreviewProps) {
const playerRef = useRef<HTMLVideoElement | null>(null); const playerRef = useRef<HTMLVideoElement | null>(null);
const sliderRef = useRef<HTMLDivElement | null>(null); const sliderRef = useRef<HTMLDivElement | null>(null);
@ -409,6 +428,10 @@ export function VideoPreview({
// time progress update // time progress update
const onProgress = useCallback(() => { const onProgress = useCallback(() => {
if (!windowVisible) {
return;
}
if (onTimeUpdate) { if (onTimeUpdate) {
onTimeUpdate( onTimeUpdate(
relevantPreview.start + (playerRef.current?.currentTime || 0), relevantPreview.start + (playerRef.current?.currentTime || 0),
@ -458,7 +481,7 @@ export function VideoPreview({
// we know that these deps are correct // we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [setProgress, lastPercent]); }, [setProgress, lastPercent, windowVisible]);
// manual playback // manual playback
// safari is incapable of playing at a speed > 2x // safari is incapable of playing at a speed > 2x
@ -596,6 +619,7 @@ type InProgressPreviewProps = {
setIgnoreClick: (ignore: boolean) => void; setIgnoreClick: (ignore: boolean) => void;
isPlayingBack: (ended: boolean) => void; isPlayingBack: (ended: boolean) => void;
onTimeUpdate?: (time: number | undefined) => void; onTimeUpdate?: (time: number | undefined) => void;
windowVisible: boolean;
}; };
export function InProgressPreview({ export function InProgressPreview({
review, review,
@ -606,6 +630,7 @@ export function InProgressPreview({
setIgnoreClick, setIgnoreClick,
isPlayingBack, isPlayingBack,
onTimeUpdate, onTimeUpdate,
windowVisible,
}: InProgressPreviewProps) { }: InProgressPreviewProps) {
const apiHost = useApiHost(); const apiHost = useApiHost();
const sliderRef = useRef<HTMLDivElement | null>(null); const sliderRef = useRef<HTMLDivElement | null>(null);
@ -620,7 +645,7 @@ export function InProgressPreview({
const [key, setKey] = useState(0); const [key, setKey] = useState(0);
const handleLoad = useCallback(() => { const handleLoad = useCallback(() => {
if (!previewFrames) { if (!previewFrames || !windowVisible) {
return; return;
} }