diff options
| author | Maze Winther <mazewinther@gmail.com> | 2025-09-03 00:02:07 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2025-09-03 00:02:07 +0200 |
| commit | 60debe2ce52a73dc554a0daa0a127fc836ca123a (patch) | |
| tree | 9c334f5de4211d0bb7893929ea63c86280679705 /apps/web/src/components/editor/timeline/timeline-cache-indicator.tsx | |
| parent | 37d40148087fc7c3497fba31e82bc7c7496bde8d (diff) | |
| parent | 167e2b83dc072f5d80ab0bf0d3f786a993248c70 (diff) | |
| download | opencut-60debe2ce52a73dc554a0daa0a127fc836ca123a.tar.gz | |
Merge branch 'staging'
Diffstat (limited to 'apps/web/src/components/editor/timeline/timeline-cache-indicator.tsx')
| -rw-r--r-- | apps/web/src/components/editor/timeline/timeline-cache-indicator.tsx | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/apps/web/src/components/editor/timeline/timeline-cache-indicator.tsx b/apps/web/src/components/editor/timeline/timeline-cache-indicator.tsx new file mode 100644 index 00000000..7def2985 --- /dev/null +++ b/apps/web/src/components/editor/timeline/timeline-cache-indicator.tsx @@ -0,0 +1,126 @@ +"use client"; + +import { cn } from "@/lib/utils"; +import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; +import { TimelineTrack } from "@/types/timeline"; +import { MediaFile } from "@/types/media"; +import { TProject } from "@/types/project"; +import { useSceneStore } from "@/stores/scene-store"; + +interface CacheSegment { + startTime: number; + endTime: number; + cached: boolean; +} + +interface TimelineCacheIndicatorProps { + duration: number; + zoomLevel: number; + tracks: TimelineTrack[]; + mediaFiles: MediaFile[]; + activeProject: TProject | null; + getRenderStatus: ( + time: number, + tracks: TimelineTrack[], + mediaFiles: MediaFile[], + activeProject: TProject | null, + sceneId?: string + ) => "cached" | "not-cached"; +} + +export function TimelineCacheIndicator({ + duration, + zoomLevel, + tracks, + mediaFiles, + activeProject, + getRenderStatus, +}: TimelineCacheIndicatorProps) { + const { currentScene } = useSceneStore(); + + // Calculate cache segments by sampling the timeline + const calculateCacheSegments = (): CacheSegment[] => { + const segments: CacheSegment[] = []; + const sampleRate = 10; // Sample every 0.1 seconds + const totalSamples = Math.ceil(duration * sampleRate); + + if (totalSamples === 0) { + return [{ startTime: 0, endTime: duration, cached: false }]; + } + + let currentSegment: CacheSegment | null = null; + + for (let i = 0; i <= totalSamples; i++) { + const time = i / sampleRate; + const cached = + getRenderStatus( + time, + tracks, + mediaFiles, + activeProject, + currentScene?.id + ) === "cached"; + + if (!currentSegment) { + // Start first segment + currentSegment = { + startTime: time, + endTime: time, + cached, + }; + } else if (currentSegment.cached === cached) { + // Extend current segment + currentSegment.endTime = time; + } else { + // Finish current segment and start new one + segments.push(currentSegment); + currentSegment = { + startTime: time, + endTime: time, + cached, + }; + } + } + + // Add the last segment + if (currentSegment) { + currentSegment.endTime = duration; + segments.push(currentSegment); + } + + return segments; + }; + + const cacheSegments = calculateCacheSegments(); + + return ( + <div className="absolute top-0 left-0 right-0 h-px z-10 pointer-events-none"> + {cacheSegments.map((segment, index) => { + const startX = + segment.startTime * TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel; + const endX = + segment.endTime * TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel; + const width = endX - startX; + + return ( + <div + key={index} + className={cn( + "absolute top-0 h-px", + segment.cached ? "bg-primary" : "bg-transparent" + )} + style={{ + left: `${startX}px`, + width: `${width}px`, + }} + title={ + segment.cached + ? "Cached (fast playback)" + : "Not cached (will render)" + } + /> + ); + })} + </div> + ); +} |
