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