mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-12 10:07:36 +03:00
tweaks
This commit is contained in:
parent
83354be7f6
commit
2827561238
@ -5,7 +5,10 @@ import { getLifecycleItemDescription } from "@/utils/lifecycleUtil";
|
||||
import { useDetailStream } from "@/context/detail-stream-context";
|
||||
import scrollIntoView from "scroll-into-view-if-needed";
|
||||
import useUserInteraction from "@/hooks/use-user-interaction";
|
||||
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
||||
import {
|
||||
formatUnixTimestampToDateTime,
|
||||
formatSecondsToDuration,
|
||||
} from "@/utils/dateUtil";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import AnnotationOffsetSlider from "@/components/overlay/detail/AnnotationOffsetSlider";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
@ -13,7 +16,7 @@ import useSWR from "swr";
|
||||
import ActivityIndicator from "../indicators/activity-indicator";
|
||||
import { Event } from "@/types/event";
|
||||
import { getIconForLabel } from "@/utils/iconUtil";
|
||||
import { ReviewSegment, REVIEW_PADDING } from "@/types/review";
|
||||
import { ReviewSegment } from "@/types/review";
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleTrigger,
|
||||
@ -49,7 +52,6 @@ export default function DetailStream({
|
||||
});
|
||||
|
||||
const effectiveTime = currentTime + annotationOffset / 1000;
|
||||
const PAD = 0; // REVIEW_PADDING ?? 2;
|
||||
const [upload, setUpload] = useState<Event | undefined>(undefined);
|
||||
|
||||
// Ensure we initialize the active review when reviewItems first arrive.
|
||||
@ -64,8 +66,8 @@ export default function DetailStream({
|
||||
let closest: { r: ReviewSegment; diff: number } | undefined;
|
||||
|
||||
for (const r of reviewItems) {
|
||||
const start = (r.start_time ?? 0) - PAD;
|
||||
const end = (r.end_time ?? r.start_time ?? start) + PAD;
|
||||
const start = r.start_time ?? 0;
|
||||
const end = r.end_time ?? r.start_time ?? start;
|
||||
if (effectiveTime >= start && effectiveTime <= end) {
|
||||
target = r;
|
||||
break;
|
||||
@ -78,12 +80,12 @@ export default function DetailStream({
|
||||
if (!target && closest) target = closest.r;
|
||||
|
||||
if (target) {
|
||||
const start = (target.start_time ?? 0) - PAD;
|
||||
const start = target.start_time ?? 0;
|
||||
setActiveReviewId(
|
||||
`review-${target.id ?? target.start_time ?? Math.floor(start)}`,
|
||||
);
|
||||
}
|
||||
}, [reviewItems, activeReviewId, effectiveTime, PAD]);
|
||||
}, [reviewItems, activeReviewId, effectiveTime]);
|
||||
|
||||
// Auto-scroll to current time
|
||||
useEffect(() => {
|
||||
@ -99,8 +101,8 @@ export default function DetailStream({
|
||||
let closest: { r: ReviewSegment; diff: number } | undefined;
|
||||
|
||||
for (const r of items) {
|
||||
const start = (r.start_time ?? 0) - PAD;
|
||||
const end = (r.end_time ?? r.start_time ?? start) + PAD;
|
||||
const start = r.start_time ?? 0;
|
||||
const end = r.end_time ?? r.start_time ?? start;
|
||||
if (effectiveTime >= start && effectiveTime <= end) {
|
||||
target = r;
|
||||
break;
|
||||
@ -113,7 +115,7 @@ export default function DetailStream({
|
||||
if (!target && closest) target = closest.r;
|
||||
|
||||
if (target) {
|
||||
const start = (target.start_time ?? 0) - PAD;
|
||||
const start = target.start_time ?? 0;
|
||||
const id = `review-${target.id ?? target.start_time ?? Math.floor(start)}`;
|
||||
const element = scrollRef.current.querySelector(
|
||||
`[data-review-id="${id}"]`,
|
||||
@ -132,15 +134,14 @@ export default function DetailStream({
|
||||
annotationOffset,
|
||||
userInteracting,
|
||||
setProgrammaticScroll,
|
||||
PAD,
|
||||
]);
|
||||
|
||||
// Auto-select active review based on effectiveTime (if inside a review range)
|
||||
useEffect(() => {
|
||||
if (!reviewItems || reviewItems.length === 0) return;
|
||||
for (const r of reviewItems) {
|
||||
const start = (r.start_time ?? 0) - PAD;
|
||||
const end = (r.end_time ?? r.start_time ?? start) + PAD;
|
||||
const start = r.start_time ?? 0;
|
||||
const end = r.end_time ?? r.start_time ?? start;
|
||||
if (effectiveTime >= start && effectiveTime <= end) {
|
||||
setActiveReviewId(
|
||||
`review-${r.id ?? r.start_time ?? Math.floor(start)}`,
|
||||
@ -148,7 +149,7 @@ export default function DetailStream({
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, [effectiveTime, reviewItems, PAD]);
|
||||
}, [effectiveTime, reviewItems]);
|
||||
|
||||
if (!config) {
|
||||
return <ActivityIndicator />;
|
||||
@ -173,7 +174,7 @@ export default function DetailStream({
|
||||
</div>
|
||||
) : (
|
||||
reviewItems?.map((review: ReviewSegment) => {
|
||||
const id = `review-${review.id ?? review.start_time ?? Math.floor((review.start_time ?? 0) - PAD)}`;
|
||||
const id = `review-${review.id ?? review.start_time ?? Math.floor(review.start_time ?? 0)}`;
|
||||
return (
|
||||
<ReviewGroup
|
||||
key={id}
|
||||
@ -219,18 +220,14 @@ function ReviewGroup({
|
||||
effectiveTime,
|
||||
}: ReviewGroupProps) {
|
||||
const { t } = useTranslation("views/events");
|
||||
const PAD = REVIEW_PADDING ?? 2;
|
||||
const start = review.start_time ?? 0;
|
||||
|
||||
// derive start timestamp from the review
|
||||
const start = (review.start_time ?? 0) - PAD;
|
||||
|
||||
// display time first in the header
|
||||
const displayTime = formatUnixTimestampToDateTime(start, {
|
||||
timezone: config.ui.timezone,
|
||||
date_format:
|
||||
config.ui.time_format == "24hour"
|
||||
? t("time.formattedTimestamp.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestamp.12hour", { ns: "common" }),
|
||||
? t("time.formattedTimestampHourMinuteSecond.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestampHourMinuteSecond.12hour", { ns: "common" }),
|
||||
time_style: "medium",
|
||||
date_style: "medium",
|
||||
});
|
||||
@ -268,6 +265,13 @@ function ReviewGroup({
|
||||
}
|
||||
}, [review, t, fetchedEvents]);
|
||||
|
||||
const reviewDuration =
|
||||
review.end_time != null
|
||||
? formatSecondsToDuration(
|
||||
Math.max(0, Math.floor((review.end_time ?? 0) - start)),
|
||||
)
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div
|
||||
data-review-id={id}
|
||||
@ -287,6 +291,11 @@ function ReviewGroup({
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex flex-col">
|
||||
<div className="text-sm font-medium">{displayTime}</div>
|
||||
{reviewDuration && (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{reviewDuration}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-xs text-muted-foreground">{reviewInfo}</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -398,7 +407,7 @@ function EventCollapsible({
|
||||
event.id != selectedObjectId &&
|
||||
(effectiveTime ?? 0) >= (event.start_time ?? 0) &&
|
||||
(effectiveTime ?? 0) <= (event.end_time ?? event.start_time ?? 0) &&
|
||||
"bg-secondary outline-[1px] -outline-offset-[0.8px] outline-primary/40",
|
||||
"bg-secondary-highlight outline-[1.5px] -outline-offset-[1.1px] outline-primary/40",
|
||||
)}
|
||||
>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
|
||||
@ -36,8 +36,8 @@
|
||||
--secondary-foreground: hsl(222.2, 17.4%, 36.2%);
|
||||
--secondary-foreground: 222.2 17.4% 36.2%;
|
||||
|
||||
--secondary-highlight: hsl(0, 0%, 94%);
|
||||
--secondary-highlight: 0 0% 94%;
|
||||
--secondary-highlight: hsl(210, 17.4%, 94%);
|
||||
--secondary-highlight: 210 17.4% 94%;
|
||||
|
||||
--neutral: hsl(0, 0%, 45.1%);
|
||||
--neutral: 0 0% 45.1%;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user