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