1import React from 'react'; 2import {StyleSheet, View} from 'react-native'; 3import rpx from '@/utils/rpx'; 4import {List} from 'react-native-paper'; 5import Tag from './tag'; 6import ThemeText from './themeText'; 7import IconButton from './iconButton'; 8import FastImage from './fastImage'; 9import {fontSizeConst} from '@/constants/uiConst'; 10 11export interface ILeftProps { 12 /** 序号 */ 13 index?: number | string; 14 /** 封面图 */ 15 artwork?: string; 16 /** 封面图的兜底 */ 17 fallback?: any; 18 /** icon */ 19 icon?: Parameters<typeof IconButton>[0]; 20 /** 宽度 */ 21 width?: number; 22 /** 组件 */ 23 component?: () => JSX.Element; 24} 25 26function Left(props?: ILeftProps) { 27 const { 28 index, 29 artwork, 30 fallback, 31 icon, 32 width = rpx(100), 33 component: Component, 34 } = props ?? {}; 35 36 return props && Object.keys(props).length ? ( 37 Component ? ( 38 <Component /> 39 ) : ( 40 <View style={[leftStyle.artworkWrapper, {width}]}> 41 {index !== undefined ? ( 42 <ThemeText 43 fontColor="secondary" 44 style={{ 45 fontStyle: 'italic', 46 fontSize: Math.min( 47 (width / `${index}`.length) * 0.8, 48 fontSizeConst.content, 49 ), 50 }}> 51 {index} 52 </ThemeText> 53 ) : icon !== undefined ? ( 54 <IconButton {...icon} /> 55 ) : ( 56 <FastImage 57 style={leftStyle.artwork} 58 uri={ 59 artwork?.startsWith('//') 60 ? `https:${artwork}` 61 : artwork 62 } 63 emptySrc={fallback} 64 /> 65 )} 66 </View> 67 ) 68 ) : null; 69} 70 71const leftStyle = StyleSheet.create({ 72 artworkWrapper: { 73 justifyContent: 'center', 74 alignItems: 'center', 75 }, 76 artwork: { 77 width: rpx(76), 78 height: rpx(76), 79 borderRadius: rpx(16), 80 }, 81}); 82 83/** 歌单item */ 84interface IListItemProps { 85 /** 标题 */ 86 title: string | number; 87 /** 描述 */ 88 desc?: string | JSX.Element; 89 /** 标签 */ 90 tag?: string; 91 left?: ILeftProps; 92 /** 右侧按钮 */ 93 right?: () => JSX.Element; 94 itemPaddingHorizontal?: number; 95 itemPaddingLeft?: number; 96 itemPaddingRight?: number; 97 itemWidth?: number | string; 98 itemHeight?: number; 99 itemBackgroundColor?: string; 100 onPress?: () => void; 101 onLongPress?: () => void; 102} 103 104export default function ListItem(props: IListItemProps) { 105 const { 106 title, 107 desc, 108 tag, 109 right, 110 itemWidth, 111 itemHeight, 112 onPress, 113 onLongPress, 114 left, 115 itemBackgroundColor, 116 itemPaddingHorizontal = rpx(24), 117 itemPaddingLeft, 118 itemPaddingRight, 119 } = props; 120 121 return ( 122 <List.Item 123 onLongPress={onLongPress} 124 left={() => <Left {...(left ?? {})} />} 125 style={[ 126 style.wrapper, 127 { 128 paddingHorizontal: itemPaddingHorizontal, 129 paddingLeft: itemPaddingLeft, 130 paddingRight: itemPaddingRight, 131 width: itemWidth, 132 height: itemHeight ?? rpx(120), 133 paddingVertical: 0, 134 backgroundColor: itemBackgroundColor, 135 }, 136 ]} 137 title={() => ( 138 <View 139 accessible 140 accessibilityLabel={`${title}`} 141 style={{ 142 alignItems: 'stretch', 143 justifyContent: 'center', 144 height: itemHeight ?? rpx(120), 145 marginRight: right ? rpx(18) : 0, 146 }}> 147 <View style={style.titleWrapper}> 148 <ThemeText numberOfLines={1} style={style.titleText}> 149 {title} 150 </ThemeText> 151 {tag ? <Tag tagName={tag} /> : null} 152 </View> 153 {desc ? ( 154 <ThemeText 155 fontColor="secondary" 156 fontSize="description" 157 numberOfLines={1} 158 style={style.descText}> 159 {desc} 160 </ThemeText> 161 ) : null} 162 </View> 163 )} 164 titleStyle={{ 165 paddingVertical: 0, 166 marginLeft: 0, 167 marginVertical: 0, 168 }} 169 right={right ? right : () => null} 170 onPress={onPress} 171 /> 172 ); 173} 174const style = StyleSheet.create({ 175 wrapper: { 176 justifyContent: 'center', 177 width: '100%', 178 }, 179 titleWrapper: { 180 flexDirection: 'row', 181 alignItems: 'center', 182 justifyContent: 'space-between', 183 }, 184 titleText: { 185 flex: 1, 186 paddingRight: rpx(12), 187 }, 188 descText: { 189 marginTop: rpx(18), 190 }, 191 artworkWrapper: { 192 width: rpx(76), 193 justifyContent: 'center', 194 alignItems: 'center', 195 marginRight: rpx(12), 196 }, 197 artwork: { 198 width: rpx(76), 199 height: rpx(76), 200 borderRadius: rpx(16), 201 }, 202}); 203