feat: slider
This commit is contained in:
@@ -8,13 +8,7 @@ import React, {
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import {
|
||||
AppState,
|
||||
BackHandler,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from "react-native";
|
||||
import { BackHandler, Text, TouchableOpacity, View } from "react-native";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import Svg, { Circle } from "react-native-svg";
|
||||
import alert from "../../components/Alert";
|
||||
@@ -62,7 +56,7 @@ const RecordPlayback = ({ route }) => {
|
||||
const isPausedRef = useRef(false);
|
||||
const stopRequestedRef = useRef(false);
|
||||
const restartRequestedRef = useRef(false);
|
||||
const interruptedRef = useRef(false); // New ref to track interruptions
|
||||
const recordingStartTimeRef = useRef(0); // Track recording start time for duration check
|
||||
const manualRestartInFlightRef = useRef(false);
|
||||
const stopRequestedAtRef = useRef(0);
|
||||
const activeRecordingPromiseRef = useRef(null);
|
||||
@@ -114,42 +108,8 @@ const RecordPlayback = ({ route }) => {
|
||||
isPausedRef.current = isPaused;
|
||||
}, [isPaused]);
|
||||
|
||||
// Monitor AppState to detect backgrounding/interruptions
|
||||
useEffect(() => {
|
||||
const subscription = AppState.addEventListener("change", (nextAppState) => {
|
||||
if (
|
||||
nextAppState.match(/inactive|background/) &&
|
||||
(isRecording || isPreparing)
|
||||
) {
|
||||
log("App backgrounded/interrupted during recording session");
|
||||
interruptedRef.current = true;
|
||||
|
||||
// If we are merely preparing (countdown), we can just stop the timer
|
||||
if (isPreparing) {
|
||||
if (countdownTimerRef.current) {
|
||||
clearInterval(countdownTimerRef.current);
|
||||
countdownTimerRef.current = null;
|
||||
}
|
||||
setIsPreparing(false);
|
||||
setCountdown(0);
|
||||
}
|
||||
|
||||
// If recording, request stop immediately.
|
||||
// The recording promise will resolve, and we will check interruptedRef there.
|
||||
if (isRecording) {
|
||||
stopRequestedRef.current = true;
|
||||
stopRequestedAtRef.current = Date.now();
|
||||
try {
|
||||
cameraRef.current?.stopRecording?.();
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
subscription.remove();
|
||||
};
|
||||
}, [isRecording, isPreparing]);
|
||||
// Removed AppState listener as it was too aggressive.
|
||||
// We now use duration validation at the end of recording.
|
||||
|
||||
const musicIndex = useMemo(() => {
|
||||
const i = Number(songIndex);
|
||||
@@ -495,9 +455,7 @@ const RecordPlayback = ({ route }) => {
|
||||
try {
|
||||
stopRequestedRef.current = false;
|
||||
stopRequestedAtRef.current = 0;
|
||||
stopRequestedRef.current = false;
|
||||
stopRequestedAtRef.current = 0;
|
||||
interruptedRef.current = false; // Reset interruption flag
|
||||
recordingStartTimeRef.current = Date.now(); // Start timer
|
||||
listenedMsRef.current = 0;
|
||||
incrementDoneRef.current = false;
|
||||
|
||||
@@ -679,6 +637,7 @@ const RecordPlayback = ({ route }) => {
|
||||
}
|
||||
|
||||
const video = await recordPromise;
|
||||
const recordEndTime = Date.now();
|
||||
log("Recording promise resolved", { hasVideo: !!video?.uri });
|
||||
activeRecordingPromiseRef.current = null;
|
||||
stopRequestedRef.current = false;
|
||||
@@ -707,21 +666,32 @@ const RecordPlayback = ({ route }) => {
|
||||
progressLogRef.current = { bucket: -1, lastPos: -1, lastDur: -1 };
|
||||
const exitRequested = exitRequestedRef.current;
|
||||
const shouldRestart = restartRequestedRef.current;
|
||||
const wasInterrupted = interruptedRef.current;
|
||||
// Duration check logic
|
||||
const recordedDurationMs = recordEndTime - recordingStartTimeRef.current;
|
||||
const expectedDurationMs = (player?.duration || 0) * 1000;
|
||||
|
||||
if (wasInterrupted) {
|
||||
log(
|
||||
"Recording was interrupted (background/inactive), discarding and exiting"
|
||||
);
|
||||
exitRequestedRef.current = false;
|
||||
restartRequestedRef.current = false;
|
||||
manualRestartInFlightRef.current = false;
|
||||
interruptedRef.current = false;
|
||||
await discardRecordingFile(video?.uri, "interrupted");
|
||||
try {
|
||||
goBack();
|
||||
} catch (_) {}
|
||||
return;
|
||||
if (!exitRequested && !shouldRestart) {
|
||||
// If the app was backgrounded/interrupted, the camera stops early,
|
||||
// resulting in a duration significantly shorter than the song.
|
||||
// We only check this if we have a valid song duration.
|
||||
// Tolerance: 1.5s
|
||||
if (
|
||||
expectedDurationMs > 0 &&
|
||||
recordedDurationMs < expectedDurationMs - 1500
|
||||
) {
|
||||
log(
|
||||
"Recording too short compared to song duration - likely interrupted",
|
||||
{
|
||||
recordedDurationMs,
|
||||
expectedDurationMs,
|
||||
}
|
||||
);
|
||||
await discardRecordingFile(video?.uri, "too_short");
|
||||
try {
|
||||
goBack();
|
||||
} catch (_) {}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (exitRequested) {
|
||||
@@ -1140,7 +1110,7 @@ const RecordPlayback = ({ route }) => {
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: bottom + 130,
|
||||
bottom: bottom + 200,
|
||||
paddingHorizontal: gutters,
|
||||
}}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user