diff --git a/web/src/components/player/PreviewThumbnailPlayer.tsx b/web/src/components/player/PreviewThumbnailPlayer.tsx index c39b281d9..d6ae40fe4 100644 --- a/web/src/components/player/PreviewThumbnailPlayer.tsx +++ b/web/src/components/player/PreviewThumbnailPlayer.tsx @@ -4,12 +4,12 @@ import { useApiHost } from "@/api"; import Player from "video.js/dist/types/player"; import { isCurrentHour } from "@/utils/dateUtil"; import { isSafari } from "@/utils/browserUtil"; +import { ReviewSegment } from "@/types/review"; +import { Slider } from "../ui/slider"; type PreviewPlayerProps = { - camera: string; + review: ReviewSegment; relevantPreview?: Preview; - startTs: number; - eventId: string; isMobile: boolean; onClick?: () => void; }; @@ -23,17 +23,17 @@ type Preview = { }; export default function PreviewThumbnailPlayer({ - camera, + review, relevantPreview, - startTs, - eventId, isMobile, onClick, }: PreviewPlayerProps) { const playerRef = useRef(null); const [visible, setVisible] = useState(false); + const [hover, setHover] = useState(false); const [isInitiallyVisible, setIsInitiallyVisible] = useState(false); + const [progress, setProgress] = useState(0); const onPlayback = useCallback( (isHovered: Boolean) => { @@ -50,13 +50,18 @@ export default function PreviewThumbnailPlayer({ } if (isHovered) { + setHover(true); playerRef.current.play(); } else { + setHover(false); + setProgress(0); playerRef.current.pause(); - playerRef.current.currentTime(startTs - relevantPreview.start); + playerRef.current.currentTime( + review.start_time - relevantPreview.start + ); } }, - [relevantPreview, startTs, playerRef] + [relevantPreview, review, playerRef] ); const autoPlayObserver = useRef(); @@ -111,47 +116,53 @@ export default function PreviewThumbnailPlayer({ return (
onPlayback(true)} onMouseLeave={() => onPlayback(false)} >
+ {hover && ( + + )}
); } type PreviewContentProps = { playerRef: React.MutableRefObject; - camera: string; + review: ReviewSegment; relevantPreview: Preview | undefined; - eventId: string; isVisible: boolean; isInitiallyVisible: boolean; - startTs: number; isMobile: boolean; + setProgress?: (progress: number) => void; onClick?: () => void; }; function PreviewContent({ playerRef, - camera, + review, relevantPreview, - eventId, isVisible, isInitiallyVisible, - startTs, isMobile, + setProgress, onClick, }: PreviewContentProps) { const apiHost = useApiHost(); @@ -183,18 +194,18 @@ function PreviewContent({ if (relevantPreview && !isVisible) { return
; - } else if (!relevantPreview && isCurrentHour(startTs)) { + } else if (!relevantPreview && isCurrentHour(review.start_time)) { return ( ); - } else if (!relevantPreview && !isCurrentHour(startTs)) { + } else if (!relevantPreview && !isCurrentHour(review.start_time)) { return ( ); } else { @@ -224,12 +235,31 @@ function PreviewContent({ return; } + const playerStartTime = review.start_time - relevantPreview.start; + if (!isInitiallyVisible) { player.pause(); // autoplay + pause is required for iOS } player.playbackRate(slowPlayack ? 2 : 8); - player.currentTime(startTs - relevantPreview.start); + player.currentTime(playerStartTime); + player.on("timeupdate", () => { + if (!setProgress || playerRef.current?.paused()) { + return; + } + + const playerProgress = + (player.currentTime() || 0) - playerStartTime; + const playerDuration = review.end_time - review.start_time; + const playerPercent = (playerProgress / playerDuration) * 100; + + if (playerPercent > 100) { + playerRef.current?.pause(); + setProgress(100.0); + } else { + setProgress(playerPercent); + } + }); if (isMobile && onClick) { player.on("touchstart", handleTouchStart); } diff --git a/web/src/components/ui/slider.tsx b/web/src/components/ui/slider.tsx index e161daec0..2ed9fa769 100644 --- a/web/src/components/ui/slider.tsx +++ b/web/src/components/ui/slider.tsx @@ -1,7 +1,7 @@ -import * as React from "react" -import * as SliderPrimitive from "@radix-ui/react-slider" +import * as React from "react"; +import * as SliderPrimitive from "@radix-ui/react-slider"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const Slider = React.forwardRef< React.ElementRef, @@ -15,12 +15,11 @@ const Slider = React.forwardRef< )} {...props} > - - + + - -)) -Slider.displayName = SliderPrimitive.Root.displayName +)); +Slider.displayName = SliderPrimitive.Root.displayName; -export { Slider } +export { Slider }; diff --git a/web/src/pages/Events.tsx b/web/src/pages/Events.tsx index 7cda1b454..c4bd547bf 100644 --- a/web/src/pages/Events.tsx +++ b/web/src/pages/Events.tsx @@ -186,17 +186,15 @@ export default function Events() {
{(severity == "alert" || severity == "detection") && (