add cancellation to player status fade

This commit is contained in:
jeffvli
2025-11-30 19:25:30 -08:00
parent 02144db221
commit 2ceca9c034
2 changed files with 59 additions and 17 deletions
@@ -40,31 +40,42 @@ export function WebPlayer() {
const [localPlayerStatus, setLocalPlayerStatus] = useState<PlayerStatus>(status);
const [isTransitioning, setIsTransitioning] = useState<boolean | string>(false);
const fadeIntervalRef = useRef<NodeJS.Timeout | null>(null);
const [player1Source, setPlayer1Source] = useState<MediaElementAudioSourceNode | null>(null);
const [player2Source, setPlayer2Source] = useState<MediaElementAudioSourceNode | null>(null);
const fadeAndSetStatus = useCallback(
async (startVolume: number, endVolume: number, duration: number, status: PlayerStatus) => {
if (isTransitioning) {
return setLocalPlayerStatus(status);
// Cancel any in-progress fade
if (fadeIntervalRef.current) {
clearInterval(fadeIntervalRef.current);
fadeIntervalRef.current = null;
}
// Set initial volume immediately to ensure we start from the correct position
// This is especially important when cancelling a previous fade
playerRef.current?.setVolume(startVolume);
const steps = duration / PLAY_PAUSE_FADE_INTERVAL;
const volumeStep = (endVolume - startVolume) / steps;
let currentStep = 0;
const promise = new Promise((resolve) => {
const interval = setInterval(() => {
const promise = new Promise<void>((resolve) => {
fadeIntervalRef.current = setInterval(() => {
currentStep++;
const newVolume = startVolume + volumeStep * currentStep;
playerRef.current?.setVolume(newVolume);
if (currentStep >= steps) {
clearInterval(interval);
setIsTransitioning(false);
resolve(true);
if (fadeIntervalRef.current) {
clearInterval(fadeIntervalRef.current);
fadeIntervalRef.current = null;
}
// Ensure final volume is exactly the target
playerRef.current?.setVolume(endVolume);
resolve();
}
}, PLAY_PAUSE_FADE_INTERVAL);
});
@@ -77,7 +88,7 @@ export function WebPlayer() {
await promise;
}
},
[isTransitioning],
[],
);
const onProgressPlayer1 = useCallback(
@@ -242,6 +253,16 @@ export function WebPlayer() {
[volume, num, isTransitioning, transitionType],
);
// Cleanup fade interval on unmount
useEffect(() => {
return () => {
if (fadeIntervalRef.current) {
clearInterval(fadeIntervalRef.current);
fadeIntervalRef.current = null;
}
};
}, []);
useEffect(() => {
if (localPlayerStatus !== PlayerStatus.PLAYING) {
return;