import React, { useState, useCallback, memo, useMemo, useRef, useEffect } from 'react' import { StyleSheet, FlatList, View, RefreshControl } from 'react-native' import { useGetter, useDispatch } from '@/store' import Menu from '@/components/common/Menu' import MusicAddModal from '@/components/MusicAddModal' import MusicMultiAddModal from '@/components/MusicMultiAddModal' import ListItem from './ListItem' import ExitMultipleModeBar from './ExitMultipleModeBar' import LoadingMask from '@/components/common/LoadingMask' import { useTranslation } from '@/plugins/i18n' import { Loading as FooterLoading, End as FooterEnd } from './Footer' import { LIST_ID_PLAY_LATER } from '@/config/constant' export default memo(({ list, isEnd, page, isListRefreshing, // visibleLoadingMask, onRefresh, onLoadMore, onPlayList, isLoading, progressViewOffset, ListHeaderComponent, }) => { const defaultList = useGetter('list', 'defaultList') const defaultListRef = useRef(defaultList) const addMusicToList = useDispatch('list', 'listAdd') const setPlayList = useDispatch('player', 'setList') const setTempPlayList = useDispatch('player', 'setTempPlayList') const isClickPlayList = useGetter('common', 'isClickPlayList') const [buttonPosition, setButtonPosition] = useState({ w: 0, h: 0, x: 0, y: 0 }) const selectedData = useRef({ data: null, index: -1 }) const [visibleMenu, setVisibleMenu] = useState(false) const [visibleLoadingMask, setVisibleLoadingMask] = useState(false) const flatListRef = useRef() const { t } = useTranslation() const [visibleMusicAddModal, setVisibleMusicAddModal] = useState(false) const [isMultiSelectMode, setIsMultiSelectMode] = useState(false) const isMultiSelectModeRef = useRef(isMultiSelectMode) const [selectedList, setSelectedList] = useState([]) const selectedListRef = useRef([]) const [visibleMusicMultiAddModal, setVisibleMusicMultiAddModal] = useState(false) const listRef = useRef([]) const [selectMode, setSelectMode] = useState('single') const selectModeRef = useRef('single') const prevSelectIndexRef = useRef(-1) const addMultiMusicToList = useDispatch('list', 'listAddMultiple') const theme = useGetter('common', 'theme') useEffect(() => { defaultListRef.current = defaultList }, [defaultList]) useEffect(() => { listRef.current = list }, [list]) const handlePlay = useCallback((targetSong, index) => { addMusicToList({ musicInfo: targetSong, id: defaultListRef.current.id, }) const targetIndex = defaultListRef.current.list.findIndex(s => s.songmid === targetSong.songmid) if (targetIndex > -1) { setPlayList({ list: defaultListRef.current, index: targetIndex, }) } }, [addMusicToList, setPlayList]) const handleSelect = useCallback((item, index) => { if (selectModeRef.current == 'single') { const index = selectedListRef.current.indexOf(item) if (index < 0) { selectedListRef.current.push(item) // setSelectedItem({ item, isChecked: true }) } else { selectedListRef.current.splice(index, 1) // setSelectedItem({ item, isChecked: false }) } } else { if (selectedListRef.current.length) { const prevIndex = prevSelectIndexRef.current const currentIndex = index if (prevIndex == currentIndex) { selectedListRef.current = [] } else if (currentIndex > prevIndex) { selectedListRef.current = listRef.current.slice(prevIndex, currentIndex + 1) } else { selectedListRef.current = listRef.current.slice(currentIndex, prevIndex + 1) selectedListRef.current.reverse() } } else { selectedListRef.current.push(item) prevSelectIndexRef.current = index } } setSelectedList([...selectedListRef.current]) }, []) const handleSelectAll = useCallback(() => { if (!listRef.current.length) return if (selectedListRef.current.length == listRef.current.length) { selectedListRef.current = [] } else { selectedListRef.current = [...listRef.current] } setSelectedList([...selectedListRef.current]) }, []) const handleSetSelectMode = useCallback(mode => { setSelectMode(mode) selectModeRef.current = mode if (mode == 'range' && selectedListRef.current.length) { prevSelectIndexRef.current = listRef.current.indexOf(selectedListRef.current[selectedListRef.current.length - 1]) } }, []) const handleCancelMultiSelect = useCallback(() => { setIsMultiSelectMode(false) isMultiSelectModeRef.current = false selectedListRef.current = [] setSelectedList([]) }, []) const handlePress = useCallback((item, index) => { if (isMultiSelectModeRef.current) { handleSelect(item, index) } else { if (isClickPlayList && typeof onPlayList == 'function') { onPlayList(index, item) } else { handlePlay(item, index) } } }, [handlePlay, handleSelect, isClickPlayList, onPlayList]) const handleLongPress = useCallback((item, index) => { setIsMultiSelectMode(true) isMultiSelectModeRef.current = true handleSelect(item, index) }, [handleSelect]) const menus = useMemo(() => { return [ { action: 'play', label: t('play') }, { action: 'playLater', label: t('play_later') }, // { action: 'copyName', label: t('copy_name') }, // { action: 'download', label: '下载' }, // { action: 'add', label: '添加到...' }, // { action: 'move', label: '移动到...' }, { action: 'add', label: t('add_to') }, ] }, [t]) const showMenu = useCallback((item, index, position) => { setButtonPosition({ ...position }) selectedData.current.data = item selectedData.current.index = index setVisibleMenu(true) }, [setButtonPosition]) const hideMenu = useCallback(() => { setVisibleMenu(false) }, [setVisibleMenu]) const handleMenuPress = useCallback(({ action }) => { switch (action) { case 'play': if (selectedListRef.current.length) { addMultiMusicToList({ id: 'default', list: [...selectedListRef.current] }) handleCancelMultiSelect() } handlePlay(selectedData.current.data, selectedData.current.index) break case 'playLater': if (selectedListRef.current.length) { setTempPlayList(selectedListRef.current.map(s => ({ listId: LIST_ID_PLAY_LATER, musicInfo: s }))) handleCancelMultiSelect() } else { setTempPlayList([{ listId: LIST_ID_PLAY_LATER, musicInfo: selectedData.current.data }]) } break // case 'copyName': // break case 'add': // console.log(selectedListRef.current.length) selectedListRef.current.length ? setVisibleMusicMultiAddModal(true) : setVisibleMusicAddModal(true) break default: break } }, [addMultiMusicToList, handleCancelMultiSelect, handlePlay, setTempPlayList]) useEffect(() => { if (isLoading && page == 1) { setVisibleLoadingMask(true) } else { setVisibleLoadingMask(false) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoading]) useEffect(() => { if (!flatListRef.current) return if (page == 1) flatListRef.current.scrollToOffset({ offset: 0, animated: true }) }, [list, page]) const hideMusicAddModal = useCallback(() => { setVisibleMusicAddModal(false) }, []) const hideMusicMultiAddModal = useCallback(() => { setVisibleMusicMultiAddModal(false) }, []) const loadingMaskmomponent = useMemo(() => ( ), [visibleLoadingMask]) const exitMultipleModeBtn = useMemo(() => ( ), [handleCancelMultiSelect, handleSelectAll, handleSetSelectMode, isMultiSelectMode, list, selectMode, selectedList]) const renderItem = useCallback(({ item, index }) => ( ), [handleLongPress, handlePress, selectedList, showMenu]) const refreshControl = useMemo(() => ( ), [isListRefreshing, onRefresh, theme]) return ( item.songmid.toString()} onRefresh={onRefresh} refreshing={isListRefreshing} maxToRenderPerBatch={8} updateCellsBatchingPeriod={80} windowSize={18} removeClippedSubviews={true} initialNumToRender={15} onEndReached={onLoadMore} progressViewOffset={progressViewOffset} ListHeaderComponent={ListHeaderComponent} refreshControl={refreshControl} ListFooterComponent={{isLoading ? : isEnd ? : null}} /> { exitMultipleModeBtn } { loadingMaskmomponent } ) }) const styles = StyleSheet.create({ container: { flex: 1, overflow: 'hidden', }, list: { flex: 1, }, exitMultipleModeBtn: { height: 40, }, })