new song structure

This commit is contained in:
2025-10-21 11:38:48 +02:00
parent 59328aaaed
commit 3a5d449424
11 changed files with 807 additions and 175 deletions
+35 -25
View File
@@ -15,6 +15,12 @@ import { navigate } from "../../navigation/NavigationService";
import { useUser } from "../../providers/UserDataProvider";
import { Palette, gutters } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts";
import {
formatStructureLabel,
getSegmentMeta,
normalizeStructureType,
sanitizeStructureList,
} from "../../utils/songStructure";
import CustomInput from "./components/CustomInput";
const Lyrics = ({ navigation }) => {
@@ -36,26 +42,23 @@ const Lyrics = ({ navigation }) => {
const initial = useMemo(() => {
const title = projectTitle || "";
const aiSections = Array.isArray(projectLyrics) ? projectLyrics : [];
// Respecter l'ordre de la structure choisie si disponible
const normalizedSections = Array.isArray(projectLyrics)
? projectLyrics.map((s) => ({
type: normalizeStructureType(s?.type),
lyrics: s?.lyrics || "",
}))
: [];
const targetStructure = Array.isArray(projectConfig?.structure)
? projectConfig.structure.map((t) => (t || "").toLowerCase())
? sanitizeStructureList(projectConfig.structure)
: null;
// 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.
if (normalizedSections.length) {
return {
title,
sections: aiSections.map((s) => ({
type: (s?.type || "").toLowerCase(),
lyrics: s?.lyrics || "",
})),
sections: normalizedSections,
};
}
// 2) Sinon, créer à partir de la structure si fournie
if (targetStructure && targetStructure.length) {
return {
title,
@@ -63,7 +66,6 @@ const Lyrics = ({ navigation }) => {
};
}
// 3) Fallback vide
return { title, sections: [] };
}, [projectTitle, projectLyrics, projectConfig]);
@@ -133,17 +135,17 @@ const Lyrics = ({ navigation }) => {
if (invalid) {
alertMessage(
"Champs incomplets",
"Chaque couplet et refrain doit contenir du texte."
"Chaque section doit contenir du texte."
);
return;
}
const normalizedNewLyrics = (sections || []).map((s) => ({
type: (s?.type || "").toLowerCase(),
type: normalizeStructureType(s?.type),
lyrics: (s?.lyrics || "").trim(),
}));
const normalizedOldLyrics = Array.isArray(projectLyrics)
? projectLyrics.map((s) => ({
type: (s?.type || "").toLowerCase(),
type: normalizeStructureType(s?.type),
lyrics: (s?.lyrics || "").trim(),
}))
: [];
@@ -264,6 +266,8 @@ const Lyrics = ({ navigation }) => {
projectLyrics,
]);
const typeOccurrences = {};
return (
<Page
backgroundImg={isWeb ? background.libraryBgWeb : background.writingBG}
@@ -332,19 +336,25 @@ const Lyrics = ({ navigation }) => {
}}
/>
{sections.map((s, idx) => {
// Calculer l'index humain par type
const type = (s?.type || "").toLowerCase();
const countBefore = sections
.slice(0, idx)
.filter((x) => (x?.type || "").toLowerCase() === type).length;
const labelBase = type === "refrain" ? "Refrain" : "Couplet";
const label = `${labelBase} ${countBefore + 1}`;
const normalizedType = normalizeStructureType(s?.type);
const key = normalizedType || "section";
typeOccurrences[key] = (typeOccurrences[key] || 0) + 1;
const occurrence = typeOccurrences[key];
const label = formatStructureLabel(key, occurrence);
const meta = getSegmentMeta(key);
const inputHeight =
typeof meta?.inputHeight === "number"
? meta.inputHeight
: key === "refrain"
? 170
: 225;
const placeholder = meta?.label || label;
return (
<CustomInput
key={idx}
label={label}
placeholder={labelBase}
height={type === "refrain" ? 170 : 225}
placeholder={placeholder}
height={inputHeight}
value={s?.lyrics || ""}
setValue={(val) => setSectionAt(idx, val)}
onFocus={() => {