fix: buggy exit progress when changing clips

This commit is contained in:
talksik
2026-03-19 13:02:19 -07:00
parent aa2e2bc424
commit 1524107cb1
2 changed files with 23 additions and 37 deletions
+23 -15
View File
@@ -100,7 +100,7 @@ function useExitCountdown(
composeActive: boolean,
onExit: () => void,
) {
const [exitProgress, setExitProgress] = useState<number | null>(null);
const [remainingMs, setRemainingMs] = useState<number | null>(null);
const handleExit = useEffectEvent(() => {
onExit();
@@ -109,35 +109,35 @@ function useExitCountdown(
// Start/cancel countdown based on playback status
useEffect(() => {
if (status === "ended") {
setExitProgress(0);
setRemainingMs(EXIT_DELAY_MS);
} else {
setExitProgress(null);
setRemainingMs(null);
}
}, [status]);
// Tick the countdown forward (pauses when compose is active)
// Tick the countdown down (pauses when compose is active)
useEffect(() => {
if (exitProgress === null || composeActive) return;
if (remainingMs === null || remainingMs <= 0 || composeActive) return;
const interval = setInterval(() => {
setExitProgress((prev) => {
setRemainingMs((prev) => {
if (prev === null) return null;
const next = prev + EXIT_TICK_MS / EXIT_DELAY_MS;
return next >= 1 ? 1 : next;
const next = prev - EXIT_TICK_MS;
return next <= 0 ? 0 : next;
});
}, EXIT_TICK_MS);
return () => clearInterval(interval);
}, [exitProgress !== null, composeActive]);
}, [remainingMs !== null && remainingMs > 0, composeActive]);
// Navigate once countdown completes
// Navigate once countdown hits zero
useEffect(() => {
if (exitProgress !== null && exitProgress >= 1) {
if (remainingMs !== null && remainingMs <= 0) {
handleExit();
}
}, [exitProgress]);
}, [remainingMs]);
return exitProgress;
return remainingMs;
}
// --- StreamView ---
@@ -161,7 +161,7 @@ export function StreamView({ path, streamParticle }: StreamViewProps) {
navigate(`/${networkId}`);
}, [navigate, networkId]);
const exitProgress = useExitCountdown(
const exitRemainingMs = useExitCountdown(
state.status,
composeActive,
handleExitNavigate,
@@ -336,7 +336,6 @@ export function StreamView({ path, streamParticle }: StreamViewProps) {
current={state.currentIndex}
progress={progress}
onGoTo={goTo}
exitProgress={exitProgress}
/>
</div>
@@ -372,6 +371,15 @@ export function StreamView({ path, streamParticle }: StreamViewProps) {
onActiveChange={setComposeActive}
/>
{/* Exit countdown */}
{exitRemainingMs !== null && (
<div className="absolute left-5 top-5 z-10 flex items-center justify-center pointer-events-none">
<span className="text-sm text-white/60">
Closing in {Math.ceil(exitRemainingMs / 1000)}s
</span>
</div>
)}
{/* Bottom overlay: stream info + reply */}
<div className="absolute right-0 left-0 bottom-0 z-10">
<ControlsIndicator type={"reply"} />
@@ -5,7 +5,6 @@ interface PlaybackPageIndicatorProps {
current: number;
progress: number;
onGoTo: (index: number) => void;
exitProgress?: number | null;
}
export function PlaybackPageIndicator({
@@ -13,7 +12,6 @@ export function PlaybackPageIndicator({
current,
progress,
onGoTo,
exitProgress,
}: PlaybackPageIndicatorProps) {
if (total === 0) return null;
@@ -53,26 +51,6 @@ export function PlaybackPageIndicator({
/>
</button>
))}
{/* Exit countdown segment */}
{exitProgress != null && (
<div className="relative h-3 flex-1">
<div
className={cn(
"absolute inset-x-0 top-1 h-1 rounded-full bg-white/30",
)}
/>
<div
className={cn(
"absolute left-0 top-1 h-1 rounded-full bg-white/90",
)}
style={{
width: `${exitProgress * 100}%`,
transition: "width 150ms linear",
}}
/>
</div>
)}
</div>
);
}