xref: /MusicFree/src/pages/searchPage/components/resultPanel/resultSubPanel.tsx (revision 2aa881935ca35b8fb1abc4206e0dc35149231456)
1import React, {memo, useCallback, useEffect, useRef, useState} from 'react';
2import {Text} from 'react-native';
3import rpx from '@/utils/rpx';
4import {SceneMap, TabBar, TabView} from 'react-native-tab-view';
5import DefaultResults from './results/defaultResults';
6import {renderMap} from './results';
7import ResultWrapper from './resultWrapper';
8import {fontWeightConst} from '@/constants/uiConst';
9import {useAtomValue} from 'jotai';
10import {searchResultsAtom} from '../../store/atoms';
11import PluginManager from '@/core/pluginManager';
12
13interface IResultSubPanelProps {
14    tab: ICommon.SupportMediaType;
15}
16
17// 展示结果的视图
18function getResultComponent(
19    tab: ICommon.SupportMediaType,
20    pluginHash: string,
21    pluginName: string,
22) {
23    return tab in renderMap
24        ? memo(
25              () => {
26                  const searchResults = useAtomValue(searchResultsAtom);
27                  const pluginSearchResult = searchResults[tab][pluginHash];
28                  const pluginSearchResultRef = useRef(pluginSearchResult);
29
30                  useEffect(() => {
31                      pluginSearchResultRef.current = pluginSearchResult;
32                  }, [pluginSearchResult]);
33
34                  return (
35                      <ResultWrapper
36                          tab={tab}
37                          searchResult={pluginSearchResult}
38                          pluginHash={pluginHash}
39                          pluginName={pluginName}
40                          pluginSearchResultRef={pluginSearchResultRef}
41                      />
42                  );
43              },
44              () => true,
45          )
46        : () => <DefaultResults />;
47}
48
49/** 结果scene */
50function getSubRouterScene(
51    tab: ICommon.SupportMediaType,
52    routes: Array<{key: string; title: string}>,
53) {
54    const scene: Record<string, React.FC> = {};
55    routes.forEach(r => {
56        // todo: 是否声明不可搜索
57        scene[r.key] = getResultComponent(tab, r.key, r.title);
58    });
59    return SceneMap(scene);
60}
61
62function ResultSubPanel(props: IResultSubPanelProps) {
63    const [index, setIndex] = useState(0);
64
65    const routes = PluginManager.getSortedSearchablePlugins().map(_ => ({
66        key: _.hash,
67        title: _.name,
68    }));
69
70    return (
71        <TabView
72            lazy
73            navigationState={{
74                index,
75                routes,
76            }}
77            renderTabBar={_ => (
78                <TabBar
79                    {..._}
80                    scrollEnabled
81                    style={{
82                        backgroundColor: 'transparent',
83                        shadowColor: 'transparent',
84                        borderColor: 'transparent',
85                    }}
86                    tabStyle={{
87                        width: rpx(200),
88                    }}
89                    renderIndicator={() => null}
90                    pressColor="transparent"
91                    renderLabel={({route, focused, color}) => (
92                        <Text
93                            numberOfLines={1}
94                            style={{
95                                fontWeight: focused
96                                    ? fontWeightConst.bolder
97                                    : fontWeightConst.bold,
98                                color,
99                            }}>
100                            {route.title ?? '(未命名)'}
101                        </Text>
102                    )}
103                />
104            )}
105            renderScene={useCallback(getSubRouterScene(props.tab, routes), [
106                props.tab,
107            ])}
108            onIndexChange={setIndex}
109            initialLayout={{width: rpx(750)}}
110        />
111    );
112}
113
114// 不然会一直重新渲染
115export default memo(ResultSubPanel);
116