xref: /MusicFree/src/pages/searchPage/components/resultPanel/resultWrapper.tsx (revision 5589cdf32b2bb0f641e5ac7bf1f6152cd6b9b70e)
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={() =>
67                searchState & RequestStateCode.LOADING ? null : <Empty />
68            }
69            ListFooterComponent={() => (
70                <View style={style.wrapper}>
71                    {searchState === RequestStateCode.PENDING_REST_PAGE ? (
72                        <ListLoading />
73                    ) : searchState === RequestStateCode.FINISHED ? (
74                        <ListReachEnd />
75                    ) : (
76                        <></>
77                    )}
78                </View>
79            )}
80            data={data}
81            refreshing={false}
82            onRefresh={() => {
83                search(query, 1, tab, pluginHash);
84            }}
85            onEndReached={() => {
86                (searchState === RequestStateCode.PARTLY_DONE ||
87                    searchState === RequestStateCode.IDLE) &&
88                    search(undefined, undefined, tab, pluginHash);
89            }}
90            estimatedItemSize={tab === 'sheet' ? rpx(306) : rpx(120)}
91            numColumns={
92                tab === 'sheet' ? (orientation === 'vertical' ? 3 : 4) : 1
93            }
94            renderItem={renderItem}
95            keyExtractor={keyExtractor}
96        />
97    );
98}
99
100export default memo(ResultWrapper);
101const style = StyleSheet.create({
102    wrapper: {
103        width: '100%',
104        height: rpx(140),
105        justifyContent: 'center',
106        alignItems: 'center',
107    },
108});
109