diff options
| author | Maze Winther <mazewinther@gmail.com> | 2025-06-25 16:18:00 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2025-06-25 16:18:00 +0200 |
| commit | 0ae852c185d5d3ff0bd94310bd8000de8bed5ccc (patch) | |
| tree | 008549c7b27e3bfe7a6bcf265609b36a1e8ca855 /apps/web/src/stores/playback-store.ts | |
| parent | db603543494cc55372191d723f1817e9c4f4b383 (diff) | |
| parent | 067b6e3d7373d37dbc4542acf9f2ecce1dc1b9f6 (diff) | |
| download | opencut-0ae852c185d5d3ff0bd94310bd8000de8bed5ccc.tar.gz | |
Merge branch 'main' of https://github.com/mazeincoding/AppCut
Diffstat (limited to 'apps/web/src/stores/playback-store.ts')
| -rw-r--r-- | apps/web/src/stores/playback-store.ts | 67 |
1 files changed, 54 insertions, 13 deletions
diff --git a/apps/web/src/stores/playback-store.ts b/apps/web/src/stores/playback-store.ts index a4794b7f..0cc01cc1 100644 --- a/apps/web/src/stores/playback-store.ts +++ b/apps/web/src/stores/playback-store.ts @@ -10,7 +10,7 @@ let playbackTimer: number | null = null; const startTimer = (store: any) => { if (playbackTimer) cancelAnimationFrame(playbackTimer); - + // Use requestAnimationFrame for smoother updates const updateTime = () => { const state = store(); @@ -18,14 +18,22 @@ const startTimer = (store: any) => { const now = performance.now(); const delta = (now - lastUpdate) / 1000; // Convert to seconds lastUpdate = now; - - const newTime = state.currentTime + (delta * state.speed); + + const newTime = state.currentTime + delta * state.speed; if (newTime >= state.duration) { + // When video completes, pause and reset playhead to start state.pause(); + state.setCurrentTime(0); + // Notify video elements to sync with reset + window.dispatchEvent( + new CustomEvent("playback-seek", { detail: { time: 0 } }) + ); } else { state.setCurrentTime(newTime); // Notify video elements to sync - window.dispatchEvent(new CustomEvent('playback-update', { detail: { time: newTime } })); + window.dispatchEvent( + new CustomEvent("playback-update", { detail: { time: newTime } }) + ); } } playbackTimer = requestAnimationFrame(updateTime); @@ -47,6 +55,8 @@ export const usePlaybackStore = create<PlaybackStore>((set, get) => ({ currentTime: 0, duration: 0, volume: 1, + muted: false, + previousVolume: 1, speed: 1.0, play: () => { @@ -72,22 +82,53 @@ export const usePlaybackStore = create<PlaybackStore>((set, get) => ({ const { duration } = get(); const clampedTime = Math.max(0, Math.min(duration, time)); set({ currentTime: clampedTime }); - - // Notify video elements to seek - const event = new CustomEvent('playback-seek', { detail: { time: clampedTime } }); + + const event = new CustomEvent("playback-seek", { + detail: { time: clampedTime }, + }); window.dispatchEvent(event); }, - - setVolume: (volume: number) => set({ volume: Math.max(0, Math.min(1, volume)) }), - + + setVolume: (volume: number) => + set((state) => ({ + volume: Math.max(0, Math.min(1, volume)), + muted: volume === 0, + previousVolume: volume > 0 ? volume : state.previousVolume, + })), + setSpeed: (speed: number) => { const newSpeed = Math.max(0.1, Math.min(2.0, speed)); set({ speed: newSpeed }); - - const event = new CustomEvent('playback-speed', { detail: { speed: newSpeed } }); + + const event = new CustomEvent("playback-speed", { + detail: { speed: newSpeed }, + }); window.dispatchEvent(event); }, setDuration: (duration: number) => set({ duration }), setCurrentTime: (time: number) => set({ currentTime: time }), -}));
\ No newline at end of file + + mute: () => { + const { volume, previousVolume } = get(); + set({ + muted: true, + previousVolume: volume > 0 ? volume : previousVolume, + volume: 0, + }); + }, + + unmute: () => { + const { previousVolume } = get(); + set({ muted: false, volume: previousVolume ?? 1 }); + }, + + toggleMute: () => { + const { muted } = get(); + if (muted) { + get().unmute(); + } else { + get().mute(); + } + }, +})); |
