diff options
Diffstat (limited to 'apps/web/src/lib/timeline/placement/resolve.ts')
| -rw-r--r-- | apps/web/src/lib/timeline/placement/resolve.ts | 277 |
1 files changed, 0 insertions, 277 deletions
diff --git a/apps/web/src/lib/timeline/placement/resolve.ts b/apps/web/src/lib/timeline/placement/resolve.ts deleted file mode 100644 index 67943912..00000000 --- a/apps/web/src/lib/timeline/placement/resolve.ts +++ /dev/null @@ -1,277 +0,0 @@ -import type { SceneTracks, TrackType, TimelineTrack } from "@/lib/timeline"; -import { - getDefaultInsertIndexForTrack, - getHighestInsertIndexForTrack, - resolvePreferredNewTrackPlacement, -} from "./insert-index"; -import { getTrackTypeForElementType } from "./compatibility"; -import { enforceMainTrackStart } from "./main-track"; -import { canPlaceTimeSpansOnTrack } from "./overlap"; -import type { - PlacementResult, - PlacementStrategy, - PlacementSubject, - PlacementTimeSpan, -} from "./types"; - -type ResolveTrackPlacementParams = PlacementSubject & { - tracks: SceneTracks; - timeSpans: PlacementTimeSpan[]; - strategy: PlacementStrategy; -}; - -function buildExistingTrackResult({ - track, - trackIndex, - tracks, - timeSpans, -}: { - track: TimelineTrack; - trackIndex: number; - tracks: SceneTracks; - timeSpans: PlacementTimeSpan[]; -}): PlacementResult { - const firstSpan = timeSpans[0]; - const requestedStartTime = firstSpan?.startTime ?? 0; - const adjustedStartTime = enforceMainTrackStart({ - tracks, - targetTrackId: track.id, - requestedStartTime, - excludeElementId: firstSpan?.excludeElementId, - }); - return { - kind: "existingTrack", - trackId: track.id, - trackIndex, - trackType: track.type, - ...(adjustedStartTime !== requestedStartTime ? { adjustedStartTime } : {}), - }; -} - -function buildNewTrackResult({ - trackType, - insertIndex, - insertPosition, -}: { - trackType: TrackType; - insertIndex: number; - insertPosition: "above" | "below" | null; -}): PlacementResult { - return { - kind: "newTrack", - trackType, - insertIndex, - insertPosition, - }; -} - -function findFirstAvailableTrackIndex({ - tracks, - trackType, - timeSpans, -}: { - tracks: TimelineTrack[]; - trackType: TrackType; - timeSpans: PlacementTimeSpan[]; -}): number { - return tracks.findIndex((track) => { - return ( - track.type === trackType && - canPlaceTimeSpansOnTrack({ - track, - timeSpans, - }) - ); - }); -} - -function resolveAlwaysNewTrack({ - tracks, - trackType, - position, -}: { - tracks: SceneTracks; - trackType: TrackType; - position: "highest" | "default"; -}): PlacementResult { - const insertIndex = - position === "highest" - ? getHighestInsertIndexForTrack({ - tracks, - trackType, - }) - : getDefaultInsertIndexForTrack({ - tracks, - trackType, - }); - - return buildNewTrackResult({ - trackType, - insertIndex, - insertPosition: null, - }); -} - -function getInsertDirection({ - hoverDirection, - verticalDragDirection, -}: { - hoverDirection: "above" | "below"; - verticalDragDirection?: "up" | "down" | null; -}): "above" | "below" { - if (verticalDragDirection === "up") { - return "above"; - } - - if (verticalDragDirection === "down") { - return "below"; - } - - return hoverDirection; -} - -export function resolveTrackPlacement({ - tracks, - ...placement -}: ResolveTrackPlacementParams): PlacementResult | null { - const orderedTracks = [...tracks.overlay, tracks.main, ...tracks.audio]; - const trackType = - "trackType" in placement - ? placement.trackType - : getTrackTypeForElementType({ - elementType: placement.elementType, - }); - const { timeSpans, strategy } = placement; - - if (strategy.type === "explicit") { - const trackIndex = orderedTracks.findIndex( - (track) => track.id === strategy.trackId, - ); - if (trackIndex < 0) { - return null; - } - - const track = orderedTracks[trackIndex]; - if (track.type !== trackType) { - return null; - } - - return buildExistingTrackResult({ - track, - trackIndex, - tracks, - timeSpans, - }); - } - - if (strategy.type === "firstAvailable") { - const existingTrackIndex = findFirstAvailableTrackIndex({ - tracks: orderedTracks, - trackType, - timeSpans, - }); - if (existingTrackIndex >= 0) { - return buildExistingTrackResult({ - track: orderedTracks[existingTrackIndex], - trackIndex: existingTrackIndex, - tracks, - timeSpans, - }); - } - - return resolveAlwaysNewTrack({ - tracks, - trackType, - position: "highest", - }); - } - - if (strategy.type === "preferIndex") { - const preferredTrack = orderedTracks[strategy.trackIndex]; - const isPreferredTrackCompatible = - !!preferredTrack && preferredTrack.type === trackType; - const canUseExistingTrack = - !strategy.createNewTrackOnly && - isPreferredTrackCompatible && - canPlaceTimeSpansOnTrack({ - track: preferredTrack, - timeSpans, - }); - if (canUseExistingTrack) { - return buildExistingTrackResult({ - track: preferredTrack, - trackIndex: strategy.trackIndex, - tracks, - timeSpans, - }); - } - - const { insertIndex, insertPosition } = resolvePreferredNewTrackPlacement({ - tracks, - trackType, - preferredIndex: strategy.trackIndex, - direction: getInsertDirection({ - hoverDirection: strategy.hoverDirection, - verticalDragDirection: !isPreferredTrackCompatible - ? strategy.verticalDragDirection - : null, - }), - }); - return buildNewTrackResult({ - trackType, - insertIndex, - insertPosition, - }); - } - - if (strategy.type === "aboveSource") { - const aboveTrackIndex = strategy.sourceTrackIndex - 1; - const aboveTrack = orderedTracks[aboveTrackIndex]; - if ( - aboveTrack && - aboveTrack.type === trackType && - canPlaceTimeSpansOnTrack({ - track: aboveTrack, - timeSpans, - }) - ) { - return buildExistingTrackResult({ - track: aboveTrack, - trackIndex: aboveTrackIndex, - tracks, - timeSpans, - }); - } - - const firstAvailableTrackIndex = findFirstAvailableTrackIndex({ - tracks: orderedTracks, - trackType, - timeSpans, - }); - if (firstAvailableTrackIndex >= 0) { - return buildExistingTrackResult({ - track: orderedTracks[firstAvailableTrackIndex], - trackIndex: firstAvailableTrackIndex, - tracks, - timeSpans, - }); - } - - const insertIndex = getHighestInsertIndexForTrack({ - tracks, - trackType, - }); - - return buildNewTrackResult({ - trackType, - insertIndex, - insertPosition: null, - }); - } - - return resolveAlwaysNewTrack({ - tracks, - trackType, - position: strategy.position, - }); -} |
