diff options
Diffstat (limited to 'apps/web/src/lib/commands/timeline/element/update-element-trim.ts')
| -rw-r--r-- | apps/web/src/lib/commands/timeline/element/update-element-trim.ts | 92 |
1 files changed, 73 insertions, 19 deletions
diff --git a/apps/web/src/lib/commands/timeline/element/update-element-trim.ts b/apps/web/src/lib/commands/timeline/element/update-element-trim.ts index 99c63287..7548638a 100644 --- a/apps/web/src/lib/commands/timeline/element/update-element-trim.ts +++ b/apps/web/src/lib/commands/timeline/element/update-element-trim.ts @@ -1,18 +1,40 @@ import { Command } from "@/lib/commands/base-command"; import type { TimelineTrack } from "@/types/timeline"; import { EditorCore } from "@/core"; +import { clampAnimationsToDuration } from "@/lib/animation"; +import { rippleShiftElements } from "@/lib/timeline"; export class UpdateElementTrimCommand extends Command { private savedState: TimelineTrack[] | null = null; + private readonly elementId: string; + private readonly trimStart: number; + private readonly trimEnd: number; + private readonly startTime: number | undefined; + private readonly duration: number | undefined; + private readonly rippleEnabled: boolean; - constructor( - private elementId: string, - private trimStart: number, - private trimEnd: number, - private startTime?: number, - private duration?: number, - ) { + constructor({ + elementId, + trimStart, + trimEnd, + startTime, + duration, + rippleEnabled = false, + }: { + elementId: string; + trimStart: number; + trimEnd: number; + startTime?: number; + duration?: number; + rippleEnabled?: boolean; + }) { super(); + this.elementId = elementId; + this.trimStart = trimStart; + this.trimEnd = trimEnd; + this.startTime = startTime; + this.duration = duration; + this.rippleEnabled = rippleEnabled; } execute(): void { @@ -20,20 +42,52 @@ export class UpdateElementTrimCommand extends Command { this.savedState = editor.timeline.getTracks(); const updatedTracks = this.savedState.map((track) => { - const newElements = track.elements.map((element) => { - if (element.id !== this.elementId) { - return element; - } + const targetElement = track.elements.find( + (element) => element.id === this.elementId, + ); + if (!targetElement) return track; + const nextDuration = this.duration ?? targetElement.duration; + const nextStartTime = this.startTime ?? targetElement.startTime; + + const oldEndTime = targetElement.startTime + targetElement.duration; + const newEndTime = nextStartTime + nextDuration; + const shiftAmount = oldEndTime - newEndTime; + + const updatedElement = { + ...targetElement, + trimStart: this.trimStart, + trimEnd: this.trimEnd, + startTime: nextStartTime, + duration: nextDuration, + animations: clampAnimationsToDuration({ + animations: targetElement.animations, + duration: nextDuration, + }), + }; + + if (this.rippleEnabled && Math.abs(shiftAmount) > 0) { + const shiftedOthers = rippleShiftElements({ + elements: track.elements.filter((element) => element.id !== this.elementId), + afterTime: oldEndTime, + shiftAmount, + }); return { - ...element, - trimStart: this.trimStart, - trimEnd: this.trimEnd, - startTime: this.startTime ?? element.startTime, - duration: this.duration ?? element.duration, - }; - }); - return { ...track, elements: newElements } as typeof track; + ...track, + elements: track.elements.map((element) => + element.id === this.elementId + ? updatedElement + : (shiftedOthers.find((shifted) => shifted.id === element.id) ?? element) + ), + } as typeof track; + } + + return { + ...track, + elements: track.elements.map((element) => + element.id === this.elementId ? updatedElement : element + ), + } as typeof track; }); editor.timeline.updateTracks(updatedTracks); |
