272 lines
8.6 KiB
JavaScript
272 lines
8.6 KiB
JavaScript
import { Image as ExpoImage } from "expo-image";
|
|
import React, { useCallback, useMemo, useState } from "react";
|
|
import { Pressable, Text, View } from "react-native";
|
|
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
|
|
import { background } from "../../assets";
|
|
import GradientButton from "../../components/GradientButton";
|
|
import MusicLandHeader from "../../components/MusicLandHeader";
|
|
import { isWeb } from "../../hooks/useLayoutType";
|
|
import Page from "../../layouts/Page";
|
|
import { Routes } from "../../navigation";
|
|
import { goBack, navigate } from "../../navigation/NavigationService";
|
|
import { useUserData } from "../../providers/UserDataProvider";
|
|
import { gutters, Palette, Style } from "../../styles";
|
|
import { getStageAction } from "../../utils/projectStages";
|
|
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
|
|
|
|
const ValidateCover = () => {
|
|
const { selectedProject, updateProjectData } = useUserData();
|
|
const { setIsLoading } = useMinuit();
|
|
|
|
const coverOptions = useMemo(() => {
|
|
if (!Array.isArray(selectedProject?.cover?.options)) {
|
|
return [];
|
|
}
|
|
return selectedProject.cover.options.filter((option) => option);
|
|
}, [selectedProject]);
|
|
|
|
const selectedOptionId = selectedProject?.cover?.selectedOptionId || null;
|
|
const selectedOption = useMemo(() => {
|
|
if (!coverOptions.length) {
|
|
return null;
|
|
}
|
|
const found = coverOptions.find(
|
|
(option) => option?.id === selectedOptionId
|
|
);
|
|
return found || coverOptions[0] || null;
|
|
}, [coverOptions, selectedOptionId]);
|
|
|
|
const isMultipleOptions = coverOptions.length > 1;
|
|
const [isSelecting, setIsSelecting] = useState(false);
|
|
|
|
async function onStartAgain() {
|
|
try {
|
|
await setIsLoading(true);
|
|
await updateProjectData({
|
|
cover: null,
|
|
coverUrl: null,
|
|
});
|
|
navigate(Routes.ChooseCoverType);
|
|
} catch (e) {
|
|
console.log(e);
|
|
} finally {
|
|
await setIsLoading(false);
|
|
}
|
|
}
|
|
|
|
const handleSelectOption = useCallback(
|
|
async (option) => {
|
|
if (!option || option?.id === selectedOptionId || isSelecting) {
|
|
return;
|
|
}
|
|
const existingCover = selectedProject?.cover || {};
|
|
const finalUrl = option.finalUrl || option.generatedUrl || null;
|
|
setIsSelecting(true);
|
|
try {
|
|
await updateProjectData({
|
|
cover: {
|
|
...existingCover,
|
|
options: coverOptions,
|
|
selectedOptionId: option.id,
|
|
result: finalUrl,
|
|
generatedBackground: option.generatedUrl || option.finalUrl || null,
|
|
},
|
|
});
|
|
} catch (e) {
|
|
console.log("ValidateCover: unable to select cover", e?.message);
|
|
} finally {
|
|
setIsSelecting(false);
|
|
}
|
|
},
|
|
[
|
|
coverOptions,
|
|
isSelecting,
|
|
selectedOptionId,
|
|
selectedProject,
|
|
updateProjectData,
|
|
]
|
|
);
|
|
|
|
async function onValidatePicture() {
|
|
if (!selectedOption) {
|
|
return;
|
|
}
|
|
try {
|
|
await setIsLoading(true);
|
|
const existingCover = selectedProject?.cover || {};
|
|
const finalUrl =
|
|
selectedOption.finalUrl || selectedOption.generatedUrl || null;
|
|
const nextCoverData = {
|
|
...existingCover,
|
|
options: coverOptions,
|
|
selectedOptionId: selectedOption.id,
|
|
result: finalUrl,
|
|
generatedBackground:
|
|
selectedOption.generatedUrl || selectedOption.finalUrl || null,
|
|
};
|
|
await updateProjectData({
|
|
cover: nextCoverData,
|
|
coverUrl: finalUrl,
|
|
});
|
|
const projectForStage = {
|
|
...selectedProject,
|
|
cover: nextCoverData,
|
|
coverUrl: finalUrl,
|
|
};
|
|
const playbackStage = getStageAction("director", projectForStage);
|
|
await setIsLoading(false);
|
|
const targetRoute = playbackStage?.route || Routes.Playback;
|
|
const params = playbackStage?.params || { project: projectForStage };
|
|
navigate(targetRoute, params);
|
|
return;
|
|
} catch (e) {
|
|
console.log(e);
|
|
} finally {
|
|
await setIsLoading(false);
|
|
}
|
|
}
|
|
|
|
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="Choisis ta version préférée."
|
|
/>
|
|
<View style={{ flex: 1, ...Style.containerCenter }}>
|
|
<View
|
|
style={{
|
|
width: "90%",
|
|
gap: 16,
|
|
flexDirection: isMultipleOptions ? "row" : "column",
|
|
flexWrap: isMultipleOptions ? "wrap" : "nowrap",
|
|
justifyContent: "center",
|
|
alignItems: isMultipleOptions ? "stretch" : "center",
|
|
}}
|
|
>
|
|
{coverOptions.map((option, index) => {
|
|
const isSelected = option?.id === selectedOption?.id;
|
|
const imageSource =
|
|
option?.finalUrl || option?.generatedUrl || null;
|
|
|
|
if (!imageSource) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<Pressable
|
|
key={option?.id || index}
|
|
onPress={() => handleSelectOption(option)}
|
|
disabled={isSelecting}
|
|
style={{
|
|
borderRadius: 20,
|
|
borderWidth: isSelected ? 2 : 1,
|
|
borderColor: isSelected
|
|
? Palette.primary
|
|
: Palette.ultraLightWhite,
|
|
overflow: "hidden",
|
|
width: isMultipleOptions
|
|
? isWeb
|
|
? 280
|
|
: "48%"
|
|
: isWeb
|
|
? 300
|
|
: "90%",
|
|
maxWidth: isWeb ? 320 : "100%",
|
|
position: "relative",
|
|
}}
|
|
>
|
|
<ExpoImage
|
|
source={{ uri: imageSource }}
|
|
cachePolicy="memory-disk"
|
|
contentFit="cover"
|
|
transition={120}
|
|
style={{ width: "100%", aspectRatio: 1 }}
|
|
/>
|
|
<View
|
|
style={{
|
|
position: "absolute",
|
|
top: 12,
|
|
right: 12,
|
|
backgroundColor: Palette.transparentBlack,
|
|
paddingHorizontal: 10,
|
|
paddingVertical: 6,
|
|
borderRadius: 12,
|
|
}}
|
|
>
|
|
<Text
|
|
style={{
|
|
color: Palette.white,
|
|
fontWeight: "600",
|
|
fontSize: 12,
|
|
}}
|
|
>
|
|
{`Option ${index + 1}`}
|
|
</Text>
|
|
</View>
|
|
{isSelected && (
|
|
<View
|
|
style={{
|
|
position: "absolute",
|
|
bottom: 12,
|
|
left: 12,
|
|
backgroundColor: Palette.primary,
|
|
paddingHorizontal: 12,
|
|
paddingVertical: 6,
|
|
borderRadius: 12,
|
|
}}
|
|
>
|
|
<Text
|
|
style={{
|
|
color: Palette.white,
|
|
fontWeight: "600",
|
|
fontSize: 12,
|
|
}}
|
|
>
|
|
Sélectionnée
|
|
</Text>
|
|
</View>
|
|
)}
|
|
</Pressable>
|
|
);
|
|
})}
|
|
{!coverOptions.length && (
|
|
<Text
|
|
style={{
|
|
color: Palette.white,
|
|
textAlign: "center",
|
|
opacity: 0.8,
|
|
}}
|
|
>
|
|
Les options de pochette seront disponibles à la fin de la
|
|
génération.
|
|
</Text>
|
|
)}
|
|
</View>
|
|
</View>
|
|
</View>
|
|
<View
|
|
style={{
|
|
paddingBottom: gutters * 2,
|
|
width: "80%",
|
|
alignSelf: "center",
|
|
gap: 12,
|
|
}}
|
|
>
|
|
{/* <BorderGradientButton
|
|
title="Recommencer la création"
|
|
onPress={onStartAgain}
|
|
/> */}
|
|
<GradientButton
|
|
title="Valider la pochette"
|
|
onPress={onValidatePicture}
|
|
disabled={!selectedOption || isSelecting}
|
|
/>
|
|
</View>
|
|
</Page>
|
|
);
|
|
};
|
|
|
|
export default ValidateCover;
|