| import { create } from 'zustand'; |
| import type { IndexableTypeArray } from 'dexie'; |
| import { db, type Snapshot } from '@/lib/utils/database'; |
| import { useStageStore } from './stage'; |
| import type { Scene } from '@/lib/types/stage'; |
|
|
| export interface SnapshotState { |
| |
| snapshotCursor: number; |
| snapshotLength: number; |
|
|
| |
| canUndo: () => boolean; |
| canRedo: () => boolean; |
|
|
| |
| setSnapshotCursor: (cursor: number) => void; |
| setSnapshotLength: (length: number) => void; |
| initSnapshotDatabase: () => Promise<void>; |
| addSnapshot: () => Promise<void>; |
| undo: () => Promise<void>; |
| redo: () => Promise<void>; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export const useSnapshotStore = create<SnapshotState>((set, get) => ({ |
| |
| snapshotCursor: -1, |
| snapshotLength: 0, |
|
|
| |
| canUndo: () => get().snapshotCursor > 0, |
| canRedo: () => get().snapshotCursor < get().snapshotLength - 1, |
|
|
| |
| setSnapshotCursor: (cursor: number) => set({ snapshotCursor: cursor }), |
| setSnapshotLength: (length: number) => set({ snapshotLength: length }), |
|
|
| |
| |
| |
| initSnapshotDatabase: async () => { |
| const stageStore = useStageStore.getState(); |
|
|
| const newFirstSnapshot = { |
| index: stageStore.getSceneIndex(stageStore.currentSceneId || ''), |
| slides: JSON.parse(JSON.stringify(stageStore.scenes)), |
| }; |
| await db.snapshots.add(newFirstSnapshot); |
|
|
| set({ |
| snapshotCursor: 0, |
| snapshotLength: 1, |
| }); |
| }, |
|
|
| |
| |
| |
| |
| addSnapshot: async () => { |
| const stageStore = useStageStore.getState(); |
| const { snapshotCursor } = get(); |
|
|
| |
| const allKeys = await db.snapshots.orderBy('id').keys(); |
|
|
| let needDeleteKeys: IndexableTypeArray = []; |
|
|
| |
| |
| if (snapshotCursor >= 0 && snapshotCursor < allKeys.length - 1) { |
| needDeleteKeys = allKeys.slice(snapshotCursor + 1); |
| } |
|
|
| |
| const snapshot = { |
| index: stageStore.getSceneIndex(stageStore.currentSceneId || ''), |
| slides: JSON.parse(JSON.stringify(stageStore.scenes)), |
| }; |
| await db.snapshots.add(snapshot); |
|
|
| |
| let snapshotLength = allKeys.length - needDeleteKeys.length + 1; |
|
|
| |
| const snapshotLengthLimit = 20; |
| if (snapshotLength > snapshotLengthLimit) { |
| needDeleteKeys.push(allKeys[0]); |
| snapshotLength--; |
| } |
|
|
| |
| |
| if (snapshotLength >= 2) { |
| const currentSceneIndex = stageStore.getSceneIndex(stageStore.currentSceneId || ''); |
| await db.snapshots.update(allKeys[snapshotLength - 2] as number, { |
| index: currentSceneIndex, |
| }); |
| } |
|
|
| |
| await db.snapshots.bulkDelete(needDeleteKeys as number[]); |
|
|
| set({ |
| snapshotCursor: snapshotLength - 1, |
| snapshotLength, |
| }); |
| }, |
|
|
| |
| |
| |
| undo: async () => { |
| const { snapshotCursor } = get(); |
| if (snapshotCursor <= 0) return; |
|
|
| const stageStore = useStageStore.getState(); |
|
|
| const newSnapshotCursor = snapshotCursor - 1; |
| const snapshots: Snapshot[] = await db.snapshots.orderBy('id').toArray(); |
| const snapshot = snapshots[newSnapshotCursor]; |
| const { index, slides } = snapshot; |
|
|
| const sceneIndex = index > slides.length - 1 ? slides.length - 1 : index; |
|
|
| |
| stageStore.setScenes(slides as unknown as Scene[]); |
| if (slides[sceneIndex]) { |
| stageStore.setCurrentSceneId(slides[sceneIndex].id); |
| } |
|
|
| set({ snapshotCursor: newSnapshotCursor }); |
| }, |
|
|
| |
| |
| |
| redo: async () => { |
| const { snapshotCursor, snapshotLength } = get(); |
| if (snapshotCursor >= snapshotLength - 1) return; |
|
|
| const stageStore = useStageStore.getState(); |
|
|
| const newSnapshotCursor = snapshotCursor + 1; |
| const snapshots: Snapshot[] = await db.snapshots.orderBy('id').toArray(); |
| const snapshot = snapshots[newSnapshotCursor]; |
| const { index, slides } = snapshot; |
|
|
| const sceneIndex = index > slides.length - 1 ? slides.length - 1 : index; |
|
|
| |
| stageStore.setScenes(slides as unknown as Scene[]); |
| if (slides[sceneIndex]) { |
| stageStore.setCurrentSceneId(slides[sceneIndex].id); |
| } |
|
|
| set({ snapshotCursor: newSnapshotCursor }); |
| }, |
| })); |
|
|