This commit is contained in:
Philip Cesar Garay
2025-08-06 21:06:01 +08:00
parent d08ec7b778
commit 40e877774b
33 changed files with 1148 additions and 517 deletions
+76
View File
@@ -0,0 +1,76 @@
import { View, Text, StyleSheet, FlatList } from "react-native";
import React from "react";
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
import { responsiveHeight } from "react-native-responsive-dimensions";
import { BlurView } from "expo-blur";
import { FONT_FAMILY } from "../../styles/Fonts";
import { Palette } from "../../styles";
import { CHOOSE_GENRE } from "../../data/data";
import ItemContainer from "../../components/ItemContainer/ItemContainer";
const ChooseGenre = () => {
return (
<View style={{ flex: 1, gap: 10 }}>
<CreateLyricsHeader
title="Choisis un genre"
subTitle="Tu peux choisir jusqu’à 2 genres différents"
/>
<ItemContainer height={responsiveHeight(55)}>
<FlatList
data={CHOOSE_GENRE}
contentContainerStyle={{
gap: 16,
flexGrow: 1,
zIndex: 2,
}}
renderItem={({ item, index }) => (
<View style={{ borderRadius: 14, overflow: "hidden" }}>
<BlurView
intensity={30}
style={{ paddingVertical: 14, paddingHorizontal: 12 }}
>
<Text
style={{
fontSize: 16,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
}}
>
<Text style={{ fontFamily: FONT_FAMILY.InterBold }}>
{item.title}
</Text>{" "}
: {item.description}
</Text>
</BlurView>
</View>
)}
/>
</ItemContainer>
</View>
);
};
export default ChooseGenre;
const styles = StyleSheet.create({
borderGradientStyle: {
borderWidth: 1,
borderRadius: 20,
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 100,
position: "absolute",
width: "100%",
},
blurContainer: {
borderRadius: 20,
overflow: "hidden",
zIndex: 1,
maxHeight: responsiveHeight(55),
},
});
+79
View File
@@ -0,0 +1,79 @@
import { View, Text, FlatList, StyleSheet } from "react-native";
import React, { useState } from "react";
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
import ItemContainer from "../../components/ItemContainer/ItemContainer";
import { Palette } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts";
import { BlurView } from "expo-blur";
const ChooseInstruments = () => {
const [containerLayout, setContainerLayout] = useState(null);
return (
<View style={{ flex: 1, gap: 10 }}>
<CreateLyricsHeader
title="Choisis des instruments"
subTitle="Tu peux choisir jusqu’à 5 instruments différents"
/>
<View
style={{ flex: 1 }}
onLayout={(event) => setContainerLayout(event.nativeEvent.layout)}
>
<ItemContainer height={containerLayout?.height}>
<FlatList
data={Array.from({ length: 10 })}
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.contentContainer}
renderItem={() => (
<View style={styles.itemContainer}>
<BlurView
intensity={30}
style={{
flex: 1,
backgroundColor: Palette.glass,
paddingHorizontal: 12,
justifyContent: "center",
}}
>
<Text style={styles.itemText}>Piano classique</Text>
</BlurView>
</View>
)}
/>
</ItemContainer>
</View>
</View>
);
};
export default ChooseInstruments;
const styles = StyleSheet.create({
contentContainer: {
flexGrow: 1,
padding: 8,
gap: 10,
backgroundColor: "#FFFFFF00",
paddingBottom: 50,
},
itemContainer: {
height: 54,
backgroundColor: Palette.glass,
borderRadius: 14,
overflow: "hidden",
shadowColor: "#00000040",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
itemText: {
fontSize: 16,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
},
});
+70
View File
@@ -0,0 +1,70 @@
import { View, Text, FlatList, StyleSheet } from "react-native";
import React from "react";
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
import ItemContainer from "../../components/ItemContainer/ItemContainer";
import { BlurView } from "expo-blur";
import { Palette } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts";
const ChooseRhythm = () => {
return (
<View style={{ flex: 1, gap: 10 }}>
<CreateLyricsHeader title="Choisis un rythme" />
<View style={{ flex: 1 }}>
<ItemContainer height={340}>
<FlatList
data={Array.from({ length: 5 })}
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.contentContainer}
renderItem={() => (
<View style={styles.itemContainer}>
<BlurView
intensity={30}
style={{
flex: 1,
backgroundColor: Palette.glass,
paddingHorizontal: 12,
justifyContent: "center",
}}
>
<Text style={styles.itemText}>Très rapide</Text>
</BlurView>
</View>
)}
/>
</ItemContainer>
</View>
</View>
);
};
export default ChooseRhythm;
const styles = StyleSheet.create({
contentContainer: {
flexGrow: 1,
padding: 8,
gap: 10,
backgroundColor: "#FFFFFF00",
},
itemContainer: {
height: 54,
backgroundColor: Palette.glass,
borderRadius: 14,
overflow: "hidden",
shadowColor: "#00000040",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
itemText: {
fontSize: 16,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
},
});
+46
View File
@@ -0,0 +1,46 @@
import { View, Text, StyleSheet, Image } 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 { Routes } from "../../navigation";
import GradientButton from "../../components/GradientButton";
import { gutters } from "../../styles";
const Compose = () => {
return (
<Page backgroundImg={background.studioBG2} headerType="NONE">
<Image source={ai.theo} style={styles.img} resizeMode="contain" />
<MusicLandHeader showSkip onPressBack={goBack} progress={7.1} />
<View
style={{ flex: 1, position: "relative", justifyContent: "flex-end" }}
>
<View
style={{
paddingBottom: gutters * 2,
paddingHorizontal: gutters,
gap: 12,
}}
>
<GradientButton
title="Composer ma chanson"
onPress={() => navigate(Routes.ComposeSong)}
/>
</View>
</View>
</Page>
);
};
export default Compose;
const styles = StyleSheet.create({
img: {
width: "100%",
height: "70%",
position: "absolute",
bottom: -40,
right: -30,
},
});
+121 -4
View File
@@ -1,10 +1,127 @@
import { View, Text } from "react-native";
import React from "react";
import { View, Text, Image, StyleSheet, Dimensions } from "react-native";
import React, { useRef, useState } from "react";
import Page from "../../layouts/Page";
import { background } from "../../assets";
import { ai, background } from "../../assets";
import MusicLandHeader from "../../components/MusicLandHeader";
import GradientButton from "../../components/GradientButton";
import { goBack, navigate } from "../../navigation/NavigationService";
import { Routes } from "../../navigation";
import { gutters } from "../../styles";
import SwiperFlatList from "react-native-swiper-flatlist";
import ChooseGenre from "./ChooseGenre";
import CustomizeVoice from "./CustomizeVoice";
import ChooseInstruments from "./ChooseInstruments";
import ChooseRhythm from "./ChooseRhythm";
import CreatingSong from "./CreatingSong";
const { width } = Dimensions.get("window");
const ComposeSong = () => {
return <Page backgroundImg={background.studioBG2}></Page>;
const scrollRef = useRef(null);
const [selectedIndex, setSelectedIndex] = useState(0);
const [progress, setProgress] = useState(14.2);
const [containerLayout, setContainerLayout] = useState(null);
console.log("progress: ", progress);
const onPressNext = () => {
setSelectedIndex(selectedIndex + 1);
setProgress(progress + 7.1);
scrollRef.current.scrollToIndex({
index: selectedIndex + 1,
animated: true,
});
};
const onPressBack = () => {
if (selectedIndex > 0) {
setSelectedIndex(selectedIndex - 1);
setProgress(progress - 7.1);
scrollRef.current.scrollToIndex({
index: selectedIndex - 1,
animated: true,
});
} else {
goBack();
}
};
return (
<Page backgroundImg={background.studioBG2} headerType="NONE">
<Image source={ai.theo} style={styles.img} resizeMode="contain" />
<MusicLandHeader onPressBack={onPressBack} progress={progress} />
<View style={{ flex: 1, marginTop: 16, paddingBottom: gutters, gap: 48 }}>
<View
style={{ flex: 1 }}
onLayout={(event) => setContainerLayout(event.nativeEvent.layout)}
>
<SwiperFlatList
style={{ width, left: -gutters }}
ref={scrollRef}
disableGesture
>
<View
style={{
width: width,
height: containerLayout?.height,
paddingHorizontal: gutters,
}}
>
<ChooseGenre />
</View>
<View
style={{
width: width,
height: containerLayout?.height,
paddingHorizontal: gutters,
}}
>
<CustomizeVoice />
</View>
<View
style={{
width: width,
height: containerLayout?.height,
paddingHorizontal: gutters,
}}
>
<ChooseInstruments />
</View>
<View
style={{
width: width,
height: containerLayout?.height,
paddingHorizontal: gutters,
}}
>
<ChooseRhythm />
</View>
<View
style={{
width: width,
height: containerLayout?.height,
paddingHorizontal: gutters,
}}
>
<CreatingSong active={selectedIndex === 4} />
</View>
</SwiperFlatList>
</View>
{selectedIndex !== 4 && (
<GradientButton title="Suivant" onPress={onPressNext} />
)}
</View>
</Page>
);
};
export default ComposeSong;
const styles = StyleSheet.create({
img: {
width: "100%",
height: "70%",
position: "absolute",
bottom: -40,
right: -30,
},
});
+126
View File
@@ -0,0 +1,126 @@
import { View, Text, Image, Pressable } from "react-native";
import React, { useEffect, useState } from "react";
import { ai, icons } from "../../assets";
import { BlurView } from "expo-blur";
import Style, { size } from "../../styles/Style";
import { Palette } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts";
import ProgressBar from "../../components/ProgressBar";
import { navigate } from "../../navigation/NavigationService";
import { Routes } from "../../navigation";
import GradientButton from "../../components/GradientButton";
const CreatingSong = ({ active }) => {
const [progress, setProgress] = useState(0);
useEffect(() => {
if (active) {
const interval = setInterval(() => {
setProgress((prevProgress) => {
if (prevProgress >= 100) {
clearInterval(interval);
navigate(Routes.SongReady)
return 100;
}
return prevProgress + 1;
});
}, 100);
return () => clearInterval(interval);
}
}, [active]);
return (
<View
style={{
flex: 1,
...Style.containerCenter,
}}
>
<View
style={{
width: "100%",
height: "50%",
}}
>
<View
style={{
zIndex: 1,
position: "absolute",
top: -150,
width: "50%",
height: "80%",
alignSelf: "center",
}}
>
<Image
source={ai.theo}
style={{ width: "100%", height: "100%", right: -10 }}
resizeMode="contain"
/>
</View>
<View
style={{
flex: 1,
borderRadius: 20,
overflow: "hidden",
backgroundColor: "#0F0C1933",
}}
>
<BlurView
intensity={40}
style={{ flex: 1, padding: 10, paddingBottom: 20 }}
>
<Pressable
style={{
...size({ size: 24 }),
...Style.containerCenter,
position: "absolute",
top: 10,
left: 10,
zIndex: 3,
}}
onPress={() => console.log("Pressed")}
>
<Image source={icons.close} style={size({ size: 11 })} />
</Pressable>
<View style={{ flex: 1, justifyContent: "flex-end", gap: 20 }}>
<Text
style={{
fontSize: 22,
color: Palette.white,
fontFamily: FONT_FAMILY.InterSemiBold,
textAlign: "center",
}}
>
Ton texte est{"\n"}en cours de création
</Text>
<View style={{ alignItems: "center", gap: 16 }}>
<ProgressBar gradient progress={progress} />
<Text
style={{
fontSize: 14,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
}}
>
{progress}%
</Text>
</View>
<GradientButton
title="Découvrir mon texte"
containerStyle={{
width: "80%",
alignSelf: "center",
}}
onPress={() => navigate(Routes.SongReady)}
/>
</View>
</BlurView>
</View>
</View>
</View>
);
};
export default CreatingSong;
+92
View File
@@ -0,0 +1,92 @@
import { View, Text, FlatList, StyleSheet } from "react-native";
import React, { useState } from "react";
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
import ItemContainer from "../../components/ItemContainer/ItemContainer";
import { Palette, Style } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts";
import { BlurView } from "expo-blur";
const CustomizeVoice = () => {
const [containerLayout, setContainerLayout] = useState(null);
return (
<View style={{ flex: 1, gap: 10 }}>
<CreateLyricsHeader
title="Personnalise la voix que tu veux pour ta chanson"
subTitle="Choisis maximum 1 option par catégorie."
/>
<View
style={{ flex: 1 }}
onLayout={(event) => setContainerLayout(event.nativeEvent.layout)}
>
<ItemContainer height={containerLayout?.height}>
<View style={{ flex: 1, gap: 10 }}>
<Text
style={{
fontSize: 16,
color: Palette.white,
fontFamily: FONT_FAMILY.InterBold,
left: 16,
marginTop: 5,
}}
>
Base
</Text>
<FlatList
data={Array.from({ length: 10 })}
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.contentContainer}
renderItem={() => (
<View style={styles.itemContainer}>
<BlurView
intensity={30}
style={{
flex: 1,
backgroundColor: Palette.glass,
paddingHorizontal: 12,
justifyContent: "center",
}}
>
<Text style={styles.itemText}>Une voix féminine interpretra ta chanson.</Text>
</BlurView>
</View>
)}
/>
</View>
</ItemContainer>
</View>
</View>
);
};
export default CustomizeVoice;
const styles = StyleSheet.create({
contentContainer: {
flexGrow: 1,
padding: 8,
gap: 10,
backgroundColor: "#FFFFFF00",
paddingBottom: 50,
},
itemContainer: {
height: 54,
backgroundColor: Palette.glass,
borderRadius: 14,
overflow: "hidden",
shadowColor: "#00000040",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
itemText: {
fontSize: 16,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
},
});
+47
View File
@@ -0,0 +1,47 @@
import { View, Text } from "react-native";
import React from "react";
import Page from "../../layouts/Page";
import { background } from "../../assets";
import MusicLandHeader from "../../components/MusicLandHeader";
import { goBack } from "../../navigation/NavigationService";
import { LinearGradient } from "../../components/LinearGradient/LinearGradient";
import Slider from "../../components/Slider";
const SongReady = () => {
return (
<Page headerType="NONE" backgroundImg={background.studioBG2}>
<MusicLandHeader onPressBack={goBack} progress={49.7} />
<View>
<LinearGradient
colors={["#FF0000", "#FFFF00", "#0000FF"]} // Red to Yellow to Blue gradient
start={{ x: 0, y: 0.5 }}
end={{ x: 1, y: 0.5 }}
style={{
width: "100%",
height: 40,
borderRadius: 20, // Optional: for rounded corners
}}
>
<Slider
style={{ height: 40, width: "100%" }}
minimumValue={0}
maximumValue={100}
minimumTrackTintColor="transparent"
maximumTrackTintColor="red"
thumbTintColor="#FFFFFF"
/>
</LinearGradient>
<Slider
minimumValue={0}
maximumValue={100}
minimumTrackTintColor="transparent"
maximumTrackTintColor="red"
thumbTintColor="#FFFFFF"
/>
</View>
</Page>
);
};
export default SongReady;
+1 -1
View File
@@ -20,7 +20,7 @@ const Studio = () => {
<View style={{ flex: 1, justifyContent: "flex-end" }}>
<GradientButton
title="Commencer"
onPress={() => navigate(Routes.ComposeSong)}
onPress={() => navigate(Routes.Compose)}
/>
</View>
</Page>