mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-01 00:22:19 +03:00
Add Detail stream in History view (#20525)
* new type * activity stream panel * use context provider for activity stream * new activity stream panel in history view * overlay for object tracking details in history view * use overlay in video player * don't refetch timeline * fix activity stream group from being highlighted prematurely * use annotation offset * fix scrolling and use custom hook for interaction * memoize to prevent unnecessary renders * i18n and timestamp formatting * add annotation offset slider * bg color * add collapsible component * refactor * rename activity to detail * fix merge conflicts * i18n * more i18n
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useTimelineUtils } from "./use-timeline-utils";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import useSWR from "swr";
|
||||
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
||||
import { useDateLocale } from "./use-date-locale";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import useUserInteraction from "./use-user-interaction";
|
||||
|
||||
type DraggableElementProps = {
|
||||
contentRef: React.RefObject<HTMLElement>;
|
||||
@@ -71,9 +72,9 @@ function useDraggableElement({
|
||||
|
||||
// track user interaction and adjust scrolling behavior
|
||||
|
||||
const [userInteracting, setUserInteracting] = useState(false);
|
||||
const interactionTimeout = useRef<NodeJS.Timeout>();
|
||||
const isProgrammaticScroll = useRef(false);
|
||||
const { userInteracting } = useUserInteraction({
|
||||
elementRef: timelineRef,
|
||||
});
|
||||
|
||||
const draggingAtTopEdge = useMemo(() => {
|
||||
if (clientYPosition && timelineRef.current && scrollEdgeSize) {
|
||||
@@ -507,47 +508,6 @@ function useDraggableElement({
|
||||
}
|
||||
}, [timelineRef, segmentsRef, segments]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleUserInteraction = () => {
|
||||
if (!isProgrammaticScroll.current) {
|
||||
setUserInteracting(true);
|
||||
|
||||
if (interactionTimeout.current) {
|
||||
clearTimeout(interactionTimeout.current);
|
||||
}
|
||||
|
||||
interactionTimeout.current = setTimeout(() => {
|
||||
setUserInteracting(false);
|
||||
}, 3000);
|
||||
} else {
|
||||
isProgrammaticScroll.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
const timelineElement = timelineRef.current;
|
||||
|
||||
if (timelineElement) {
|
||||
timelineElement.addEventListener("scroll", handleUserInteraction);
|
||||
timelineElement.addEventListener("mousedown", handleUserInteraction);
|
||||
timelineElement.addEventListener("mouseup", handleUserInteraction);
|
||||
timelineElement.addEventListener("touchstart", handleUserInteraction);
|
||||
timelineElement.addEventListener("touchmove", handleUserInteraction);
|
||||
timelineElement.addEventListener("touchend", handleUserInteraction);
|
||||
|
||||
return () => {
|
||||
timelineElement.removeEventListener("scroll", handleUserInteraction);
|
||||
timelineElement.removeEventListener("mousedown", handleUserInteraction);
|
||||
timelineElement.removeEventListener("mouseup", handleUserInteraction);
|
||||
timelineElement.removeEventListener(
|
||||
"touchstart",
|
||||
handleUserInteraction,
|
||||
);
|
||||
timelineElement.removeEventListener("touchmove", handleUserInteraction);
|
||||
timelineElement.removeEventListener("touchend", handleUserInteraction);
|
||||
};
|
||||
}
|
||||
}, [timelineRef]);
|
||||
|
||||
return { handleMouseDown, handleMouseUp, handleMouseMove };
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
|
||||
type UseUserInteractionProps = {
|
||||
elementRef: React.RefObject<HTMLElement>;
|
||||
};
|
||||
|
||||
function useUserInteraction({ elementRef }: UseUserInteractionProps) {
|
||||
const [userInteracting, setUserInteracting] = useState(false);
|
||||
const interactionTimeout = useRef<NodeJS.Timeout>();
|
||||
const isProgrammaticScroll = useRef(false);
|
||||
|
||||
const setProgrammaticScroll = useCallback(() => {
|
||||
isProgrammaticScroll.current = true;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleUserInteraction = () => {
|
||||
if (!isProgrammaticScroll.current) {
|
||||
setUserInteracting(true);
|
||||
|
||||
if (interactionTimeout.current) {
|
||||
clearTimeout(interactionTimeout.current);
|
||||
}
|
||||
|
||||
interactionTimeout.current = setTimeout(() => {
|
||||
setUserInteracting(false);
|
||||
}, 3000);
|
||||
} else {
|
||||
isProgrammaticScroll.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
const element = elementRef.current;
|
||||
|
||||
if (element) {
|
||||
element.addEventListener("scroll", handleUserInteraction);
|
||||
element.addEventListener("mousedown", handleUserInteraction);
|
||||
element.addEventListener("mouseup", handleUserInteraction);
|
||||
element.addEventListener("touchstart", handleUserInteraction);
|
||||
element.addEventListener("touchmove", handleUserInteraction);
|
||||
element.addEventListener("touchend", handleUserInteraction);
|
||||
|
||||
return () => {
|
||||
element.removeEventListener("scroll", handleUserInteraction);
|
||||
element.removeEventListener("mousedown", handleUserInteraction);
|
||||
element.removeEventListener("mouseup", handleUserInteraction);
|
||||
element.removeEventListener("touchstart", handleUserInteraction);
|
||||
element.removeEventListener("touchmove", handleUserInteraction);
|
||||
element.removeEventListener("touchend", handleUserInteraction);
|
||||
};
|
||||
}
|
||||
}, [elementRef]);
|
||||
|
||||
return { userInteracting, setProgrammaticScroll };
|
||||
}
|
||||
|
||||
export default useUserInteraction;
|
||||
Reference in New Issue
Block a user