pre-refrain always before refrain
This commit is contained in:
@@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
|||||||
import { FlatList, Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
|
import { FlatList, Image, StyleSheet, Text, TouchableOpacity, 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 { useGlobal } from 'reactn'
|
||||||
import { icons } from '../../assets'
|
import { icons } from '../../assets'
|
||||||
import { Palette } from '../../styles'
|
import { Palette } from '../../styles'
|
||||||
import { FONT_FAMILY } from '../../styles/Fonts'
|
import { FONT_FAMILY } from '../../styles/Fonts'
|
||||||
@@ -21,6 +22,11 @@ const createSortableItem = (type, index = 0) => ({
|
|||||||
type,
|
type,
|
||||||
value: type,
|
value: type,
|
||||||
})
|
})
|
||||||
|
const PRE_REFRAIN_TYPE = 'pre_refrain_instrumental'
|
||||||
|
const INTRO_TYPES = new Set(['short_intro', 'long_intro', 'intro', 'introduction'])
|
||||||
|
const PRE_REFRAIN_ERROR_MESSAGE =
|
||||||
|
'Impossible de positionner un pré-refrain ici. Place-le juste avant un refrain.'
|
||||||
|
const INTRO_ERROR_MESSAGE = "L'introduction musicale doit rester en première position."
|
||||||
const SANITIZE_OPTIONS = { autoInjectPreChorus: false }
|
const SANITIZE_OPTIONS = { autoInjectPreChorus: false }
|
||||||
|
|
||||||
const buildSortableItems = (values = []) =>
|
const buildSortableItems = (values = []) =>
|
||||||
@@ -28,8 +34,36 @@ const buildSortableItems = (values = []) =>
|
|||||||
createSortableItem(type, index)
|
createSortableItem(type, index)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const validateStructureRules = (values = []) => {
|
||||||
|
for (let index = 0; index < values.length; index += 1) {
|
||||||
|
const type = values[index]
|
||||||
|
if (type === PRE_REFRAIN_TYPE) {
|
||||||
|
const nextType = values[index + 1]
|
||||||
|
if (nextType !== 'refrain') {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
reason: 'pre_refrain_invalid_position',
|
||||||
|
message: PRE_REFRAIN_ERROR_MESSAGE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const introIndex = values.findIndex((type) => INTRO_TYPES.has(type))
|
||||||
|
if (introIndex > 0) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
reason: 'intro_must_be_first',
|
||||||
|
message: INTRO_ERROR_MESSAGE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { valid: true }
|
||||||
|
}
|
||||||
|
|
||||||
const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
||||||
const scrollRef = useAnimatedRef()
|
const scrollRef = useAnimatedRef()
|
||||||
|
const [, setTooltip] = useGlobal('_tooltip')
|
||||||
const sanitizedBase = useMemo(
|
const sanitizedBase = useMemo(
|
||||||
() => sanitizeStructureList(baseStructure, SANITIZE_OPTIONS),
|
() => sanitizeStructureList(baseStructure, SANITIZE_OPTIONS),
|
||||||
[baseStructure]
|
[baseStructure]
|
||||||
@@ -39,6 +73,13 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
const [sortableItems, setSortableItems] = useState(() => buildSortableItems(sanitizedBase))
|
const [sortableItems, setSortableItems] = useState(() => buildSortableItems(sanitizedBase))
|
||||||
|
const showTooltip = useCallback(
|
||||||
|
(text, type = 'error') => {
|
||||||
|
if (!text) return
|
||||||
|
setTooltip({ text, type })
|
||||||
|
},
|
||||||
|
[setTooltip]
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSortableItems((prev) => {
|
setSortableItems((prev) => {
|
||||||
@@ -119,12 +160,32 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|||||||
return buildSortableItems(sanitized)
|
return buildSortableItems(sanitized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === PRE_REFRAIN_TYPE) {
|
||||||
|
const firstRefrainIndex = nextValues.findIndex((value) => value === 'refrain')
|
||||||
|
if (firstRefrainIndex === -1) {
|
||||||
|
showTooltip(PRE_REFRAIN_ERROR_MESSAGE)
|
||||||
|
return prev
|
||||||
|
}
|
||||||
|
nextValues.splice(firstRefrainIndex, 0, type)
|
||||||
|
} else if (meta?.exclusiveGroup === 'intro') {
|
||||||
|
nextValues.unshift(type)
|
||||||
|
} else if (meta?.exclusiveGroup === 'outro') {
|
||||||
nextValues.push(type)
|
nextValues.push(type)
|
||||||
|
} else {
|
||||||
|
nextValues.push(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
const validation = validateStructureRules(nextValues)
|
||||||
|
if (!validation.valid) {
|
||||||
|
showTooltip(validation.message)
|
||||||
|
return prev
|
||||||
|
}
|
||||||
|
|
||||||
const sanitized = sanitizeStructureList(nextValues, SANITIZE_OPTIONS)
|
const sanitized = sanitizeStructureList(nextValues, SANITIZE_OPTIONS)
|
||||||
return buildSortableItems(sanitized)
|
return buildSortableItems(sanitized)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
[extractValues]
|
[extractValues, showTooltip]
|
||||||
)
|
)
|
||||||
|
|
||||||
const Row = ({ item: rowData, onPress }) => {
|
const Row = ({ item: rowData, onPress }) => {
|
||||||
@@ -201,6 +262,12 @@ const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
|||||||
scrollableRef={scrollRef}
|
scrollableRef={scrollRef}
|
||||||
onDragEnd={({ data: newData }) => {
|
onDragEnd={({ data: newData }) => {
|
||||||
const values = extractValues(newData)
|
const values = extractValues(newData)
|
||||||
|
const validation = validateStructureRules(values)
|
||||||
|
if (!validation.valid) {
|
||||||
|
showTooltip(validation.message)
|
||||||
|
setSortableItems((prev) => buildSortableItems(extractValues(prev)))
|
||||||
|
return
|
||||||
|
}
|
||||||
const sanitized = sanitizeStructureList(values, SANITIZE_OPTIONS)
|
const sanitized = sanitizeStructureList(values, SANITIZE_OPTIONS)
|
||||||
setSortableItems(buildSortableItems(sanitized))
|
setSortableItems(buildSortableItems(sanitized))
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user