Files
OpenCut/apps/web/src/components/editor/timeline/timeline-cache-indicator.tsx
T

117 lines
3.0 KiB
TypeScript

"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";
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
) => "cached" | "not-cached";
}
export function TimelineCacheIndicator({
duration,
zoomLevel,
tracks,
mediaFiles,
activeProject,
getRenderStatus,
}: TimelineCacheIndicatorProps) {
// 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) === "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-border"
)}
style={{
left: `${startX}px`,
width: `${width}px`,
}}
title={
segment.cached
? "Cached (fast playback)"
: "Not cached (will render)"
}
/>
);
})}
</div>
);
}