mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Implement swipe gesture instead of autoplay for mobile (#10110)
* Implement swipe gesture instead of autoplay * Cleanup
This commit is contained in:
parent
fd24007618
commit
3fed6a0ab3
9
web/package-lock.json
generated
9
web/package-lock.json
generated
@ -46,6 +46,7 @@
|
|||||||
"react-hook-form": "^7.48.2",
|
"react-hook-form": "^7.48.2",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
"react-router-dom": "^6.20.1",
|
"react-router-dom": "^6.20.1",
|
||||||
|
"react-swipeable": "^7.0.1",
|
||||||
"react-tracked": "^1.7.11",
|
"react-tracked": "^1.7.11",
|
||||||
"react-transition-group": "^4.4.5",
|
"react-transition-group": "^4.4.5",
|
||||||
"react-use-websocket": "^4.5.0",
|
"react-use-websocket": "^4.5.0",
|
||||||
@ -6735,6 +6736,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-swipeable": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-swipeable/-/react-swipeable-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-RKB17JdQzvECfnVj9yDZsiYn3vH0eyva/ZbrCZXZR0qp66PBRhtg4F9yJcJTWYT5Adadi+x4NoG53BxKHwIYLQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.3 || ^17 || ^18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-tracked": {
|
"node_modules/react-tracked": {
|
||||||
"version": "1.7.11",
|
"version": "1.7.11",
|
||||||
"resolved": "https://registry.npmjs.org/react-tracked/-/react-tracked-1.7.11.tgz",
|
"resolved": "https://registry.npmjs.org/react-tracked/-/react-tracked-1.7.11.tgz",
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
"react-hook-form": "^7.48.2",
|
"react-hook-form": "^7.48.2",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
"react-router-dom": "^6.20.1",
|
"react-router-dom": "^6.20.1",
|
||||||
|
"react-swipeable": "^7.0.1",
|
||||||
"react-tracked": "^1.7.11",
|
"react-tracked": "^1.7.11",
|
||||||
"react-transition-group": "^4.4.5",
|
"react-transition-group": "^4.4.5",
|
||||||
"react-use-websocket": "^4.5.0",
|
"react-use-websocket": "^4.5.0",
|
||||||
|
@ -21,6 +21,7 @@ import axios from "axios";
|
|||||||
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 { Skeleton } from "../ui/skeleton";
|
||||||
|
import { useSwipeable } from "react-swipeable";
|
||||||
|
|
||||||
type PreviewPlayerProps = {
|
type PreviewPlayerProps = {
|
||||||
review: ReviewSegment;
|
review: ReviewSegment;
|
||||||
@ -41,7 +42,6 @@ type Preview = {
|
|||||||
export default function PreviewThumbnailPlayer({
|
export default function PreviewThumbnailPlayer({
|
||||||
review,
|
review,
|
||||||
relevantPreview,
|
relevantPreview,
|
||||||
autoPlayback = false,
|
|
||||||
setReviewed,
|
setReviewed,
|
||||||
onClick,
|
onClick,
|
||||||
}: PreviewPlayerProps) {
|
}: PreviewPlayerProps) {
|
||||||
@ -61,6 +61,13 @@ export default function PreviewThumbnailPlayer({
|
|||||||
}
|
}
|
||||||
}, [review, onClick]);
|
}, [review, onClick]);
|
||||||
|
|
||||||
|
const swipeHandlers = useSwipeable({
|
||||||
|
onSwipedLeft: () => setPlayback(false),
|
||||||
|
onSwipedRight: () => setPlayback(true),
|
||||||
|
preventScrollOnSwipe: true,
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
const handleSetReviewed = useCallback(() => {
|
const handleSetReviewed = useCallback(() => {
|
||||||
if (setReviewed) {
|
if (setReviewed) {
|
||||||
setReviewed(review.id);
|
setReviewed(review.id);
|
||||||
@ -69,27 +76,7 @@ export default function PreviewThumbnailPlayer({
|
|||||||
|
|
||||||
// playback
|
// playback
|
||||||
|
|
||||||
const playingBack = useMemo(() => playback, [playback, autoPlayback]);
|
const playingBack = useMemo(() => playback, [playback]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!autoPlayback) {
|
|
||||||
setPlayback(false);
|
|
||||||
|
|
||||||
if (hoverTimeout) {
|
|
||||||
clearTimeout(hoverTimeout);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
setPlayback(true);
|
|
||||||
setHoverTimeout(null);
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
};
|
|
||||||
}, [autoPlayback]);
|
|
||||||
|
|
||||||
const onPlayback = useCallback(
|
const onPlayback = useCallback(
|
||||||
(isHovered: Boolean) => {
|
(isHovered: Boolean) => {
|
||||||
@ -127,6 +114,7 @@ export default function PreviewThumbnailPlayer({
|
|||||||
onMouseEnter={isMobile ? undefined : () => onPlayback(true)}
|
onMouseEnter={isMobile ? undefined : () => onPlayback(true)}
|
||||||
onMouseLeave={isMobile ? undefined : () => onPlayback(false)}
|
onMouseLeave={isMobile ? undefined : () => onPlayback(false)}
|
||||||
onClick={handleOnClick}
|
onClick={handleOnClick}
|
||||||
|
{...swipeHandlers}
|
||||||
>
|
>
|
||||||
{playingBack && (
|
{playingBack && (
|
||||||
<div className="absolute left-0 top-0 right-0 bottom-0 animate-in fade-in">
|
<div className="absolute left-0 top-0 right-0 bottom-0 animate-in fade-in">
|
||||||
|
@ -9,7 +9,7 @@ import { useEventUtils } from "@/hooks/use-event-utils";
|
|||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import { ReviewFilter, ReviewSegment, ReviewSeverity } from "@/types/review";
|
import { ReviewFilter, ReviewSegment, ReviewSeverity } from "@/types/review";
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { isDesktop, isMobile } from "react-device-detect";
|
import { isDesktop } from "react-device-detect";
|
||||||
import { LuFolderCheck } from "react-icons/lu";
|
import { LuFolderCheck } from "react-icons/lu";
|
||||||
import { MdCircle } from "react-icons/md";
|
import { MdCircle } from "react-icons/md";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
@ -283,9 +283,6 @@ export default function EventView({
|
|||||||
relevantPreview={relevantPreview}
|
relevantPreview={relevantPreview}
|
||||||
setReviewed={markItemAsReviewed}
|
setReviewed={markItemAsReviewed}
|
||||||
onClick={onSelectReview}
|
onClick={onSelectReview}
|
||||||
autoPlayback={
|
|
||||||
isMobile && minimapBounds.end == value.start_time
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{lastRow && !reachedEnd && <ActivityIndicator />}
|
{lastRow && !reachedEnd && <ActivityIndicator />}
|
||||||
|
Loading…
Reference in New Issue
Block a user