This commit is contained in:
2025-10-23 11:22:04 +02:00
parent 8024f71e1c
commit 6947195a9a
2 changed files with 190 additions and 189 deletions
+51 -70
View File
@@ -1,9 +1,7 @@
import { BlurView } from "expo-blur";
import React, { useCallback, useEffect, useMemo, useState } from "react"; import React, { useCallback, useEffect, useMemo, useState } from "react";
import { import {
FlatList, FlatList,
Image, Image,
Platform,
StyleSheet, StyleSheet,
Text, Text,
TouchableOpacity, TouchableOpacity,
@@ -21,6 +19,7 @@ import {
OPTIONAL_STRUCTURE_SEGMENTS, OPTIONAL_STRUCTURE_SEGMENTS,
sanitizeStructureList, sanitizeStructureList,
} from "../../utils/songStructure"; } from "../../utils/songStructure";
import ItemContainer from "../../components/ItemContainer/ItemContainer";
import CreateLyricsHeader from "./components/CreateLyricsHeader"; import CreateLyricsHeader from "./components/CreateLyricsHeader";
const randomSuffix = () => Math.random().toString(36).slice(2, 8); const randomSuffix = () => Math.random().toString(36).slice(2, 8);
@@ -138,38 +137,34 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
); );
const Row = ({ item: rowData, onPress }) => { const Row = ({ item: rowData, onPress }) => {
const isButton = typeof onPress === "function";
const Wrapper = isButton ? TouchableOpacity : View;
const selected = rowData?.selected;
const icon = rowData?.icon;
const baseType = rowData?.type || rowData?.value; const baseType = rowData?.type || rowData?.value;
const meta = getSegmentMeta(baseType); const meta = getSegmentMeta(baseType);
const canRemove = rowData?.sortable && meta?.optional === true; const canRemove = rowData?.sortable && meta?.optional === true;
const selected = rowData?.selected;
const count = rowData?.count ?? 0; const count = rowData?.count ?? 0;
return ( const containerStyle = StyleSheet.flatten([
<Wrapper styles.rowContainer,
onPress={onPress} ]);
activeOpacity={0.8} const blurStyle = StyleSheet.flatten([
style={isButton ? styles.touchable : undefined}
>
<View
style={[
styles.itemContainer,
selected && styles.selectedItem,
rowData?.sortable && styles.sortableItem,
]}
>
<BlurView
intensity={Platform.OS !== "ios" ? 10 : 30}
style={[
styles.rowBlur, styles.rowBlur,
selected && styles.selectedBlur, selected ? styles.selectedBlur : null,
isButton && styles.buttonBlur, ]);
]} const badgeStyle = StyleSheet.flatten([
styles.countBadge,
count > 0 ? styles.countBadgeActive : null,
]);
return (
<CreateLyricsHeader
tint="dark"
intensity={40}
showBorder={false}
onPress={onPress}
containerStyle={containerStyle}
blurViewStyle={blurStyle}
> >
<View style={styles.rowContent}> <View style={styles.rowContent}>
<Text style={styles.rowText}>{rowData?.label || ""}</Text> <Text style={styles.rowText}>{rowData?.label || ""}</Text>
</View>
{rowData?.sortable ? ( {rowData?.sortable ? (
<View style={styles.rowActions}> <View style={styles.rowActions}>
<Sortable.Handle> <Sortable.Handle>
@@ -186,18 +181,12 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
)} )}
</View> </View>
) : ( ) : (
<View <View style={badgeStyle}>
style={[
styles.countBadge,
count > 0 ? styles.countBadgeActive : null,
]}
>
<Text style={styles.countBadgeText}>{count}</Text> <Text style={styles.countBadgeText}>{count}</Text>
</View> </View>
)} )}
</BlurView>
</View> </View>
</Wrapper> </CreateLyricsHeader>
); );
}; };
@@ -216,6 +205,11 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
<View style={styles.sectionTag}> <View style={styles.sectionTag}>
<Text style={styles.sectionTagText}>Structure actuelle</Text> <Text style={styles.sectionTagText}>Structure actuelle</Text>
</View> </View>
<ItemContainer
height="auto"
disableKeyboardHeight
style={styles.blurSection}
>
<Sortable.Grid <Sortable.Grid
columns={1} columns={1}
rowGap={12} rowGap={12}
@@ -229,17 +223,24 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
setSortableItems(buildSortableItems(sanitized)); setSortableItems(buildSortableItems(sanitized));
}} }}
/> />
</ItemContainer>
<View style={[styles.sectionTag, { marginTop: 24 }]}> <View style={[styles.sectionTag, { marginTop: 24 }]}>
<Text style={styles.sectionTagText}>Éléments à ajouter</Text> <Text style={styles.sectionTagText}>Éléments à ajouter</Text>
</View> </View>
<ItemContainer
height="auto"
disableKeyboardHeight
style={styles.blurSection}
>
<FlatList <FlatList
data={optionalSegments} data={optionalSegments}
gap={12} gap={12}
renderItem={({ item }) => { renderItem={({ item, index }) => {
const count = segmentCounts[item.type] || 0; const count = segmentCounts[item.type] || 0;
const selected = count > 0; const selected = count > 0;
const wrapperStyle = index === 0 ? null : styles.optionWrapper;
return ( return (
<View style={{ marginTop: 12 }}> <View style={wrapperStyle}>
<Row <Row
item={{ item={{
...item, ...item,
@@ -257,6 +258,7 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
scrollEnabled={false} scrollEnabled={false}
nestedScrollEnabled={false} nestedScrollEnabled={false}
/> />
</ItemContainer>
</Animated.ScrollView> </Animated.ScrollView>
</View> </View>
</View> </View>
@@ -266,40 +268,19 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
export default CustomizeSongStructure; export default CustomizeSongStructure;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
touchable: { rowContainer: {
borderRadius: 14,
width: "100%", width: "100%",
}, },
itemContainer: { blurSection: {
height: 54, marginTop: 12,
backgroundColor: Palette.glass, width: "100%",
borderRadius: 14,
overflow: "hidden",
shadowColor: "#00000040",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
sortableItem: {
marginBottom: 0,
},
selectedItem: {
borderWidth: 1,
borderColor: Palette.white,
}, },
rowBlur: { rowBlur: {
flex: 1, minHeight: 54,
backgroundColor: Palette.glass, paddingHorizontal: 16,
justifyContent: "center",
paddingHorizontal: 12,
flexDirection: "row", flexDirection: "row",
alignItems: "center", alignItems: "center",
height: "100%",
},
buttonBlur: {
justifyContent: "space-between", justifyContent: "space-between",
}, },
selectedBlur: { selectedBlur: {
@@ -307,7 +288,9 @@ const styles = StyleSheet.create({
}, },
rowContent: { rowContent: {
flex: 1, flex: 1,
justifyContent: "center", flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
}, },
rowText: { rowText: {
fontSize: 16, fontSize: 16,
@@ -320,11 +303,6 @@ const styles = StyleSheet.create({
tintColor: Palette.white, tintColor: Palette.white,
marginRight: 12, marginRight: 12,
}, },
optionIcon: {
width: 20,
height: 20,
tintColor: Palette.white,
},
countBadge: { countBadge: {
minWidth: 28, minWidth: 28,
paddingHorizontal: 8, paddingHorizontal: 8,
@@ -356,6 +334,9 @@ const styles = StyleSheet.create({
height: 16, height: 16,
tintColor: Palette.white, tintColor: Palette.white,
}, },
optionWrapper: {
marginTop: 12,
},
sectionTag: { sectionTag: {
alignSelf: "flex-start", alignSelf: "flex-start",
paddingHorizontal: 12, paddingHorizontal: 12,
@@ -23,6 +23,7 @@ import {
OPTIONAL_STRUCTURE_SEGMENTS, OPTIONAL_STRUCTURE_SEGMENTS,
sanitizeStructureList, sanitizeStructureList,
} from "../../utils/songStructure"; } from "../../utils/songStructure";
import ItemContainer from "../../components/ItemContainer/ItemContainer";
import CreateLyricsHeader from "./components/CreateLyricsHeader"; import CreateLyricsHeader from "./components/CreateLyricsHeader";
const ROW_HEIGHT = 54; const ROW_HEIGHT = 54;
@@ -222,12 +223,22 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
const baseType = item?.type || item?.value; const baseType = item?.type || item?.value;
const meta = getSegmentMeta(baseType); const meta = getSegmentMeta(baseType);
const canRemove = meta?.optional === true; const canRemove = meta?.optional === true;
const containerStyle = StyleSheet.flatten([
styles.rowContainer,
activeItemId === item.id ? styles.activeItem : null,
]);
const blurStyle = StyleSheet.flatten([
styles.itemBlur,
activeItemId === item.id ? styles.activeBlur : null,
]);
return ( return (
<View <CreateLyricsHeader
style={[ tint="dark"
styles.itemContainer, intensity={40}
activeItemId === item.id && styles.activeItem, showBorder={false}
]} containerStyle={containerStyle}
blurViewStyle={blurStyle}
> >
<View style={styles.row}> <View style={styles.row}>
<Text style={styles.rowText}>{item.label}</Text> <Text style={styles.rowText}>{item.label}</Text>
@@ -253,7 +264,7 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
</View> </View>
</View> </View>
</View> </View>
</View> </CreateLyricsHeader>
); );
}; };
@@ -271,38 +282,59 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
<View style={styles.sectionTag}> <View style={styles.sectionTag}>
<Text style={styles.sectionTagText}>Structure actuelle</Text> <Text style={styles.sectionTagText}>Structure actuelle</Text>
</View> </View>
<ItemContainer
height="auto"
disableKeyboardHeight
style={styles.blurSection}
>
<View style={styles.listContainer} ref={containerRef}> <View style={styles.listContainer} ref={containerRef}>
{labeledItems.map((item) => ( {labeledItems.map((item) => (
<StructureRow key={item.id} item={item} /> <StructureRow key={item.id} item={item} />
))} ))}
</View> </View>
</ItemContainer>
<View style={[styles.sectionTag, styles.addSectionTag]}> <View style={[styles.sectionTag, styles.addSectionTag]}>
<Text style={styles.sectionTagText}>Éléments à ajouter</Text> <Text style={styles.sectionTagText}>Éléments à ajouter</Text>
</View> </View>
<ItemContainer
height="auto"
disableKeyboardHeight
style={styles.blurSection}
>
<View style={styles.optionsContainer}> <View style={styles.optionsContainer}>
{optionalSegments.map((segment) => { {optionalSegments.map((segment) => {
const count = segmentCounts[segment.type] || 0; const count = segmentCounts[segment.type] || 0;
const selected = count > 0; const selected = count > 0;
return ( const blurStyle = StyleSheet.flatten([
<TouchableOpacity styles.itemBlur,
key={segment.type} selected ? styles.selectedBlur : null,
activeOpacity={0.85} ]);
onPress={() => handleOptionalSegmentPress(segment.type)} const badgeStyle = StyleSheet.flatten([
style={[styles.optionItem, selected && styles.selectedItem]}
>
<Text style={styles.rowText}>{segment.label}</Text>
<View
style={[
styles.countBadge, styles.countBadge,
selected && styles.countBadgeActive, selected ? styles.countBadgeActive : null,
]} ]);
return (
<CreateLyricsHeader
key={segment.type}
tint="dark"
intensity={40}
showBorder={false}
onPress={() => handleOptionalSegmentPress(segment.type)}
containerStyle={styles.rowContainer}
blurViewStyle={blurStyle}
> >
<View style={styles.row}>
<Text style={styles.rowText}>{segment.label}</Text>
<View style={badgeStyle}>
<Text style={styles.countBadgeText}>{count}</Text> <Text style={styles.countBadgeText}>{count}</Text>
</View> </View>
</TouchableOpacity> </View>
</CreateLyricsHeader>
); );
})} })}
</View> </View>
</ItemContainer>
</ScrollView> </ScrollView>
</View> </View>
</View> </View>
@@ -337,24 +369,32 @@ const styles = StyleSheet.create({
listContainer: { listContainer: {
gap: 12, gap: 12,
}, },
itemContainer: { blurSection: {
height: ROW_HEIGHT, marginTop: 12,
width: "100%",
},
rowContainer: {
borderRadius: 14, borderRadius: 14,
backgroundColor: Palette.glass,
shadowColor: "#00000040",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
overflow: "hidden",
}, },
activeItem: { activeItem: {
borderWidth: 1, borderWidth: 1,
borderColor: Palette.white, borderColor: Palette.white,
}, },
itemBlur: {
minHeight: ROW_HEIGHT,
paddingHorizontal: 16,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
},
activeBlur: {
backgroundColor: Palette.transparentWhite,
},
selectedBlur: {
backgroundColor: Palette.transparentWhite,
},
row: { row: {
flex: 1, flex: 1,
paddingHorizontal: 16,
flexDirection: "row", flexDirection: "row",
alignItems: "center", alignItems: "center",
justifyContent: "space-between", justifyContent: "space-between",
@@ -391,26 +431,6 @@ const styles = StyleSheet.create({
}, },
optionsContainer: { optionsContainer: {
gap: 12, gap: 12,
marginTop: 12,
},
optionItem: {
height: ROW_HEIGHT,
borderRadius: 14,
backgroundColor: Palette.glass,
shadowColor: "#00000040",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
overflow: "hidden",
paddingHorizontal: 16,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
},
selectedItem: {
borderWidth: 1,
borderColor: Palette.white,
}, },
countBadge: { countBadge: {
minWidth: 28, minWidth: 28,