big refacto change all flows

This commit is contained in:
Thomas Demirdjian
2025-09-03 15:43:22 +02:00
parent 8f1c062b33
commit 60d1794c99
29 changed files with 841 additions and 344 deletions
+123
View File
@@ -0,0 +1,123 @@
import { View, Text, Image } from "react-native";
import React, { useState } from "react";
import MusicLandHeader from "../../components/MusicLandHeader";
import { background, icons, img } from "../../assets";
import Page from "../../layouts/Page";
import { goBack, navigate } from "../../navigation/NavigationService";
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
import { gutters, Palette, Style } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts";
import BorderGradientButton from "../../components/BorderGradientButton";
import GradientButton from "../../components/GradientButton";
import { launchImageLibraryAsync } from "expo-image-picker";
import { Routes } from "../../navigation";
const AddPhotoCover = () => {
const [image, setImage] = useState(null);
const onPressAddImage = async () => {
const result = await launchImageLibraryAsync({
mediaTypes: ["images"],
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.canceled) {
setImage(result.assets[0]?.uri);
}
};
return (
<Page backgroundImg={background.studioBG2} headerType="NONE">
<MusicLandHeader onPressBack={goBack} progress={90} />
<View style={{ flex: 1, marginTop: 16 }}>
<CreateLyricsHeader
title="Ta pochette est prête!"
subTitle="Quen penses-tu ?"
/>
<View style={{ flex: 1, ...Style.containerCenter }}>
<View style={{ width: "80%", position: "relative" }}>
<Image
source={img.placeholder}
style={{
width: "100%",
height: 300,
borderRadius: 20,
transform: [{ rotateY: "180deg" }],
}}
/>
<View
style={{ position: "absolute", width: "100%", height: "100%" }}
>
<Image
source={{ uri: image }}
style={{ width: "100%", height: "100%", borderRadius: 20 }}
/>
</View>
<View
style={{
position: "absolute",
alignSelf: "center",
alignItems: "center",
top: 10,
}}
>
<Text
style={{
fontSize: 22,
color: Palette.white,
fontFamily: FONT_FAMILY.InterSemiBold,
}}
>
Lust for Life
</Text>
<Text
style={{
fontSize: 14,
color: Palette.gray,
fontFamily: FONT_FAMILY.InterRegular,
}}
>
Lana del Rey
</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>
<View
style={{
paddingBottom: gutters * 2,
width: "80%",
alignSelf: "center",
gap: 12,
}}
>
<BorderGradientButton
title="Ajouter une autre photo"
onPress={onPressAddImage}
/>
<GradientButton
title="Valider"
onPress={() => navigate(Routes.FlowSelection)}
/>
</View>
</Page>
);
};
export default AddPhotoCover;
+54
View File
@@ -0,0 +1,54 @@
import { View, StyleSheet, Image } from "react-native";
import React, { useState } from "react";
import { ai, background } from "../../assets";
import Page from "../../layouts/Page";
import { goBack, navigate } from "../../navigation/NavigationService";
import MusicLandHeader from "../../components/MusicLandHeader";
import { Routes } from "../../navigation";
import GradientButton from "../../components/GradientButton";
import { gutters } from "../../styles";
import FullscreenIntroVideo from "../../components/FullscreenIntroVideo";
import BorderGradientButton from "../../components/BorderGradientButton";
const ChooseCoverType = () => {
const [showIntro, setShowIntro] = useState(true);
return (
<Page backgroundImg={background.productionBG2} headerType="NONE">
<Image source={ai.bena} style={styles.img} resizeMode="contain" />
<MusicLandHeader onPressBack={goBack} progress={9} />
<View
style={{ flex: 1, position: "relative", justifyContent: "flex-end" }}
>
<View
style={{
paddingBottom: gutters * 2,
paddingHorizontal: gutters,
gap: 12,
}}
>
<BorderGradientButton title="Choisir une image" />
<GradientButton
title="Générer une pochette"
onPress={() => navigate(Routes.PouchReady)}
/>
</View>
</View>
<FullscreenIntroVideo
visible={showIntro}
onClose={() => setShowIntro(false)}
/>
</Page>
);
};
export default ChooseCoverType;
const styles = StyleSheet.create({
img: {
width: "100%",
height: "70%",
position: "absolute",
bottom: -40,
right: -30,
},
});
+53
View File
@@ -0,0 +1,53 @@
import { View, Image, StyleSheet } from "react-native";
import React from "react";
import { ai, background } from "../../assets";
import Page from "../../layouts/Page";
import { goBack, navigate } from "../../navigation/NavigationService";
import MusicLandHeader from "../../components/MusicLandHeader";
import { gutters } from "../../styles";
import { Routes } from "../../navigation";
import GradientButton from "../../components/GradientButton";
import BorderGradientButton from "../../components/BorderGradientButton";
const FinishCompose = () => {
return (
<Page backgroundImg={background.studioBG2} headerType="NONE">
<Image source={ai.theo} style={styles.img} resizeMode="contain" />
<MusicLandHeader onPressBack={goBack} progress={100} />
<View
style={{ flex: 1, position: "relative", justifyContent: "flex-end" }}
>
<View
style={{
paddingBottom: gutters * 2,
width: "70%",
alignSelf: "center",
gap: 12,
}}
>
<BorderGradientButton
title="Continuer plus tard"
onPress={() => navigate(Routes.Home)}
/>
<GradientButton
title="Continuer la création"
onPress={() => navigate(Routes.Home)}
/>
</View>
</View>
</Page>
);
};
export default FinishCompose;
const styles = StyleSheet.create({
img: {
width: "100%",
height: "70%",
position: "absolute",
bottom: -40,
right: -30,
},
});
+93
View File
@@ -0,0 +1,93 @@
import { View, Text, Image } from "react-native";
import React from "react";
import MusicLandHeader from "../../components/MusicLandHeader";
import { background, icons, img } from "../../assets";
import Page from "../../layouts/Page";
import { goBack, navigate } from "../../navigation/NavigationService";
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
import { gutters, Palette, Style } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts";
import BorderGradientButton from "../../components/BorderGradientButton";
import { Routes } from "../../navigation";
import GradientButton from "../../components/GradientButton";
const PhotoCover = () => {
return (
<Page backgroundImg={background.studioBG2} headerType="NONE">
<MusicLandHeader onPressBack={goBack} progress={81} />
<View style={{ flex: 1, marginTop: 16 }}>
<CreateLyricsHeader title="Souhaites-tu rajouter une photo de toi sur la pochette?" />
<View style={{ flex: 1, ...Style.containerCenter }}>
<View style={{ width: "80%", position: "relative" }}>
<Image
source={img.placeholder}
style={{
width: "100%",
height: 300,
borderRadius: 20,
transform: [{ rotateY: "180deg" }],
}}
/>
<View
style={{
position: "absolute",
alignSelf: "center",
alignItems: "center",
top: 10,
}}
>
<Text
style={{
fontSize: 22,
color: Palette.white,
fontFamily: FONT_FAMILY.InterSemiBold,
}}
>
Lust for Life
</Text>
<Text
style={{
fontSize: 14,
color: Palette.gray,
fontFamily: FONT_FAMILY.InterRegular,
}}
>
Lana del Rey
</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>
<View
style={{
paddingBottom: gutters * 2,
width: "80%",
alignSelf: "center",
gap: 12,
}}
>
<BorderGradientButton title="Non, laisser la pochette telle quelle" />
<GradientButton
title="Oui"
onPress={() => navigate(Routes.AddPhotoCover)}
/>
</View>
</Page>
);
};
export default PhotoCover;
+171
View File
@@ -0,0 +1,171 @@
import { View, Text, Image, ActivityIndicator } from "react-native";
import { Image as ExpoImage } from "expo-image";
import React, { useEffect, useState } from "react";
import Page from "../../layouts/Page";
import { background, icons, img } from "../../assets";
import MusicLandHeader from "../../components/MusicLandHeader";
import { goBack, navigate } from "../../navigation/NavigationService";
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
import { gutters, Palette, Style } from "../../styles";
import BorderGradientButton from "../../components/BorderGradientButton";
import GradientButton from "../../components/GradientButton";
import { Routes } from "../../navigation";
import { FONT_FAMILY } from "../../styles/Fonts";
import firebase, { tasksRef } from "../../config/firebase";
import { useUser } from "../../providers/UserDataProvider";
const PouchReady = () => {
const { selectedProjectId, selectedProject, updateProjectData } = useUser();
const [coverUrl, setCoverUrl] = useState(null);
const [loading, setLoading] = useState(false);
const [title, setTitle] = useState("");
const [coverStatus, setCoverStatus] = useState(null);
const isGenerating = coverStatus === "GENERATING";
useEffect(() => {
const d = selectedProject || {};
setTitle(d?.title || "");
setCoverUrl(d?.coverUrl || null);
setCoverStatus(d?.coverStatus || null);
}, [
selectedProject?.title,
selectedProject?.coverUrl,
selectedProject?.coverStatus,
]);
const generateCover = async () => {
if (!selectedProjectId) return;
try {
setLoading(true);
await updateProjectData({ coverStatus: "GENERATING" });
await tasksRef.add({
type: "cover",
projectId: selectedProjectId,
status: "PENDING",
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
});
} catch (e) {
console.log("Cover task error", e?.message);
} finally {
setLoading(false);
}
};
useEffect(() => {
if (!selectedProjectId) return;
if (!coverUrl && !isGenerating && !loading) {
generateCover();
}
}, [selectedProjectId, coverUrl, isGenerating]);
return (
<Page backgroundImg={background.studioBG2} headerType="NONE">
<MusicLandHeader onPressBack={goBack} progress={72} />
<View style={{ flex: 1, marginTop: 16 }}>
<CreateLyricsHeader
title={
coverUrl ? "Ta pochette est prête!" : "Génération de la pochette"
}
subTitle="Quen penses-tu ?"
/>
<View style={{ flex: 1, ...Style.containerCenter }}>
<View style={{ width: "80%", position: "relative" }}>
{coverUrl ? (
<ExpoImage
source={{ uri: coverUrl }}
cachePolicy="memory-disk"
priority="high"
contentFit="cover"
transition={120}
style={{ width: "100%", height: 300, borderRadius: 20 }}
/>
) : (
<View
style={{
width: "100%",
height: 300,
borderRadius: 20,
backgroundColor: "#00000040",
...Style.containerCenter,
}}
>
{isGenerating || loading ? (
<ActivityIndicator color={Palette.white} />
) : (
<Image
source={img.placeholder}
style={{ width: 120, height: 120, opacity: 0.5 }}
/>
)}
</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>
<View
style={{
paddingBottom: gutters * 2,
width: "80%",
alignSelf: "center",
gap: 12,
}}
>
<BorderGradientButton
title={isGenerating ? "Génération en cours..." : "Regénérer"}
icon={icons.stars}
onPress={generateCover}
disabled={isGenerating}
/>
<GradientButton
title={isGenerating ? "Veuillez patienter..." : "Valider"}
disabled={isGenerating || !coverUrl}
onPress={() => navigate(Routes.PhotoCover)}
/>
</View>
</Page>
);
};
export default PouchReady;