play segments functionality

This commit is contained in:
Yiannis Christodoulou 2025-05-22 03:50:30 +03:00
parent 39fcf3c97c
commit 3453ec279b
4 changed files with 87 additions and 9 deletions

View File

@ -285,6 +285,7 @@ const App = () => {
isPlaying={isPlaying} isPlaying={isPlaying}
setIsPlaying={setIsPlaying} setIsPlaying={setIsPlaying}
onPlayPause={handlePlay} onPlayPause={handlePlay}
isPlayingSegments={isPlayingSegments}
/> />
{/* Clip Segments */} {/* Clip Segments */}

View File

@ -103,8 +103,8 @@ const EditingTools = ({
)} )}
</button> </button>
{/* Standard Play button (only shown when not in preview mode) */} {/* Standard Play button (only shown when not in preview mode or segments playback) */}
{!isPreviewMode && ( {!isPreviewMode && !isPlayingSegments && (
<button <button
className="button play-button" className="button play-button"
onClick={handlePlay} onClick={handlePlay}
@ -134,6 +134,18 @@ const EditingTools = ({
</button> </button>
)} )}
{/* Segments Playback message (replaces play button during segments playback) */}
{isPlayingSegments && (
<div className="segments-playback-message">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="16" x2="12" y2="12" />
<line x1="12" y1="8" x2="12" y2="8" />
</svg>
Segments Playback
</div>
)}
{/* Preview mode message (replaces play button) */} {/* Preview mode message (replaces play button) */}
{isPreviewMode && ( {isPreviewMode && (
<div className="preview-mode-message"> <div className="preview-mode-message">

View File

@ -49,6 +49,7 @@ interface TimelineControlsProps {
isPlaying: boolean; isPlaying: boolean;
setIsPlaying: (playing: boolean) => void; setIsPlaying: (playing: boolean) => void;
onPlayPause: () => void; // Add this prop onPlayPause: () => void; // Add this prop
isPlayingSegments?: boolean;
} }
// Function to calculate and constrain tooltip position to keep it on screen // Function to calculate and constrain tooltip position to keep it on screen
@ -95,7 +96,8 @@ const TimelineControls = ({
isIOSUninitialized = false, isIOSUninitialized = false,
isPlaying, isPlaying,
setIsPlaying, setIsPlaying,
onPlayPause // Add this prop onPlayPause, // Add this prop
isPlayingSegments = false,
}: TimelineControlsProps) => { }: TimelineControlsProps) => {
const timelineRef = useRef<HTMLDivElement>(null); const timelineRef = useRef<HTMLDivElement>(null);
const leftHandleRef = useRef<HTMLDivElement>(null); const leftHandleRef = useRef<HTMLDivElement>(null);
@ -1108,11 +1110,13 @@ const TimelineControls = ({
// Handle timeline click to seek and show a tooltip // Handle timeline click to seek and show a tooltip
const handleTimelineClick = (e: React.MouseEvent<HTMLDivElement>) => { const handleTimelineClick = (e: React.MouseEvent<HTMLDivElement>) => {
// Prevent interaction if segments are playing
if (isPlayingSegments) return;
if (!timelineRef.current || !scrollContainerRef.current) return; if (!timelineRef.current || !scrollContainerRef.current) return;
// If on mobile device and video hasn't been initialized, don't handle timeline clicks // If on mobile device and video hasn't been initialized, don't handle timeline clicks
if (isIOSUninitialized) { if (isIOSUninitialized) {
// Don't do anything on timeline click if mobile device hasn't been initialized
return; return;
} }
@ -1238,6 +1242,9 @@ const TimelineControls = ({
// Handle segment resize - works with both mouse and touch events // Handle segment resize - works with both mouse and touch events
const handleSegmentResize = (segmentId: number, isLeft: boolean) => (e: React.MouseEvent | React.TouchEvent) => { const handleSegmentResize = (segmentId: number, isLeft: boolean) => (e: React.MouseEvent | React.TouchEvent) => {
// Prevent interaction if segments are playing
if (isPlayingSegments) return;
e.preventDefault(); e.preventDefault();
e.stopPropagation(); // Prevent triggering parent's events e.stopPropagation(); // Prevent triggering parent's events
@ -1571,6 +1578,9 @@ const TimelineControls = ({
// Handle segment click to show the tooltip // Handle segment click to show the tooltip
const handleSegmentClick = (segmentId: number) => (e: React.MouseEvent) => { const handleSegmentClick = (segmentId: number) => (e: React.MouseEvent) => {
// Prevent interaction if segments are playing
if (isPlayingSegments) return;
// Don't show tooltip if clicked on handle // Don't show tooltip if clicked on handle
if ((e.target as HTMLElement).classList.contains('clip-segment-handle')) { if ((e.target as HTMLElement).classList.contains('clip-segment-handle')) {
return; return;
@ -2235,7 +2245,7 @@ const TimelineControls = ({
}, [showSuccessModal, redirectUrl, onSave]); }, [showSuccessModal, redirectUrl, onSave]);
return ( return (
<div className={`timeline-container-card ${isPreviewMode ? 'preview-mode' : ''}`}> <div className={`timeline-container-card ${isPlayingSegments ? 'segments-playback-mode' : ''}`}>
{/* Current Timecode with Milliseconds */} {/* Current Timecode with Milliseconds */}
<div className="timeline-header"> <div className="timeline-header">
<div className="timeline-title"> <div className="timeline-title">
@ -2250,10 +2260,11 @@ const TimelineControls = ({
{/* Timeline Container with Scrollable Wrapper */} {/* Timeline Container with Scrollable Wrapper */}
<div <div
ref={scrollContainerRef} ref={scrollContainerRef}
className="timeline-scroll-container" className={`timeline-scroll-container ${isPlayingSegments ? 'segments-playback-mode' : ''}`}
style={{ style={{
overflow: zoomLevel > 1 ? 'auto' : 'hidden' overflow: zoomLevel > 1 ? 'auto' : 'hidden'
}}> }}
>
<div <div
ref={timelineRef} ref={timelineRef}
className="timeline-container" className="timeline-container"
@ -2342,7 +2353,7 @@ const TimelineControls = ({
{/* Segment Tooltip */} {/* Segment Tooltip */}
{selectedSegmentId !== null && ( {selectedSegmentId !== null && (
<div <div
className={`segment-tooltip two-row-tooltip ${isPreviewMode ? 'preview-mode' : ''}`} className={`segment-tooltip two-row-tooltip ${isPlayingSegments ? 'segments-playback-mode' : ''}`}
style={{ style={{
position: 'absolute', position: 'absolute',
...constrainTooltipPosition(currentTimePercent) ...constrainTooltipPosition(currentTimePercent)
@ -2639,7 +2650,7 @@ const TimelineControls = ({
{/* Empty space tooltip - positioned absolutely within timeline container */} {/* Empty space tooltip - positioned absolutely within timeline container */}
{showEmptySpaceTooltip && selectedSegmentId === null && ( {showEmptySpaceTooltip && selectedSegmentId === null && (
<div <div
className={`empty-space-tooltip two-row-tooltip ${isPreviewMode ? 'preview-mode' : ''}`} className={`empty-space-tooltip two-row-tooltip ${isPlayingSegments ? 'segments-playback-mode' : ''}`}
style={{ style={{
position: 'absolute', position: 'absolute',
...constrainTooltipPosition(currentTimePercent) ...constrainTooltipPosition(currentTimePercent)

View File

@ -850,4 +850,58 @@
box-shadow: none; box-shadow: none;
border-color: rgba(0, 0, 0, 0.15); border-color: rgba(0, 0, 0, 0.15);
background-color: inherit !important; background-color: inherit !important;
}
/* Segments playback mode styles */
.segments-playback-mode {
pointer-events: none;
cursor: not-allowed;
}
.segments-playback-mode .timeline-container,
.segments-playback-mode .clip-segment,
.segments-playback-mode .clip-segment-handle,
.segments-playback-mode .timeline-marker-head,
.segments-playback-mode .timeline-marker-drag,
.segments-playback-mode .trim-handle {
pointer-events: none;
cursor: not-allowed;
}
.segments-playback-mode .tooltip-action-btn {
opacity: 0.5;
pointer-events: none;
cursor: not-allowed;
}
.segments-playback-mode .tooltip-time-btn {
opacity: 0.5;
pointer-events: none;
cursor: not-allowed;
}
.segments-playback-mode .clip-segment:hover {
box-shadow: none;
border-color: rgba(0, 0, 0, 0.15);
background-color: inherit !important;
}
/* Show segments playback message */
.segments-playback-message {
display: flex;
align-items: center;
background-color: rgba(59, 130, 246, 0.1);
color: #3b82f6;
padding: 6px 12px;
border-radius: 4px;
font-weight: 600;
font-size: 0.875rem;
animation: pulse 2s infinite;
}
.segments-playback-message svg {
height: 1.25rem;
width: 1.25rem;
margin-right: 0.5rem;
color: #3b82f6;
} }