Fix loading of images

This commit is contained in:
Nicolas Mowen 2024-03-26 10:13:14 -06:00
parent bacf202fd4
commit 1b73917ba3
4 changed files with 51 additions and 25 deletions

View File

@ -7,6 +7,8 @@ import { isSafari } from "react-device-detect";
import useSWR from "swr"; import useSWR from "swr";
import TimeAgo from "../dynamic/TimeAgo"; import TimeAgo from "../dynamic/TimeAgo";
import { useMemo } from "react"; import { useMemo } from "react";
import useImageLoaded from "@/hooks/use-image-loaded";
import ImageLoadingIndicator from "../indicators/ImageLoadingIndicator";
type ReviewCardProps = { type ReviewCardProps = {
event: ReviewSegment; event: ReviewSegment;
@ -19,6 +21,7 @@ export default function ReviewCard({
onClick, onClick,
}: ReviewCardProps) { }: ReviewCardProps) {
const { data: config } = useSWR<FrigateConfig>("config"); const { data: config } = useSWR<FrigateConfig>("config");
const [imgRef, imgLoaded, onImgLoad] = useImageLoaded();
const formattedDate = useFormattedTimestamp( const formattedDate = useFormattedTimestamp(
event.start_time, event.start_time,
config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p", config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p",
@ -28,17 +31,23 @@ export default function ReviewCard({
[event, currentTime], [event, currentTime],
); );
if (event.data.objects.includes("car")) {
//console.log(`failed to load ${JSON.stringify(event)}`);
}
return ( return (
<div <div
className="w-full flex flex-col gap-1.5 cursor-pointer" className="w-full flex flex-col gap-1.5 cursor-pointer"
onClick={onClick} onClick={onClick}
> >
<ImageLoadingIndicator className="size-full" imgLoaded={imgLoaded} />
<img <img
className={`size-full rounded-lg ${isSelected ? "outline outline-3 outline-offset-1 outline-selected" : ""}`} ref={imgRef}
className={`size-full rounded-lg ${isSelected ? "outline outline-3 outline-offset-1 outline-selected" : ""} ${imgLoaded ? "visible" : "invisible"}`}
src={`${baseUrl}${event.thumb_path.replace("/media/frigate/", "")}`} src={`${baseUrl}${event.thumb_path.replace("/media/frigate/", "")}`}
loading={isSafari ? "eager" : "lazy"} loading={isSafari ? "eager" : "lazy"}
onLoad={() => { onLoad={() => {
//onImgLoad(); onImgLoad();
}} }}
/> />
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">

View File

@ -0,0 +1,20 @@
import { isSafari } from "react-device-detect";
import { Skeleton } from "../ui/skeleton";
export default function ImageLoadingIndicator({
className,
imgLoaded,
}: {
className?: string;
imgLoaded: boolean;
}) {
if (imgLoaded) {
return;
}
return isSafari ? (
<div className={`bg-gray-300 pointer-events-none ${className ?? ""}`} />
) : (
<Skeleton className={`pointer-events-none ${className ?? ""}`} />
);
}

View File

@ -17,9 +17,9 @@ import { isFirefox, isMobile, isSafari } from "react-device-detect";
import Chip from "@/components/indicators/Chip"; import Chip from "@/components/indicators/Chip";
import { useFormattedTimestamp } from "@/hooks/use-date-utils"; import { useFormattedTimestamp } from "@/hooks/use-date-utils";
import useImageLoaded from "@/hooks/use-image-loaded"; import useImageLoaded from "@/hooks/use-image-loaded";
import { Skeleton } from "../ui/skeleton";
import { useSwipeable } from "react-swipeable"; import { useSwipeable } from "react-swipeable";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip"; import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
import ImageLoadingIndicator from "../indicators/ImageLoadingIndicator";
type PreviewPlayerProps = { type PreviewPlayerProps = {
review: ReviewSegment; review: ReviewSegment;
@ -187,7 +187,10 @@ export default function PreviewThumbnailPlayer({
/> />
</div> </div>
)} )}
<PreviewPlaceholder imgLoaded={imgLoaded} /> <ImageLoadingIndicator
className="absolute inset-0"
imgLoaded={imgLoaded}
/>
<div className={`${imgLoaded ? "visible" : "invisible"}`}> <div className={`${imgLoaded ? "visible" : "invisible"}`}>
<img <img
ref={imgRef} ref={imgRef}
@ -700,15 +703,3 @@ function InProgressPreview({
</div> </div>
); );
} }
function PreviewPlaceholder({ imgLoaded }: { imgLoaded: boolean }) {
if (imgLoaded) {
return;
}
return isSafari ? (
<div className={`absolute inset-0 bg-gray-300 pointer-events-none`} />
) : (
<Skeleton className={`absolute inset-0 pointer-events-none`} />
);
}

View File

@ -277,7 +277,7 @@ export function RecordingView({
</div> </div>
<div <div
className={`flex h-full justify-center overflow-hidden ${isDesktop ? "" : "flex-col"}`} className={`flex h-full mb-2 justify-center overflow-hidden ${isDesktop ? "" : "flex-col"}`}
> >
<div className="flex flex-1 flex-wrap"> <div className="flex flex-1 flex-wrap">
<div <div
@ -418,14 +418,20 @@ function Timeline({
return ( return (
<div className="w-60 h-full p-4 flex flex-col gap-4 bg-secondary overflow-auto"> <div className="w-60 h-full p-4 flex flex-col gap-4 bg-secondary overflow-auto">
{mainCameraReviewItems.map((review) => ( {mainCameraReviewItems.map((review) => {
<ReviewCard if (review.severity == "significant_motion") {
key={review.id} return;
event={review} }
currentTime={currentTime}
onClick={() => setCurrentTime(review.start_time)} return (
/> <ReviewCard
))} key={review.id}
event={review}
currentTime={currentTime}
onClick={() => setCurrentTime(review.start_time)}
/>
);
})}
</div> </div>
); );
} }