new options

This commit is contained in:
2025-10-21 10:26:47 +02:00
parent 4796dbd434
commit 59328aaaed
3 changed files with 71 additions and 40 deletions
+5 -1
View File
@@ -40,7 +40,11 @@ const MusicLandHeader = ({
<View style={{ alignItems: "center", gap: 16 }}> <View style={{ alignItems: "center", gap: 16 }}>
<Image <Image
source={logo || icons.musicLandLogo} source={logo || icons.musicLandLogo}
style={{ alignSelf: "center", height: 150, resizeMode: "contain" }} style={{
alignSelf: "center",
height: isWeb ? 150 : 100,
resizeMode: "contain",
}}
/> />
<View style={{ width: "100%", ...Style.containerRow, gap: 16 }}> <View style={{ width: "100%", ...Style.containerRow, gap: 16 }}>
<Pressable style={backButtonStyle} onPress={onPressBack}> <Pressable style={backButtonStyle} onPress={onPressBack}>
+2 -14
View File
@@ -250,13 +250,7 @@ const MusicDetails = ({ route }) => {
console.log("MusicDetails seek error", e?.message); console.log("MusicDetails seek error", e?.message);
} }
}, },
[ [trackDescriptor, durationMs, isCurrentTrack, ensureLoaded, seekTrackTo]
trackDescriptor,
durationMs,
isCurrentTrack,
ensureLoaded,
seekTrackTo,
]
); );
const handleSliderSeekEnd = useCallback(async () => { const handleSliderSeekEnd = useCallback(async () => {
@@ -293,13 +287,7 @@ const MusicDetails = ({ route }) => {
console.log("MusicDetails seekBy error", e?.message); console.log("MusicDetails seekBy error", e?.message);
} }
}, },
[ [trackDescriptor, positionMs, isCurrentTrack, ensureLoaded, seekTrackBy]
trackDescriptor,
positionMs,
isCurrentTrack,
ensureLoaded,
seekTrackBy,
]
); );
const handleLyricsSeek = useCallback( const handleLyricsSeek = useCallback(
+64 -25
View File
@@ -1,6 +1,13 @@
import { BlurView } from "expo-blur"; import { BlurView } from "expo-blur";
import React, { useEffect, useMemo, useState } from "react"; import React, { useEffect, useMemo } from "react";
import { Image, Platform, StyleSheet, Text, View } from "react-native"; import {
FlatList,
Image,
Platform,
StyleSheet,
Text,
View,
} from "react-native";
import Animated, { useAnimatedRef } from "react-native-reanimated"; import Animated, { useAnimatedRef } from "react-native-reanimated";
import Sortable from "react-native-sortables"; import Sortable from "react-native-sortables";
import { icons } from "../../assets"; import { icons } from "../../assets";
@@ -11,7 +18,6 @@ import CreateLyricsHeader from "./components/CreateLyricsHeader";
// baseStructure: array like ['couplet','refrain',...] // baseStructure: array like ['couplet','refrain',...]
// onChange: callback that receives array like ['couplet','refrain',...] // onChange: callback that receives array like ['couplet','refrain',...]
const CustomizeSongStructure = ({ baseStructure = [], onChange }) => { const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
const [containerLayout, setContainerLayout] = useState(null);
const scrollRef = useAnimatedRef(); const scrollRef = useAnimatedRef();
// Build stable keyed data like { 'couplet-1': { label, value }, ... } // Build stable keyed data like { 'couplet-1': { label, value }, ... }
@@ -34,6 +40,23 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
const items = useMemo(() => Object.values(data), [data]); const items = useMemo(() => Object.values(data), [data]);
const newItems = [
{
id: "short_intro",
label: "Introduction instrumentale courte",
value: "short_intro",
},
{
id: "long_intro",
label: "Introduction instrumentale longue",
value: "long_intro",
},
{
id: "pre_chorus",
label: "Pré-refrain",
value: "pre_chorus",
},
];
// Initialize parent with current order (so it's saved even without drag) // Initialize parent with current order (so it's saved even without drag)
useEffect(() => { useEffect(() => {
const initialValues = (items || []).map((it) => it?.value).filter(Boolean); const initialValues = (items || []).map((it) => it?.value).filter(Boolean);
@@ -65,9 +88,12 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
<Text style={styles.rowText}>{rowData?.label || ""}</Text> <Text style={styles.rowText}>{rowData?.label || ""}</Text>
</View> </View>
</View> </View>
<Sortable.Handle> {/* Render handle only for items that come from the sortable data (have an id like 'couplet-1') */}
<Image source={icons.dragDots} style={styles.handleIcon} /> {String(rowData?.id || "").includes("-") ? (
</Sortable.Handle> <Sortable.Handle>
<Image source={icons.dragDots} style={styles.handleIcon} />
</Sortable.Handle>
) : null}
</View> </View>
</BlurView> </BlurView>
</View> </View>
@@ -79,30 +105,43 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
title="Personnalise la structure de ta chanson" title="Personnalise la structure de ta chanson"
subTitle="Réorganise par glisser-déposer" subTitle="Réorganise par glisser-déposer"
/> />
<View <View style={{ flex: 1 }}>
style={{ flex: 1 }}
onLayout={(e) => setContainerLayout(e.nativeEvent.layout)}
>
<Animated.ScrollView <Animated.ScrollView
ref={scrollRef} ref={scrollRef}
contentContainerStyle={{ paddingVertical: 4, paddingBottom: 24 }} contentContainerStyle={{ paddingVertical: 4, paddingBottom: 24 }}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
> >
<Sortable.Grid <>
columns={1} <Sortable.Grid
rowGap={12} columns={1}
data={items} rowGap={12}
renderItem={({ item }) => <Row item={item} />} data={items}
customHandle renderItem={({ item }) => <Row item={item} />}
// Enable auto-scroll when dragging near edges customHandle
scrollableRef={scrollRef} // Enable auto-scroll when dragging near edges
onDragEnd={({ data: newData }) => { scrollableRef={scrollRef}
const values = (newData || []) onDragEnd={({ data: newData }) => {
.map((it) => it?.value) const values = (newData || [])
.filter(Boolean); .map((it) => it?.value)
onChange?.(values); .filter(Boolean);
}} onChange?.(values);
/> }}
/>
<FlatList
data={newItems}
gap={12}
renderItem={({ item }) => (
<View style={{ marginTop: 12 }}>
<Row item={item} />
</View>
)}
keyExtractor={(item) => item.id}
contentContainerStyle={{ paddingBottom: 24 }}
// Prevent FlatList from capturing scroll gestures so Sortable can handle drags
scrollEnabled={false}
nestedScrollEnabled={false}
/>
</>
</Animated.ScrollView> </Animated.ScrollView>
</View> </View>
</View> </View>