diff --git a/web/src/components/player/PreviewThumbnailPlayer.tsx b/web/src/components/player/PreviewThumbnailPlayer.tsx index 5afea161b..a7a54ae60 100644 --- a/web/src/components/player/PreviewThumbnailPlayer.tsx +++ b/web/src/components/player/PreviewThumbnailPlayer.tsx @@ -13,13 +13,14 @@ import { getIconForLabel } from "@/utils/iconUtil"; import TimeAgo from "../dynamic/TimeAgo"; import useSWR from "swr"; import { FrigateConfig } from "@/types/frigateConfig"; -import { isFirefox, isMobile, isSafari } from "react-device-detect"; +import { isFirefox, isIOS, isMobile, isSafari } from "react-device-detect"; import Chip from "@/components/indicators/Chip"; import { useFormattedTimestamp } from "@/hooks/use-date-utils"; import useImageLoaded from "@/hooks/use-image-loaded"; import { useSwipeable } from "react-swipeable"; import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip"; import ImageLoadingIndicator from "../indicators/ImageLoadingIndicator"; +import useContextMenu from "@/hooks/use-contextmenu"; type PreviewPlayerProps = { review: ReviewSegment; @@ -73,6 +74,10 @@ export default function PreviewThumbnailPlayer({ setReviewed(review); }, [review, setReviewed]); + useContextMenu(imgRef, () => { + onClick(review, true); + }); + // playback const relevantPreview = useMemo(() => { @@ -170,10 +175,6 @@ export default function PreviewThumbnailPlayer({ className="relative size-full cursor-pointer" onMouseOver={isMobile ? undefined : () => setIsHovered(true)} onMouseLeave={isMobile ? undefined : () => setIsHovered(false)} - onContextMenu={(e) => { - e.preventDefault(); - onClick(review, true); - }} onClick={handleOnClick} {...swipeHandlers} > @@ -196,9 +197,18 @@ export default function PreviewThumbnailPlayer({
{ diff --git a/web/src/hooks/use-contextmenu.ts b/web/src/hooks/use-contextmenu.ts new file mode 100644 index 000000000..f121846ae --- /dev/null +++ b/web/src/hooks/use-contextmenu.ts @@ -0,0 +1,46 @@ +import { MutableRefObject, useEffect } from "react"; +import { isIOS } from "react-device-detect"; + +export default function useContextMenu( + ref: MutableRefObject, + callback: () => void, +) { + useEffect(() => { + if (!ref.current) { + return; + } + + const elem = ref.current; + + if (isIOS) { + let timeoutId: NodeJS.Timeout; + const touchStart = () => { + timeoutId = setTimeout(() => { + callback(); + }, 610); + }; + const touchClear = () => { + clearTimeout(timeoutId); + }; + elem.addEventListener("touchstart", touchStart); + elem.addEventListener("touchmove", touchClear); + elem.addEventListener("touchend", touchClear); + + return () => { + elem.removeEventListener("touchstart", touchStart); + elem.removeEventListener("touchmove", touchClear); + elem.removeEventListener("touchend", touchClear); + }; + } else { + const context = (e: MouseEvent) => { + e.preventDefault(); + callback(); + }; + elem.addEventListener("contextmenu", context); + + return () => { + elem.removeEventListener("contextmenu", context); + }; + } + }, [callback, ref]); +}