fix: papercuts around last particle in stream

Pause when holding space during close countdown. Prevent arrow keys
starting exit countdown when on last particle
This commit is contained in:
talksik
2026-04-25 13:06:26 -07:00
parent 03ced6d180
commit a686d85e96
+15 -6
View File
@@ -197,6 +197,7 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
const [composeStep, setComposeStep] = useState<ComposeStep>("idle"); const [composeStep, setComposeStep] = useState<ComposeStep>("idle");
const playbackSuspended = usePlaybackSuspenderStore((s) => s.suspendCount > 0); const playbackSuspended = usePlaybackSuspenderStore((s) => s.suspendCount > 0);
const playbackBlocked = composeActive || playbackSuspended; const playbackBlocked = composeActive || playbackSuspended;
const [spaceHeld, setSpaceHeld] = useState(false);
const [progress, setProgress] = useState(0); const [progress, setProgress] = useState(0);
const [fastPlayback, setFastPlayback] = useState(false); const [fastPlayback, setFastPlayback] = useState(false);
const [showKeybindings, setShowKeybindings] = useState(false); const [showKeybindings, setShowKeybindings] = useState(false);
@@ -239,7 +240,7 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
const exitRemainingMs = useExitCountdown( const exitRemainingMs = useExitCountdown(
status, status,
playbackBlocked, playbackBlocked || spaceHeld,
handleExitNavigate, handleExitNavigate,
); );
@@ -269,14 +270,18 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
if (playbackBlocked) return; if (playbackBlocked) return;
if (isInputTarget(e)) return; if (isInputTarget(e)) return;
const hasNext = currentIndex >= 0 && currentIndex < children.length - 1;
switch (e.key) { switch (e.key) {
case "ArrowRight": case "ArrowRight":
e.preventDefault(); e.preventDefault();
if (!e.shiftKey || !mediaRef.current?.seek(SEEK_DELTA_SEC)) next(); if (!e.shiftKey || !mediaRef.current?.seek(SEEK_DELTA_SEC)) {
if (hasNext) next();
}
break; break;
case "ArrowDown": case "ArrowDown":
e.preventDefault(); e.preventDefault();
next(); if (hasNext) next();
break; break;
case "ArrowLeft": case "ArrowLeft":
e.preventDefault(); e.preventDefault();
@@ -288,7 +293,10 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
break; break;
case " ": case " ":
e.preventDefault(); e.preventDefault();
if (!e.repeat) pause(); if (!e.repeat) {
if (status !== "ended") pause();
setSpaceHeld(true);
}
break; break;
case "Shift": case "Shift":
if (!e.repeat) { if (!e.repeat) {
@@ -329,7 +337,8 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
if (e.key === " ") { if (e.key === " ") {
e.preventDefault(); e.preventDefault();
resume(); if (status !== "ended") resume();
setSpaceHeld(false);
} }
if (e.key === "Shift") { if (e.key === "Shift") {
mediaRef.current?.setPlaybackRate(1); mediaRef.current?.setPlaybackRate(1);
@@ -344,7 +353,7 @@ function StreamViewInner({ path, streamParticle }: StreamViewProps) {
window.removeEventListener("keyup", handleKeyUp); window.removeEventListener("keyup", handleKeyUp);
}; };
}, },
[playbackBlocked, next, prev, pause, resume, navigate, networkId, streamParticle.id, setShowKeybindings, handleToggleReaction, recordingMode, setRecordingMode], [playbackBlocked, status, currentIndex, children.length, next, prev, pause, resume, navigate, networkId, streamParticle.id, setShowKeybindings, handleToggleReaction, recordingMode, setRecordingMode],
); );
if (children.length === 0) { if (children.length === 0) {