feat: restart
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { useFocusEffect } from "@react-navigation/native";
|
import { useFocusEffect } from "@react-navigation/native";
|
||||||
import { CameraView, useCameraPermissions } from "expo-camera";
|
import { CameraView, useCameraPermissions } from "expo-camera";
|
||||||
|
import * as FileSystem from "expo-file-system";
|
||||||
import React, {
|
import React, {
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
@@ -9,7 +10,7 @@ import React, {
|
|||||||
} from "react";
|
} from "react";
|
||||||
import { Text, TouchableOpacity, View } from "react-native";
|
import { Text, TouchableOpacity, View } from "react-native";
|
||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import Svg, { Circle } from "react-native-svg";
|
import Svg, { Circle, Path, G, Defs, Rect, ClipPath } from "react-native-svg";
|
||||||
import alert from "../../components/Alert";
|
import alert from "../../components/Alert";
|
||||||
import GradientButton from "../../components/GradientButton";
|
import GradientButton from "../../components/GradientButton";
|
||||||
import KaraokeLyrics from "../../components/KaraokeLyrics";
|
import KaraokeLyrics from "../../components/KaraokeLyrics";
|
||||||
@@ -51,6 +52,7 @@ const RecordPlayback = ({ route }) => {
|
|||||||
const listenTimerRef = useRef(null);
|
const listenTimerRef = useRef(null);
|
||||||
const checkSongEndRef = useRef(null);
|
const checkSongEndRef = useRef(null);
|
||||||
const stopRequestedRef = useRef(false);
|
const stopRequestedRef = useRef(false);
|
||||||
|
const restartRequestedRef = useRef(false);
|
||||||
const startedRef = useRef(false); // empêche les doubles démarrages
|
const startedRef = useRef(false); // empêche les doubles démarrages
|
||||||
const countdownActiveRef = useRef(false); // évite le déclenchement avant 1er tick
|
const countdownActiveRef = useRef(false); // évite le déclenchement avant 1er tick
|
||||||
const playbackStartedRef = useRef(false); // devient vrai lorsque l'audio progresse réellement
|
const playbackStartedRef = useRef(false); // devient vrai lorsque l'audio progresse réellement
|
||||||
@@ -161,7 +163,7 @@ const RecordPlayback = ({ route }) => {
|
|||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}, [alignedWords]);
|
}, [alignedWords]);
|
||||||
// console.log("alignedWords:", alignedWords);
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
listenedMsRef.current = 0;
|
listenedMsRef.current = 0;
|
||||||
incrementDoneRef.current = false;
|
incrementDoneRef.current = false;
|
||||||
@@ -228,6 +230,8 @@ const RecordPlayback = ({ route }) => {
|
|||||||
return -1;
|
return -1;
|
||||||
}, [lines, currentTimeS]);
|
}, [lines, currentTimeS]);
|
||||||
|
|
||||||
|
const getScrollY = () => (typeof window !== "undefined" ? window.scrollY : 0);
|
||||||
|
|
||||||
// Permissions au mount + cleanup
|
// Permissions au mount + cleanup
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
@@ -340,6 +344,7 @@ const RecordPlayback = ({ route }) => {
|
|||||||
}
|
}
|
||||||
log("startCountdownThenRecord invoked", { projectId, songUrl });
|
log("startCountdownThenRecord invoked", { projectId, songUrl });
|
||||||
await resetSession();
|
await resetSession();
|
||||||
|
restartRequestedRef.current = false;
|
||||||
setIsPreparing(true);
|
setIsPreparing(true);
|
||||||
setShowProgress(false);
|
setShowProgress(false);
|
||||||
setCountdown(5);
|
setCountdown(5);
|
||||||
@@ -553,6 +558,32 @@ const RecordPlayback = ({ route }) => {
|
|||||||
log("Recording flow completed", { hasVideo: !!video?.uri });
|
log("Recording flow completed", { hasVideo: !!video?.uri });
|
||||||
playbackStartedRef.current = false;
|
playbackStartedRef.current = false;
|
||||||
progressLogRef.current = { bucket: -1, lastPos: -1, lastDur: -1 };
|
progressLogRef.current = { bucket: -1, lastPos: -1, lastDur: -1 };
|
||||||
|
const shouldRestart = restartRequestedRef.current;
|
||||||
|
if (shouldRestart) {
|
||||||
|
restartRequestedRef.current = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (video?.uri && shouldRestart) {
|
||||||
|
try {
|
||||||
|
const info = await FileSystem.getInfoAsync(video.uri);
|
||||||
|
if (info?.exists) {
|
||||||
|
await FileSystem.deleteAsync(video.uri, { idempotent: true });
|
||||||
|
log("Discarded interim recording file");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
log("Failed to discard interim recording", {
|
||||||
|
message: error?.message || String(error || ""),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldRestart) {
|
||||||
|
log("Restart requested, relaunching countdown");
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
void startCountdownThenRecord();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (video?.uri) {
|
if (video?.uri) {
|
||||||
log("Navigating to RecordedPlayback with video", {
|
log("Navigating to RecordedPlayback with video", {
|
||||||
@@ -585,6 +616,15 @@ const RecordPlayback = ({ route }) => {
|
|||||||
}
|
}
|
||||||
playbackStartedRef.current = false;
|
playbackStartedRef.current = false;
|
||||||
progressLogRef.current = { bucket: -1, lastPos: -1, lastDur: -1 };
|
progressLogRef.current = { bucket: -1, lastPos: -1, lastDur: -1 };
|
||||||
|
const shouldRestart = restartRequestedRef.current;
|
||||||
|
if (shouldRestart) {
|
||||||
|
restartRequestedRef.current = false;
|
||||||
|
log("Restart requested despite error, restarting flow");
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
void startCountdownThenRecord();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Inform the user when using a simulator where recording isn't supported
|
// Inform the user when using a simulator where recording isn't supported
|
||||||
const msg = String(e?.message || e || "");
|
const msg = String(e?.message || e || "");
|
||||||
if (/not supported on the simulator/i.test(msg)) {
|
if (/not supported on the simulator/i.test(msg)) {
|
||||||
@@ -607,6 +647,28 @@ const RecordPlayback = ({ route }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRestartRecording = async () => {
|
||||||
|
try {
|
||||||
|
log("Restart button pressed", {
|
||||||
|
isPreparing,
|
||||||
|
isRecording,
|
||||||
|
});
|
||||||
|
if (isPreparing || !isRecording) {
|
||||||
|
restartRequestedRef.current = false;
|
||||||
|
await startCountdownThenRecord();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
restartRequestedRef.current = true;
|
||||||
|
stopRequestedRef.current = true;
|
||||||
|
try {
|
||||||
|
if (player?.playing) await player.pause?.();
|
||||||
|
} catch (_) {}
|
||||||
|
try {
|
||||||
|
cameraRef.current?.stopRecording?.();
|
||||||
|
} catch (_) {}
|
||||||
|
} catch (_) {}
|
||||||
|
};
|
||||||
|
|
||||||
const permissionsGranted = !!cameraPermission?.granted;
|
const permissionsGranted = !!cameraPermission?.granted;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -700,8 +762,9 @@ const RecordPlayback = ({ route }) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Progress circulaire */}
|
{/* Progress circulaire + restart */}
|
||||||
{permissionsGranted && (isRecording || showProgress) && (
|
{permissionsGranted &&
|
||||||
|
(isRecording || showProgress || isPreparing) && (
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@@ -714,31 +777,45 @@ const RecordPlayback = ({ route }) => {
|
|||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 100,
|
width: 120,
|
||||||
height: 100,
|
height: 120,
|
||||||
borderRadius: 105,
|
borderRadius: 120,
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ProgressRing
|
<ProgressRing
|
||||||
size={100}
|
size={120}
|
||||||
strokeWidth={8}
|
strokeWidth={8}
|
||||||
progress={
|
progress={
|
||||||
progressInfo.dur
|
progressInfo.dur
|
||||||
? Math.min(1, (progressInfo.pos || 0) / progressInfo.dur)
|
? Math.min(
|
||||||
|
1,
|
||||||
|
(progressInfo.pos || 0) / progressInfo.dur
|
||||||
|
)
|
||||||
: 0
|
: 0
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<View
|
<TouchableOpacity
|
||||||
|
activeOpacity={0.9}
|
||||||
|
onPress={handleRestartRecording}
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
width: 50,
|
width: 70,
|
||||||
height: 50,
|
height: 70,
|
||||||
borderRadius: 55,
|
borderRadius: 80,
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
backgroundColor: Palette.white,
|
backgroundColor: Palette.white,
|
||||||
|
shadowColor: "#000000",
|
||||||
|
shadowOpacity: 0.12,
|
||||||
|
shadowRadius: 10,
|
||||||
|
shadowOffset: { width: 0, height: 4 },
|
||||||
|
elevation: 4,
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<RestartSpinnerIcon />
|
||||||
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
@@ -792,7 +869,7 @@ const ProgressRing = ({ size = 50, strokeWidth = 12, progress = 0 }) => {
|
|||||||
style={{
|
style={{
|
||||||
transform: [{ rotate: "-90deg" }],
|
transform: [{ rotate: "-90deg" }],
|
||||||
backgroundColor: "#ffffff3d",
|
backgroundColor: "#ffffff3d",
|
||||||
borderRadius: 55,
|
borderRadius: size / 2,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Circle
|
<Circle
|
||||||
@@ -810,6 +887,60 @@ const ProgressRing = ({ size = 50, strokeWidth = 12, progress = 0 }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const RestartSpinnerIcon = ({
|
||||||
|
size = 30,
|
||||||
|
color = "#F94697", // couleur unie
|
||||||
|
background = "transparent",
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
width: size + 8,
|
||||||
|
height: size + 8,
|
||||||
|
borderRadius: size,
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
backgroundColor: background,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
||||||
|
<G clipPath="url(#clip0)">
|
||||||
|
{/* Cercle re-dessiné sans opacité */}
|
||||||
|
<Path
|
||||||
|
d="
|
||||||
|
M19.7285 10.9286
|
||||||
|
C20.4412 13.5975 19.7507 16.5633 17.6569 18.6571
|
||||||
|
C14.5327 21.7813 9.46734 21.7813 6.34315 18.6571
|
||||||
|
C3.21895 15.5329 3.21895 10.4676 6.34315 7.34338
|
||||||
|
C9.46734 4.21918 14.5327 4.21918 17.6569 7.34338
|
||||||
|
L18.364 8.05048
|
||||||
|
"
|
||||||
|
stroke={color}
|
||||||
|
strokeWidth={2}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Flèche */}
|
||||||
|
<Path
|
||||||
|
d="M14.1214 8.05026H18.364V3.80762"
|
||||||
|
stroke={color}
|
||||||
|
strokeWidth={2}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</G>
|
||||||
|
|
||||||
|
<Defs>
|
||||||
|
<ClipPath id="clip0">
|
||||||
|
<Rect width="24" height="24" fill="white" />
|
||||||
|
</ClipPath>
|
||||||
|
</Defs>
|
||||||
|
</Svg>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default RecordPlayback;
|
export default RecordPlayback;
|
||||||
|
|
||||||
// Render previous/current/next line to reduce jumpiness
|
// Render previous/current/next line to reduce jumpiness
|
||||||
@@ -851,7 +982,11 @@ const KaraokeLines = ({ lines = [], currentLineIdx = -1 }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const CameraFacingSelector = ({ value = "front", onChange, disabled = false }) => {
|
const CameraFacingSelector = ({
|
||||||
|
value = "front",
|
||||||
|
onChange,
|
||||||
|
disabled = false,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ const reorder = (list, from, to) => {
|
|||||||
return next;
|
return next;
|
||||||
};
|
};
|
||||||
|
|
||||||
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
|
const clamp = (value, min, max) => Math.max(mn, Math.min(max, value));
|
||||||
|
|
||||||
const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
||||||
const [, setTooltip] = useGlobal("_tooltip");
|
const [, setTooltip] = useGlobal("_tooltip");
|
||||||
|
|||||||
+115
-18
@@ -3,10 +3,12 @@ import { ScrollView, StyleSheet, Text, View } from "react-native";
|
|||||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
|
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
|
||||||
import { background, icons } from "../../assets";
|
import { background, icons } from "../../assets";
|
||||||
import alert from "../../components/Alert";
|
import alert from "../../components/Alert";
|
||||||
|
import AppCheckbox from "../../components/AppCheckbox";
|
||||||
import BorderGradientButton from "../../components/BorderGradientButton";
|
import BorderGradientButton from "../../components/BorderGradientButton";
|
||||||
import GradientButton from "../../components/GradientButton";
|
import GradientButton from "../../components/GradientButton";
|
||||||
import ItemContainer from "../../components/ItemContainer/ItemContainer";
|
import ItemContainer from "../../components/ItemContainer/ItemContainer";
|
||||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||||
|
import Overlay from "../../components/Overlay";
|
||||||
import firebase, { projectsRef } from "../../config/firebase";
|
import firebase, { projectsRef } from "../../config/firebase";
|
||||||
import { strings } from "../../constants/strings";
|
import { strings } from "../../constants/strings";
|
||||||
import { isWeb } from "../../hooks/useLayoutType";
|
import { isWeb } from "../../hooks/useLayoutType";
|
||||||
@@ -27,6 +29,9 @@ import {
|
|||||||
import { getStageAction } from "../../utils/projectStages";
|
import { getStageAction } from "../../utils/projectStages";
|
||||||
import CustomInput from "./components/CustomInput";
|
import CustomInput from "./components/CustomInput";
|
||||||
|
|
||||||
|
const RESPONSIBILITY_CHECKBOX_LABEL =
|
||||||
|
"Vous êtes responsable du contenu que vous validez et Musicland ne sera en aucun cas tenu responsable du contenu que vous validez.";
|
||||||
|
|
||||||
const Lyrics = ({ navigation }) => {
|
const Lyrics = ({ navigation }) => {
|
||||||
const scrollRef = useRef(null);
|
const scrollRef = useRef(null);
|
||||||
const [containerLayout, setContainerLayout] = useState(null);
|
const [containerLayout, setContainerLayout] = useState(null);
|
||||||
@@ -34,6 +39,23 @@ const Lyrics = ({ navigation }) => {
|
|||||||
const { selectedProjectId, selectedProject } = useUser();
|
const { selectedProjectId, selectedProject } = useUser();
|
||||||
const [isFocus, setIsFocus] = useState(null);
|
const [isFocus, setIsFocus] = useState(null);
|
||||||
const [itemsContainerLayout, setItemsContainerLayout] = useState([]);
|
const [itemsContainerLayout, setItemsContainerLayout] = useState([]);
|
||||||
|
const [sensitiveContentModal, setSensitiveContentModal] = useState({
|
||||||
|
visible: false,
|
||||||
|
title: "",
|
||||||
|
message: "",
|
||||||
|
});
|
||||||
|
const [isSensitiveContentAcknowledged, setIsSensitiveContentAcknowledged] =
|
||||||
|
useState(false);
|
||||||
|
const sensitiveContentResolverRef = useRef(null);
|
||||||
|
|
||||||
|
const closeSensitiveContentModal = useCallback((result) => {
|
||||||
|
setSensitiveContentModal((prev) => ({ ...prev, visible: false }));
|
||||||
|
setIsSensitiveContentAcknowledged(false);
|
||||||
|
if (sensitiveContentResolverRef.current) {
|
||||||
|
sensitiveContentResolverRef.current(result);
|
||||||
|
sensitiveContentResolverRef.current = null;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Effective sources from provider only
|
// Effective sources from provider only
|
||||||
const projectTitle = selectedProject?.title || "";
|
const projectTitle = selectedProject?.title || "";
|
||||||
@@ -129,24 +151,26 @@ const Lyrics = ({ navigation }) => {
|
|||||||
alert(title, message);
|
alert(title, message);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const confirmSensitiveContent = useCallback(
|
const confirmSensitiveContent = useCallback((title, message) => {
|
||||||
(title, message) =>
|
return new Promise((resolve) => {
|
||||||
new Promise((resolve) => {
|
sensitiveContentResolverRef.current = resolve;
|
||||||
alert(title, message, [
|
setSensitiveContentModal({
|
||||||
{
|
visible: true,
|
||||||
text: "Annuler",
|
title,
|
||||||
style: "cancel",
|
message,
|
||||||
onPress: () => resolve(false),
|
});
|
||||||
},
|
setIsSensitiveContentAcknowledged(false);
|
||||||
{
|
});
|
||||||
text: "Continuer",
|
}, []);
|
||||||
style: "destructive",
|
|
||||||
onPress: () => resolve(true),
|
const handleSensitiveCancel = useCallback(() => {
|
||||||
},
|
closeSensitiveContentModal(false);
|
||||||
]);
|
}, [closeSensitiveContentModal]);
|
||||||
}),
|
|
||||||
[]
|
const handleSensitiveConfirm = useCallback(() => {
|
||||||
);
|
if (!isSensitiveContentAcknowledged) return;
|
||||||
|
closeSensitiveContentModal(true);
|
||||||
|
}, [closeSensitiveContentModal, isSensitiveContentAcknowledged]);
|
||||||
|
|
||||||
const onValidate = useCallback(async () => {
|
const onValidate = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -461,6 +485,49 @@ const Lyrics = ({ navigation }) => {
|
|||||||
)}
|
)}
|
||||||
<GradientButton title="Valider" onPress={onValidate} />
|
<GradientButton title="Valider" onPress={onValidate} />
|
||||||
</View>
|
</View>
|
||||||
|
<Overlay
|
||||||
|
isVisible={sensitiveContentModal.visible}
|
||||||
|
setIsVisible={(visible) => {
|
||||||
|
if (visible === false) {
|
||||||
|
handleSensitiveCancel();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
contentContainerStyle={{
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View style={styles.sensitiveModal}>
|
||||||
|
<Text style={styles.sensitiveModalTitle}>
|
||||||
|
{sensitiveContentModal.title}
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.sensitiveModalMessage}>
|
||||||
|
{sensitiveContentModal.message}
|
||||||
|
</Text>
|
||||||
|
<View style={styles.sensitiveCheckboxWrapper}>
|
||||||
|
<AppCheckbox
|
||||||
|
selected={isSensitiveContentAcknowledged}
|
||||||
|
onPress={() =>
|
||||||
|
setIsSensitiveContentAcknowledged((prev) => !prev)
|
||||||
|
}
|
||||||
|
label={RESPONSIBILITY_CHECKBOX_LABEL}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.sensitiveModalActions}>
|
||||||
|
<BorderGradientButton
|
||||||
|
title="Annuler"
|
||||||
|
onPress={handleSensitiveCancel}
|
||||||
|
containerStyle={{ flex: 1 }}
|
||||||
|
/>
|
||||||
|
<GradientButton
|
||||||
|
title="Continuer"
|
||||||
|
onPress={handleSensitiveConfirm}
|
||||||
|
disabled={!isSensitiveContentAcknowledged}
|
||||||
|
containerStyle={{ flex: 1 }}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Overlay>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -513,4 +580,34 @@ const styles = StyleSheet.create({
|
|||||||
color: Palette.white,
|
color: Palette.white,
|
||||||
opacity: 0.8,
|
opacity: 0.8,
|
||||||
},
|
},
|
||||||
|
sensitiveModal: {
|
||||||
|
width: "90%",
|
||||||
|
maxWidth: 460,
|
||||||
|
backgroundColor: Palette.lightPurple,
|
||||||
|
borderRadius: 18,
|
||||||
|
paddingVertical: 24,
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
gap: 16,
|
||||||
|
},
|
||||||
|
sensitiveModalTitle: {
|
||||||
|
fontFamily: FONT_FAMILY.InterSemiBold,
|
||||||
|
fontSize: 20,
|
||||||
|
color: Palette.white,
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
sensitiveModalMessage: {
|
||||||
|
fontFamily: FONT_FAMILY.InterRegular,
|
||||||
|
fontSize: 15,
|
||||||
|
color: Palette.white,
|
||||||
|
lineHeight: 20,
|
||||||
|
textAlign: "left",
|
||||||
|
opacity: 0.9,
|
||||||
|
},
|
||||||
|
sensitiveCheckboxWrapper: {
|
||||||
|
paddingVertical: 4,
|
||||||
|
},
|
||||||
|
sensitiveModalActions: {
|
||||||
|
flexDirection: "row",
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const SpecificityContext = ({ context, setContext }) => {
|
|||||||
subTitle="Dis-nous en un peu plus pour qu’on puisse mieux t’aider."
|
subTitle="Dis-nous en un peu plus pour qu’on puisse mieux t’aider."
|
||||||
/>
|
/>
|
||||||
<CustomInput
|
<CustomInput
|
||||||
placeholder="Écris à qui s'adresse ta chanson"
|
placeholder="Décris le contexte de ta chanson"
|
||||||
height={283}
|
height={283}
|
||||||
value={context}
|
value={context}
|
||||||
setValue={setContext}
|
setValue={setContext}
|
||||||
|
|||||||
Reference in New Issue
Block a user