clear last tickets

This commit is contained in:
Thomas Demirdjian
2025-11-25 14:58:06 +01:00
parent 72852ad92b
commit ee9cc5dccd
31 changed files with 1009 additions and 531 deletions
+2 -1
View File
@@ -26,6 +26,7 @@ import { FONT_FAMILY } from "../../styles/Fonts";
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
const TIME_BEFORE_INCREMENT_MS = 20000; // 20s
const COUNTDOWN_SECONDS = 10;
const LOG_PREFIX = "[RecordPlayback]";
const log =
typeof __DEV__ === "undefined" || __DEV__
@@ -410,7 +411,7 @@ const RecordPlayback = ({ route }) => {
}
setIsPreparing(true);
setShowProgress(false);
setCountdown(5);
setCountdown(COUNTDOWN_SECONDS);
// On démarre l'intervalle puis on active le flag
if (countdownTimerRef.current) {
+7 -6
View File
@@ -28,6 +28,7 @@ import RestartSpinnerIcon from "../../assets/UI/RestartSpinnerIcon";
import { registerBlobUrl, releaseBlobUrl } from "../../utils/blobUrlCache";
const TIME_BEFORE_INCREMENT_MS = 20000;
const COUNTDOWN_SECONDS = __DEV__ ? 1 : 10;
const WEB_PREVIEW_WIDTH = 360;
const toSeconds = (v) => {
@@ -318,7 +319,7 @@ const RecordPlayback = ({ route }) => {
setLooping(!!originalLoopingValueRef.current.value);
}
};
}, [setLooping])
}, [setLooping]),
);
useFocusEffect(
@@ -327,7 +328,7 @@ const RecordPlayback = ({ route }) => {
return () => {
void resetSessionRef.current?.();
};
}, [])
}, []),
);
useEffect(() => {
@@ -359,7 +360,7 @@ const RecordPlayback = ({ route }) => {
!navigator.mediaDevices?.getUserMedia
) {
setMediaError(
new Error("La capture vidéo n'est pas supportée sur ce navigateur")
new Error("La capture vidéo n'est pas supportée sur ce navigateur"),
);
setMediaReady(false);
return;
@@ -473,7 +474,7 @@ const RecordPlayback = ({ route }) => {
perfStartRef.current != null
? Math.max(
0,
(performance.now() - perfStartRef.current - pausedTotal) / 1000
(performance.now() - perfStartRef.current - pausedTotal) / 1000,
)
: 0;
@@ -588,7 +589,7 @@ const RecordPlayback = ({ route }) => {
},
},
],
{ cancelable: false }
{ cancelable: false },
);
}
}
@@ -603,7 +604,7 @@ const RecordPlayback = ({ route }) => {
setIsPaused(false);
isPausedRef.current = false;
setIsPreparing(true);
setCountdown(5);
setCountdown(COUNTDOWN_SECONDS);
if (countdownTimerRef.current) clearInterval(countdownTimerRef.current);
countdownTimerRef.current = setInterval(() => {
setCountdown((c) => {
+25 -30
View File
@@ -7,7 +7,7 @@ import { background, icons } from "../../assets";
import BorderGradientButton from "../../components/BorderGradientButton";
import GradientButton from "../../components/GradientButton";
import MusicLandHeader from "../../components/MusicLandHeader";
import Slider from "../../components/Slider";
import ProgressSlider from "../../components/player/ProgressSlider";
import Page from "../../layouts/Page";
import { Routes } from "../../navigation";
import { goBack, navigate } from "../../navigation/NavigationService";
@@ -34,19 +34,8 @@ const RecordedPlayback = ({ route }) => {
dur: 0,
isPlaying: false,
});
const wasPlayingBeforeSeek = useRef(false);
const playbackEndedRef = useRef(false);
// Format mm:ss
const fmt = (ms) => {
const total = Math.max(0, Math.floor((ms || 0) / 1000));
const m = Math.floor(total / 60)
.toString()
.padStart(1, "0");
const s = (total % 60).toString().padStart(2, "0");
return `${m}:${s}`;
};
// Start both players on mount
const stopPlayback = useCallback(async () => {
try {
@@ -94,32 +83,37 @@ const RecordedPlayback = ({ route }) => {
return () => global.clearInterval(id);
}, [audioPlayer, videoPlayer]);
const onSeek = async (ratio) => {
const onSeek = async (targetMs) => {
try {
const dur = progressInfo.dur || 0;
const pos = Math.floor(dur * ratio);
const pos = Math.max(0, Math.min(dur, Math.floor(targetMs)));
if (audioPlayer && dur > 0)
await audioPlayer.seekTo?.(Math.floor(pos / 1000));
if (videoPlayer) videoPlayer.currentTime = Math.max(0, pos / 1000);
} catch (e) {}
};
const onSeekStart = async () => {
const onSeekStart = useCallback(() => {
playbackEndedRef.current = false;
}, []);
const pauseDuringSeek = useCallback(async () => {
try {
wasPlayingBeforeSeek.current = !!audioPlayer?.playing;
playbackEndedRef.current = false;
if (audioPlayer?.playing) await audioPlayer.pause?.();
} catch (e) {}
try {
if (videoPlayer?.playing) videoPlayer.pause();
} catch (e) {}
};
const onSeekEnd = async () => {
}, [audioPlayer, videoPlayer]);
const resumeAfterSeek = useCallback(async () => {
try {
if (wasPlayingBeforeSeek.current) {
if (audioPlayer) await audioPlayer.play?.();
if (videoPlayer) videoPlayer.play();
}
if (audioPlayer) await audioPlayer.play?.();
} catch (e) {}
};
try {
if (videoPlayer) videoPlayer.play();
} catch (e) {}
}, [audioPlayer, videoPlayer]);
const sliderProgress = useMemo(() => {
return progressInfo.dur
@@ -190,14 +184,15 @@ const RecordedPlayback = ({ route }) => {
}}
/>
)}
<Slider
value={fmt(progressInfo.pos)}
maxValue={fmt(progressInfo.dur)}
progress={sliderProgress}
seekEnabled={!!songUrl}
<ProgressSlider
positionMs={progressInfo.pos}
durationMs={progressInfo.dur}
isPlaying={progressInfo.isPlaying}
onSeek={onSeek}
onSeekStart={onSeekStart}
onSeekEnd={onSeekEnd}
onPause={pauseDuringSeek}
onPlay={resumeAfterSeek}
disabled={!songUrl}
/>
<Pressable
onPress={handleTogglePlayback}
+43 -14
View File
@@ -142,6 +142,7 @@ const RecordedPlayback = ({ route }) => {
const sliderProgress = useMemo(() => {
return progress.durS > 0 ? Math.min(1, progress.posS / progress.durS) : 0;
}, [progress]);
const pendingSeekRef = useRef(null);
useEffect(() => {
const duration = progress?.durS || 0;
@@ -154,22 +155,48 @@ const RecordedPlayback = ({ route }) => {
const remaining = Math.max(0, duration - position);
if (remaining <= 0.35 && !playbackEndedRef.current) {
playbackEndedRef.current = true;
void stopPlayback();
void (async () => {
await stopPlayback();
try {
if (audioPlayer) await audioPlayer.seekTo?.(0);
} catch {}
try {
if (videoElRef.current) {
videoElRef.current.currentTime = 0;
}
} catch {}
})();
}
}, [progress, stopPlayback]);
}, [progress, stopPlayback, audioPlayer]);
const onSeek = async (ratio) => {
try {
const onSeek = useCallback(
async (ratio) => {
const durS = Number(progress.durS || 0);
const target = durS * ratio; // secondes
if (audioPlayer && durS > 0) {
await audioPlayer.seekTo?.(Math.floor(target)); // seek en secondes
}
if (videoElRef.current && videoUri) {
videoElRef.current.currentTime = Math.max(0, target);
}
const target = durS > 0 ? durS * ratio : 0; // secondes
const promise = (async () => {
try {
if (audioPlayer && durS > 0) {
await audioPlayer.seekTo?.(Math.max(0, target));
}
if (videoElRef.current && videoUri) {
videoElRef.current.currentTime = Math.max(0, target);
}
} catch {}
})();
pendingSeekRef.current = promise;
await promise;
},
[audioPlayer, progress.durS, videoUri],
);
const waitForPendingSeek = useCallback(async () => {
const promise = pendingSeekRef.current;
pendingSeekRef.current = null;
if (!promise) return;
try {
await promise;
} catch {}
};
}, []);
const wasPlayingRef = useRef(false);
const isSeekingRef = useRef(false);
@@ -178,6 +205,7 @@ const RecordedPlayback = ({ route }) => {
if (isSeekingRef.current) return;
isSeekingRef.current = true;
wasPlayingRef.current = !!audioPlayer?.playing;
pendingSeekRef.current = null;
playbackEndedRef.current = false;
if (audioPlayer?.playing) await audioPlayer.pause?.();
if (videoElRef.current && !videoElRef.current.paused) {
@@ -188,14 +216,15 @@ const RecordedPlayback = ({ route }) => {
const onSeekEnd = useCallback(async () => {
try {
if (!isSeekingRef.current) return;
await waitForPendingSeek();
isSeekingRef.current = false;
if (wasPlayingRef.current) {
if (audioPlayer) await audioPlayer.play?.();
if (audioPlayer) await audioPlayer.resume?.();
if (videoElRef.current && videoUri)
videoElRef.current.play().catch(() => {});
}
} catch {}
}, [audioPlayer, videoUri]);
}, [audioPlayer, videoUri, waitForPendingSeek]);
const handleTogglePlayback = useCallback(async () => {
try {