xref: /MusicFree/src/pages/searchPage/components/resultPanel/resultSubPanel.tsx (revision 9677305be11b30a8953a6c14fd24375953a2309d)
1import React, {memo, useEffect, useMemo, useRef, useState} from 'react';
2import {Text} from 'react-native';
3import rpx, {vw} 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';
12import useColors from '@/hooks/useColors';
13import Empty from '@/components/base/empty';
14
15interface IResultSubPanelProps {
16    tab: ICommon.SupportMediaType;
17}
18
19// 展示结果的视图
20function getResultComponent(
21    tab: ICommon.SupportMediaType,
22    pluginHash: string,
23    pluginName: string,
24) {
25    return tab in renderMap
26        ? memo(
27              () => {
28                  const searchResults = useAtomValue(searchResultsAtom);
29                  const pluginSearchResult = searchResults[tab][pluginHash];
30                  const pluginSearchResultRef = useRef(pluginSearchResult);
31
32                  useEffect(() => {
33                      pluginSearchResultRef.current = pluginSearchResult;
34                  }, [pluginSearchResult]);
35
36                  return (
37                      <ResultWrapper
38                          tab={tab}
39                          searchResult={pluginSearchResult}
40                          pluginHash={pluginHash}
41                          pluginName={pluginName}
42                          pluginSearchResultRef={pluginSearchResultRef}
43                      />
44                  );
45              },
46              () => true,
47          )
48        : () => <DefaultResults />;
49}
50
51/** 结果scene */
52function getSubRouterScene(
53    tab: ICommon.SupportMediaType,
54    routes: Array<{key: string; title: string}>,
55) {
56    const scene: Record<string, React.FC> = {};
57    routes.forEach(r => {
58        // todo: 是否声明不可搜索
59        scene[r.key] = getResultComponent(tab, r.key, r.title);
60    });
61    return SceneMap(scene);
62}
63
64function ResultSubPanel(props: IResultSubPanelProps) {
65    const [index, setIndex] = useState(0);
66    const colors = useColors();
67
68    const routes = PluginManager.getSortedSearchablePlugins(props.tab).map(
69        _ => ({
70            key: _.hash,
71            title: _.name,
72        }),
73    );
74    const renderScene = useMemo(
75        () => getSubRouterScene(props.tab, routes),
76        [props.tab],
77    );
78
79    if (!routes.length) {
80        return <Empty />;
81    }
82
83    return (
84        <TabView
85            lazy
86            navigationState={{
87                index,
88                routes,
89            }}
90            renderTabBar={_ => (
91                <TabBar
92                    {..._}
93                    scrollEnabled
94                    style={{
95                        backgroundColor: 'transparent',
96                        shadowColor: 'transparent',
97                        borderColor: 'transparent',
98                    }}
99                    inactiveColor={colors.text}
100                    activeColor={colors.primary}
101                    tabStyle={{
102                        width: 'auto',
103                    }}
104                    renderIndicator={() => null}
105                    pressColor="transparent"
106                    renderLabel={({route, focused, color}) => (
107                        <Text
108                            numberOfLines={1}
109                            style={{
110                                width: rpx(140),
111                                fontWeight: focused
112                                    ? fontWeightConst.bolder
113                                    : fontWeightConst.medium,
114                                color,
115                                textAlign: 'center',
116                            }}>
117                            {route.title ?? '(未命名)'}
118                        </Text>
119                    )}
120                />
121            )}
122            renderScene={renderScene}
123            onIndexChange={setIndex}
124            initialLayout={{width: vw(100)}}
125        />
126    );
127}
128
129// 不然会一直重新渲染
130export default memo(ResultSubPanel);
131