feat: enhance playback controls with keyboard shortcuts for clip manipulation and audio separation

This commit is contained in:
DevloperAmanSingh
2025-06-26 23:40:56 +05:30
parent 3224dd974a
commit b799615654

View File

@ -1,18 +1,174 @@
import { useEffect } from "react";
import { usePlaybackStore } from "@/stores/playback-store";
import { useTimelineStore } from "@/stores/timeline-store";
import { toast } from "sonner";
export function usePlaybackControls() {
const { toggle } = usePlaybackStore();
export const usePlaybackControls = () => {
const { isPlaying, currentTime, play, pause, seek } = usePlaybackStore();
const {
selectedClips,
tracks,
splitClip,
splitAndKeepLeft,
splitAndKeepRight,
separateAudio,
} = useTimelineStore();
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.code === "Space" && e.target === document.body) {
e.preventDefault();
toggle();
const handleKeyPress = (e: KeyboardEvent) => {
if (
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLTextAreaElement
) {
return;
}
switch (e.key) {
case " ":
e.preventDefault();
if (isPlaying) {
pause();
} else {
play();
}
break;
case "s":
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
handleSplitSelectedClip();
}
break;
case "q":
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
handleSplitAndKeepLeft();
}
break;
case "w":
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
handleSplitAndKeepRight();
}
break;
case "d":
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
handleSeparateAudio();
}
break;
}
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [toggle]);
}
const handleSplitSelectedClip = () => {
if (selectedClips.length !== 1) {
toast.error("Select exactly one clip to split");
return;
}
const { trackId, clipId } = selectedClips[0];
const track = tracks.find((t) => t.id === trackId);
const clip = track?.clips.find((c) => c.id === clipId);
if (!clip) return;
const effectiveStart = clip.startTime;
const effectiveEnd =
clip.startTime + (clip.duration - clip.trimStart - clip.trimEnd);
if (currentTime <= effectiveStart || currentTime >= effectiveEnd) {
toast.error("Playhead must be within selected clip");
return;
}
splitClip(trackId, clipId, currentTime);
toast.success("Clip split at playhead");
};
const handleSplitAndKeepLeft = () => {
if (selectedClips.length !== 1) {
toast.error("Select exactly one clip");
return;
}
const { trackId, clipId } = selectedClips[0];
const track = tracks.find((t) => t.id === trackId);
const clip = track?.clips.find((c) => c.id === clipId);
if (!clip) return;
const effectiveStart = clip.startTime;
const effectiveEnd =
clip.startTime + (clip.duration - clip.trimStart - clip.trimEnd);
if (currentTime <= effectiveStart || currentTime >= effectiveEnd) {
toast.error("Playhead must be within selected clip");
return;
}
splitAndKeepLeft(trackId, clipId, currentTime);
toast.success("Split and kept left portion");
};
const handleSplitAndKeepRight = () => {
if (selectedClips.length !== 1) {
toast.error("Select exactly one clip");
return;
}
const { trackId, clipId } = selectedClips[0];
const track = tracks.find((t) => t.id === trackId);
const clip = track?.clips.find((c) => c.id === clipId);
if (!clip) return;
const effectiveStart = clip.startTime;
const effectiveEnd =
clip.startTime + (clip.duration - clip.trimStart - clip.trimEnd);
if (currentTime <= effectiveStart || currentTime >= effectiveEnd) {
toast.error("Playhead must be within selected clip");
return;
}
splitAndKeepRight(trackId, clipId, currentTime);
toast.success("Split and kept right portion");
};
const handleSeparateAudio = () => {
if (selectedClips.length !== 1) {
toast.error("Select exactly one video clip to separate audio");
return;
}
const { trackId, clipId } = selectedClips[0];
const track = tracks.find((t) => t.id === trackId);
if (!track || track.type !== "video") {
toast.error("Select a video clip to separate audio");
return;
}
separateAudio(trackId, clipId);
toast.success("Audio separated to audio track");
};
document.addEventListener("keydown", handleKeyPress);
return () => document.removeEventListener("keydown", handleKeyPress);
}, [
isPlaying,
currentTime,
selectedClips,
tracks,
play,
pause,
splitClip,
splitAndKeepLeft,
splitAndKeepRight,
separateAudio,
]);
};