generate two covers

This commit is contained in:
2025-10-23 10:16:36 +02:00
parent b4375d04be
commit ebe26542fe
9 changed files with 754 additions and 436 deletions
+165 -125
View File
@@ -1,6 +1,5 @@
import { useIsFocused } from "@react-navigation/native";
import { Image as ExpoImage } from "expo-image";
import React, { useCallback, useEffect } from "react";
import React, { useCallback, useEffect, useState } from "react";
import { ActivityIndicator, Text, View } from "react-native";
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
import { background, icons } from "../../assets";
@@ -17,20 +16,48 @@ import { goBack, navigate } from "../../navigation/NavigationService";
import { useUser } from "../../providers/UserDataProvider";
import { gutters, Palette, Style } from "../../styles";
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
import CustomInput from "../Writing/components/CustomInput";
const PouchReady = () => {
const { selectedProjectId, selectedProject } = useUser();
const { selectedProjectId, selectedProject, updateProjectData } = useUser();
const { setIsLoading } = useMinuit();
const isGenerating = selectedProject?.coverStatus === "GENERATING";
const isFocused = useIsFocused();
const coverOptions = Array.isArray(selectedProject?.cover?.options)
? selectedProject.cover.options
: [];
const hasGeneratedOptions = coverOptions.length > 0;
const coverBackgroundMessage = isWeb
? loaderMessages.pouchReadyGenerationWeb
: "";
const generateCover = useCallback(async () => {
const [coverStyle, setCoverStyle] = useState(
selectedProject?.coverStyle || ""
);
useEffect(() => {
setCoverStyle(selectedProject?.coverStyle || "");
}, [selectedProject?.coverStyle]);
const generateCover = useCallback(async (styleValue) => {
if (!selectedProjectId) return;
if (hasGeneratedOptions) {
return;
}
const trimmedStyle = String(styleValue || "").trim();
if (!trimmedStyle) {
alert("Attention", "Merci de renseigner un style pour la pochette.", [
{ text: "OK" },
]);
return;
}
try {
await setIsLoading(true);
await updateProjectData(
{
coverStyle: trimmedStyle,
},
{ merge: true }
);
await tasksRef.add({
type: "cover",
projectId: selectedProjectId,
@@ -42,40 +69,49 @@ const PouchReady = () => {
} finally {
setIsLoading(false);
}
}, [selectedProjectId, setIsLoading]);
}, [hasGeneratedOptions, selectedProjectId, setIsLoading, updateProjectData]);
const requestCoverGeneration = useCallback(() => {
const trimmedStyle = (coverStyle || "").trim();
if (!trimmedStyle) {
alert("Attention", "Merci de renseigner un style pour la pochette.", [
{ text: "OK" },
]);
return;
}
alert("Attention", "Générer une pochette ?", [
{
text: "Annuler",
style: "cancel",
},
{
text: "Oui",
onPress: () => generateCover(trimmedStyle),
},
]);
}, [coverStyle, generateCover]);
const validateCover = () => {
navigate(Routes.ValidateCover);
};
useEffect(() => {
if (
isFocused &&
!selectedProject?.cover?.generatedBackground &&
selectedProject?.coverStatus !== "GENERATING"
) {
alert(
"Attention",
"Générer une pochette ?",
[
{
text: "Oui",
onPress: generateCover,
},
{
text: "Non",
},
],
{ cancelable: true }
);
}
}, [generateCover, isFocused, selectedProject]);
const coverPreviewUrl =
selectedProject?.cover?.result ||
selectedProject?.cover?.generatedBackground ||
null;
const displayOptions = hasGeneratedOptions
? coverOptions
: coverPreviewUrl
? [
{
id: "preview",
finalUrl: selectedProject?.cover?.result || null,
generatedUrl: coverPreviewUrl,
},
]
: [];
return (
<Page backgroundImg={background.studioBG2} headerType="NONE">
<MusicLandHeader onPressBack={goBack} progress={72} />
@@ -89,37 +125,82 @@ const PouchReady = () => {
// subTitle="Quen penses-tu ?"
/>
<View style={{ flex: 1, ...Style.containerCenter }}>
<View style={{ width: "80%", position: "relative" }}>
{coverPreviewUrl && !isGenerating ? (
<ExpoImage
source={{ uri: coverPreviewUrl }}
cachePolicy="memory-disk"
priority="high"
contentFit="cover"
transition={120}
style={{
width: isWeb ? 300 : "100%",
height: 300,
borderRadius: 20,
alignSelf: "center",
}}
/>
) : (
<View
style={{
width: isWeb ? 300 : "100%",
height: 300,
borderRadius: 20,
backgroundColor: "#00000040",
alignSelf: "center",
...Style.containerCenter,
}}
>
{isGenerating && (
<View style={{ alignItems: "center", gap: 8 }}>
<ActivityIndicator color={Palette.white} />
{isWeb ? (
coverBackgroundMessage ? (
<View style={{ width: "80%", gap: 24 }}>
<View
style={{
width: "100%",
flexDirection: isWeb ? "row" : "column",
gap: 16,
justifyContent: "center",
flexWrap: "wrap",
}}
>
{displayOptions.length > 0 ? (
displayOptions.map((option, index) => {
const optionUri = option?.finalUrl || option?.generatedUrl || "";
if (!optionUri) return null;
return (
<View
key={option?.id || index}
style={{
width: isWeb ? 280 : "100%",
alignItems: "center",
gap: 8,
}}
>
<ExpoImage
source={{ uri: optionUri }}
cachePolicy="memory-disk"
priority="high"
contentFit="cover"
transition={120}
style={{
width: "100%",
height: 260,
borderRadius: 20,
}}
/>
{hasGeneratedOptions && (
<Text
style={{
color: Palette.white,
opacity: 0.7,
}}
>
Pochette {index + 1}
</Text>
)}
</View>
);
})
) : (
<View
style={{
width: isWeb ? 300 : "100%",
height: 300,
borderRadius: 20,
backgroundColor: "#00000040",
alignSelf: "center",
...Style.containerCenter,
}}
>
{isGenerating && (
<View style={{ alignItems: "center", gap: 8 }}>
<ActivityIndicator color={Palette.white} />
{isWeb ? (
coverBackgroundMessage ? (
<Text
style={{
color: Palette.white,
marginTop: 6,
textAlign: "center",
opacity: 0.9,
}}
>
{coverBackgroundMessage}
</Text>
) : null
) : (
<Text
style={{
color: Palette.white,
@@ -128,66 +209,23 @@ const PouchReady = () => {
opacity: 0.9,
}}
>
{coverBackgroundMessage}
Génération en cours.
</Text>
) : null
) : (
<Text
style={{
color: Palette.white,
marginTop: 6,
textAlign: "center",
opacity: 0.9,
}}
>
Génération en cours.
</Text>
)}
</View>
)}
</View>
)}
{/*<View*/}
{/* style={{*/}
{/* position: "absolute",*/}
{/* alignSelf: "center",*/}
{/* alignItems: "center",*/}
{/* top: 10,*/}
{/* }}*/}
{/*>*/}
{/* <Text*/}
{/* style={{*/}
{/* fontSize: 22,*/}
{/* color: Palette.white,*/}
{/* fontFamily: FONT_FAMILY.InterSemiBold,*/}
{/* }}*/}
{/* >*/}
{/* {title || "Titre"}*/}
{/* </Text>*/}
{/* <Text*/}
{/* style={{*/}
{/* fontSize: 14,*/}
{/* color: Palette.gray,*/}
{/* fontFamily: FONT_FAMILY.InterRegular,*/}
{/* }}*/}
{/* >*/}
{/* MusicLand*/}
{/* </Text>*/}
{/*</View>*/}
{/*<View*/}
{/* style={{*/}
{/* position: "absolute",*/}
{/* alignItems: "center",*/}
{/* bottom: 10,*/}
{/* width: "100%",*/}
{/* }}*/}
{/*>*/}
{/* <Image*/}
{/* source={icons.musicLandLogo}*/}
{/* style={{ width: "100%", height: 30 }}*/}
{/* resizeMode="contain"*/}
{/* />*/}
{/*</View>*/}
)}
</View>
)}
</View>
)}
</View>
<CustomInput
label="Style de la pochette"
placeholder="Exemple : Collage rétro futuriste lumineux"
value={coverStyle}
setValue={setCoverStyle}
multiline={false}
height={55}
maxLength={120}
/>
</View>
</View>
</View>
@@ -199,12 +237,14 @@ const PouchReady = () => {
gap: 12,
}}
>
<BorderGradientButton
title={isGenerating ? "Génération en cours..." : "Regénérer"}
icon={icons.stars}
onPress={generateCover}
disabled={isGenerating}
/>
{!hasGeneratedOptions && (
<BorderGradientButton
title={isGenerating ? "Génération en cours..." : "Générer la pochette"}
icon={icons.stars}
onPress={requestCoverGeneration}
disabled={isGenerating}
/>
)}
<GradientButton
title={isGenerating ? "Veuillez patienter..." : "Valider"}
disabled={isGenerating || !coverPreviewUrl}