xref: /MusicFree/src/pages/searchPage/components/resultPanel/resultWrapper.tsx (revision 410a159129b1f6a7a1f44fde7bfad9a46f91e161)
1import React, {memo, useCallback, useEffect, useState} from 'react';
2import {useAtomValue} from 'jotai';
3import {ISearchResult, queryAtom} from '../../store/atoms';
4import {renderMap} from './results';
5import useSearch from '../../hooks/useSearch';
6import Loading from '@/components/base/loading';
7import {RequestStateCode} from '@/constants/commonConst';
8import ListLoading from '@/components/base/listLoading';
9import Empty from '@/components/base/empty';
10import ListReachEnd from '@/components/base/listReachEnd';
11import useOrientation from '@/hooks/useOrientation';
12import {FlashList} from '@shopify/flash-list';
13import rpx from '@/utils/rpx';
14import {StyleSheet, View} from 'react-native';
15
16interface IResultWrapperProps<
17    T extends ICommon.SupportMediaType = ICommon.SupportMediaType,
18> {
19    tab: T;
20    pluginHash: string;
21    pluginName: string;
22    searchResult: ISearchResult<T>;
23    pluginSearchResultRef: React.MutableRefObject<ISearchResult<T>>;
24}
25function ResultWrapper(props: IResultWrapperProps) {
26    const {tab, pluginHash, searchResult, pluginSearchResultRef} = props;
27    const search = useSearch();
28    const [searchState, setSearchState] = useState<RequestStateCode>(
29        searchResult?.state ?? RequestStateCode.IDLE,
30    );
31    const orientation = useOrientation();
32    const query = useAtomValue(queryAtom);
33
34    const ResultComponent = renderMap[tab]!;
35    const data: any = searchResult?.data ?? [];
36
37    const keyExtractor = useCallback(
38        (item: any, i: number) => `${i}-${item.platform}-${item.id}`,
39        [],
40    );
41
42    useEffect(() => {
43        if (searchState === RequestStateCode.IDLE) {
44            search(query, 1, tab, pluginHash);
45        }
46    }, []);
47
48    useEffect(() => {
49        setSearchState(searchResult?.state ?? RequestStateCode.IDLE);
50    }, [searchResult]);
51
52    const renderItem = ({item, index}: any) => (
53        <ResultComponent
54            item={item}
55            index={index}
56            pluginHash={pluginHash}
57            pluginSearchResultRef={pluginSearchResultRef}
58        />
59    );
60
61    return searchState === RequestStateCode.PENDING_FIRST_PAGE ? (
62        <Loading />
63    ) : (
64        <FlashList
65            extraData={searchState}
66            ListEmptyComponent={() => <Empty />}
67            ListFooterComponent={() => (
68                <View style={style.wrapper}>
69                    {searchState === RequestStateCode.PENDING_REST_PAGE ? (
70                        <ListLoading />
71                    ) : searchState === RequestStateCode.FINISHED ? (
72                        <ListReachEnd />
73                    ) : (
74                        <></>
75                    )}
76                </View>
77            )}
78            data={data}
79            refreshing={false}
80            onRefresh={() => {
81                search(query, 1, tab, pluginHash);
82            }}
83            onEndReached={() => {
84                (searchState === RequestStateCode.PARTLY_DONE ||
85                    searchState === RequestStateCode.IDLE) &&
86                    search(undefined, undefined, tab, pluginHash);
87            }}
88            estimatedItemSize={tab === 'sheet' ? rpx(306) : rpx(120)}
89            numColumns={
90                tab === 'sheet' ? (orientation === 'vertical' ? 3 : 4) : 1
91            }
92            renderItem={renderItem}
93            keyExtractor={keyExtractor}
94        />
95    );
96}
97
98export default memo(ResultWrapper);
99const style = StyleSheet.create({
100    wrapper: {
101        width: '100%',
102        height: rpx(140),
103        justifyContent: 'center',
104        alignItems: 'center',
105    },
106});
107