"use client"; import { RefObject } from "react"; import { Play, Pause, SkipBack, SkipForward, ChevronFirst, ChevronLast, Maximize2, MessageSquarePlus, Pencil, Eye, EyeOff, RectangleHorizontal, Scissors, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { Select, SelectContent, SelectItem, SelectSeparator, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { useReviewStore } from "@/hooks/use-review-player"; import { frameToTimecode } from "@/lib/frame-utils"; import { ASPECT_OFF, ASPECT_PRESETS } from "@/lib/aspect-overlays"; import { cn } from "@/lib/utils"; const PLAYBACK_RATES = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2]; interface PlaybackControlsProps { videoRef: RefObject; fps: number; isReversing: boolean; onStepBackward: () => void; onStepForward: () => void; onReverse: () => void; onTogglePlay: () => void; onToggleFullscreen: () => void; onAddComment: () => void; } export function PlaybackControls({ videoRef, fps, isReversing, onStepBackward, onStepForward, onReverse, onTogglePlay, onToggleFullscreen, onAddComment, }: PlaybackControlsProps) { const { isPlaying, currentFrame, currentTime, totalFrames, playbackRate, isAnnotating, showAnnotations, aspectPresetId, blankingMode, setPlaybackRate, setAnnotating, setShowAnnotations, setAspectPresetId, setBlankingMode, editRange, editRangeOnly, setEditRangeOnly, } = useReviewStore(); // Keeping to the edit, the ends of the transport are the cut points. const keepToEdit = editRangeOnly && !!editRange; const goToFrame = (frame: number) => { const video = videoRef.current; if (!video) return; video.pause(); video.currentTime = frame / fps; }; const handleRateChange = (val: string) => { const rate = parseFloat(val); if (videoRef.current) videoRef.current.playbackRate = rate; setPlaybackRate(rate); }; const blankingOn = aspectPresetId !== ASPECT_OFF; const timecode = frameToTimecode(currentFrame, fps); return (
{/* Frame info */}
{timecode} F{String(currentFrame).padStart(4, "0")} / {totalFrames}
{/* Divider */}
{/* Transport Controls */}
{/* Go to start + Reverse — hidden on mobile */}
{keepToEdit ? "Go to cut in" : "Go to start"} Reverse (J)
Step back (←) {/* Play/Pause — slightly larger */} Play / Pause (K or Space) Step forward (→) {/* Go to end — hidden on mobile */}
{keepToEdit ? "Go to cut out" : "Go to end"}
{/* Spacer */}
{/* Right Controls */}
{/* Playback speed — hidden on mobile */}
{/* Delivery blanking — hidden on mobile */}
{blankingOn && ( {blankingMode === "solid" ? "Dim the crop instead of hiding it" : "Hide the crop behind solid bars"} )}
{/* Edit range only — only for versions with handles marked */} {editRange && ( {editRangeOnly ? "Playing the edit only — click to include handles" : "Play the edit only (skip handles)"} )} {/* Annotation toggle */} {isAnnotating ? "Stop drawing" : "Draw annotation"} {/* Show/hide annotations */} {showAnnotations ? "Hide annotations" : "Show annotations"} {/* Add Comment */} Add comment at frame {currentFrame} {/* Fullscreen */} Fullscreen (F)
); }