diff --git a/frontend-tools/video-editor/client/src/components/TimelineControls.tsx b/frontend-tools/video-editor/client/src/components/TimelineControls.tsx index ca1bf569..aaeca32c 100644 --- a/frontend-tools/video-editor/client/src/components/TimelineControls.tsx +++ b/frontend-tools/video-editor/client/src/components/TimelineControls.tsx @@ -1201,20 +1201,51 @@ const TimelineControls = ({ setActiveSegment(segmentAtClickedTime); } - // Resume playback in two cases: - // 1. If it was playing before (regular playback) - // 2. If we're in preview mode (regardless of previous playing state) - if ((wasPlaying || isPreviewMode) && videoRef.current) { - logger.debug("Resuming playback after timeline click"); - videoRef.current.play() - .then(() => { - setIsPlayingSegment(true); - logger.debug("Resumed playback after seeking"); - }) - .catch(err => { - console.error("Error resuming playback:", err); - setIsPlayingSegment(false); - }); + // Resume playback based on the current mode + if (videoRef.current) { + // Special handling for segments playback mode + if (isPlayingSegments && wasPlaying) { + // Update the current segment index if we clicked into a segment + if (segmentAtClickedTime) { + const orderedSegments = [...clipSegments].sort((a, b) => a.startTime - b.startTime); + const targetSegmentIndex = orderedSegments.findIndex(seg => seg.id === segmentAtClickedTime.id); + + if (targetSegmentIndex !== -1) { + // Dispatch a custom event to update the current segment index + const updateSegmentIndexEvent = new CustomEvent('update-segment-index', { + detail: { segmentIndex: targetSegmentIndex } + }); + document.dispatchEvent(updateSegmentIndexEvent); + logger.debug(`Segments playback mode: updating segment index to ${targetSegmentIndex} for timeline click in segment ${segmentAtClickedTime.id}`); + } + } + + logger.debug("Segments playback mode: resuming playback after timeline click"); + videoRef.current.play() + .then(() => { + setIsPlayingSegment(true); + logger.debug("Resumed segments playback after timeline seeking"); + }) + .catch(err => { + console.error("Error resuming segments playback:", err); + setIsPlayingSegment(false); + }); + } + // Resume playback in two cases (but not during segments playback): + // 1. If it was playing before (regular playback) + // 2. If we're in preview mode (regardless of previous playing state) + else if ((wasPlaying || isPreviewMode) && !isPlayingSegments) { + logger.debug("Resuming playback after timeline click"); + videoRef.current.play() + .then(() => { + setIsPlayingSegment(true); + logger.debug("Resumed playback after seeking"); + }) + .catch(err => { + console.error("Error resuming playback:", err); + setIsPlayingSegment(false); + }); + } } // Only process tooltip display if clicked on the timeline background or thumbnails, not on other UI elements @@ -1678,34 +1709,63 @@ const TimelineControls = ({ // Seek to this position (this will update the video's current time) onSeek(boundedTime); - // If video was playing before OR we're in preview mode, ensure it continues playing - if ((wasPlaying || isPreviewMode) && videoRef.current) { - // Set current segment as active segment for boundary checking - setActiveSegment(segment); - // Reset the continuePastBoundary flag when clicking on a segment to ensure boundaries work - setContinuePastBoundary(false); - // Continue playing from the new position - videoRef.current.play() - .then(() => { - setIsPlayingSegment(true); - logger.debug("Continued preview playback after segment click"); - }) - .catch(err => { - console.error("Error resuming playback after segment click:", err); - }); - } - - // Always continue playback in preview mode, even if video was paused when clicking - if (isPreviewMode && videoRef.current) { - setActiveSegment(segment); - videoRef.current.play() - .then(() => { - setIsPlayingSegment(true); - logger.debug("Continued preview playback after segment click"); - }) - .catch(err => { - console.error("Error continuing preview playback:", err); - }); + // Handle playback continuation based on the current mode + if (videoRef.current) { + // Special handling for segments playback mode + if (isPlayingSegments && wasPlaying) { + // Update the current segment index for segments playback mode + const orderedSegments = [...clipSegments].sort((a, b) => a.startTime - b.startTime); + const targetSegmentIndex = orderedSegments.findIndex(seg => seg.id === segmentId); + + if (targetSegmentIndex !== -1) { + // Dispatch a custom event to update the current segment index + const updateSegmentIndexEvent = new CustomEvent('update-segment-index', { + detail: { segmentIndex: targetSegmentIndex } + }); + document.dispatchEvent(updateSegmentIndexEvent); + logger.debug(`Segments playback mode: updating segment index to ${targetSegmentIndex} for segment ${segmentId}`); + } + + // In segments playback mode, we want to continue the segments playback from the new position + // The segments playback will naturally handle continuing to the next segments + logger.debug("Segments playback mode: continuing playback from new position"); + videoRef.current.play() + .then(() => { + setIsPlayingSegment(true); + logger.debug("Continued segments playback after segment click"); + }) + .catch(err => { + console.error("Error continuing segments playback after segment click:", err); + }); + } + // If video was playing before OR we're in preview mode, ensure it continues playing (but not in segments mode) + else if ((wasPlaying || isPreviewMode) && !isPlayingSegments) { + // Set current segment as active segment for boundary checking + setActiveSegment(segment); + // Reset the continuePastBoundary flag when clicking on a segment to ensure boundaries work + setContinuePastBoundary(false); + // Continue playing from the new position + videoRef.current.play() + .then(() => { + setIsPlayingSegment(true); + logger.debug("Continued preview playback after segment click"); + }) + .catch(err => { + console.error("Error resuming playback after segment click:", err); + }); + } + // Always continue playback in preview mode, even if video was paused when clicking (but not in segments mode) + else if (isPreviewMode && !isPlayingSegments) { + setActiveSegment(segment); + videoRef.current.play() + .then(() => { + setIsPlayingSegment(true); + logger.debug("Continued preview playback after segment click"); + }) + .catch(err => { + console.error("Error continuing preview playback:", err); + }); + } } // Calculate tooltip position directly above click point diff --git a/frontend-tools/video-editor/client/src/hooks/useVideoTrimmer.tsx b/frontend-tools/video-editor/client/src/hooks/useVideoTrimmer.tsx index 35aa8789..e5cf9296 100644 --- a/frontend-tools/video-editor/client/src/hooks/useVideoTrimmer.tsx +++ b/frontend-tools/video-editor/client/src/hooks/useVideoTrimmer.tsx @@ -1035,6 +1035,23 @@ const useVideoTrimmer = () => { }; }, [isPlayingSegments, currentSegmentIndex, clipSegments]); + // Effect to handle manual segment index updates during segments playback + useEffect(() => { + const handleSegmentIndexUpdate = (event: CustomEvent) => { + const { segmentIndex } = event.detail; + if (isPlayingSegments && segmentIndex !== currentSegmentIndex) { + logger.debug(`Updating current segment index from ${currentSegmentIndex} to ${segmentIndex}`); + setCurrentSegmentIndex(segmentIndex); + } + }; + + document.addEventListener('update-segment-index', handleSegmentIndexUpdate as EventListener); + + return () => { + document.removeEventListener('update-segment-index', handleSegmentIndexUpdate as EventListener); + }; + }, [isPlayingSegments, currentSegmentIndex]); + // Handle play segments const handlePlaySegments = () => { const video = videoRef.current; diff --git a/frontend-tools/video-editor/client/src/styles/TimelineControls.css b/frontend-tools/video-editor/client/src/styles/TimelineControls.css index 157f4bd8..a030b0e9 100644 --- a/frontend-tools/video-editor/client/src/styles/TimelineControls.css +++ b/frontend-tools/video-editor/client/src/styles/TimelineControls.css @@ -852,30 +852,23 @@ background-color: inherit !important; } -/* Segments playback mode styles */ -.segments-playback-mode { -} - -.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 { -} - -.segments-playback-mode .tooltip-action-btn { - opacity: 0.5; -} - +/* Segments playback mode styles - minimal functional styling */ .segments-playback-mode .tooltip-time-btn { - opacity: 0.5; + opacity: 1; + cursor: pointer; } -.segments-playback-mode .clip-segment:hover { - box-shadow: none; - border-color: rgba(0, 0, 0, 0.15); - background-color: inherit !important; +.segments-playback-mode .tooltip-action-btn.set-in, +.segments-playback-mode .tooltip-action-btn.set-out, +.segments-playback-mode .tooltip-action-btn.play-from-start { + opacity: 0.5; + pointer-events: none; +} + +.segments-playback-mode .tooltip-action-btn.play, +.segments-playback-mode .tooltip-action-btn.pause { + opacity: 1; + cursor: pointer; } /* Show segments playback message */