import React, { memo, useMemo, useCallback, useEffect, useRef } from 'react' import { View, Text, StyleSheet, FlatList } from 'react-native' import { useGetter, useDispatch } from '@/store' import { useLayout } from '@/utils/hooks' import { useLrcPlay, useLrcSet } from '@/plugins/lyric' import { log } from '@/utils/log' import { toast } from '@/utils/tools' const LrcLine = memo(({ text, line, activeLine }) => { const theme = useGetter('common', 'theme') return ( {text} ) }, (prevProps, nextProps) => { return prevProps.text == nextProps.text && prevProps.line == nextProps.line && prevProps.activeLine != nextProps.line && nextProps.activeLine != nextProps.line }) const wait = new Promise(resolve => setTimeout(resolve, 500)) export default memo(() => { const lyricLines = useLrcSet() const { line } = useLrcPlay() const scrollViewRef = useRef() const isPauseScrollRef = useRef(true) const scrollTimoutRef = useRef(null) const lineRef = useRef(0) const linesRef = useRef([]) const isFirstSetLrc = useRef(true) // const playMusicInfo = useGetter('player', 'playMusicInfo') // const [imgUrl, setImgUrl] = useState(null) // const theme = useGetter('common', 'theme') // const { onLayout, ...layout } = useLayout() // useEffect(() => { // const url = playMusicInfo ? playMusicInfo.musicInfo.img : null // if (imgUrl == url) return // setImgUrl(url) // // eslint-disable-next-line react-hooks/exhaustive-deps // }, [playMusicInfo]) // const imgWidth = useMemo(() => layout.width * 0.75, [layout.width]) const handleScrollToActive = useCallback((index = lineRef.current) => { if (index < 0) return if (scrollViewRef.current) { try { scrollViewRef.current.scrollToIndex({ index: index, animated: true, viewPosition: 0.4, }) } catch (err) { toast('出了点意外...你可以去错误日志查看错误', 'long') log.warn('Scroll failed: ', err.message) } } }, []) const handleScrollBeginDrag = () => { isPauseScrollRef.current = true if (scrollTimoutRef.current) clearTimeout(scrollTimoutRef.current) scrollTimoutRef.current = setTimeout(() => { scrollTimoutRef.current = null isPauseScrollRef.current = false handleScrollToActive() }, 3000) } const handleScrollToIndexFailed = (info) => { // console.log(info) wait.then(() => { scrollViewRef.current?.scrollToIndex({ index: info.index, animated: true }) }) } useEffect(() => { return () => { if (scrollTimoutRef.current) { clearTimeout(scrollTimoutRef.current) scrollTimoutRef.current = null } } }, []) useEffect(() => { linesRef.current = lyricLines if (!scrollViewRef.current || !lyricLines.length) return scrollViewRef.current.scrollToOffset({ offset: 0, animated: false, }) if (isFirstSetLrc.current) { isFirstSetLrc.current = false setTimeout(() => { isPauseScrollRef.current = false handleScrollToActive() }, 100) } else { handleScrollToActive(0) } }, [handleScrollToActive, lyricLines]) useEffect(() => { lineRef.current = line if (!scrollViewRef.current || isPauseScrollRef.current) return handleScrollToActive() }, [handleScrollToActive, line]) const handleRenderItem = ({ item, index }) => { return ( ) } const spaceComponent = useMemo(() => ( ), []) return ( index} style={styles.container} ref={scrollViewRef} showsVerticalScrollIndicator={false} ListHeaderComponent={spaceComponent} ListFooterComponent={spaceComponent} onScrollBeginDrag={handleScrollBeginDrag} fadingEdgeLength={200} initialNumToRender={Math.max(line + 10, 10)} onScrollToIndexFailed={handleScrollToIndexFailed} /> ) }) const styles = StyleSheet.create({ container: { flex: 1, paddingLeft: 10, paddingRight: 10, // backgroundColor: 'rgba(0,0,0,0.1)', }, space: { paddingTop: '80%', }, line: { borderRadius: 4, textAlign: 'center', fontSize: 16, lineHeight: 22, paddingTop: 5, paddingBottom: 5, // opacity: 0, }, })