refactor: improve playback controls by replacing inline functions with useCallback for clip manipulation and audio separation

This commit is contained in:
DevloperAmanSingh
2025-06-27 00:07:41 +05:30
parent 0383000ada
commit 3f0fe9d20e

View File

@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useCallback } from "react";
import { usePlaybackStore } from "@/stores/playback-store";
import { useTimelineStore } from "@/stores/timeline-store";
import { toast } from "sonner";
@ -15,8 +15,101 @@ export const usePlaybackControls = () => {
separateAudio,
} = useTimelineStore();
useEffect(() => {
const handleKeyPress = (e: KeyboardEvent) => {
const handleSplitSelectedClip = useCallback(() => {
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");
}, [selectedClips, tracks, currentTime, splitClip]);
const handleSplitAndKeepLeftCallback = useCallback(() => {
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");
}, [selectedClips, tracks, currentTime, splitAndKeepLeft]);
const handleSplitAndKeepRightCallback = useCallback(() => {
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");
}, [selectedClips, tracks, currentTime, splitAndKeepRight]);
const handleSeparateAudioCallback = useCallback(() => {
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");
}, [selectedClips, tracks, separateAudio]);
const handleKeyPress = useCallback(
(e: KeyboardEvent) => {
if (
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLTextAreaElement
@ -44,131 +137,38 @@ export const usePlaybackControls = () => {
case "q":
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
handleSplitAndKeepLeft();
handleSplitAndKeepLeftCallback();
}
break;
case "w":
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
handleSplitAndKeepRight();
handleSplitAndKeepRightCallback();
}
break;
case "d":
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
handleSeparateAudio();
handleSeparateAudioCallback();
}
break;
}
};
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");
};
},
[
isPlaying,
play,
pause,
handleSplitSelectedClip,
handleSplitAndKeepLeftCallback,
handleSplitAndKeepRightCallback,
handleSeparateAudioCallback,
]
);
useEffect(() => {
document.addEventListener("keydown", handleKeyPress);
return () => document.removeEventListener("keydown", handleKeyPress);
}, [
isPlaying,
currentTime,
selectedClips,
tracks,
play,
pause,
splitClip,
splitAndKeepLeft,
splitAndKeepRight,
separateAudio,
]);
}, [handleKeyPress]);
};