mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Implement scroll lock for previews (#10180)
* Implement scroll lock * Fix seekbar not working
This commit is contained in:
parent
ebf34ce378
commit
a67e970fca
@ -23,6 +23,7 @@ import { useSwipeable } from "react-swipeable";
|
|||||||
type PreviewPlayerProps = {
|
type PreviewPlayerProps = {
|
||||||
review: ReviewSegment;
|
review: ReviewSegment;
|
||||||
allPreviews?: Preview[];
|
allPreviews?: Preview[];
|
||||||
|
scrollLock?: boolean;
|
||||||
onTimeUpdate?: React.Dispatch<React.SetStateAction<number | undefined>>;
|
onTimeUpdate?: React.Dispatch<React.SetStateAction<number | undefined>>;
|
||||||
setReviewed: (reviewId: string) => void;
|
setReviewed: (reviewId: string) => void;
|
||||||
onClick: (reviewId: string, ctrl: boolean) => void;
|
onClick: (reviewId: string, ctrl: boolean) => void;
|
||||||
@ -39,6 +40,7 @@ type Preview = {
|
|||||||
export default function PreviewThumbnailPlayer({
|
export default function PreviewThumbnailPlayer({
|
||||||
review,
|
review,
|
||||||
allPreviews,
|
allPreviews,
|
||||||
|
scrollLock = false,
|
||||||
setReviewed,
|
setReviewed,
|
||||||
onClick,
|
onClick,
|
||||||
onTimeUpdate,
|
onTimeUpdate,
|
||||||
@ -116,12 +118,16 @@ export default function PreviewThumbnailPlayer({
|
|||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}, [allPreviews]);
|
}, [allPreviews, review]);
|
||||||
|
|
||||||
const playingBack = useMemo(() => playback, [playback]);
|
const playingBack = useMemo(() => playback, [playback]);
|
||||||
|
|
||||||
const onPlayback = useCallback(
|
const onPlayback = useCallback(
|
||||||
(isHovered: boolean) => {
|
(isHovered: boolean) => {
|
||||||
|
if (isHovered && scrollLock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isHovered) {
|
if (isHovered) {
|
||||||
setHoverTimeout(
|
setHoverTimeout(
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -144,7 +150,7 @@ export default function PreviewThumbnailPlayer({
|
|||||||
|
|
||||||
// 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
|
||||||
[hoverTimeout, review],
|
[hoverTimeout, scrollLock, review],
|
||||||
);
|
);
|
||||||
|
|
||||||
// date
|
// date
|
||||||
@ -462,7 +468,7 @@ function VideoPreview({
|
|||||||
<source src={relevantPreview.src} type={relevantPreview.type} />
|
<source src={relevantPreview.src} type={relevantPreview.type} />
|
||||||
</video>
|
</video>
|
||||||
<Slider
|
<Slider
|
||||||
className="absolute inset-x-0 bottom-0"
|
className="absolute inset-x-0 bottom-0 z-30"
|
||||||
value={[progress]}
|
value={[progress]}
|
||||||
onValueChange={onManualSeek}
|
onValueChange={onManualSeek}
|
||||||
onValueCommit={onStopManualSeek}
|
onValueCommit={onStopManualSeek}
|
||||||
@ -580,7 +586,7 @@ function InProgressPreview({
|
|||||||
onLoad={handleLoad}
|
onLoad={handleLoad}
|
||||||
/>
|
/>
|
||||||
<Slider
|
<Slider
|
||||||
className="absolute inset-x-0 bottom-0"
|
className="absolute inset-x-0 bottom-0 z-30"
|
||||||
value={[key]}
|
value={[key]}
|
||||||
onValueChange={onManualSeek}
|
onValueChange={onManualSeek}
|
||||||
onValueCommit={onStopManualSeek}
|
onValueCommit={onStopManualSeek}
|
||||||
|
38
web/src/hooks/use-mouse-listener.ts
Normal file
38
web/src/hooks/use-mouse-listener.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { MutableRefObject, useCallback, useEffect, useState } from "react";
|
||||||
|
import { isMobile } from "react-device-detect";
|
||||||
|
|
||||||
|
export function useScrollLockout(ref: MutableRefObject<HTMLElement | null>) {
|
||||||
|
const [scrollLock, setScrollLockout] = useState(false);
|
||||||
|
|
||||||
|
const onScroll = useCallback(() => {
|
||||||
|
if (!scrollLock) {
|
||||||
|
setScrollLockout(true);
|
||||||
|
}
|
||||||
|
}, [scrollLock, setScrollLockout]);
|
||||||
|
const onMouseMove = useCallback(() => {
|
||||||
|
if (scrollLock) {
|
||||||
|
setScrollLockout(false);
|
||||||
|
}
|
||||||
|
}, [scrollLock, setScrollLockout]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isMobile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ref.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = ref.current;
|
||||||
|
content.addEventListener("scroll", onScroll);
|
||||||
|
content.addEventListener("mousemove", onMouseMove);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
content.removeEventListener("scroll", onScroll);
|
||||||
|
content.removeEventListener("mousemove", onMouseMove);
|
||||||
|
};
|
||||||
|
}, [ref, onScroll, onMouseMove]);
|
||||||
|
|
||||||
|
return scrollLock;
|
||||||
|
}
|
@ -7,6 +7,7 @@ import EventReviewTimeline from "@/components/timeline/EventReviewTimeline";
|
|||||||
import ActivityIndicator from "@/components/ui/activity-indicator";
|
import ActivityIndicator from "@/components/ui/activity-indicator";
|
||||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||||
import { useEventUtils } from "@/hooks/use-event-utils";
|
import { useEventUtils } from "@/hooks/use-event-utils";
|
||||||
|
import { useScrollLockout } from "@/hooks/use-mouse-listener";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import { Preview } from "@/types/preview";
|
import { Preview } from "@/types/preview";
|
||||||
import { ReviewFilter, ReviewSegment, ReviewSeverity } from "@/types/review";
|
import { ReviewFilter, ReviewSegment, ReviewSeverity } from "@/types/review";
|
||||||
@ -192,6 +193,7 @@ export default function EventView({
|
|||||||
// preview playback
|
// preview playback
|
||||||
|
|
||||||
const [previewTime, setPreviewTime] = useState<number>();
|
const [previewTime, setPreviewTime] = useState<number>();
|
||||||
|
const scrollLock = useScrollLockout(contentRef);
|
||||||
|
|
||||||
// review interaction
|
// review interaction
|
||||||
|
|
||||||
@ -220,7 +222,7 @@ export default function EventView({
|
|||||||
onOpenReview(reviewId);
|
onOpenReview(reviewId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[selectedReviews, setSelectedReviews],
|
[selectedReviews, setSelectedReviews, onOpenReview],
|
||||||
);
|
);
|
||||||
|
|
||||||
const exportReview = useCallback(
|
const exportReview = useCallback(
|
||||||
@ -236,7 +238,7 @@ export default function EventView({
|
|||||||
{ playback: "realtime" },
|
{ playback: "realtime" },
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[selectedReviews],
|
[currentItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
@ -342,6 +344,7 @@ export default function EventView({
|
|||||||
review={value}
|
review={value}
|
||||||
allPreviews={relevantPreviews}
|
allPreviews={relevantPreviews}
|
||||||
setReviewed={markItemAsReviewed}
|
setReviewed={markItemAsReviewed}
|
||||||
|
scrollLock={scrollLock}
|
||||||
onTimeUpdate={setPreviewTime}
|
onTimeUpdate={setPreviewTime}
|
||||||
onClick={onSelectReview}
|
onClick={onSelectReview}
|
||||||
/>
|
/>
|
||||||
|
Loading…
Reference in New Issue
Block a user