clear lot of tickets

This commit is contained in:
Thomas Demirdjian
2025-11-07 17:33:06 +01:00
parent 4365f1e46d
commit d7d9211fbe
30 changed files with 970 additions and 355 deletions
+87 -12
View File
@@ -1,9 +1,9 @@
import useSharedAudioPlayer from "../../hooks/useSharedAudioPlayer";
import * as FileSystem from "expo-file-system";
import { VideoView, useVideoPlayer } from "expo-video";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { View } from "react-native";
import { background } from "../../assets";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Image, Pressable, View } from "react-native";
import { background, icons } from "../../assets";
import BorderGradientButton from "../../components/BorderGradientButton";
import GradientButton from "../../components/GradientButton";
import MusicLandHeader from "../../components/MusicLandHeader";
@@ -30,8 +30,13 @@ const RecordedPlayback = ({ route }) => {
p.timeUpdateEventInterval = 0.2;
});
const [progressInfo, setProgressInfo] = useState({ pos: 0, dur: 0 });
const [progressInfo, setProgressInfo] = useState({
pos: 0,
dur: 0,
isPlaying: false,
});
const wasPlayingBeforeSeek = useRef(false);
const playbackEndedRef = useRef(false);
// Format mm:ss
const fmt = (ms) => {
@@ -44,7 +49,17 @@ const RecordedPlayback = ({ route }) => {
};
// Start both players on mount
const stopPlayback = useCallback(async () => {
try {
if (audioPlayer?.playing) await audioPlayer.pause?.();
} catch (e) {}
try {
if (videoPlayer?.playing) videoPlayer.pause();
} catch (e) {}
}, [audioPlayer, videoPlayer]);
useEffect(() => {
playbackEndedRef.current = false;
const start = async () => {
try {
if (audioPlayer && songUrl) await audioPlayer.play?.();
@@ -53,12 +68,10 @@ const RecordedPlayback = ({ route }) => {
};
start();
return () => {
try {
if (audioPlayer?.playing) audioPlayer.pause?.();
if (videoPlayer?.playing) videoPlayer.pause();
} catch (e) {}
playbackEndedRef.current = false;
void stopPlayback();
};
}, [audioPlayer, videoPlayer, songUrl]);
}, [audioPlayer, songUrl, stopPlayback, videoPlayer]);
// Poll from audio player for progress display; keep video in sync if drifting
useEffect(() => {
@@ -66,7 +79,8 @@ const RecordedPlayback = ({ route }) => {
try {
const dur = (audioPlayer?.duration || 0) * 1000;
const pos = (audioPlayer?.currentTime || 0) * 1000;
setProgressInfo({ pos, dur });
const playing = !!audioPlayer?.playing || !!videoPlayer?.playing;
setProgressInfo({ pos, dur, isPlaying: playing });
// basic drift correction: if desync > 300ms, align video
if (videoPlayer && !Number.isNaN(videoPlayer.currentTime)) {
@@ -94,6 +108,7 @@ const RecordedPlayback = ({ route }) => {
const onSeekStart = async () => {
try {
wasPlayingBeforeSeek.current = !!audioPlayer?.playing;
playbackEndedRef.current = false;
if (audioPlayer?.playing) await audioPlayer.pause?.();
if (videoPlayer?.playing) videoPlayer.pause();
} catch (e) {}
@@ -113,6 +128,47 @@ const RecordedPlayback = ({ route }) => {
: 0;
}, [progressInfo]);
useEffect(() => {
const duration = progressInfo?.dur || 0;
if (!duration) return;
const position = progressInfo?.pos || 0;
if (playbackEndedRef.current && duration - position > 1000) {
playbackEndedRef.current = false;
return;
}
const remaining = Math.max(0, duration - position);
if (remaining <= 400 && !playbackEndedRef.current) {
playbackEndedRef.current = true;
void stopPlayback();
}
}, [progressInfo, stopPlayback]);
const handleTogglePlayback = async () => {
try {
const duration = progressInfo?.dur || 0;
const position = progressInfo?.pos || 0;
const isAtEnd = duration > 0 && duration - position < 350;
const isCurrentlyPlaying =
!!audioPlayer?.playing || !!videoPlayer?.playing;
if (isCurrentlyPlaying) {
playbackEndedRef.current = false;
if (audioPlayer?.playing) await audioPlayer.pause?.();
if (videoPlayer?.playing) videoPlayer.pause();
return;
}
if (isAtEnd) {
if (audioPlayer) await audioPlayer.seekTo?.(0);
if (videoPlayer) videoPlayer.currentTime = 0;
}
playbackEndedRef.current = false;
if (songUrl && audioPlayer) await audioPlayer.play?.();
if (videoPlayer) videoPlayer.play();
} catch (e) {}
};
return (
<Page backgroundImg={background.playbackBG2} headerType="NONE">
<MusicLandHeader progress={19} onPressBack={goBack} />
@@ -144,6 +200,26 @@ const RecordedPlayback = ({ route }) => {
onSeekStart={onSeekStart}
onSeekEnd={onSeekEnd}
/>
<Pressable
onPress={handleTogglePlayback}
style={{
width: 72,
height: 72,
borderRadius: 36,
alignSelf: "center",
marginTop: 4,
alignItems: "center",
justifyContent: "center",
backgroundColor: "rgba(10, 5, 24, 0.65)",
borderWidth: 1,
borderColor: "#F94697",
}}
>
<Image
source={progressInfo.isPlaying ? icons.pause : icons.play}
style={{ width: 26, height: 26 }}
/>
</Pressable>
</View>
<View
style={{ width: "80%", alignSelf: "center", marginTop: 4, gap: 12 }}
@@ -162,8 +238,7 @@ const RecordedPlayback = ({ route }) => {
title="Recommencer"
onPress={async () => {
try {
if (audioPlayer?.playing) await audioPlayer.pause?.();
if (videoPlayer?.playing) videoPlayer.pause();
await stopPlayback();
} catch (e) {}
try {
if (videoUri) {