fix: Disable Segment Tools and Reset Preview State During Playback

This commit is contained in:
Yiannis Christodoulou 2025-06-23 20:02:12 +03:00
parent a5acce4ab1
commit 1505a155e6
11 changed files with 137 additions and 351 deletions

2
.gitignore vendored
View File

@ -25,3 +25,5 @@ yt.readme.md
frontend-tools/.DS_Store
static/video_editor/videos/sample-video-30s.mp4
static/video_editor/videos/sample-video-37s.mp4
/frontend-tools/video-editor-v2
.DS_Store

View File

@ -10,3 +10,6 @@ client/public/videos/sample-video-30s.mp4
client/public/videos/sample-video-37s.mp4
videos/sample-video-37s.mp4
client/public/videos/sample-video-30s.mp4
client/public/videos/sample-video-1.mp4
client/public/videos/sample-video-10m.mp4
client/public/videos/sample-video-10s.mp4

View File

@ -16,7 +16,6 @@ const App = () => {
isPlaying,
setIsPlaying,
isMuted,
isPreviewMode,
thumbnails,
trimStart,
trimEnd,
@ -34,7 +33,6 @@ const App = () => {
handleReset,
handleUndo,
handleRedo,
handlePreview,
toggleMute,
handleSave,
handleSaveACopy,
@ -251,10 +249,8 @@ const App = () => {
onReset={handleReset}
onUndo={handleUndo}
onRedo={handleRedo}
onPreview={handlePreview}
onPlaySegments={handlePlaySegments}
onPlay={handlePlay}
isPreviewMode={isPreviewMode}
isPlaying={isPlaying}
isPlayingSegments={isPlayingSegments}
canUndo={historyPosition > 0}
@ -279,7 +275,6 @@ const App = () => {
onSave={handleSave}
onSaveACopy={handleSaveACopy}
onSaveSegments={handleSaveSegments}
isPreviewMode={isPreviewMode}
hasUnsavedChanges={hasUnsavedChanges}
isIOSUninitialized={isMobile && !videoInitialized}
isPlaying={isPlaying}

View File

@ -6,12 +6,10 @@ interface EditingToolsProps {
onReset: () => void;
onUndo: () => void;
onRedo: () => void;
onPreview: () => void;
onPlaySegments: () => void;
onPlay: () => void;
canUndo: boolean;
canRedo: boolean;
isPreviewMode?: boolean;
isPlaying?: boolean;
isPlayingSegments?: boolean;
}
@ -21,12 +19,10 @@ const EditingTools = ({
onReset,
onUndo,
onRedo,
onPreview,
onPlaySegments,
onPlay,
canUndo,
canRedo,
isPreviewMode = false,
isPlaying = false,
isPlayingSegments = false,
}: EditingToolsProps) => {
@ -116,8 +112,8 @@ const EditingTools = ({
)}
</button> */}
{/* Standard Play button (only shown when not in preview mode or segments playback) */}
{!isPreviewMode && (!isPlayingSegments || !isSmallScreen) && (
{/* Standard Play button (only shown when not in segments playback on small screens) */}
{(!isPlayingSegments || !isSmallScreen) && (
<button
className={`button play-button ${isPlayingSegments ? 'greyed-out' : ''}`}
onClick={handlePlay}
@ -125,7 +121,7 @@ const EditingTools = ({
style={{ fontSize: '0.875rem' }}
disabled={isPlayingSegments}
>
{isPlaying ? (
{isPlaying && !isPlayingSegments ? (
<>
<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" />

View File

@ -37,7 +37,7 @@ const IOSVideoPlayer = ({
}
} else {
// Fallback to sample video if needed
setVideoUrl("/videos/sample-video-37s.mp4");
setVideoUrl("/videos/sample-video-10m.mp4");
}
}, [videoRef]);

View File

@ -43,7 +43,6 @@ interface TimelineControlsProps {
onSave?: () => void;
onSaveACopy?: () => void;
onSaveSegments?: () => void;
isPreviewMode?: boolean;
hasUnsavedChanges?: boolean;
isIOSUninitialized?: boolean;
isPlaying: boolean;
@ -116,7 +115,6 @@ const TimelineControls = ({
onSave,
onSaveACopy,
onSaveSegments,
isPreviewMode,
hasUnsavedChanges = false,
isIOSUninitialized = false,
isPlaying,
@ -572,12 +570,11 @@ const TimelineControls = ({
useEffect(() => {
// Skip if no video or no active segment
const video = videoRef.current;
if (!video || !activeSegment || !isPlayingSegment || isPreviewMode) {
if (!video || !activeSegment || !isPlayingSegment) {
// Log why we're skipping
if (!video) logger.debug("Skipping segment boundary check - no video element");
else if (!activeSegment) logger.debug("Skipping segment boundary check - no active segment");
else if (!isPlayingSegment) logger.debug("Skipping segment boundary check - not in segment playback mode");
else if (isPreviewMode) logger.debug("Skipping segment boundary check in preview mode");
else if (!activeSegment) logger.debug("Skipping segment boundary check - no active segment");
else if (!isPlayingSegment) logger.debug("Skipping segment boundary check - not in segment playback mode");
return;
}
@ -664,7 +661,7 @@ const TimelineControls = ({
video.removeEventListener('timeupdate', handleTimeUpdate);
logger.debug("Segment boundary check DEACTIVATED");
};
}, [activeSegment, isPlayingSegment, isPreviewMode, continuePastBoundary, clipSegments]);
}, [activeSegment, isPlayingSegment, continuePastBoundary, clipSegments]);
// Update display time and check for transitions between segments and empty spaces
useEffect(() => {
@ -1231,10 +1228,8 @@ const TimelineControls = ({
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) {
// Resume playback if it was playing before (but not during segments playback)
else if (wasPlaying && !isPlayingSegments) {
logger.debug("Resuming playback after timeline click");
videoRef.current.play()
.then(() => {
@ -1581,17 +1576,7 @@ const TimelineControls = ({
else if (!wasInsideSegmentBefore && isInsideSegment) {
logger.debug("Playhead moved INTO segment during drag - can start playback");
setActiveSegment(segment);
// In preview mode, we automatically start playing when playhead enters segment
if (isPreviewMode) {
videoRef.current.play()
.then(() => {
setIsPlayingSegment(true);
logger.debug("Started playback after dragging segment to include playhead");
})
.catch(err => {
console.error("Error starting playback:", err);
});
}
// Removed automatic playback - user needs to manually start playback
}
// Another special case: playhead was inside segment before, but now is also inside but at a different position
else if (wasInsideSegmentBefore && isInsideSegment &&
@ -1738,8 +1723,8 @@ const TimelineControls = ({
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) {
// If video was playing before, ensure it continues playing (but not in segments mode)
else if (wasPlaying && !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
@ -1754,18 +1739,7 @@ const TimelineControls = ({
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);
});
}
// Removed preview mode playback - preview functionality replaced by segments playback
}
// Calculate tooltip position directly above click point
@ -2448,15 +2422,16 @@ const TimelineControls = ({
{/* First row with time adjustment buttons */}
<div className="tooltip-row">
<button
className="tooltip-time-btn"
data-tooltip="Seek -50ms (click or hold)"
{...handleContinuousTimeAdjustment(-0.05)}
className={`tooltip-time-btn ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Seek -50ms (click or hold)"}
disabled={isPlayingSegments}
{...(!isPlayingSegments ? handleContinuousTimeAdjustment(-0.05) : {})}
style={{
userSelect: 'none',
WebkitUserSelect: 'none',
WebkitTouchCallout: 'none',
touchAction: 'manipulation',
cursor: 'pointer',
cursor: isPlayingSegments ? 'not-allowed' : 'pointer',
WebkitTapHighlightColor: 'transparent'
}}
>
@ -2464,15 +2439,16 @@ const TimelineControls = ({
</button>
<div className="tooltip-time-display">{formatDetailedTime(displayTime)}</div>
<button
className="tooltip-time-btn"
data-tooltip="Seek +50ms (click or hold)"
{...handleContinuousTimeAdjustment(0.05)}
className={`tooltip-time-btn ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Seek +50ms (click or hold)"}
disabled={isPlayingSegments}
{...(!isPlayingSegments ? handleContinuousTimeAdjustment(0.05) : {})}
style={{
userSelect: 'none',
WebkitUserSelect: 'none',
WebkitTouchCallout: 'none',
touchAction: 'manipulation',
cursor: 'pointer',
cursor: isPlayingSegments ? 'not-allowed' : 'pointer',
WebkitTapHighlightColor: 'transparent'
}}
>
@ -2483,8 +2459,9 @@ const TimelineControls = ({
{/* Second row with action buttons */}
<div className="tooltip-row tooltip-actions">
<button
className="tooltip-action-btn delete"
data-tooltip="Delete segment"
className={`tooltip-action-btn delete ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Delete segment"}
disabled={isPlayingSegments}
onClick={(e) => {
e.stopPropagation();
// Call the delete segment function with the current segment ID
@ -2505,8 +2482,9 @@ const TimelineControls = ({
</svg>
</button>
<button
className="tooltip-action-btn scissors"
data-tooltip="Split segment at current position"
className={`tooltip-action-btn scissors ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Split segment at current position"}
disabled={isPlayingSegments}
onClick={(e) => {
e.stopPropagation();
// Call the split segment function with the current segment ID and time
@ -2530,8 +2508,9 @@ const TimelineControls = ({
</svg>
</button>
<button
className="tooltip-action-btn play-from-start"
data-tooltip="Play segment from beginning"
className={`tooltip-action-btn play-from-start ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Play segment from beginning"}
disabled={isPlayingSegments}
onClick={(e) => {
e.stopPropagation();
@ -2626,8 +2605,9 @@ const TimelineControls = ({
{/* Play/Pause button for empty space - Same as main play/pause button */}
<button
className={`tooltip-action-btn ${isPlaying ? 'pause' : 'play'}`}
data-tooltip={isPlaying ? "Pause playback" : "Play from current position"}
className={`tooltip-action-btn ${isPlaying ? 'pause' : 'play'} ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : (isPlaying ? "Pause playback" : "Play from current position")}
disabled={isPlayingSegments}
onClick={(e) => {
e.stopPropagation();
@ -2654,8 +2634,9 @@ const TimelineControls = ({
</button>
<button
className="tooltip-action-btn set-in"
data-tooltip="Set start point at current position"
className={`tooltip-action-btn set-in ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Set start point at current position"}
disabled={isPlayingSegments}
onClick={(e) => {
e.stopPropagation();
@ -2692,8 +2673,9 @@ const TimelineControls = ({
<img src={segmentStartIcon} alt="Set start point" style={{width: '24px', height: '24px'}} />
</button>
<button
className="tooltip-action-btn set-out"
data-tooltip="Set end point at current position"
className={`tooltip-action-btn set-out ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Set end point at current position"}
disabled={isPlayingSegments}
onClick={(e) => {
e.stopPropagation();
@ -2745,17 +2727,35 @@ const TimelineControls = ({
{/* First row with time adjustment buttons - same as segment tooltip */}
<div className="tooltip-row">
<button
className="tooltip-time-btn"
data-tooltip="Seek -50ms (click or hold)"
{...handleContinuousTimeAdjustment(-0.05)}
className={`tooltip-time-btn ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Seek -50ms (click or hold)"}
disabled={isPlayingSegments}
{...(!isPlayingSegments ? handleContinuousTimeAdjustment(-0.05) : {})}
style={{
userSelect: 'none',
WebkitUserSelect: 'none',
WebkitTouchCallout: 'none',
touchAction: 'manipulation',
cursor: isPlayingSegments ? 'not-allowed' : 'pointer',
WebkitTapHighlightColor: 'transparent'
}}
>
-50ms
</button>
<div className="tooltip-time-display">{formatDetailedTime(clickedTime)}</div>
<button
className="tooltip-time-btn"
data-tooltip="Seek +50ms (click or hold)"
{...handleContinuousTimeAdjustment(0.05)}
className={`tooltip-time-btn ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Seek +50ms (click or hold)"}
disabled={isPlayingSegments}
{...(!isPlayingSegments ? handleContinuousTimeAdjustment(0.05) : {})}
style={{
userSelect: 'none',
WebkitUserSelect: 'none',
WebkitTouchCallout: 'none',
touchAction: 'manipulation',
cursor: isPlayingSegments ? 'not-allowed' : 'pointer',
WebkitTapHighlightColor: 'transparent'
}}
>
+50ms
</button>
@ -2765,9 +2765,9 @@ const TimelineControls = ({
<div className="tooltip-row tooltip-actions">
{/* New segment button - Moved to first position */}
<button
className={`tooltip-action-btn new-segment ${availableSegmentDuration < 0.5 ? 'disabled' : ''}`}
data-tooltip={availableSegmentDuration < 0.5 ? 'Not enough space for new segment' : 'Create new segment'}
disabled={availableSegmentDuration < 0.5}
className={`tooltip-action-btn new-segment ${availableSegmentDuration < 0.5 || isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? 'Disabled during preview' : (availableSegmentDuration < 0.5 ? 'Not enough space for new segment' : 'Create new segment')}
disabled={availableSegmentDuration < 0.5 || isPlayingSegments}
onClick={async (e) => {
e.stopPropagation();
@ -2831,8 +2831,9 @@ const TimelineControls = ({
{/* Go to start button - play from beginning of cutaway (until next segment) */}
<button
className="tooltip-action-btn play-from-start"
data-tooltip="Play from beginning of cutaway"
className={`tooltip-action-btn play-from-start ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Play from beginning of cutaway"}
disabled={isPlayingSegments}
onClick={(e) => {
e.stopPropagation();
@ -3283,8 +3284,9 @@ const TimelineControls = ({
{/* Play/Pause button for empty space - Same as main play/pause button */}
<button
className={`tooltip-action-btn ${isPlaying ? 'pause' : 'play'}`}
data-tooltip={isPlaying ? "Pause playback" : "Play from here until next segment"}
className={`tooltip-action-btn ${isPlaying ? 'pause' : 'play'} ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : (isPlaying ? "Pause playback" : "Play from here until next segment")}
disabled={isPlayingSegments}
onClick={(e) => {
e.stopPropagation();
@ -3312,8 +3314,9 @@ const TimelineControls = ({
{/* Segment end adjustment button (always shown) */}
<button
className="tooltip-action-btn segment-end"
data-tooltip="Adjust end of previous segment"
className={`tooltip-action-btn segment-end ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Adjust end of previous segment"}
disabled={isPlayingSegments}
onClick={(e) => {
e.stopPropagation();
@ -3489,8 +3492,9 @@ const TimelineControls = ({
{/* Segment start adjustment button (always shown) */}
<button
className="tooltip-action-btn segment-start"
data-tooltip="Adjust start of next segment"
className={`tooltip-action-btn segment-start ${isPlayingSegments ? 'disabled' : ''}`}
data-tooltip={isPlayingSegments ? "Disabled during preview" : "Adjust start of next segment"}
disabled={isPlayingSegments}
onClick={(e) => {
e.stopPropagation();

View File

@ -35,7 +35,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
const sampleVideoUrl = typeof window !== 'undefined' &&
(window as any).MEDIA_DATA?.videoUrl ||
"/videos/sample-video-37s.mp4";
"/videos/sample-video-10m.mp4";
// Detect iOS device
useEffect(() => {

View File

@ -21,9 +21,7 @@ const useVideoTrimmer = () => {
const [isPlaying, setIsPlaying] = useState(false);
const [isMuted, setIsMuted] = useState(false);
// Preview mode state for playing only segments
const [isPreviewMode, setIsPreviewMode] = useState(false);
const [previewSegmentIndex, setPreviewSegmentIndex] = useState(0);
// Removed preview mode - replaced by isPlayingSegments
// Timeline state
const [thumbnails, setThumbnails] = useState<string[]>([]);
@ -146,18 +144,12 @@ const useVideoTrimmer = () => {
};
const handlePlay = () => {
// Only update isPlaying if we're not in preview mode
if (!isPreviewMode) {
setIsPlaying(true);
setVideoInitialized(true);
}
setIsPlaying(true);
setVideoInitialized(true);
};
const handlePause = () => {
// Only update isPlaying if we're not in preview mode
if (!isPreviewMode) {
setIsPlaying(false);
}
setIsPlaying(false);
};
const handleEnded = () => {
@ -180,7 +172,7 @@ const useVideoTrimmer = () => {
video.removeEventListener('pause', handlePause);
video.removeEventListener('ended', handleEnded);
};
}, [isPreviewMode]);
}, []);
// Play/pause video
const playPauseVideo = () => {
@ -226,9 +218,6 @@ const useVideoTrimmer = () => {
// Track if the video was playing before seeking
const wasPlaying = !video.paused;
// Store current preview mode state to preserve it
const wasInPreviewMode = isPreviewMode;
// Update the video position
video.currentTime = time;
setCurrentTime(time);
@ -239,36 +228,12 @@ const useVideoTrimmer = () => {
window.lastSeekedPosition = time;
}
// Find segment at this position for preview mode playback
if (wasInPreviewMode) {
const segmentAtPosition = clipSegments.find(
seg => time >= seg.startTime && time <= seg.endTime
);
if (segmentAtPosition) {
// Update the active segment index in preview mode
const orderedSegments = [...clipSegments].sort((a, b) => a.startTime - b.startTime);
const newSegmentIndex = orderedSegments.findIndex(seg => seg.id === segmentAtPosition.id);
if (newSegmentIndex !== -1) {
setPreviewSegmentIndex(newSegmentIndex);
}
}
}
// Resume playback in two scenarios:
// 1. If it was playing before (regular mode)
// 2. If we're in preview mode (regardless of previous state)
if (wasPlaying || wasInPreviewMode) {
// Ensure preview mode stays on if it was on before
if (wasInPreviewMode) {
setIsPreviewMode(true);
}
// Resume playback if it was playing before
if (wasPlaying) {
// Play immediately without delay
video.play()
.then(() => {
setIsPlaying(true); // Update state to reflect we're playing
// "Resumed playback after seeking in " + (wasInPreviewMode ? "preview" : "regular") + " mode"
})
.catch(err => {
console.error("Error resuming playback:", err);
@ -550,152 +515,9 @@ const useVideoTrimmer = () => {
};
}, [clipSegments, duration]);
// Preview mode effect to handle playing only segments
useEffect(() => {
if (!isPreviewMode || !videoRef.current) return;
// Sort segments by start time
const orderedSegments = [...clipSegments].sort((a, b) => a.startTime - b.startTime);
if (orderedSegments.length === 0) return;
const video = videoRef.current;
// Function to handle segment playback
const handleSegmentPlayback = () => {
if (!isPreviewMode || !video) return;
const currentSegment = orderedSegments[previewSegmentIndex];
if (!currentSegment) return;
const currentTime = video.currentTime;
// If we're before the current segment's start, jump to it
if (currentTime < currentSegment.startTime) {
video.currentTime = currentSegment.startTime;
return;
}
// If we've reached the end of the current segment
if (currentTime >= currentSegment.endTime - 0.01) { // Small threshold to ensure smooth transition
// Move to the next segment if available
if (previewSegmentIndex < orderedSegments.length - 1) {
// Play next segment
const nextSegment = orderedSegments[previewSegmentIndex + 1];
video.currentTime = nextSegment.startTime;
setPreviewSegmentIndex(previewSegmentIndex + 1);
logger.debug("Preview: Moving to next segment", {
from: formatDetailedTime(currentSegment.endTime),
to: formatDetailedTime(nextSegment.startTime),
segmentIndex: previewSegmentIndex + 1
});
} else {
// Loop back to first segment
logger.debug("Preview: Looping back to first segment");
video.currentTime = orderedSegments[0].startTime;
setPreviewSegmentIndex(0);
}
// Ensure playback continues
video.play().catch(err => {
console.error("Error continuing preview playback:", err);
});
}
};
// Add event listener for timeupdate to check segment boundaries
video.addEventListener('timeupdate', handleSegmentPlayback);
// Start playing if not already playing
if (video.paused) {
video.currentTime = orderedSegments[previewSegmentIndex].startTime;
video.play().catch(err => {
console.error("Error starting preview playback:", err);
});
}
return () => {
if (video) {
video.removeEventListener('timeupdate', handleSegmentPlayback);
}
};
}, [isPreviewMode, previewSegmentIndex, clipSegments]);
// Removed preview mode effect - functionality replaced by isPlayingSegments
// Handle starting preview mode
const handleStartPreview = () => {
const video = videoRef.current;
if (!video || clipSegments.length === 0) return;
// If preview is already active, do nothing
if (isPreviewMode) {
return;
}
// If normal playback is happening, pause it
if (isPlaying) {
video.pause();
setIsPlaying(false);
}
// Sort segments by start time
const orderedSegments = [...clipSegments].sort((a, b) => a.startTime - b.startTime);
if (orderedSegments.length === 0) return;
// Set the preview mode flag
setIsPreviewMode(true);
logger.debug("Entering preview mode");
// Set the first segment as the current one in the preview sequence
setPreviewSegmentIndex(0);
// Move to the start of the first segment
video.currentTime = orderedSegments[0].startTime;
};
// Handle playing/stopping preview mode
const handlePreview = () => {
const video = videoRef.current;
if (!video || clipSegments.length === 0) return;
// If preview is already active, turn it off
if (isPreviewMode) {
setIsPreviewMode(false);
// Always pause the video when exiting preview mode
video.pause();
setIsPlaying(false);
logger.debug("Exiting preview mode - video paused");
return;
}
// Sort segments by start time
const orderedSegments = [...clipSegments].sort((a, b) => a.startTime - b.startTime);
if (orderedSegments.length === 0) return;
// Set the preview mode flag
setIsPreviewMode(true);
logger.debug("Entering preview mode");
// Set the first segment as the current one in the preview sequence
setPreviewSegmentIndex(0);
// Start preview mode by playing the first segment
video.currentTime = orderedSegments[0].startTime;
// Start playback
video.play()
.then(() => {
setIsPlaying(true);
logger.debug("Preview started successfully");
})
.catch(err => {
console.error("Error starting preview:", err);
setIsPreviewMode(false);
setIsPlaying(false);
});
};
// Removed preview mode functions - replaced by handlePlaySegments
// Handle trim start change
const handleTrimStartChange = (time: number) => {
@ -820,16 +642,6 @@ const useVideoTrimmer = () => {
const video = videoRef.current;
if (!video) return;
// If in preview mode, exit it before toggling normal play
if (isPreviewMode) {
setIsPreviewMode(false);
// Don't immediately start playing when exiting preview mode
// Just update the state and return
setIsPlaying(false);
video.pause();
return;
}
if (isPlaying) {
// Pause the video
video.pause();
@ -1067,10 +879,7 @@ const useVideoTrimmer = () => {
setIsPlayingSegments(true);
setCurrentSegmentIndex(0);
// Exit preview mode if active
if (isPreviewMode) {
setIsPreviewMode(false);
}
// Start segments playback
// Sort segments by start time
const orderedSegments = [...clipSegments].sort((a, b) => a.startTime - b.startTime);
@ -1095,7 +904,6 @@ const useVideoTrimmer = () => {
isPlaying,
setIsPlaying,
isMuted,
isPreviewMode,
isPlayingSegments,
thumbnails,
trimStart,
@ -1114,7 +922,6 @@ const useVideoTrimmer = () => {
handleReset,
handleUndo,
handleRedo,
handlePreview,
handlePlaySegments,
toggleMute,
handleSave,

View File

@ -201,18 +201,7 @@
flex-shrink: 0;
}
/* Style for the preview mode message that replaces the play button */
.preview-mode-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;
}
/* Preview mode styles removed - replaced by segments playback mode */
@keyframes pulse {
0% {
@ -226,13 +215,6 @@
}
}
.preview-mode-message svg {
height: 1.25rem;
width: 1.25rem;
margin-right: 0.5rem;
color: #3b82f6;
}
/* Add responsive button text class */
.button-text {
margin-left: 0.25rem;
@ -340,11 +322,7 @@
padding: 0.25rem;
}
/* Smaller preview mode message */
.preview-mode-message {
font-size: 0.8rem;
padding: 4px 8px;
}
/* Removed preview mode message styles */
.divider {
margin: 0 0.25rem;

View File

@ -814,43 +814,7 @@
100% { opacity: 0.7; transform: scale(1); }
}
/* Preview mode styles */
.preview-mode .tooltip-action-btn {
opacity: 0.5;
pointer-events: none;
cursor: not-allowed;
}
.preview-mode .tooltip-time-btn {
opacity: 0.5;
pointer-events: none;
cursor: not-allowed;
}
/* Timeline preview mode styles */
.timeline-container-card.preview-mode {
pointer-events: none;
}
.timeline-container-card.preview-mode .timeline-marker-head,
.timeline-container-card.preview-mode .timeline-marker-drag,
.timeline-container-card.preview-mode .clip-segment,
.timeline-container-card.preview-mode .clip-segment-handle,
.timeline-container-card.preview-mode .time-button,
.timeline-container-card.preview-mode .zoom-button,
.timeline-container-card.preview-mode .save-button,
.timeline-container-card.preview-mode .save-copy-button,
.timeline-container-card.preview-mode .save-segments-button {
opacity: 0.5;
pointer-events: none;
cursor: not-allowed;
}
.timeline-container-card.preview-mode .clip-segment:hover {
box-shadow: none;
border-color: rgba(0, 0, 0, 0.15);
background-color: inherit !important;
}
/* Preview mode styles removed - replaced by segments playback mode */
/* Segments playback mode styles - minimal functional styling */
.segments-playback-mode .tooltip-time-btn {

View File

@ -227,6 +227,43 @@
color: #9ca3af;
}
/* Ensure pause button is properly styled when disabled */
.tooltip-action-btn.pause.disabled {
color: #9ca3af !important;
opacity: 0.5;
cursor: not-allowed;
}
.tooltip-action-btn.pause.disabled:hover {
background-color: #f3f4f6 !important;
color: #9ca3af !important;
}
/* Ensure play button is properly styled when disabled */
.tooltip-action-btn.play.disabled {
color: #9ca3af !important;
opacity: 0.5;
cursor: not-allowed;
}
.tooltip-action-btn.play.disabled:hover {
background-color: #f3f4f6 !important;
color: #9ca3af !important;
}
/* Ensure time adjustment buttons are properly styled when disabled */
.tooltip-time-btn.disabled {
opacity: 0.5 !important;
cursor: not-allowed !important;
background-color: #f3f4f6 !important;
color: #9ca3af !important;
}
.tooltip-time-btn.disabled:hover {
background-color: #f3f4f6 !important;
color: #9ca3af !important;
}
/* Additional mobile optimizations */
@media (max-width: 768px) {
.two-row-tooltip {