import { View, Text, Image, Pressable, Platform } from "react-native"; import React, { useEffect, useState } from "react"; import { ai, icons } from "../../assets"; import { BlurView } from "expo-blur"; import Style, { size } from "../../styles/Style"; import { Palette } from "../../styles"; import { FONT_FAMILY } from "../../styles/Fonts"; import ProgressBar from "../../components/ProgressBar"; import { goBack, navigate } from "../../navigation/NavigationService"; import { useUser } from "../../providers/UserDataProvider"; import { Routes } from "../../navigation"; import GradientButton from "../../components/GradientButton"; 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 [, setResult] = useState(null); const { setIsLoading } = useMinuit(); const [musicStatus, setMusicStatus] = useState(null); const [generationStartAt, setGenerationStartAt] = useState(null); const progressTimerRef = React.useRef(null); const { selectedProjectId } = useUser(); // Abonnement au document projet pour suivre le statut et la date de début useEffect(() => { if (!config?.projectId) return undefined; const unsub = firebase .firestore() .collection("projects") .doc(config.projectId) .onSnapshot((doc) => { const data = doc.data() || {}; setMusicStatus(data?.musicStatus || null); setGenerationStartAt(data?.generationStartAt || null); }); return () => { if (typeof unsub === "function") unsub(); }; }, [config?.projectId]); // Progression basée sur 8 minutes max, arrête si statut change avant useEffect(() => { const totalMs = 8 * 60 * 1000; // 8 minutes const clearTimer = () => { if (progressTimerRef.current) { globalThis.clearInterval(progressTimerRef.current); progressTimerRef.current = null; } }; if (musicStatus && musicStatus !== "GENERATING") { setProgress(100); clearTimer(); return () => clearTimer(); } if (!generationStartAt) { // En attente de la date de début return () => clearTimer(); } const startDate = generationStartAt?.toDate ? generationStartAt.toDate() : new Date(generationStartAt); const update = () => { const elapsed = moment().diff(moment(startDate)); const pct = Math.max( 0, Math.min(100, Math.floor((elapsed / totalMs) * 100)) ); setProgress(pct); if (pct >= 100) { clearTimer(); } }; // Initial update + interval chaque seconde update(); clearTimer(); progressTimerRef.current = globalThis.setInterval(update, 1000); return () => clearTimer(); }, [generationStartAt, musicStatus]); useEffect(() => { const run = async () => { try { setCalled(true); 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, }); setResult(data); // Extraire le taskId renvoyé par l'API Suno à travers la Cloud Function const taskId = data?.response?.data?.taskId || data?.response?.data?.task_id; // Si un projectId et un taskId existent, mettre à jour le projet if (config?.projectId && taskId) { const projectRef = projectsRef.doc(config.projectId); await projectRef.set( { sunoTaskId: taskId, musicStatus: "GENERATING", musicConfig: { title: config?.title || "", lyrics: config?.lyrics || [], genres: config?.genres || [], voice: config?.voice || "", instruments: config?.instruments || [], tempo: config?.tempo || "", }, generationStartAt: firebase.firestore.FieldValue.serverTimestamp(), updatedAt: firebase.firestore.FieldValue.serverTimestamp(), }, { merge: true } ); } } catch (e) { console.log(e); } finally { await setIsLoading(false); } }; if (active && !called) { run(); } }, [active, called, config, setIsLoading]); return ( Ta musique est{"\n"}en cours de création {progress}% navigate(Routes.SongReady)} /> ); }; export default CreatingSong;