continue fix generating flow
This commit is contained in:
@@ -44,22 +44,13 @@ const ValidateModal = ({ visible, onClose, onPressValidate }) => {
|
||||
fontSize: 16,
|
||||
color: Palette.white,
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
Lorsque tu clique sur valider, tu ne pourra plus changer ni le
|
||||
texte ni la mélodie.{" "}
|
||||
texte ni la mélodie.
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: Palette.white,
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
Valider
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ width: "85%", alignSelf: "center", gap: 15 }}>
|
||||
<BorderGradientButton title="Retour" onPress={onClose} />
|
||||
|
||||
@@ -45,6 +45,7 @@ import RecordedPlayback from "../screens/Playback/RecordedPlayback";
|
||||
import ChooseDecor from "../screens/Playback/ChooseDecor";
|
||||
import CreatingDecor from "../screens/Playback/CreatingDecor";
|
||||
import VideoFinalize from "../screens/Playback/VideoFinalize";
|
||||
import GeneratingSong from "../screens/Studio/GeneratingSong";
|
||||
import AllMyMusic from "../screens/Library/AllMyMusic";
|
||||
import AllMyPlaylist from "../screens/Library/AllMyPlaylist";
|
||||
import AllMyLikedMusic from "../screens/Library/AllMyLikedMusic";
|
||||
@@ -185,6 +186,10 @@ const screens = [
|
||||
name: Routes.StreamSong,
|
||||
component: StreamSong,
|
||||
},
|
||||
{
|
||||
name: Routes.GeneratingSong,
|
||||
component: GeneratingSong,
|
||||
},
|
||||
{
|
||||
name: Routes.SongRelease,
|
||||
component: SongRelease,
|
||||
|
||||
@@ -49,6 +49,7 @@ export const Routes = {
|
||||
StreamSong: "StreamSong",
|
||||
SongRelease: "SongRelease",
|
||||
PlaybackExample: "PlaybackExample",
|
||||
GeneratingSong: "GeneratingSong",
|
||||
|
||||
PlaybackOnboarding: "PlaybackOnboarding",
|
||||
Playback: "Playback",
|
||||
|
||||
@@ -174,17 +174,22 @@ const MusicDetails = () => {
|
||||
}
|
||||
};
|
||||
const description = useMemo(() => {
|
||||
// Try to build a readable text from lyrics if present
|
||||
// Build a readable text from lyrics with section labels
|
||||
if (Array.isArray(project?.lyrics)) {
|
||||
return project.lyrics
|
||||
.map((s) => (s?.lyrics || "").trim())
|
||||
.map((s) => {
|
||||
const body = (s?.lyrics || "").trim();
|
||||
if (!body) return null;
|
||||
const t = (s?.type || "").toLowerCase();
|
||||
const label = t === "refrain" ? "Refrain" : "Couplet";
|
||||
return `[${label}]\n${body}`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.slice(0, 4)
|
||||
.join("\n\n");
|
||||
}
|
||||
const c = project?.lyrics?.couplet;
|
||||
const r = project?.lyrics?.refrain;
|
||||
const parts = [c, r].filter(Boolean);
|
||||
const parts = [c ? `[Couplet]\n${c}` : null, r ? `[Refrain]\n${r}` : null].filter(Boolean);
|
||||
return parts.length ? parts.join("\n\n") : "";
|
||||
}, [project]);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { navigate } from "../navigation/NavigationService";
|
||||
import { useUserData } from "../providers/UserDataProvider";
|
||||
import FontAwesome from "@expo/vector-icons/FontAwesome";
|
||||
import palette from "../styles/Palette";
|
||||
import GeneratingSong from "./Studio/GeneratingSong";
|
||||
|
||||
const CREATE_DATA = [
|
||||
{
|
||||
@@ -77,13 +78,19 @@ const NewMusicOptions = ({ route }) => {
|
||||
});
|
||||
break;
|
||||
case 1:
|
||||
navigate(Routes.Compose, { projectId: currentProjet.id });
|
||||
if (currentProjet?.musicStatus === "GENERATING") {
|
||||
navigate(Routes.GeneratingSong, { projectId: currentProjet.id });
|
||||
} else if (currentProjet?.musicStatus === "GENERATED") {
|
||||
navigate(Routes.SongReady, { projectId: currentProjet.id });
|
||||
} else {
|
||||
navigate(Routes.Compose, { projectId: currentProjet.id });
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
navigate(Routes.PouchReady, { projectId: currentProjet.id });
|
||||
break;
|
||||
default:
|
||||
navigate(Routes.PouchReady, { projectId: currentProjet.id });
|
||||
case 3:
|
||||
navigate(Routes.Playback, { projectId: currentProjet.id });
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,17 +4,17 @@ import Page from "../../layouts/Page";
|
||||
import { background } from "../../assets";
|
||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||
import GradientButton from "../../components/GradientButton";
|
||||
import { goBack } from "../../navigation/NavigationService";
|
||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||
import { gutters } from "../../styles";
|
||||
import SwiperFlatList from "react-native-swiper-flatlist";
|
||||
import ChooseGenre from "./ChooseGenre";
|
||||
import CustomizeVoice from "./CustomizeVoice";
|
||||
import ChooseInstruments from "./ChooseInstruments";
|
||||
import ChooseRhythm from "./ChooseRhythm";
|
||||
import CreatingSong from "./CreatingSong";
|
||||
import { useRoute } from "@react-navigation/native";
|
||||
import firebase from "../../config/firebase";
|
||||
import { projectsRef } from "../../config/firebase";
|
||||
import useDataFromRef from "../../hooks/useDataFromRef";
|
||||
import { Routes } from "../../navigation";
|
||||
|
||||
const { width } = Dimensions.get("window");
|
||||
|
||||
@@ -27,20 +27,14 @@ const ComposeSong = () => {
|
||||
const projectId = route?.params?.projectId;
|
||||
|
||||
// Selections state
|
||||
const [genres, setGenres] = useState(__DEV__ ? ["Hip Hop/Rap", "Punk"] : []);
|
||||
const [voice, setVoice] = useState(
|
||||
__DEV__ ? "Deux voix pour interpreter ta chanson" : null,
|
||||
);
|
||||
const [instruments, setInstruments] = useState(
|
||||
__DEV__ ? ["Synthétiseur", "Trompette", "Piano classique"] : [],
|
||||
);
|
||||
const [rhythm, setRhythm] = useState(__DEV__ ? "Rapide" : null);
|
||||
const [genres, setGenres] = useState([]);
|
||||
const [voice, setVoice] = useState(null);
|
||||
const [instruments, setInstruments] = useState([]);
|
||||
const [rhythm, setRhythm] = useState(null);
|
||||
|
||||
// Fetch selected project to get title + lyrics
|
||||
const { data: project } = useDataFromRef({
|
||||
ref: projectId
|
||||
? firebase.firestore().collection("projects").doc(projectId)
|
||||
: null,
|
||||
ref: projectId ? projectsRef.doc(projectId) : null,
|
||||
simpleRef: true,
|
||||
listener: true,
|
||||
condition: !!projectId,
|
||||
@@ -86,6 +80,10 @@ const ComposeSong = () => {
|
||||
}, [project, genres, voice, instruments, rhythm, projectId]);
|
||||
|
||||
const onPressNext = () => {
|
||||
if (selectedIndex === 3) {
|
||||
navigate(Routes.GeneratingSong, { config: musicConfig, projectId });
|
||||
return;
|
||||
}
|
||||
setSelectedIndex(selectedIndex + 1);
|
||||
setProgress(progress + 9);
|
||||
scrollRef.current.scrollToIndex({
|
||||
@@ -159,15 +157,6 @@ const ComposeSong = () => {
|
||||
>
|
||||
<ChooseRhythm selected={rhythm} setSelected={setRhythm} />
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
width: width,
|
||||
height: containerLayout?.height,
|
||||
paddingHorizontal: gutters,
|
||||
}}
|
||||
>
|
||||
<CreatingSong active={selectedIndex === 4} config={musicConfig} />
|
||||
</View>
|
||||
</SwiperFlatList>
|
||||
</View>
|
||||
{selectedIndex !== 4 && (
|
||||
|
||||
@@ -9,14 +9,14 @@ import ProgressBar from "../../components/ProgressBar";
|
||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||
import { Routes } from "../../navigation";
|
||||
import GradientButton from "../../components/GradientButton";
|
||||
import firebase from "../../config/firebase";
|
||||
import firebase, { projectsRef } from "../../config/firebase";
|
||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
|
||||
import moment from "moment";
|
||||
|
||||
const CreatingSong = ({ active, config }) => {
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [called, setCalled] = useState(false);
|
||||
const [result, setResult] = useState(null);
|
||||
const [, setResult] = useState(null);
|
||||
const { setIsLoading } = useMinuit();
|
||||
const [musicStatus, setMusicStatus] = useState(null);
|
||||
const [generationStartAt, setGenerationStartAt] = useState(null);
|
||||
@@ -110,10 +110,7 @@ const CreatingSong = ({ active, config }) => {
|
||||
|
||||
// Si un projectId et un taskId existent, mettre à jour le projet
|
||||
if (config?.projectId && taskId) {
|
||||
const projectRef = firebase
|
||||
.firestore()
|
||||
.collection("projects")
|
||||
.doc(config.projectId);
|
||||
const projectRef = projectsRef.doc(config.projectId);
|
||||
|
||||
await projectRef.set(
|
||||
{
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Image, Platform, Text, View } from "react-native";
|
||||
import Page from "../../layouts/Page";
|
||||
import { ai, background } from "../../assets";
|
||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
|
||||
import { BlurView } from "expo-blur";
|
||||
import { Palette } from "../../styles";
|
||||
import ProgressBar from "../../components/ProgressBar";
|
||||
import GradientButton from "../../components/GradientButton";
|
||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||
import { Routes } from "../../navigation";
|
||||
import firebase, { projectsRef } from "../../config/firebase";
|
||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
|
||||
import moment from "moment";
|
||||
import { responsiveHeight } from "react-native-responsive-dimensions";
|
||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||
import useDataFromRef from "../../hooks/useDataFromRef";
|
||||
|
||||
const GeneratingSong = ({ route }) => {
|
||||
const { config, projectId } = route.params;
|
||||
const [progress, setProgress] = useState(0);
|
||||
const { setIsLoading } = useMinuit();
|
||||
const progressTimerRef = useRef(null);
|
||||
const navigatedRef = useRef(false);
|
||||
|
||||
const { data: project } = useDataFromRef({
|
||||
ref: projectId ? projectsRef.doc(projectId) : null,
|
||||
simpleRef: true,
|
||||
listener: true,
|
||||
condition: !!projectId,
|
||||
refreshArray: [projectId],
|
||||
});
|
||||
|
||||
// Progress based on 8 minutes cap or until status changes
|
||||
useEffect(() => {
|
||||
const totalMs = 8 * 60 * 1000;
|
||||
const clearTimer = () => {
|
||||
if (progressTimerRef.current) {
|
||||
clearInterval(progressTimerRef.current);
|
||||
progressTimerRef.current = null;
|
||||
}
|
||||
};
|
||||
if (project?.musicStatus !== "GENERATING") {
|
||||
setProgress(100);
|
||||
clearTimer();
|
||||
return () => clearTimer();
|
||||
}
|
||||
const update = () => {
|
||||
const startDate = project?.generationStartAt?.toDate
|
||||
? project.generationStartAt.toDate()
|
||||
: new Date(project?.generationStartAt || Date.now());
|
||||
const elapsed = moment().diff(moment(startDate));
|
||||
const raw = Math.floor((elapsed / totalMs) * 100);
|
||||
// While status is GENERATING, block visual progress at 99%
|
||||
const pct = Math.max(0, Math.min(99, raw));
|
||||
setProgress(pct);
|
||||
};
|
||||
update();
|
||||
clearTimer();
|
||||
progressTimerRef.current = setInterval(update, 1000);
|
||||
return () => clearTimer();
|
||||
}, [project?.musicStatus]);
|
||||
|
||||
// Auto navigate to SongReady when generation completed
|
||||
useEffect(() => {
|
||||
if (!config?.projectId) return;
|
||||
if (project?.musicStatus !== "GENERATING" && !navigatedRef.current) {
|
||||
navigatedRef.current = true;
|
||||
navigate(Routes.SongReady, { projectId: config.projectId });
|
||||
}
|
||||
}, [project?.musicStatus, config?.projectId]);
|
||||
|
||||
async function startMusicGeneration() {
|
||||
try {
|
||||
console.log("startMusicGeneration");
|
||||
await setIsLoading(true);
|
||||
const callable = firebase
|
||||
.functions()
|
||||
.httpsCallable("music-generateMusic");
|
||||
const { data } = await callable({
|
||||
title: config?.title,
|
||||
lyrics: config?.lyrics,
|
||||
genres: config?.genres,
|
||||
voice: config?.voice,
|
||||
instruments: config?.instruments,
|
||||
tempo: config?.tempo,
|
||||
projectId: config?.projectId,
|
||||
});
|
||||
const taskId =
|
||||
data?.response?.data?.taskId || data?.response?.data?.task_id;
|
||||
if (config?.projectId && taskId) {
|
||||
const baseUpdate = {
|
||||
sunoTaskId: taskId,
|
||||
musicStatus: "GENERATING",
|
||||
generationStartAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
};
|
||||
const updatePayload = project?.musicConfig
|
||||
? baseUpdate
|
||||
: {
|
||||
...baseUpdate,
|
||||
musicConfig: {
|
||||
title: config?.title || "",
|
||||
lyrics: config?.lyrics || [],
|
||||
genres: config?.genres || [],
|
||||
voice: config?.voice || "",
|
||||
instruments: config?.instruments || [],
|
||||
tempo: config?.tempo || "",
|
||||
},
|
||||
};
|
||||
await projectsRef
|
||||
.doc(config.projectId)
|
||||
.set(updatePayload, { merge: true });
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("GeneratingSong error", e?.message);
|
||||
} finally {
|
||||
await setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger generation only if not already GENERATING
|
||||
useEffect(() => {
|
||||
if (!!project?.title && project?.musicStatus !== "GENERATING") {
|
||||
startMusicGeneration();
|
||||
}
|
||||
}, [project]);
|
||||
|
||||
return (
|
||||
<Page headerType="NONE" backgroundImg={background.studioBG2}>
|
||||
<MusicLandHeader onPressBack={goBack} progress={63} />
|
||||
<View style={{ flex: 1, marginTop: 16 }}>
|
||||
<CreateLyricsHeader
|
||||
title="Ta musique est en cours de création !"
|
||||
subTitle="Encore un peu de patience"
|
||||
containerStyle={{ marginBottom: responsiveHeight(2) }}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
height: responsiveHeight(50),
|
||||
marginTop: responsiveHeight(10),
|
||||
gap: 16,
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
zIndex: 1,
|
||||
position: "absolute",
|
||||
top: -150,
|
||||
width: "50%",
|
||||
height: "100%",
|
||||
alignSelf: "center",
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
source={ai.theo}
|
||||
style={{ width: "100%", height: "100%", right: -10 }}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
</View>
|
||||
<BlurView
|
||||
intensity={40}
|
||||
tint="dark"
|
||||
style={{
|
||||
flex: 1,
|
||||
borderRadius: 16,
|
||||
overflow: "hidden",
|
||||
padding: 12,
|
||||
backgroundColor: "#FFFFFF0A",
|
||||
}}
|
||||
experimentalBlurMethod={
|
||||
Platform.OS !== "ios" ? "dimezisBlurView" : "none"
|
||||
}
|
||||
>
|
||||
<View style={{ flex: 1 }}>
|
||||
<BlurView
|
||||
intensity={40}
|
||||
tint="dark"
|
||||
style={{ flex: 1, padding: 10, paddingBottom: 20 }}
|
||||
experimentalBlurMethod={
|
||||
Platform.OS !== "ios" ? "dimezisBlurView" : "none"
|
||||
}
|
||||
>
|
||||
<View style={{ flex: 1, justifyContent: "flex-end", gap: 20 }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 22,
|
||||
color: Palette.white,
|
||||
fontFamily: FONT_FAMILY.InterSemiBold,
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
Ta musique est{"\n"}en cours de création
|
||||
</Text>
|
||||
<View style={{ alignItems: "center", gap: 16 }}>
|
||||
<ProgressBar gradient progress={progress} />
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 14,
|
||||
color: Palette.white,
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
}}
|
||||
>
|
||||
{progress}%
|
||||
</Text>
|
||||
</View>
|
||||
<GradientButton
|
||||
title={"Création en cours..."}
|
||||
disabled={project?.musicStatus === "GENERATING"}
|
||||
containerStyle={{ width: "80%", alignSelf: "center" }}
|
||||
onPress={() =>
|
||||
navigate(Routes.SongReady, {
|
||||
projectId: config?.projectId,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</BlurView>
|
||||
</View>
|
||||
</BlurView>
|
||||
</View>
|
||||
</View>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default GeneratingSong;
|
||||
@@ -13,14 +13,12 @@ import BorderGradientButton from "../../components/BorderGradientButton";
|
||||
import GradientButton from "../../components/GradientButton";
|
||||
import { Routes } from "../../navigation";
|
||||
import ValidateModal from "../../components/modal/ValidateModal";
|
||||
import { useRoute } from "@react-navigation/core";
|
||||
import firebase from "../../config/firebase";
|
||||
import firebase, { projectsRef } from "../../config/firebase";
|
||||
import { useAudioPlayer } from "expo-audio";
|
||||
import { responsiveHeight } from "react-native-responsive-dimensions";
|
||||
|
||||
const SongReady = () => {
|
||||
const params = useRoute().params || {};
|
||||
const projectId = params?.projectId;
|
||||
const SongReady = ({ route }) => {
|
||||
const { projectId = null } = route?.params || {};
|
||||
const [showValidateModal, setShowValidateModal] = useState(false);
|
||||
const [musicUrls, setMusicUrls] = useState([]);
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
@@ -35,6 +33,7 @@ const SongReady = () => {
|
||||
const player1 = useAudioPlayer(
|
||||
musicUrls[1] ? { uri: musicUrls[1] } : undefined,
|
||||
);
|
||||
const wasPlayingBeforeSeek = useRef({ 0: false, 1: false });
|
||||
|
||||
// Charger les URLs depuis le document projet
|
||||
useEffect(() => {
|
||||
@@ -118,18 +117,14 @@ const SongReady = () => {
|
||||
try {
|
||||
const url = musicUrls[selectedIndex];
|
||||
if (!projectId || !url) return;
|
||||
await firebase
|
||||
.firestore()
|
||||
.collection("projects")
|
||||
.doc(projectId)
|
||||
.set(
|
||||
{
|
||||
songUrl: url,
|
||||
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
},
|
||||
{ merge: true },
|
||||
);
|
||||
navigate(Routes.PouchReady, { projectId });
|
||||
await projectsRef.doc(projectId).set(
|
||||
{
|
||||
songUrl: url,
|
||||
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
},
|
||||
{ merge: true },
|
||||
);
|
||||
navigate(Routes.FlowSelection, { projectId });
|
||||
} catch (e) {
|
||||
console.log("Validate error", e?.message);
|
||||
}
|
||||
@@ -137,36 +132,7 @@ const SongReady = () => {
|
||||
|
||||
const onPressRegenerate = async () => {
|
||||
try {
|
||||
if (!projectId) return goBack();
|
||||
const doc = await firebase
|
||||
.firestore()
|
||||
.collection("projects")
|
||||
.doc(projectId)
|
||||
.get();
|
||||
const project = doc.data() || {};
|
||||
const musicConfig = project?.musicConfig || {};
|
||||
|
||||
const callable = firebase
|
||||
.functions()
|
||||
.httpsCallable("music-generateMusic");
|
||||
const { data } = await callable({
|
||||
...musicConfig,
|
||||
projectId,
|
||||
});
|
||||
|
||||
const taskId =
|
||||
data?.response?.data?.taskId || data?.response?.data?.task_id;
|
||||
if (taskId) {
|
||||
await firebase.firestore().collection("projects").doc(projectId).set(
|
||||
{
|
||||
sunoTaskId: taskId,
|
||||
musicStatus: "GENERATING",
|
||||
generationStartAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
},
|
||||
{ merge: true },
|
||||
);
|
||||
}
|
||||
navigate(Routes.GeneratingSong, { projectId });
|
||||
} catch (e) {
|
||||
console.log("Regenerate error", e?.message);
|
||||
} finally {
|
||||
@@ -176,7 +142,10 @@ const SongReady = () => {
|
||||
|
||||
return (
|
||||
<Page headerType="NONE" backgroundImg={background.studioBG2}>
|
||||
<MusicLandHeader onPressBack={goBack} progress={63} />
|
||||
<MusicLandHeader
|
||||
onPressBack={() => navigate(Routes.FlowSelection, { projectId })}
|
||||
progress={63}
|
||||
/>
|
||||
<View style={{ flex: 1, marginTop: 16 }}>
|
||||
<CreateLyricsHeader
|
||||
title="Ta chanson est prête !"
|
||||
@@ -226,7 +195,34 @@ const SongReady = () => {
|
||||
: 0
|
||||
}
|
||||
seekEnabled={!!musicUrls[idx]}
|
||||
onSeekStart={async () => {
|
||||
try {
|
||||
const player = idx === 0 ? player0 : player1;
|
||||
wasPlayingBeforeSeek.current[idx] = !!player?.playing;
|
||||
if (player?.playing) {
|
||||
await player.pause?.();
|
||||
setIsPlaying((p) => ({ ...p, [idx]: false }));
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(
|
||||
"SongReady pause on seek start",
|
||||
e?.message,
|
||||
);
|
||||
}
|
||||
}}
|
||||
onSeek={(ratio) => onSeek(idx, ratio)}
|
||||
onSeekEnd={async () => {
|
||||
try {
|
||||
const player = idx === 0 ? player0 : player1;
|
||||
if (player && wasPlayingBeforeSeek.current[idx]) {
|
||||
await player.play?.();
|
||||
setIsPlaying((p) => ({ ...p, [idx]: true }));
|
||||
}
|
||||
wasPlayingBeforeSeek.current[idx] = false;
|
||||
} catch (e) {
|
||||
console.log("SongReady resume after seek", e?.message);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<Pressable
|
||||
|
||||
Reference in New Issue
Block a user