clear last tickets
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user