big refacto change all flows
This commit is contained in:
@@ -17,13 +17,14 @@ import CustomizeSongStructure from "./CustomizeSongStructure";
|
||||
import Rhymes from "./Rhymes";
|
||||
import CreatingLyrics from "./CreatingLyrics";
|
||||
import { responsiveHeight } from "react-native-responsive-dimensions";
|
||||
import { useUser } from "../../providers/UserDataProvider";
|
||||
|
||||
const { width } = Dimensions.get("window");
|
||||
|
||||
const CreateLyricsWithAi = ({ route }) => {
|
||||
const { hasLyrics = false, regenerateKey } = route?.params || {};
|
||||
const CreateLyricsWithAi = () => {
|
||||
const { selectedProject, updateProjectData } = useUser();
|
||||
const hasLyrics = selectedProject?.hasLyrics === true;
|
||||
const scrollRef = useRef(null);
|
||||
// If user already has lyrics, start at SongStructure (index 5)
|
||||
const [selectedIndex, setSelectedIndex] = useState(hasLyrics ? 5 : 0);
|
||||
const [progress, setProgress] = useState(16);
|
||||
const [parentLayout, setparentLayout] = useState(null);
|
||||
@@ -40,6 +41,58 @@ const CreateLyricsWithAi = ({ route }) => {
|
||||
const [rhymes, setRhymes] = useState(null);
|
||||
const [customStructure, setCustomStructure] = useState(null); // array like ['couplet','refrain']
|
||||
|
||||
// Pré-remplir les états depuis le projet sélectionné si disponibles
|
||||
React.useEffect(() => {
|
||||
if (!selectedProject) return;
|
||||
const sel = selectedProject?.selections || {};
|
||||
const cfg = selectedProject?.config || {};
|
||||
|
||||
// Text inputs / choix simples
|
||||
if (objective == null && typeof sel.objective === "string" && sel.objective)
|
||||
setObjective(sel.objective);
|
||||
if (!otherObjective && typeof sel.otherObjective === "string")
|
||||
setOtherObjective(sel.otherObjective);
|
||||
if (!context && typeof sel.context === "string") setContext(sel.context);
|
||||
|
||||
// Emotion: accepter objet {title, description} ou string "Titre : description"
|
||||
if (emotion == null && sel.emotion) {
|
||||
if (typeof sel.emotion === "object" && sel.emotion.title) {
|
||||
setEmotion({
|
||||
title: sel.emotion.title,
|
||||
description: sel.emotion.description || "",
|
||||
});
|
||||
} else if (typeof sel.emotion === "string") {
|
||||
const [t, d] = sel.emotion.split(":");
|
||||
const title = (t || "").trim();
|
||||
const description = (d || "").trim();
|
||||
if (title) setEmotion({ title, description });
|
||||
}
|
||||
}
|
||||
|
||||
if (style == null && typeof sel.style === "string" && sel.style)
|
||||
setStyle(sel.style);
|
||||
if (!otherStyle && typeof sel.otherStyle === "string")
|
||||
setOtherStyle(sel.otherStyle);
|
||||
if (!audience && typeof sel.audience === "string") setAudience(sel.audience);
|
||||
|
||||
// Structure choisie (string) si déjà enregistrée dans selections
|
||||
if (structure == null && typeof sel.structure === "string" && sel.structure)
|
||||
setStructure(sel.structure);
|
||||
|
||||
// Rimes
|
||||
if (rhymes == null && typeof sel.rhymes === "string" && sel.rhymes)
|
||||
setRhymes(sel.rhymes);
|
||||
|
||||
// Structure personnalisée: prioriser selections.customStructure puis config.structure
|
||||
const savedCustom = Array.isArray(sel.customStructure)
|
||||
? sel.customStructure
|
||||
: null;
|
||||
const cfgStructure = Array.isArray(cfg.structure) ? cfg.structure : null;
|
||||
if (!Array.isArray(customStructure) && (savedCustom || cfgStructure)) {
|
||||
setCustomStructure(savedCustom || cfgStructure);
|
||||
}
|
||||
}, [selectedProject]);
|
||||
|
||||
const parsedStructure = useMemo(() => {
|
||||
// Parses strings like "1 couplet, 1 refrain, 1 couplet, 1 refrain"
|
||||
try {
|
||||
@@ -65,6 +118,13 @@ const CreateLyricsWithAi = ({ route }) => {
|
||||
}
|
||||
}, [structure]);
|
||||
|
||||
// Si déjà des paroles, forcer l'accès à partir de l'étape 5 et ignorer 0-4
|
||||
React.useEffect(() => {
|
||||
if (hasLyrics && selectedIndex < 5) {
|
||||
setSelectedIndex(5);
|
||||
}
|
||||
}, [hasLyrics]);
|
||||
|
||||
const lyricsConfig = useMemo(() => {
|
||||
return {
|
||||
objective: otherObjective?.trim()
|
||||
@@ -98,9 +158,9 @@ const CreateLyricsWithAi = ({ route }) => {
|
||||
customStructure,
|
||||
]);
|
||||
|
||||
const onPressNext = () => {
|
||||
// If user already has lyrics and just finished CustomizeSongStructure (index 6),
|
||||
// skip AI generation and go straight to Lyrics editor
|
||||
const onPressNext = async () => {
|
||||
// Si l'utilisateur a déjà des paroles et vient de finir CustomizeSongStructure (index 6),
|
||||
// sauter Rhymes et CreatingLyrics et aller directement sur Lyrics
|
||||
if (hasLyrics && selectedIndex === 6) {
|
||||
const chosenStructure =
|
||||
(customStructure &&
|
||||
@@ -108,7 +168,7 @@ const CreateLyricsWithAi = ({ route }) => {
|
||||
customStructure.length === parsedStructure.length
|
||||
? customStructure
|
||||
: parsedStructure) || [];
|
||||
navigate(Routes.Lyrics, {
|
||||
await updateProjectData({
|
||||
config: { structure: chosenStructure },
|
||||
selections: {
|
||||
objective,
|
||||
@@ -125,6 +185,7 @@ const CreateLyricsWithAi = ({ route }) => {
|
||||
},
|
||||
hasLyrics: true,
|
||||
});
|
||||
navigate(Routes.Lyrics);
|
||||
return;
|
||||
}
|
||||
setSelectedIndex((idx) => idx + 1);
|
||||
@@ -156,11 +217,7 @@ const CreateLyricsWithAi = ({ route }) => {
|
||||
|
||||
return (
|
||||
<Page headerType="NONE">
|
||||
<MusicLandHeader
|
||||
onPressBack={onPressBack}
|
||||
progress={progress}
|
||||
showSkip={selectedIndex === 4}
|
||||
/>
|
||||
<MusicLandHeader onPressBack={onPressBack} progress={progress} />
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
@@ -250,7 +307,14 @@ const CreateLyricsWithAi = ({ route }) => {
|
||||
}}
|
||||
>
|
||||
<CustomizeSongStructure
|
||||
baseStructure={parsedStructure || []}
|
||||
baseStructure={
|
||||
parsedStructure ||
|
||||
(Array.isArray(customStructure)
|
||||
? customStructure
|
||||
: Array.isArray(selectedProject?.config?.structure)
|
||||
? selectedProject.config.structure
|
||||
: [])
|
||||
}
|
||||
onChange={setCustomStructure}
|
||||
/>
|
||||
</View>
|
||||
@@ -273,7 +337,6 @@ const CreateLyricsWithAi = ({ route }) => {
|
||||
<CreatingLyrics
|
||||
active={selectedIndex === 8}
|
||||
config={lyricsConfig}
|
||||
regenerateKey={regenerateKey}
|
||||
selections={{
|
||||
objective,
|
||||
otherObjective,
|
||||
@@ -292,7 +355,10 @@ const CreateLyricsWithAi = ({ route }) => {
|
||||
</SwiperFlatList>
|
||||
</View>
|
||||
{selectedIndex !== 8 && (
|
||||
<GradientButton title="Suivant" onPress={onPressNext} />
|
||||
<GradientButton
|
||||
title={selectedIndex === 7 ? "Générer" : "Suivant"}
|
||||
onPress={onPressNext}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</Page>
|
||||
|
||||
@@ -11,21 +11,25 @@ import { goBack, navigate } from "../../navigation/NavigationService";
|
||||
import { Routes } from "../../navigation";
|
||||
import firebase from "../../config/firebase";
|
||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
|
||||
import { useUser } from "../../providers/UserDataProvider";
|
||||
|
||||
const CreatingLyrics = ({ active, config, regenerateKey, selections }) => {
|
||||
const CreatingLyrics = ({ active, config, selections }) => {
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [called, setCalled] = useState(false);
|
||||
const [result, setResult] = useState(null);
|
||||
const [saved, setSaved] = useState(false);
|
||||
const { setIsLoading } = useMinuit();
|
||||
const { updateProjectData } = useUser();
|
||||
|
||||
// When asked to regenerate, reset flags so effect runs again
|
||||
// Reset when becomes active
|
||||
useEffect(() => {
|
||||
if (active) {
|
||||
setCalled(false);
|
||||
setResult(null);
|
||||
setProgress(0);
|
||||
setSaved(false);
|
||||
}
|
||||
}, [regenerateKey, active]);
|
||||
}, [active]);
|
||||
|
||||
useEffect(() => {
|
||||
if (active) {
|
||||
@@ -74,7 +78,42 @@ const CreatingLyrics = ({ active, config, regenerateKey, selections }) => {
|
||||
}
|
||||
}, [active, called, config, setIsLoading]);
|
||||
|
||||
console.log(result);
|
||||
// Lorsque la génération est terminée, enregistrer et naviguer automatiquement vers Lyrics
|
||||
useEffect(() => {
|
||||
const autoSaveAndGo = async () => {
|
||||
try {
|
||||
if (saved) return;
|
||||
setSaved(true);
|
||||
await setIsLoading(true);
|
||||
await updateProjectData({
|
||||
title: result?.title || "",
|
||||
titleLower: (result?.title || "").toLowerCase(),
|
||||
lyrics: Array.isArray(result?.lyrics) ? result.lyrics : [],
|
||||
config: config || null,
|
||||
selections: selections || null,
|
||||
hasLyrics: false,
|
||||
});
|
||||
navigate(Routes.Lyrics);
|
||||
} catch (e) {
|
||||
console.log("Auto save generated lyrics error", e?.message);
|
||||
} finally {
|
||||
await setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (active && result && progress >= 100 && !saved) {
|
||||
autoSaveAndGo();
|
||||
}
|
||||
}, [
|
||||
active,
|
||||
result,
|
||||
progress,
|
||||
saved,
|
||||
setIsLoading,
|
||||
updateProjectData,
|
||||
config,
|
||||
selections,
|
||||
]);
|
||||
|
||||
return (
|
||||
<View
|
||||
@@ -121,19 +160,6 @@ const CreatingLyrics = ({ active, config, regenerateKey, selections }) => {
|
||||
Platform.OS !== "ios" ? "dimezisBlurView" : "none"
|
||||
}
|
||||
>
|
||||
<Pressable
|
||||
style={{
|
||||
...size({ size: 24 }),
|
||||
...Style.containerCenter,
|
||||
position: "absolute",
|
||||
top: 10,
|
||||
left: 10,
|
||||
zIndex: 3,
|
||||
}}
|
||||
onPress={goBack}
|
||||
>
|
||||
<Image source={icons.close} style={size({ size: 11 })} />
|
||||
</Pressable>
|
||||
<View style={{ flex: 1, justifyContent: "flex-end", gap: 20 }}>
|
||||
<Text
|
||||
style={{
|
||||
@@ -157,21 +183,37 @@ const CreatingLyrics = ({ active, config, regenerateKey, selections }) => {
|
||||
{progress}%
|
||||
</Text>
|
||||
</View>
|
||||
<GradientButton
|
||||
title="Découvrir mon texte"
|
||||
containerStyle={{
|
||||
width: "80%",
|
||||
alignSelf: "center",
|
||||
}}
|
||||
onPress={() =>
|
||||
navigate(Routes.Lyrics, {
|
||||
lyricsData: result,
|
||||
config,
|
||||
selections,
|
||||
hasLyrics: false,
|
||||
})
|
||||
}
|
||||
/>
|
||||
{!saved && (
|
||||
<GradientButton
|
||||
title="Découvrir mon texte"
|
||||
containerStyle={{
|
||||
width: "80%",
|
||||
alignSelf: "center",
|
||||
}}
|
||||
onPress={async () => {
|
||||
try {
|
||||
if (saved) return;
|
||||
setSaved(true);
|
||||
await setIsLoading(true);
|
||||
await updateProjectData({
|
||||
title: result?.title || "",
|
||||
titleLower: (result?.title || "").toLowerCase(),
|
||||
lyrics: Array.isArray(result?.lyrics)
|
||||
? result.lyrics
|
||||
: [],
|
||||
config: config || null,
|
||||
selections: selections || null,
|
||||
hasLyrics: false,
|
||||
});
|
||||
navigate(Routes.Lyrics);
|
||||
} catch (e) {
|
||||
console.log("Save generated lyrics error", e?.message);
|
||||
} finally {
|
||||
await setIsLoading(false);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</BlurView>
|
||||
</View>
|
||||
|
||||
+111
-39
@@ -1,41 +1,44 @@
|
||||
import { View, ScrollView, Alert } from "react-native";
|
||||
import React, { useMemo, useState, useCallback } from "react";
|
||||
import React, { useMemo, useState, useCallback, useEffect, useRef } from "react";
|
||||
import Page from "../../layouts/Page";
|
||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||
import { navigate } from "../../navigation/NavigationService";
|
||||
import { gutters } from "../../styles";
|
||||
import BorderGradientButton from "../../components/BorderGradientButton";
|
||||
import GradientButton from "../../components/GradientButton";
|
||||
import { Routes } from "../../navigation";
|
||||
import CustomInput from "./components/CustomInput";
|
||||
import ItemContainer from "../../components/ItemContainer/ItemContainer";
|
||||
import { useRoute } from "@react-navigation/native";
|
||||
import firebase, { projectsRef } from "../../config/firebase";
|
||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
|
||||
import { useUser } from "../../providers/UserDataProvider";
|
||||
|
||||
const Lyrics = ({ navigation }) => {
|
||||
const [containerLayout, setContainerLayout] = useState(null);
|
||||
const route = useRoute();
|
||||
const lyricsData = route?.params?.lyricsData;
|
||||
const config = route?.params?.config;
|
||||
const selections = route?.params?.selections;
|
||||
const hasLyrics = !!route?.params?.hasLyrics;
|
||||
const { setIsLoading } = useMinuit();
|
||||
const { selectedProjectId, selectedProject } = useUser();
|
||||
|
||||
// Effective sources from provider only
|
||||
const projectTitle = selectedProject?.title || "";
|
||||
const projectLyrics = Array.isArray(selectedProject?.lyrics)
|
||||
? selectedProject.lyrics
|
||||
: [];
|
||||
const projectConfig = selectedProject?.config || null;
|
||||
const projectSelections = selectedProject?.selections || null;
|
||||
const projectHasLyrics = !!selectedProject?.hasLyrics;
|
||||
|
||||
const initial = useMemo(() => {
|
||||
const title = lyricsData?.title || "";
|
||||
const aiSections = Array.isArray(lyricsData?.lyrics)
|
||||
? lyricsData.lyrics
|
||||
: [];
|
||||
const title = projectTitle || "";
|
||||
const aiSections = Array.isArray(projectLyrics) ? projectLyrics : [];
|
||||
// Respecter l'ordre de la structure choisie si disponible
|
||||
const targetStructure = Array.isArray(config?.structure)
|
||||
? config.structure.map((t) => (t || "").toLowerCase())
|
||||
const targetStructure = Array.isArray(projectConfig?.structure)
|
||||
? projectConfig.structure.map((t) => (t || "").toLowerCase())
|
||||
: null;
|
||||
if (
|
||||
aiSections.length &&
|
||||
targetStructure &&
|
||||
aiSections.length === targetStructure.length
|
||||
) {
|
||||
|
||||
// 1) Si des paroles existent déjà, les utiliser en priorité
|
||||
if (aiSections.length) {
|
||||
// Optionnel: si une structure cible de même longueur existe, garder l'ordre courant
|
||||
// et harmoniser les types en minuscule.
|
||||
return {
|
||||
title,
|
||||
sections: aiSections.map((s) => ({
|
||||
@@ -44,18 +47,51 @@ const Lyrics = ({ navigation }) => {
|
||||
})),
|
||||
};
|
||||
}
|
||||
// Sinon, créer à partir de la structure
|
||||
|
||||
// 2) Sinon, créer à partir de la structure si fournie
|
||||
if (targetStructure && targetStructure.length) {
|
||||
return {
|
||||
title,
|
||||
sections: targetStructure.map((t) => ({ type: t, lyrics: "" })),
|
||||
};
|
||||
}
|
||||
// Fallback vide
|
||||
|
||||
// 3) Fallback vide
|
||||
return { title, sections: [] };
|
||||
}, [lyricsData, config]);
|
||||
}, [projectTitle, projectLyrics, projectConfig]);
|
||||
|
||||
const [titleValue, setTitleValue] = useState(initial.title || "");
|
||||
const titleSaveTimer = useRef(null);
|
||||
|
||||
// Auto-save du titre lorsqu'il est modifié (si non vide)
|
||||
useEffect(() => {
|
||||
const newTitle = (titleValue || "").trim();
|
||||
// Annuler tout timer précédent
|
||||
if (titleSaveTimer.current) clearTimeout(titleSaveTimer.current);
|
||||
// Ne rien faire si inchangé vs projet courant
|
||||
const currentTitle = (selectedProject?.title || "").trim();
|
||||
if (!newTitle || newTitle === currentTitle) return;
|
||||
|
||||
titleSaveTimer.current = setTimeout(async () => {
|
||||
try {
|
||||
await projectsRef.doc(selectedProjectId).set(
|
||||
{
|
||||
title: newTitle,
|
||||
titleLower: newTitle.toLowerCase(),
|
||||
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
},
|
||||
{ merge: true },
|
||||
);
|
||||
} catch (e) {
|
||||
// silencieux: l'utilisateur pourra tjs valider plus tard
|
||||
console.log("Auto-save titre échoué", e?.message);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
return () => {
|
||||
if (titleSaveTimer.current) clearTimeout(titleSaveTimer.current);
|
||||
};
|
||||
}, [titleValue, selectedProjectId, selectedProject]);
|
||||
const [sections, setSections] = useState(initial.sections || []);
|
||||
const setSectionAt = (index, value) => {
|
||||
setSections((prev) => {
|
||||
@@ -67,7 +103,7 @@ const Lyrics = ({ navigation }) => {
|
||||
|
||||
// Plus d'appel direct à la cloud function ici: on retourne à l'étape précédente
|
||||
const regenerate = useCallback(() => {
|
||||
navigate(Routes.CreateLyricsWithAi, { regenerateKey: Date.now() });
|
||||
navigate(Routes.CreateLyricsWithAi);
|
||||
}, []);
|
||||
|
||||
const sanitize = (obj) => {
|
||||
@@ -102,34 +138,68 @@ const Lyrics = ({ navigation }) => {
|
||||
);
|
||||
return;
|
||||
}
|
||||
const user = firebase.auth().currentUser;
|
||||
const payload = {
|
||||
const normalizedNewLyrics = (sections || []).map((s) => ({
|
||||
type: (s?.type || "").toLowerCase(),
|
||||
lyrics: (s?.lyrics || "").trim(),
|
||||
}));
|
||||
const normalizedOldLyrics = Array.isArray(projectLyrics)
|
||||
? projectLyrics.map((s) => ({
|
||||
type: (s?.type || "").toLowerCase(),
|
||||
lyrics: (s?.lyrics || "").trim(),
|
||||
}))
|
||||
: [];
|
||||
const sameLength =
|
||||
normalizedOldLyrics.length === normalizedNewLyrics.length;
|
||||
const isSame =
|
||||
sameLength &&
|
||||
normalizedOldLyrics.every(
|
||||
(s, i) =>
|
||||
s.type === normalizedNewLyrics[i]?.type &&
|
||||
s.lyrics === normalizedNewLyrics[i]?.lyrics,
|
||||
);
|
||||
|
||||
const baseData = {
|
||||
title: titleTrimmed,
|
||||
titleLower: titleTrimmed.toLowerCase(),
|
||||
lyrics: (sections || []).map((s) => ({
|
||||
type: (s?.type || "").toLowerCase(),
|
||||
lyrics: s?.lyrics || "",
|
||||
})),
|
||||
config: sanitize(config),
|
||||
selections: sanitize(selections),
|
||||
userId: user ? user.uid : null,
|
||||
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
lyrics: normalizedNewLyrics,
|
||||
config: sanitize(projectConfig),
|
||||
selections: sanitize(projectSelections),
|
||||
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
hasLyrics,
|
||||
hasLyrics: projectHasLyrics,
|
||||
};
|
||||
const { id: projectId } = await projectsRef.add(payload);
|
||||
navigate(Routes.FlowSelection, { projectId });
|
||||
|
||||
const updateData = { ...baseData };
|
||||
if (!isSame) {
|
||||
updateData.musicUrls = firebase.firestore.FieldValue.delete();
|
||||
updateData.musicStatus = firebase.firestore.FieldValue.delete();
|
||||
await projectsRef
|
||||
.doc(selectedProjectId)
|
||||
.set(updateData, { merge: true });
|
||||
}
|
||||
navigate(Routes.FlowSelection);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
Alert.alert("Erreur", "Échec de l'enregistrement dans le projet.");
|
||||
} finally {
|
||||
await setIsLoading(false);
|
||||
}
|
||||
}, [titleValue, sections, config, selections, setIsLoading]);
|
||||
}, [
|
||||
titleValue,
|
||||
sections,
|
||||
projectConfig,
|
||||
projectSelections,
|
||||
setIsLoading,
|
||||
selectedProjectId,
|
||||
projectHasLyrics,
|
||||
projectLyrics,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Page headerType="NONE">
|
||||
<MusicLandHeader onPressBack={goBack} progress={95} />
|
||||
<MusicLandHeader
|
||||
onPressBack={() => navigate(Routes.FlowSelection)}
|
||||
progress={95}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
@@ -153,6 +223,8 @@ const Lyrics = ({ navigation }) => {
|
||||
height={45}
|
||||
value={titleValue}
|
||||
setValue={setTitleValue}
|
||||
multiline={false}
|
||||
maxLength={60}
|
||||
/>
|
||||
{sections.map((s, idx) => {
|
||||
// Calculer l'index humain par type
|
||||
@@ -184,7 +256,7 @@ const Lyrics = ({ navigation }) => {
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
{!hasLyrics && (
|
||||
{!projectHasLyrics && (
|
||||
<BorderGradientButton
|
||||
title="Générer d'autres paroles"
|
||||
onPress={regenerate}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { View, Image, StyleSheet } from "react-native";
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Page from "../../layouts/Page";
|
||||
import { ai } from "../../assets";
|
||||
import GradientButton from "../../components/GradientButton";
|
||||
@@ -8,8 +8,39 @@ import BorderGradientButton from "../../components/BorderGradientButton";
|
||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||
import { Routes } from "../../navigation";
|
||||
import { useUserData } from "../../providers/UserDataProvider";
|
||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
|
||||
import FullscreenIntroVideo from "../../components/FullscreenIntroVideo";
|
||||
|
||||
const WritingLyrics = () => {
|
||||
const { createNewProject, selectedProject, updateProjectData } =
|
||||
useUserData();
|
||||
const { setIsLoading } = useMinuit();
|
||||
|
||||
const [showIntro, setShowIntro] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProject === null) {
|
||||
setShowIntro(true);
|
||||
}
|
||||
}, [selectedProject]);
|
||||
|
||||
async function createAndNavigate({ hasLyrics = false }) {
|
||||
try {
|
||||
await setIsLoading(true);
|
||||
if (selectedProject) {
|
||||
updateProjectData({ hasLyrics });
|
||||
} else {
|
||||
await createNewProject({ hasLyrics });
|
||||
}
|
||||
setTimeout(() => navigate(Routes.CreateLyricsWithAi), 500);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
} finally {
|
||||
await setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Page headerType="NONE">
|
||||
<Image source={ai.nathalie} style={styles.img} resizeMode="contain" />
|
||||
@@ -25,18 +56,18 @@ const WritingLyrics = () => {
|
||||
}}
|
||||
>
|
||||
<BorderGradientButton
|
||||
onPress={() => {
|
||||
navigate(Routes.CreateLyricsWithAi, {
|
||||
hasLyrics: true,
|
||||
});
|
||||
}}
|
||||
onPress={() => createAndNavigate({ hasLyrics: true })}
|
||||
/>
|
||||
<GradientButton
|
||||
title="Écrire des paroles avec une IA"
|
||||
onPress={() => navigate(Routes.CreateLyricsWithAi)}
|
||||
onPress={() => createAndNavigate({ hasLyrics: false })}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<FullscreenIntroVideo
|
||||
visible={showIntro}
|
||||
onClose={() => setShowIntro(false)}
|
||||
/>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,6 +9,8 @@ const CustomInput = ({
|
||||
value,
|
||||
setValue,
|
||||
height = 65,
|
||||
multiline = true,
|
||||
maxLength,
|
||||
}) => {
|
||||
return (
|
||||
<View style={{ gap: 8 }}>
|
||||
@@ -42,8 +44,10 @@ const CustomInput = ({
|
||||
color: Palette.black,
|
||||
fontFamily: FONT_FAMILY.InterRegularItalic,
|
||||
}}
|
||||
multiline
|
||||
textAlignVertical="top"
|
||||
multiline={multiline}
|
||||
numberOfLines={multiline ? undefined : 1}
|
||||
maxLength={maxLength}
|
||||
textAlignVertical={multiline ? "top" : "center"}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
Reference in New Issue
Block a user