Files
musicland/src/screens/Playbacks/Playbacks.js
T
2026-03-05 14:16:18 +01:00

175 lines
4.9 KiB
JavaScript

import { useIsFocused, useRoute } from '@react-navigation/native'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Pressable, StyleSheet, Text, View } from 'react-native'
import Carousel from 'react-native-reanimated-carousel'
import { responsiveHeight } from 'react-native-responsive-dimensions'
import { projectsRef } from '../../config/firebase'
import useDataFromRef from '../../hooks/useDataFromRef'
import usePlayer from '../../hooks/usePlayer'
import PlaybackItem from './components/PlaybackItem'
import PlaybackCharts from './components/PlaybackCharts'
import { Palette } from '../../styles'
import { FONT_FAMILY } from '../../styles/Fonts'
const Playbacks = () => {
const [activeIndex, setActiveIndex] = useState(0)
const userCache = useRef(new Map())
const isFocused = useIsFocused()
const wasFocusedRef = useRef(false)
const route = useRoute()
const { stop } = usePlayer() || {}
const initialFocusProjectId = route?.params?.projectId || route?.params?.focusId || null
const [focusProjectId, setFocusProjectId] = useState(initialFocusProjectId)
const [viewMode, setViewMode] = useState(initialFocusProjectId ? 'feed' : 'charts')
const { data: rawPlaybacks = [], loadMore } = useDataFromRef({
ref: projectsRef.where('playbackUrl', '!=', null),
simpleRef: false,
listener: false,
usePagination: true,
batchSize: 6,
})
const focusIndex = useMemo(() => {
if (!focusProjectId) return -1
return rawPlaybacks.findIndex((p) => p?.id === focusProjectId)
}, [focusProjectId, rawPlaybacks])
const playbacks = useMemo(() => {
if (focusIndex < 0) return rawPlaybacks
const target = rawPlaybacks[focusIndex]
const before = rawPlaybacks.slice(0, focusIndex)
const after = rawPlaybacks.slice(focusIndex + 1)
return [target, ...after, ...before]
}, [focusIndex, rawPlaybacks])
const onSnap = useCallback(
(index) => {
setActiveIndex(index)
if (index >= (playbacks?.length || 0) - 6) {
loadMore?.()
}
},
[playbacks?.length, loadMore]
)
const triedLoadMoreRef = useRef(0)
const focusLoadAttemptsRef = useRef(0)
const hasAppliedFocusRef = useRef(false)
useEffect(() => {
focusLoadAttemptsRef.current = 0
hasAppliedFocusRef.current = false
if (!focusProjectId) {
setActiveIndex(0)
}
}, [focusProjectId])
useEffect(() => {
if (loadMore && triedLoadMoreRef.current < 6) {
triedLoadMoreRef.current += 1
loadMore()
}
}, [loadMore, playbacks])
useEffect(() => {
if (!focusProjectId) return
if (focusIndex >= 0 && !hasAppliedFocusRef.current) {
hasAppliedFocusRef.current = true
setActiveIndex(0)
return
}
if (loadMore && focusLoadAttemptsRef.current < 6) {
focusLoadAttemptsRef.current += 1
loadMore()
}
}, [focusIndex, focusProjectId, loadMore, playbacks])
useEffect(() => {
const nextFocusId = route?.params?.projectId || route?.params?.focusId || null
setFocusProjectId(nextFocusId)
if (nextFocusId) {
setViewMode('feed')
}
}, [route?.params?.focusId, route?.params?.projectId])
useEffect(() => {
if (isFocused && !wasFocusedRef.current) {
stop?.().catch(() => {})
}
wasFocusedRef.current = isFocused
}, [isFocused, stop])
useEffect(() => {
if (viewMode !== 'feed') {
return
}
setActiveIndex(0)
}, [viewMode])
const showFeed = viewMode === 'feed'
const openFeedForPlayback = useCallback((project) => {
const nextId =
project && typeof project === 'object'
? project?.id || project?.projectId || null
: project || null
if (!nextId) {
return
}
setFocusProjectId(nextId)
setViewMode('feed')
}, [])
if (!showFeed) {
return <PlaybackCharts onPlaybackPress={openFeedForPlayback} />
}
return (
<View style={{ flex: 1, backgroundColor: 'black' }}>
<Carousel
data={playbacks}
vertical
height={responsiveHeight(100)}
pagingEnabled
windowSize={5}
onSnapToItem={onSnap}
renderItem={({ item, index }) => (
<PlaybackItem
key={item?.id || index}
item={item}
userCache={userCache}
isActive={isFocused && index === activeIndex}
/>
)}
/>
<Pressable
style={styles.backToCharts}
hitSlop={12}
onPress={() => setViewMode('charts')}
accessibilityLabel="Revenir au classement des playbacks"
>
<Text style={styles.backToChartsText}>Classement</Text>
</Pressable>
</View>
)
}
export default Playbacks
const styles = StyleSheet.create({
backToCharts: {
position: 'absolute',
top: 32,
right: 20,
paddingVertical: 8,
paddingHorizontal: 12,
borderRadius: 12,
backgroundColor: 'rgba(0,0,0,0.55)',
zIndex: 20,
},
backToChartsText: {
color: Palette.white,
fontSize: 12,
fontFamily: FONT_FAMILY.InterSemiBold,
},
})