feat: fixes and formatter
This commit is contained in:
+243
-311
@@ -1,12 +1,6 @@
|
||||
import { BlurView } from "expo-blur";
|
||||
import { Image as ExpoImage } from "expo-image";
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { BlurView } from 'expo-blur'
|
||||
import { Image as ExpoImage } from 'expo-image'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Image,
|
||||
@@ -17,241 +11,211 @@ import {
|
||||
View,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
} from "react-native";
|
||||
import { background, icons } from "../../assets";
|
||||
import alert from "../../components/Alert";
|
||||
import AppCheckbox from "../../components/AppCheckbox";
|
||||
import BorderGradientButton from "../../components/BorderGradientButton";
|
||||
import GradientButton from "../../components/GradientButton";
|
||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||
import firebase, { tasksRef } from "../../config/firebase";
|
||||
import loaderMessages from "../../config/loaderMessages";
|
||||
import { isWeb } from "../../hooks/useLayoutType";
|
||||
import useGlobalLoading from "../../hooks/useGlobalLoading";
|
||||
import Page from "../../layouts/Page";
|
||||
import { Routes } from "../../navigation";
|
||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||
import { useUser } from "../../providers/UserDataProvider";
|
||||
import { gutters, Palette, Style } from "../../styles";
|
||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||
import { getStageAction } from "../../utils/projectStages";
|
||||
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
|
||||
import ProgressBar from "../../components/ProgressBar";
|
||||
} from 'react-native'
|
||||
import { background, icons } from '../../assets'
|
||||
import alert from '../../components/Alert'
|
||||
import AppCheckbox from '../../components/AppCheckbox'
|
||||
import BorderGradientButton from '../../components/BorderGradientButton'
|
||||
import GradientButton from '../../components/GradientButton'
|
||||
import MusicLandHeader from '../../components/MusicLandHeader'
|
||||
import firebase, { tasksRef } from '../../config/firebase'
|
||||
import loaderMessages from '../../config/loaderMessages'
|
||||
import { isWeb } from '../../hooks/useLayoutType'
|
||||
import useGlobalLoading from '../../hooks/useGlobalLoading'
|
||||
import Page from '../../layouts/Page'
|
||||
import { Routes } from '../../navigation'
|
||||
import { goBack, navigate } from '../../navigation/NavigationService'
|
||||
import { useUser } from '../../providers/UserDataProvider'
|
||||
import { gutters, Palette, Style } from '../../styles'
|
||||
import { FONT_FAMILY } from '../../styles/Fonts'
|
||||
import { getStageAction } from '../../utils/projectStages'
|
||||
import CreateLyricsHeader from '../Writing/components/CreateLyricsHeader'
|
||||
import ProgressBar from '../../components/ProgressBar'
|
||||
|
||||
const COVER_STYLE_PRESETS = [
|
||||
"Cyberpunk",
|
||||
"Dessins animé",
|
||||
"Dessins animé rétro",
|
||||
"Portrait théâtralisé",
|
||||
"Livre de coloriage",
|
||||
"Shooting",
|
||||
];
|
||||
const COVER_PROGRESS_MAX = 98;
|
||||
const COVER_PROGRESS_INTERVAL_MS = 500;
|
||||
const COVER_FAKE_DURATION_MS = 2 * 60 * 1000;
|
||||
'Cyberpunk',
|
||||
'Dessins animé',
|
||||
'Dessins animé rétro',
|
||||
'Portrait théâtralisé',
|
||||
'Livre de coloriage',
|
||||
'Shooting',
|
||||
]
|
||||
const COVER_PROGRESS_MAX = 98
|
||||
const COVER_PROGRESS_INTERVAL_MS = 500
|
||||
const COVER_FAKE_DURATION_MS = 2 * 60 * 1000
|
||||
|
||||
const PouchReady = () => {
|
||||
const { selectedProjectId, selectedProject, updateProjectData } = useUser();
|
||||
const { setLoading } = useGlobalLoading();
|
||||
const isGenerating = selectedProject?.coverStatus === "GENERATING";
|
||||
const { selectedProjectId, selectedProject, updateProjectData } = useUser()
|
||||
const { setLoading } = useGlobalLoading()
|
||||
const isGenerating = selectedProject?.coverStatus === 'GENERATING'
|
||||
const coverOptions = useMemo(() => {
|
||||
if (!Array.isArray(selectedProject?.cover?.options)) {
|
||||
return [];
|
||||
return []
|
||||
}
|
||||
return selectedProject.cover.options.filter(Boolean);
|
||||
}, [selectedProject?.cover?.options]);
|
||||
const hasGeneratedOptions = coverOptions.length > 0;
|
||||
const selectedOptionId = selectedProject?.cover?.selectedOptionId || null;
|
||||
return selectedProject.cover.options.filter(Boolean)
|
||||
}, [selectedProject?.cover?.options])
|
||||
const hasGeneratedOptions = coverOptions.length > 0
|
||||
const selectedOptionId = selectedProject?.cover?.selectedOptionId || null
|
||||
const selectedOption = useMemo(() => {
|
||||
if (!coverOptions.length) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
const found = coverOptions.find(
|
||||
(option) => option?.id === selectedOptionId,
|
||||
);
|
||||
return found || coverOptions[0] || null;
|
||||
}, [coverOptions, selectedOptionId]);
|
||||
const coverBackgroundMessage = isWeb
|
||||
? loaderMessages.pouchReadyGenerationWeb
|
||||
: "";
|
||||
const found = coverOptions.find((option) => option?.id === selectedOptionId)
|
||||
return found || coverOptions[0] || null
|
||||
}, [coverOptions, selectedOptionId])
|
||||
const coverBackgroundMessage = isWeb ? loaderMessages.pouchReadyGenerationWeb : ''
|
||||
const generationLoadingMessage = useMemo(() => {
|
||||
if (typeof coverBackgroundMessage === "string") {
|
||||
const trimmedMessage = coverBackgroundMessage.trim();
|
||||
if (typeof coverBackgroundMessage === 'string') {
|
||||
const trimmedMessage = coverBackgroundMessage.trim()
|
||||
if (trimmedMessage.length) {
|
||||
return trimmedMessage;
|
||||
return trimmedMessage
|
||||
}
|
||||
}
|
||||
return "Nous lançons la génération de ta pochette...";
|
||||
}, [coverBackgroundMessage]);
|
||||
return 'Nous lançons la génération de ta pochette...'
|
||||
}, [coverBackgroundMessage])
|
||||
|
||||
const [styleMode, setStyleMode] = useState("preset");
|
||||
const [selectedPresetStyle, setSelectedPresetStyle] = useState(
|
||||
COVER_STYLE_PRESETS[0],
|
||||
);
|
||||
const [customStyle, setCustomStyle] = useState("");
|
||||
const [isPresetDropdownOpen, setIsPresetDropdownOpen] = useState(false);
|
||||
const [isSelecting, setIsSelecting] = useState(false);
|
||||
const [isAwaitingGenerationStart, setIsAwaitingGenerationStart] =
|
||||
useState(false);
|
||||
const [coverProgress, setCoverProgress] = useState(0);
|
||||
const coverProgressIntervalRef = useRef(null);
|
||||
const coverProgressStartRef = useRef(null);
|
||||
const [styleMode, setStyleMode] = useState('preset')
|
||||
const [selectedPresetStyle, setSelectedPresetStyle] = useState(COVER_STYLE_PRESETS[0])
|
||||
const [customStyle, setCustomStyle] = useState('')
|
||||
const [isPresetDropdownOpen, setIsPresetDropdownOpen] = useState(false)
|
||||
const [isSelecting, setIsSelecting] = useState(false)
|
||||
const [isAwaitingGenerationStart, setIsAwaitingGenerationStart] = useState(false)
|
||||
const [coverProgress, setCoverProgress] = useState(0)
|
||||
const coverProgressIntervalRef = useRef(null)
|
||||
const coverProgressStartRef = useRef(null)
|
||||
|
||||
const showGenerationLoading = useCallback(async () => {
|
||||
setIsAwaitingGenerationStart(true);
|
||||
await setLoading(true, { message: generationLoadingMessage });
|
||||
}, [generationLoadingMessage, setLoading]);
|
||||
setIsAwaitingGenerationStart(true)
|
||||
await setLoading(true, { message: generationLoadingMessage })
|
||||
}, [generationLoadingMessage, setLoading])
|
||||
|
||||
useEffect(() => {
|
||||
const projectStyle = (selectedProject?.coverStyle || "").trim();
|
||||
const isPresetStyle = COVER_STYLE_PRESETS.includes(projectStyle);
|
||||
const projectStyle = (selectedProject?.coverStyle || '').trim()
|
||||
const isPresetStyle = COVER_STYLE_PRESETS.includes(projectStyle)
|
||||
|
||||
if (!projectStyle) {
|
||||
setStyleMode("preset");
|
||||
setSelectedPresetStyle(COVER_STYLE_PRESETS[0]);
|
||||
setCustomStyle("");
|
||||
setIsPresetDropdownOpen(false);
|
||||
return;
|
||||
setStyleMode('preset')
|
||||
setSelectedPresetStyle(COVER_STYLE_PRESETS[0])
|
||||
setCustomStyle('')
|
||||
setIsPresetDropdownOpen(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (isPresetStyle) {
|
||||
setStyleMode("preset");
|
||||
setSelectedPresetStyle(projectStyle);
|
||||
setCustomStyle("");
|
||||
setStyleMode('preset')
|
||||
setSelectedPresetStyle(projectStyle)
|
||||
setCustomStyle('')
|
||||
} else {
|
||||
setStyleMode("custom");
|
||||
setCustomStyle(projectStyle);
|
||||
setStyleMode('custom')
|
||||
setCustomStyle(projectStyle)
|
||||
}
|
||||
setIsPresetDropdownOpen(false);
|
||||
}, [selectedProject?.coverStyle]);
|
||||
setIsPresetDropdownOpen(false)
|
||||
}, [selectedProject?.coverStyle])
|
||||
|
||||
const generateCover = useCallback(
|
||||
async (styleValue) => {
|
||||
if (!selectedProjectId) return;
|
||||
if (!selectedProjectId) return
|
||||
if (hasGeneratedOptions) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
const trimmedStyle = String(styleValue || "").trim();
|
||||
const trimmedStyle = String(styleValue || '').trim()
|
||||
if (!trimmedStyle) {
|
||||
alert("Attention", "Merci de renseigner un style pour la pochette.", [
|
||||
{ text: "OK" },
|
||||
]);
|
||||
return;
|
||||
alert('Attention', 'Merci de renseigner un style pour la pochette.', [{ text: 'OK' }])
|
||||
return
|
||||
}
|
||||
try {
|
||||
await showGenerationLoading();
|
||||
await showGenerationLoading()
|
||||
await updateProjectData(
|
||||
{
|
||||
coverStyle: trimmedStyle,
|
||||
},
|
||||
{ merge: true },
|
||||
);
|
||||
{ merge: true }
|
||||
)
|
||||
await tasksRef.add({
|
||||
type: "cover",
|
||||
type: 'cover',
|
||||
projectId: selectedProjectId,
|
||||
status: "PENDING",
|
||||
status: 'PENDING',
|
||||
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
});
|
||||
})
|
||||
} catch (e) {
|
||||
console.log("Cover task error", e?.message);
|
||||
setIsAwaitingGenerationStart(false);
|
||||
await setLoading(false);
|
||||
console.log('Cover task error', e?.message)
|
||||
setIsAwaitingGenerationStart(false)
|
||||
await setLoading(false)
|
||||
}
|
||||
},
|
||||
[
|
||||
hasGeneratedOptions,
|
||||
selectedProjectId,
|
||||
setLoading,
|
||||
showGenerationLoading,
|
||||
updateProjectData,
|
||||
],
|
||||
);
|
||||
[hasGeneratedOptions, selectedProjectId, setLoading, showGenerationLoading, updateProjectData]
|
||||
)
|
||||
|
||||
const requestCoverGeneration = useCallback(() => {
|
||||
const selectedStyle =
|
||||
styleMode === "preset" ? selectedPresetStyle : customStyle;
|
||||
const trimmedStyle = (selectedStyle || "").trim();
|
||||
const selectedStyle = styleMode === 'preset' ? selectedPresetStyle : customStyle
|
||||
const trimmedStyle = (selectedStyle || '').trim()
|
||||
if (!trimmedStyle) {
|
||||
alert("Attention", "Merci de renseigner un style pour la pochette.", [
|
||||
{ text: "OK" },
|
||||
]);
|
||||
return;
|
||||
alert('Attention', 'Merci de renseigner un style pour la pochette.', [{ text: 'OK' }])
|
||||
return
|
||||
}
|
||||
generateCover(trimmedStyle);
|
||||
}, [customStyle, generateCover, selectedPresetStyle, styleMode]);
|
||||
generateCover(trimmedStyle)
|
||||
}, [customStyle, generateCover, selectedPresetStyle, styleMode])
|
||||
|
||||
const coverPreviewUrl =
|
||||
selectedProject?.cover?.result ||
|
||||
selectedProject?.cover?.generatedBackground ||
|
||||
null;
|
||||
selectedProject?.cover?.result || selectedProject?.cover?.generatedBackground || null
|
||||
|
||||
const shouldShowStylePanel =
|
||||
!isGenerating && !hasGeneratedOptions && !coverPreviewUrl;
|
||||
const shouldShowStylePanel = !isGenerating && !hasGeneratedOptions && !coverPreviewUrl
|
||||
|
||||
const displayOptions = hasGeneratedOptions
|
||||
? coverOptions
|
||||
: coverPreviewUrl
|
||||
? [
|
||||
{
|
||||
id: "preview",
|
||||
id: 'preview',
|
||||
finalUrl: selectedProject?.cover?.result || null,
|
||||
generatedUrl: coverPreviewUrl,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
const isCoverLoading =
|
||||
isGenerating && !hasGeneratedOptions && !coverPreviewUrl;
|
||||
const coverProgressValue = Math.max(
|
||||
0,
|
||||
Math.min(100, Math.round(coverProgress)),
|
||||
);
|
||||
: []
|
||||
const isCoverLoading = isGenerating && !hasGeneratedOptions && !coverPreviewUrl
|
||||
const coverProgressValue = Math.max(0, Math.min(100, Math.round(coverProgress)))
|
||||
|
||||
useEffect(() => {
|
||||
const clearProgressInterval = () => {
|
||||
if (coverProgressIntervalRef.current) {
|
||||
global.clearInterval(coverProgressIntervalRef.current);
|
||||
coverProgressIntervalRef.current = null;
|
||||
global.clearInterval(coverProgressIntervalRef.current)
|
||||
coverProgressIntervalRef.current = null
|
||||
}
|
||||
};
|
||||
|
||||
if (!isCoverLoading) {
|
||||
clearProgressInterval();
|
||||
coverProgressStartRef.current = null;
|
||||
setCoverProgress(hasGeneratedOptions || coverPreviewUrl ? 100 : 0);
|
||||
return clearProgressInterval;
|
||||
}
|
||||
|
||||
coverProgressStartRef.current = new Date();
|
||||
setCoverProgress(0);
|
||||
clearProgressInterval();
|
||||
coverProgressIntervalRef.current = global.setInterval(() => {
|
||||
const start = coverProgressStartRef.current;
|
||||
if (!start) return;
|
||||
const elapsed = Date.now() - start.getTime();
|
||||
const ratio = Math.max(0, Math.min(1, elapsed / COVER_FAKE_DURATION_MS));
|
||||
const next = COVER_PROGRESS_MAX * ratio;
|
||||
setCoverProgress((prev) => {
|
||||
if (prev >= COVER_PROGRESS_MAX) return COVER_PROGRESS_MAX;
|
||||
return next >= COVER_PROGRESS_MAX ? COVER_PROGRESS_MAX : next;
|
||||
});
|
||||
}, COVER_PROGRESS_INTERVAL_MS);
|
||||
if (!isCoverLoading) {
|
||||
clearProgressInterval()
|
||||
coverProgressStartRef.current = null
|
||||
setCoverProgress(hasGeneratedOptions || coverPreviewUrl ? 100 : 0)
|
||||
return clearProgressInterval
|
||||
}
|
||||
|
||||
return clearProgressInterval;
|
||||
}, [isCoverLoading, hasGeneratedOptions, coverPreviewUrl]);
|
||||
coverProgressStartRef.current = new Date()
|
||||
setCoverProgress(0)
|
||||
clearProgressInterval()
|
||||
coverProgressIntervalRef.current = global.setInterval(() => {
|
||||
const start = coverProgressStartRef.current
|
||||
if (!start) return
|
||||
const elapsed = Date.now() - start.getTime()
|
||||
const ratio = Math.max(0, Math.min(1, elapsed / COVER_FAKE_DURATION_MS))
|
||||
const next = COVER_PROGRESS_MAX * ratio
|
||||
setCoverProgress((prev) => {
|
||||
if (prev >= COVER_PROGRESS_MAX) return COVER_PROGRESS_MAX
|
||||
return next >= COVER_PROGRESS_MAX ? COVER_PROGRESS_MAX : next
|
||||
})
|
||||
}, COVER_PROGRESS_INTERVAL_MS)
|
||||
|
||||
return clearProgressInterval
|
||||
}, [isCoverLoading, hasGeneratedOptions, coverPreviewUrl])
|
||||
|
||||
const handleSelectOption = useCallback(
|
||||
async (option) => {
|
||||
if (
|
||||
!option ||
|
||||
option?.id === selectedOptionId ||
|
||||
isSelecting ||
|
||||
!option?.id
|
||||
) {
|
||||
return;
|
||||
if (!option || option?.id === selectedOptionId || isSelecting || !option?.id) {
|
||||
return
|
||||
}
|
||||
const existingCover = selectedProject?.cover || {};
|
||||
const finalUrl = option.finalUrl || option.generatedUrl || null;
|
||||
setIsSelecting(true);
|
||||
const existingCover = selectedProject?.cover || {}
|
||||
const finalUrl = option.finalUrl || option.generatedUrl || null
|
||||
setIsSelecting(true)
|
||||
try {
|
||||
await updateProjectData({
|
||||
cover: {
|
||||
@@ -261,93 +225,85 @@ const PouchReady = () => {
|
||||
result: finalUrl,
|
||||
generatedBackground: option.generatedUrl || option.finalUrl || null,
|
||||
},
|
||||
});
|
||||
})
|
||||
} catch (e) {
|
||||
console.log("PouchReady: unable to select cover", e?.message);
|
||||
console.log('PouchReady: unable to select cover', e?.message)
|
||||
} finally {
|
||||
setIsSelecting(false);
|
||||
setIsSelecting(false)
|
||||
}
|
||||
},
|
||||
[
|
||||
coverOptions,
|
||||
isSelecting,
|
||||
selectedOptionId,
|
||||
selectedProject?.cover,
|
||||
updateProjectData,
|
||||
],
|
||||
);
|
||||
[coverOptions, isSelecting, selectedOptionId, selectedProject?.cover, updateProjectData]
|
||||
)
|
||||
|
||||
const onValidatePicture = useCallback(() => {
|
||||
if (!selectedOption) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
navigate(Routes.SongDownload, {
|
||||
project: selectedProject,
|
||||
selectedOption,
|
||||
coverOptions,
|
||||
});
|
||||
}, [coverOptions, navigate, selectedOption, selectedProject]);
|
||||
})
|
||||
}, [coverOptions, navigate, selectedOption, selectedProject])
|
||||
|
||||
const isPrimaryActionDisabled =
|
||||
isGenerating ||
|
||||
(hasGeneratedOptions ? !selectedOption || isSelecting : true);
|
||||
isGenerating || (hasGeneratedOptions ? !selectedOption || isSelecting : true)
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAwaitingGenerationStart) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (isGenerating) {
|
||||
setIsAwaitingGenerationStart(false);
|
||||
setLoading(false);
|
||||
setIsAwaitingGenerationStart(false)
|
||||
setLoading(false)
|
||||
}
|
||||
}, [isAwaitingGenerationStart, isGenerating, setLoading]);
|
||||
}, [isAwaitingGenerationStart, isGenerating, setLoading])
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (isAwaitingGenerationStart) {
|
||||
setIsAwaitingGenerationStart(false);
|
||||
setLoading(false);
|
||||
setIsAwaitingGenerationStart(false)
|
||||
setLoading(false)
|
||||
}
|
||||
},
|
||||
[isAwaitingGenerationStart, setLoading],
|
||||
);
|
||||
[isAwaitingGenerationStart, setLoading]
|
||||
)
|
||||
|
||||
return (
|
||||
<Page backgroundImg={background.studioBG2} headerType="NONE">
|
||||
<MusicLandHeader onPressBack={goBack} progress={72} />
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
<View style={{ flex: 1, marginTop: 0 }}>
|
||||
<CreateLyricsHeader
|
||||
title={
|
||||
selectedProject?.cover?.backgroundGenerated
|
||||
? "Ta pochette est prête!"
|
||||
: "Génération de la pochette"
|
||||
? 'Ta pochette est prête!'
|
||||
: 'Génération de la pochette'
|
||||
}
|
||||
/>
|
||||
<View style={{ flex: 1, ...Style.containerCenter }}>
|
||||
<View style={{ width: isWeb ? "80%" : "80%", gap: 24 }}>
|
||||
<View style={{ width: isWeb ? '80%' : '80%', gap: 24 }}>
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
flexDirection: isWeb ? "row" : "column",
|
||||
width: '100%',
|
||||
flexDirection: isWeb ? 'row' : 'column',
|
||||
gap: 16,
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
justifyContent: 'center',
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
{displayOptions.length > 0 ? (
|
||||
displayOptions.map((option, index) => {
|
||||
const optionUri =
|
||||
option?.finalUrl || option?.generatedUrl || "";
|
||||
if (!optionUri) return null;
|
||||
const optionUri = option?.finalUrl || option?.generatedUrl || ''
|
||||
if (!optionUri) return null
|
||||
if (hasGeneratedOptions) {
|
||||
const isSelected = option?.id === selectedOption?.id;
|
||||
const isSelected = option?.id === selectedOption?.id
|
||||
const cardWidthStyle = isWeb
|
||||
? styles.coverOptionCardWeb
|
||||
: styles.coverOptionCardMobile;
|
||||
: styles.coverOptionCardMobile
|
||||
return (
|
||||
<Pressable
|
||||
key={option?.id || index}
|
||||
@@ -375,22 +331,18 @@ const PouchReady = () => {
|
||||
</View>
|
||||
{isSelected && (
|
||||
<View style={styles.coverOptionSelectedBadge}>
|
||||
<Text style={styles.coverOptionSelectedLabel}>
|
||||
Sélectionnée
|
||||
</Text>
|
||||
<Text style={styles.coverOptionSelectedLabel}>Sélectionnée</Text>
|
||||
</View>
|
||||
)}
|
||||
</Pressable>
|
||||
);
|
||||
)
|
||||
}
|
||||
return (
|
||||
<View
|
||||
key={option?.id || index}
|
||||
style={[
|
||||
styles.coverPreviewCard,
|
||||
isWeb
|
||||
? styles.coverPreviewCardWeb
|
||||
: styles.coverPreviewCardMobile,
|
||||
isWeb ? styles.coverPreviewCardWeb : styles.coverPreviewCardMobile,
|
||||
]}
|
||||
>
|
||||
<ExpoImage
|
||||
@@ -402,20 +354,20 @@ const PouchReady = () => {
|
||||
style={styles.coverPreviewImage}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<>
|
||||
{isGenerating && (
|
||||
<View
|
||||
style={{
|
||||
alignItems: "center",
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
width: isWeb ? 300 : "100%",
|
||||
width: isWeb ? 300 : '100%',
|
||||
height: 300,
|
||||
borderRadius: 20,
|
||||
backgroundColor: "#00000040",
|
||||
alignSelf: "center",
|
||||
backgroundColor: '#00000040',
|
||||
alignSelf: 'center',
|
||||
...Style.containerCenter,
|
||||
}}
|
||||
>
|
||||
@@ -426,7 +378,7 @@ const PouchReady = () => {
|
||||
style={{
|
||||
color: Palette.white,
|
||||
marginTop: 6,
|
||||
textAlign: "center",
|
||||
textAlign: 'center',
|
||||
opacity: 0.9,
|
||||
}}
|
||||
>
|
||||
@@ -438,7 +390,7 @@ const PouchReady = () => {
|
||||
style={{
|
||||
color: Palette.white,
|
||||
marginTop: 6,
|
||||
textAlign: "center",
|
||||
textAlign: 'center',
|
||||
opacity: 0.9,
|
||||
}}
|
||||
>
|
||||
@@ -488,75 +440,60 @@ const PouchReady = () => {
|
||||
<View
|
||||
style={[
|
||||
styles.modeCard,
|
||||
styleMode === "preset" ? styles.modeCardActive : null,
|
||||
styleMode === 'preset' ? styles.modeCardActive : null,
|
||||
]}
|
||||
>
|
||||
<AppCheckbox
|
||||
label="Choisir un style prédéfini"
|
||||
selected={styleMode === "preset"}
|
||||
selected={styleMode === 'preset'}
|
||||
onPress={() => {
|
||||
setStyleMode("preset");
|
||||
setIsPresetDropdownOpen(false);
|
||||
setStyleMode('preset')
|
||||
setIsPresetDropdownOpen(false)
|
||||
if (!selectedPresetStyle) {
|
||||
setSelectedPresetStyle(COVER_STYLE_PRESETS[0]);
|
||||
setSelectedPresetStyle(COVER_STYLE_PRESETS[0])
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
{styleMode === "preset" && (
|
||||
{styleMode === 'preset' && (
|
||||
<View style={styles.dropdownArea}>
|
||||
<Pressable
|
||||
style={styles.dropdownTrigger}
|
||||
onPress={() =>
|
||||
setIsPresetDropdownOpen((prev) => !prev)
|
||||
}
|
||||
onPress={() => setIsPresetDropdownOpen((prev) => !prev)}
|
||||
>
|
||||
<Text
|
||||
style={styles.dropdownTriggerLabel}
|
||||
numberOfLines={2}
|
||||
>
|
||||
<Text style={styles.dropdownTriggerLabel} numberOfLines={2}>
|
||||
{selectedPresetStyle}
|
||||
</Text>
|
||||
<Image
|
||||
source={icons.chevronDown}
|
||||
style={[
|
||||
styles.dropdownArrow,
|
||||
isPresetDropdownOpen
|
||||
? styles.dropdownArrowOpen
|
||||
: null,
|
||||
isPresetDropdownOpen ? styles.dropdownArrowOpen : null,
|
||||
]}
|
||||
/>
|
||||
</Pressable>
|
||||
{isPresetDropdownOpen && (
|
||||
<View style={styles.dropdownList}>
|
||||
{COVER_STYLE_PRESETS.map((styleOption, index) => {
|
||||
const isActive =
|
||||
selectedPresetStyle === styleOption;
|
||||
const isLast =
|
||||
index === COVER_STYLE_PRESETS.length - 1;
|
||||
const isActive = selectedPresetStyle === styleOption
|
||||
const isLast = index === COVER_STYLE_PRESETS.length - 1
|
||||
return (
|
||||
<Pressable
|
||||
key={styleOption}
|
||||
style={[
|
||||
styles.dropdownOption,
|
||||
!isLast
|
||||
? styles.dropdownOptionDivider
|
||||
: null,
|
||||
isActive
|
||||
? styles.dropdownOptionActive
|
||||
: null,
|
||||
!isLast ? styles.dropdownOptionDivider : null,
|
||||
isActive ? styles.dropdownOptionActive : null,
|
||||
]}
|
||||
onPress={() => {
|
||||
setSelectedPresetStyle(styleOption);
|
||||
setIsPresetDropdownOpen(false);
|
||||
setSelectedPresetStyle(styleOption)
|
||||
setIsPresetDropdownOpen(false)
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.dropdownOptionLabel,
|
||||
isActive
|
||||
? styles.dropdownOptionLabelActive
|
||||
: null,
|
||||
isActive ? styles.dropdownOptionLabelActive : null,
|
||||
]}
|
||||
>
|
||||
{styleOption}
|
||||
@@ -569,7 +506,7 @@ const PouchReady = () => {
|
||||
/>
|
||||
)}
|
||||
</Pressable>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</View>
|
||||
)}
|
||||
@@ -579,19 +516,19 @@ const PouchReady = () => {
|
||||
<View
|
||||
style={[
|
||||
styles.modeCard,
|
||||
styleMode === "custom" ? styles.modeCardActive : null,
|
||||
styleMode === 'custom' ? styles.modeCardActive : null,
|
||||
]}
|
||||
>
|
||||
<AppCheckbox
|
||||
label="Style personnalisé"
|
||||
selected={styleMode === "custom"}
|
||||
selected={styleMode === 'custom'}
|
||||
onPress={() => {
|
||||
setStyleMode("custom");
|
||||
setIsPresetDropdownOpen(false);
|
||||
setStyleMode('custom')
|
||||
setIsPresetDropdownOpen(false)
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
{styleMode === "custom" && (
|
||||
{styleMode === 'custom' && (
|
||||
<View style={styles.customInputWrapper}>
|
||||
<TextInput
|
||||
placeholder="Exemple : Collage rétro futuriste lumineux"
|
||||
@@ -618,50 +555,45 @@ const PouchReady = () => {
|
||||
<View
|
||||
style={{
|
||||
paddingBottom: gutters * 2,
|
||||
width: isWeb ? "80%" : "100%",
|
||||
alignSelf: "center",
|
||||
width: isWeb ? '80%' : '100%',
|
||||
alignSelf: 'center',
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
{!hasGeneratedOptions && (
|
||||
<BorderGradientButton
|
||||
title={
|
||||
isGenerating ? "Génération en cours..." : "Générer la pochette"
|
||||
}
|
||||
title={isGenerating ? 'Génération en cours...' : 'Générer la pochette'}
|
||||
icon={icons.stars}
|
||||
onPress={requestCoverGeneration}
|
||||
disabled={isGenerating}
|
||||
/>
|
||||
)}
|
||||
{hasGeneratedOptions && (
|
||||
<GradientButton
|
||||
title={"Valider la pochette"}
|
||||
onPress={onValidatePicture}
|
||||
/>
|
||||
<GradientButton title={'Valider la pochette'} onPress={onValidatePicture} />
|
||||
)}
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default PouchReady;
|
||||
export default PouchReady
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
coverOptionCard: {
|
||||
position: "relative",
|
||||
position: 'relative',
|
||||
borderRadius: 20,
|
||||
borderWidth: 1,
|
||||
borderColor: "rgba(255,255,255,0.12)",
|
||||
overflow: "hidden",
|
||||
backgroundColor: "rgba(15,12,20,0.4)",
|
||||
borderColor: 'rgba(255,255,255,0.12)',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: 'rgba(15,12,20,0.4)',
|
||||
},
|
||||
coverOptionCardWeb: {
|
||||
width: 280,
|
||||
maxWidth: 320,
|
||||
},
|
||||
coverOptionCardMobile: {
|
||||
width: "100%",
|
||||
width: '100%',
|
||||
},
|
||||
coverOptionCardSelected: {
|
||||
borderColor: Palette.primary,
|
||||
@@ -670,11 +602,11 @@ const styles = StyleSheet.create({
|
||||
opacity: 0.85,
|
||||
},
|
||||
coverOptionImage: {
|
||||
width: "100%",
|
||||
width: '100%',
|
||||
aspectRatio: 1,
|
||||
},
|
||||
coverOptionBadge: {
|
||||
position: "absolute",
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
right: 12,
|
||||
backgroundColor: Palette.transparentBlack,
|
||||
@@ -688,7 +620,7 @@ const styles = StyleSheet.create({
|
||||
fontFamily: FONT_FAMILY.InterSemiBold,
|
||||
},
|
||||
coverOptionSelectedBadge: {
|
||||
position: "absolute",
|
||||
position: 'absolute',
|
||||
bottom: 12,
|
||||
left: 12,
|
||||
backgroundColor: Palette.primary,
|
||||
@@ -702,16 +634,16 @@ const styles = StyleSheet.create({
|
||||
fontFamily: FONT_FAMILY.InterSemiBold,
|
||||
},
|
||||
coverPreviewCard: {
|
||||
alignItems: "center",
|
||||
alignItems: 'center',
|
||||
},
|
||||
coverPreviewCardWeb: {
|
||||
width: 300,
|
||||
},
|
||||
coverPreviewCardMobile: {
|
||||
width: "100%",
|
||||
width: '100%',
|
||||
},
|
||||
coverPreviewImage: {
|
||||
width: "100%",
|
||||
width: '100%',
|
||||
height: 260,
|
||||
borderRadius: 20,
|
||||
},
|
||||
@@ -721,9 +653,9 @@ const styles = StyleSheet.create({
|
||||
paddingVertical: 20,
|
||||
borderRadius: 24,
|
||||
borderWidth: 1,
|
||||
borderColor: "rgba(255,255,255,0.08)",
|
||||
backgroundColor: "rgba(15, 12, 20, 0.78)",
|
||||
overflow: "hidden",
|
||||
borderColor: 'rgba(255,255,255,0.08)',
|
||||
backgroundColor: 'rgba(15, 12, 20, 0.78)',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
stylePanelWeb: {
|
||||
paddingHorizontal: 26,
|
||||
@@ -746,32 +678,32 @@ const styles = StyleSheet.create({
|
||||
gap: 18,
|
||||
},
|
||||
modeCard: {
|
||||
alignSelf: "stretch",
|
||||
alignSelf: 'stretch',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 12,
|
||||
borderRadius: 14,
|
||||
borderWidth: 1,
|
||||
borderColor: "rgba(255,255,255,0.1)",
|
||||
backgroundColor: "rgba(15,12,20,0.6)",
|
||||
borderColor: 'rgba(255,255,255,0.1)',
|
||||
backgroundColor: 'rgba(15,12,20,0.6)',
|
||||
},
|
||||
modeCardActive: {
|
||||
borderColor: Palette.primary,
|
||||
backgroundColor: "rgba(251,104,168,0.12)",
|
||||
backgroundColor: 'rgba(251,104,168,0.12)',
|
||||
},
|
||||
dropdownArea: {
|
||||
alignSelf: "stretch",
|
||||
alignSelf: 'stretch',
|
||||
gap: 12,
|
||||
},
|
||||
dropdownTrigger: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 14,
|
||||
borderRadius: 16,
|
||||
borderWidth: 1,
|
||||
borderColor: "rgba(255,255,255,0.1)",
|
||||
backgroundColor: "rgba(15,12,20,0.65)",
|
||||
borderColor: 'rgba(255,255,255,0.1)',
|
||||
backgroundColor: 'rgba(15,12,20,0.65)',
|
||||
},
|
||||
dropdownTriggerLabel: {
|
||||
flex: 1,
|
||||
@@ -788,30 +720,30 @@ const styles = StyleSheet.create({
|
||||
dropdownArrowOpen: {
|
||||
transform: [
|
||||
{
|
||||
rotate: "180deg",
|
||||
rotate: '180deg',
|
||||
},
|
||||
],
|
||||
},
|
||||
dropdownList: {
|
||||
borderRadius: 16,
|
||||
borderWidth: 1,
|
||||
borderColor: "rgba(255,255,255,0.08)",
|
||||
backgroundColor: "rgba(12,10,18,0.95)",
|
||||
overflow: "hidden",
|
||||
borderColor: 'rgba(255,255,255,0.08)',
|
||||
backgroundColor: 'rgba(12,10,18,0.95)',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
dropdownOption: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 14,
|
||||
},
|
||||
dropdownOptionDivider: {
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: "rgba(255,255,255,0.06)",
|
||||
borderBottomColor: 'rgba(255,255,255,0.06)',
|
||||
},
|
||||
dropdownOptionActive: {
|
||||
backgroundColor: "rgba(251,104,168,0.12)",
|
||||
backgroundColor: 'rgba(251,104,168,0.12)',
|
||||
},
|
||||
dropdownOptionLabel: {
|
||||
flex: 1,
|
||||
@@ -834,7 +766,7 @@ const styles = StyleSheet.create({
|
||||
minWidth: 240,
|
||||
},
|
||||
coverProgressWrapper: {
|
||||
alignItems: "center",
|
||||
alignItems: 'center',
|
||||
gap: 10,
|
||||
width: 220,
|
||||
},
|
||||
@@ -842,15 +774,15 @@ const styles = StyleSheet.create({
|
||||
width: 260,
|
||||
},
|
||||
coverProgressBar: {
|
||||
width: "100%",
|
||||
width: '100%',
|
||||
},
|
||||
customInputWrapper: {
|
||||
alignSelf: "stretch",
|
||||
alignSelf: 'stretch',
|
||||
borderRadius: 18,
|
||||
padding: 1,
|
||||
borderWidth: 1,
|
||||
borderColor: "rgba(255,255,255,0.1)",
|
||||
backgroundColor: "rgba(15,12,20,0.4)",
|
||||
borderColor: 'rgba(255,255,255,0.1)',
|
||||
backgroundColor: 'rgba(15,12,20,0.4)',
|
||||
},
|
||||
customInput: {
|
||||
minHeight: 55,
|
||||
@@ -859,7 +791,7 @@ const styles = StyleSheet.create({
|
||||
paddingVertical: 12,
|
||||
fontSize: 15,
|
||||
color: Palette.white,
|
||||
backgroundColor: "rgba(15,12,20,0.85)",
|
||||
backgroundColor: 'rgba(15,12,20,0.85)',
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user