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