Files
OpenCut/apps/web/src/core/managers/save-manager.ts
T

108 lines
2.3 KiB
TypeScript

import type { EditorCore } from "@/core";
type SaveManagerOptions = {
debounceMs?: number;
};
export class SaveManager {
private debounceMs: number;
private isPaused = false;
private isSaving = false;
private hasPendingSave = false;
private saveTimer: ReturnType<typeof setTimeout> | null = null;
private unsubscribeHandlers: Array<() => void> = [];
constructor(
private editor: EditorCore,
{ debounceMs = 800 }: SaveManagerOptions = {},
) {
this.debounceMs = debounceMs;
}
start(): void {
if (this.unsubscribeHandlers.length > 0) return;
this.unsubscribeHandlers = [
this.editor.scenes.subscribe(() => {
this.markDirty();
}),
this.editor.timeline.subscribe(() => {
this.markDirty();
}),
];
}
stop(): void {
for (const unsubscribe of this.unsubscribeHandlers) {
unsubscribe();
}
this.unsubscribeHandlers = [];
this.clearTimer();
}
pause(): void {
this.isPaused = true;
}
resume(): void {
this.isPaused = false;
if (this.hasPendingSave) {
this.queueSave();
}
}
markDirty({ force = false }: { force?: boolean } = {}): void {
if (this.isPaused && !force) return;
this.hasPendingSave = true;
this.queueSave();
}
async flush(): Promise<void> {
this.hasPendingSave = true;
await this.saveNow();
}
getIsDirty(): boolean {
return this.hasPendingSave || this.isSaving;
}
private queueSave(): void {
if (this.isSaving) return;
if (this.saveTimer) {
clearTimeout(this.saveTimer);
}
this.saveTimer = setTimeout(() => {
void this.saveNow();
}, this.debounceMs);
}
private async saveNow(): Promise<void> {
if (this.isSaving) return;
if (!this.hasPendingSave) return;
const activeProject = this.editor.project.getActive();
if (!activeProject) return;
if (this.editor.project.getIsLoading()) return;
if (this.editor.project.getMigrationState().isMigrating) return;
this.isSaving = true;
this.hasPendingSave = false;
this.clearTimer();
try {
await this.editor.project.saveCurrentProject();
} finally {
this.isSaving = false;
if (this.hasPendingSave) {
this.queueSave();
}
}
}
private clearTimer(): void {
if (!this.saveTimer) return;
clearTimeout(this.saveTimer);
this.saveTimer = null;
}
}