Update
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
// TODO: I moved the sample timeline data to a dedicated file, and delayed the loading to 1 sec with useEffect. as such, alot of the ogics are broken. I need to make sure the delayed timeline should work like normal
|
||||
|
||||
import { useMitt } from '@/plugins/MittContext';
|
||||
import useVideoEditorStore from '@/stores/VideoEditorStore';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
@@ -16,8 +14,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
});
|
||||
|
||||
const [timelineElements, setTimelineElements] = useState([]);
|
||||
|
||||
// 🔧 FIX: Add ref to solve closure issue
|
||||
const timelineElementsRef = useRef([]);
|
||||
|
||||
const lastUpdateRef = useRef(0);
|
||||
@@ -39,12 +35,12 @@ const VideoEditor = ({ width, height }) => {
|
||||
|
||||
const FPS_INTERVAL = 1000 / 30; // 30 FPS
|
||||
|
||||
// 🔧 FIX: Keep ref synced with state
|
||||
// Keep ref synced with state
|
||||
useEffect(() => {
|
||||
timelineElementsRef.current = timelineElements;
|
||||
}, [timelineElements]);
|
||||
|
||||
// ✅ FIX 1: Use useEffect to automatically setup videos when timeline loads
|
||||
// Initialize timeline
|
||||
useEffect(() => {
|
||||
initTimeline();
|
||||
}, []);
|
||||
@@ -58,7 +54,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
});
|
||||
}, []);
|
||||
|
||||
// Add this useEffect to resolve the promise when timeline updates
|
||||
useEffect(() => {
|
||||
if (timelineUpdateResolverRef.current && timelineElements.length > 0) {
|
||||
timelineUpdateResolverRef.current();
|
||||
@@ -70,13 +65,35 @@ const VideoEditor = ({ width, height }) => {
|
||||
cleanupVideos(videoElements);
|
||||
setTimelineElementsAsync(sampleTimelineElements).then(() => {
|
||||
showConsoleLogs && console.log('Loaded sample timeline');
|
||||
|
||||
setupVideos();
|
||||
setupImages(); // Add image setup
|
||||
setupImages();
|
||||
});
|
||||
};
|
||||
|
||||
// ✅ NEW: Setup function for image elements
|
||||
// NEW: Handle element transformations (position, scale, rotation)
|
||||
const handleElementUpdate = useCallback(
|
||||
(elementId, updates) => {
|
||||
setTimelineElements((prev) =>
|
||||
prev.map((element) => {
|
||||
if (element.id === elementId) {
|
||||
return {
|
||||
...element,
|
||||
...updates,
|
||||
};
|
||||
}
|
||||
return element;
|
||||
}),
|
||||
);
|
||||
|
||||
// Force redraw if not playing
|
||||
if (!isPlaying && layerRef.current) {
|
||||
layerRef.current.batchDraw();
|
||||
}
|
||||
},
|
||||
[isPlaying],
|
||||
);
|
||||
|
||||
// Setup function for image elements
|
||||
const setupImages = () => {
|
||||
showConsoleLogs && console.log('setupImages');
|
||||
|
||||
@@ -108,7 +125,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
let scaledWidth = imgWidth;
|
||||
let scaledHeight = imgHeight;
|
||||
|
||||
// Scale down if image is larger than canvas
|
||||
if (imgWidth > maxWidth || imgHeight > maxHeight) {
|
||||
const scaleX = maxWidth / imgWidth;
|
||||
const scaleY = maxHeight / imgHeight;
|
||||
@@ -118,7 +134,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
scaledHeight = imgHeight * scale;
|
||||
}
|
||||
|
||||
// Use provided position or center the image
|
||||
const centeredX = element.x || (maxWidth - scaledWidth) / 2;
|
||||
const centeredY = element.y || (maxHeight - scaledHeight) / 2;
|
||||
|
||||
@@ -131,6 +146,7 @@ const VideoEditor = ({ width, height }) => {
|
||||
y: centeredY,
|
||||
width: element.width || scaledWidth,
|
||||
height: element.height || scaledHeight,
|
||||
rotation: element.rotation || 0,
|
||||
imageElement: img,
|
||||
isImageReady: true,
|
||||
};
|
||||
@@ -153,7 +169,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
});
|
||||
};
|
||||
|
||||
// ✅ FIX 3: Auto-update status when videos load
|
||||
useEffect(() => {
|
||||
setupVideoStatus();
|
||||
}, [timelineElements, loadedVideos]);
|
||||
@@ -164,7 +179,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
|
||||
const totalDuration = Math.max(...timelineElements.map((el) => el.startTime + el.duration));
|
||||
|
||||
// Use the FFmpeg hook
|
||||
const { isExporting, exportProgress, exportStatus, ffmpegCommand, copyFFmpegCommand, exportVideo } = useVideoExport({
|
||||
timelineElements,
|
||||
dimensions,
|
||||
@@ -174,7 +188,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
const setupVideos = () => {
|
||||
showConsoleLogs && console.log('setupVideos');
|
||||
|
||||
// 🔧 FIX: Read from ref instead of state to get latest data
|
||||
const elements = timelineElementsRef.current;
|
||||
|
||||
if (elements.length === 0) {
|
||||
@@ -246,6 +259,7 @@ const VideoEditor = ({ width, height }) => {
|
||||
y: centeredY,
|
||||
width: scaledWidth,
|
||||
height: scaledHeight,
|
||||
rotation: element.rotation || 0,
|
||||
posterImage: posterImg,
|
||||
isVideoPoster: true,
|
||||
};
|
||||
@@ -311,7 +325,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
};
|
||||
|
||||
const setupVideoStatus = () => {
|
||||
// Update to count both videos and images
|
||||
const mediaCount = timelineElements.filter((el) => el.type === 'video' || el.type === 'image').length;
|
||||
if (loadedVideos.size === mediaCount && mediaCount > 0) {
|
||||
setStatus('Ready to play');
|
||||
@@ -322,7 +335,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
}
|
||||
};
|
||||
|
||||
// FIXED: Removed currentTime dependency to prevent excessive recreation
|
||||
const handlePause = useCallback(() => {
|
||||
if (isPlaying) {
|
||||
setIsPlaying(false);
|
||||
@@ -412,7 +424,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
setVideoStates(desiredStates);
|
||||
}, [currentTime, isPlaying, videoElements, getDesiredVideoStates]);
|
||||
|
||||
// FIXED: Properly stop animation when not playing
|
||||
useEffect(() => {
|
||||
if (!isPlaying) {
|
||||
if (animationRef.current) {
|
||||
@@ -466,7 +477,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
};
|
||||
}, [isPlaying, totalDuration, handlePause, updateVideoTimes]);
|
||||
|
||||
// FIXED: Stabilized handlers
|
||||
const handlePlay = useCallback(() => {
|
||||
if (!isPlaying) {
|
||||
setIsPlaying(true);
|
||||
@@ -504,7 +514,6 @@ const VideoEditor = ({ width, height }) => {
|
||||
|
||||
const activeElements = getActiveElements(currentTime);
|
||||
|
||||
// FIXED: Added missing dependencies to event listeners
|
||||
useEffect(() => {
|
||||
emitter.on('video-play', handlePlay);
|
||||
emitter.on('video-reset', handleReset);
|
||||
@@ -540,6 +549,7 @@ const VideoEditor = ({ width, height }) => {
|
||||
handleSeek={handleSeek}
|
||||
copyFFmpegCommand={copyFFmpegCommand}
|
||||
exportVideo={exportVideo}
|
||||
onElementUpdate={handleElementUpdate} // NEW: Pass the update handler
|
||||
layerRef={layerRef}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user