xref: /MusicFree/src/components/base/listItem.tsx (revision 1119c2ea435417cd5c53719f91691ff2b1aa8670)
1*1119c2eaS猫头猫import React, {ReactNode} from 'react';
2*1119c2eaS猫头猫import {
3*1119c2eaS猫头猫    StyleProp,
4*1119c2eaS猫头猫    StyleSheet,
5*1119c2eaS猫头猫    TextProps,
6*1119c2eaS猫头猫    TextStyle,
7*1119c2eaS猫头猫    TouchableHighlight,
8*1119c2eaS猫头猫    TouchableOpacity,
9*1119c2eaS猫头猫    View,
10*1119c2eaS猫头猫    ViewStyle,
11*1119c2eaS猫头猫} from 'react-native';
1219dc08ecS猫头猫import rpx from '@/utils/rpx';
13*1119c2eaS猫头猫import useColors from '@/hooks/useColors';
14*1119c2eaS猫头猫import ThemeText from './themeText';
15*1119c2eaS猫头猫import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
16*1119c2eaS猫头猫import {
17*1119c2eaS猫头猫    fontSizeConst,
18*1119c2eaS猫头猫    fontWeightConst,
19*1119c2eaS猫头猫    iconSizeConst,
20*1119c2eaS猫头猫} from '@/constants/uiConst';
21*1119c2eaS猫头猫import FastImage from './fastImage';
22*1119c2eaS猫头猫import {ImageStyle} from 'react-native-fast-image';
2319dc08ecS猫头猫
24*1119c2eaS猫头猫interface IListItemProps {
25*1119c2eaS猫头猫    // 是否有左右边距
26*1119c2eaS猫头猫    withHorizonalPadding?: boolean;
27*1119c2eaS猫头猫    // 左边距
28*1119c2eaS猫头猫    leftPadding?: number;
29*1119c2eaS猫头猫    // 右边距
30*1119c2eaS猫头猫    rightPadding?: number;
31*1119c2eaS猫头猫    // height:
32*1119c2eaS猫头猫    style?: StyleProp<ViewStyle>;
33*1119c2eaS猫头猫    // 高度类型
34*1119c2eaS猫头猫    heightType?: 'big' | 'small' | 'normal' | 'none';
35*1119c2eaS猫头猫    children?: ReactNode;
36*1119c2eaS猫头猫    onPress?: () => void;
37*1119c2eaS猫头猫    onLongPress?: () => void;
38*1119c2eaS猫头猫}
39*1119c2eaS猫头猫
40*1119c2eaS猫头猫const defaultPadding = rpx(24);
41*1119c2eaS猫头猫const defaultActionWidth = rpx(80);
42*1119c2eaS猫头猫
43*1119c2eaS猫头猫const Size = {
44*1119c2eaS猫头猫    big: rpx(120),
45*1119c2eaS猫头猫    normal: rpx(108),
46*1119c2eaS猫头猫    small: rpx(96),
47*1119c2eaS猫头猫    none: undefined,
48*1119c2eaS猫头猫};
49*1119c2eaS猫头猫
50*1119c2eaS猫头猫function ListItem(props: IListItemProps) {
51*1119c2eaS猫头猫    const {
52*1119c2eaS猫头猫        withHorizonalPadding,
53*1119c2eaS猫头猫        leftPadding = defaultPadding,
54*1119c2eaS猫头猫        rightPadding = defaultPadding,
55*1119c2eaS猫头猫        style,
56*1119c2eaS猫头猫        heightType = 'normal',
57*1119c2eaS猫头猫        children,
58*1119c2eaS猫头猫        onPress,
59*1119c2eaS猫头猫        onLongPress,
60*1119c2eaS猫头猫    } = props;
61*1119c2eaS猫头猫
62*1119c2eaS猫头猫    const defaultStyle: StyleProp<ViewStyle> = {
63*1119c2eaS猫头猫        paddingLeft: withHorizonalPadding ? leftPadding : 0,
64*1119c2eaS猫头猫        paddingRight: withHorizonalPadding ? rightPadding : 0,
65*1119c2eaS猫头猫        height: Size[heightType],
66*1119c2eaS猫头猫    };
67*1119c2eaS猫头猫
68*1119c2eaS猫头猫    const colors = useColors();
69*1119c2eaS猫头猫
70*1119c2eaS猫头猫    return (
71*1119c2eaS猫头猫        <TouchableHighlight
72*1119c2eaS猫头猫            style={styles.container}
73*1119c2eaS猫头猫            underlayColor={colors.listActive}
74*1119c2eaS猫头猫            onPress={onPress}
75*1119c2eaS猫头猫            onLongPress={onLongPress}>
76*1119c2eaS猫头猫            <View style={[styles.container, defaultStyle, style]}>
77*1119c2eaS猫头猫                {children}
78*1119c2eaS猫头猫            </View>
79*1119c2eaS猫头猫        </TouchableHighlight>
80*1119c2eaS猫头猫    );
81*1119c2eaS猫头猫}
82*1119c2eaS猫头猫
83*1119c2eaS猫头猫interface IListItemTextProps {
84*1119c2eaS猫头猫    children?: number | string;
85*1119c2eaS猫头猫    fontSize?: keyof typeof fontSizeConst;
86*1119c2eaS猫头猫    fontWeight?: keyof typeof fontWeightConst;
87*1119c2eaS猫头猫    width?: number;
88*1119c2eaS猫头猫    position?: 'left' | 'right' | 'none';
89*1119c2eaS猫头猫    fixedWidth?: boolean;
90*1119c2eaS猫头猫    containerStyle?: StyleProp<ViewStyle>;
91*1119c2eaS猫头猫    contentStyle?: StyleProp<TextStyle>;
92*1119c2eaS猫头猫    contentProps?: TextProps;
93*1119c2eaS猫头猫}
94*1119c2eaS猫头猫
95*1119c2eaS猫头猫function ListItemText(props: IListItemTextProps) {
96*1119c2eaS猫头猫    const {
97*1119c2eaS猫头猫        children,
98*1119c2eaS猫头猫        fontSize,
99*1119c2eaS猫头猫        fontWeight,
100*1119c2eaS猫头猫        position = 'left',
101*1119c2eaS猫头猫        fixedWidth,
102*1119c2eaS猫头猫        width,
103*1119c2eaS猫头猫        containerStyle,
104*1119c2eaS猫头猫        contentStyle,
105*1119c2eaS猫头猫        contentProps = {},
106*1119c2eaS猫头猫    } = props;
107*1119c2eaS猫头猫
108*1119c2eaS猫头猫    const defaultStyle: StyleProp<ViewStyle> = {
109*1119c2eaS猫头猫        marginRight: position === 'left' ? defaultPadding : 0,
110*1119c2eaS猫头猫        marginLeft: position === 'right' ? defaultPadding : 0,
111*1119c2eaS猫头猫        width: fixedWidth ? width ?? defaultActionWidth : undefined,
112*1119c2eaS猫头猫        flexBasis: fixedWidth ? width ?? defaultActionWidth : undefined,
113*1119c2eaS猫头猫    };
114*1119c2eaS猫头猫
115*1119c2eaS猫头猫    return (
116*1119c2eaS猫头猫        <View style={[styles.actionBase, defaultStyle, containerStyle]}>
117*1119c2eaS猫头猫            <ThemeText
118*1119c2eaS猫头猫                fontSize={fontSize}
119*1119c2eaS猫头猫                style={contentStyle}
120*1119c2eaS猫头猫                fontWeight={fontWeight}
121*1119c2eaS猫头猫                {...contentProps}>
122*1119c2eaS猫头猫                {children}
123*1119c2eaS猫头猫            </ThemeText>
124*1119c2eaS猫头猫        </View>
125*1119c2eaS猫头猫    );
126*1119c2eaS猫头猫}
127*1119c2eaS猫头猫
128*1119c2eaS猫头猫interface IListItemIconProps {
129*1119c2eaS猫头猫    icon: string;
130*1119c2eaS猫头猫    iconSize?: number;
131*1119c2eaS猫头猫    width?: number;
132*1119c2eaS猫头猫    position?: 'left' | 'right' | 'none';
133*1119c2eaS猫头猫    fixedWidth?: boolean;
134*1119c2eaS猫头猫    containerStyle?: StyleProp<ViewStyle>;
135*1119c2eaS猫头猫    contentStyle?: StyleProp<TextStyle>;
136*1119c2eaS猫头猫    onPress?: () => void;
137*1119c2eaS猫头猫}
138*1119c2eaS猫头猫
139*1119c2eaS猫头猫function ListItemIcon(props: IListItemIconProps) {
140*1119c2eaS猫头猫    const {
141*1119c2eaS猫头猫        icon,
142*1119c2eaS猫头猫        iconSize = iconSizeConst.normal,
143*1119c2eaS猫头猫        position = 'left',
144*1119c2eaS猫头猫        fixedWidth,
145*1119c2eaS猫头猫        width,
146*1119c2eaS猫头猫        containerStyle,
147*1119c2eaS猫头猫        contentStyle,
148*1119c2eaS猫头猫        onPress,
149*1119c2eaS猫头猫    } = props;
150*1119c2eaS猫头猫
151*1119c2eaS猫头猫    const defaultStyle: StyleProp<ViewStyle> = {
152*1119c2eaS猫头猫        marginRight: position === 'left' ? defaultPadding : 0,
153*1119c2eaS猫头猫        marginLeft: position === 'right' ? defaultPadding : 0,
154*1119c2eaS猫头猫        width: fixedWidth ? width ?? defaultActionWidth : undefined,
155*1119c2eaS猫头猫        flexBasis: fixedWidth ? width ?? defaultActionWidth : undefined,
156*1119c2eaS猫头猫    };
157*1119c2eaS猫头猫
158*1119c2eaS猫头猫    const innerContent = (
159*1119c2eaS猫头猫        <View style={[styles.actionBase, defaultStyle, containerStyle]}>
160*1119c2eaS猫头猫            <Icon name={icon} size={iconSize} style={contentStyle} />
161*1119c2eaS猫头猫        </View>
162*1119c2eaS猫头猫    );
163*1119c2eaS猫头猫
164*1119c2eaS猫头猫    return onPress ? (
165*1119c2eaS猫头猫        <TouchableOpacity onPress={onPress}>{innerContent}</TouchableOpacity>
166*1119c2eaS猫头猫    ) : (
167*1119c2eaS猫头猫        innerContent
168*1119c2eaS猫头猫    );
169*1119c2eaS猫头猫}
170*1119c2eaS猫头猫
171*1119c2eaS猫头猫interface IListItemImageProps {
172*1119c2eaS猫头猫    uri?: string;
173*1119c2eaS猫头猫    fallbackImg?: number;
174*1119c2eaS猫头猫    imageSize?: number;
175*1119c2eaS猫头猫    width?: number;
176*1119c2eaS猫头猫    position?: 'left' | 'right';
177*1119c2eaS猫头猫    fixedWidth?: boolean;
178*1119c2eaS猫头猫    containerStyle?: StyleProp<ViewStyle>;
179*1119c2eaS猫头猫    contentStyle?: StyleProp<ImageStyle>;
180*1119c2eaS猫头猫}
181*1119c2eaS猫头猫
182*1119c2eaS猫头猫function ListItemImage(props: IListItemImageProps) {
183*1119c2eaS猫头猫    const {
184*1119c2eaS猫头猫        uri,
185*1119c2eaS猫头猫        fallbackImg,
186*1119c2eaS猫头猫        position = 'left',
187*1119c2eaS猫头猫        fixedWidth,
188*1119c2eaS猫头猫        width,
189*1119c2eaS猫头猫        containerStyle,
190*1119c2eaS猫头猫        contentStyle,
191*1119c2eaS猫头猫    } = props;
192*1119c2eaS猫头猫
193*1119c2eaS猫头猫    const defaultStyle: StyleProp<ViewStyle> = {
194*1119c2eaS猫头猫        marginRight: position === 'left' ? defaultPadding : 0,
195*1119c2eaS猫头猫        marginLeft: position === 'right' ? defaultPadding : 0,
196*1119c2eaS猫头猫        width: fixedWidth ? width ?? defaultActionWidth : undefined,
197*1119c2eaS猫头猫        flexBasis: fixedWidth ? width ?? defaultActionWidth : undefined,
198*1119c2eaS猫头猫    };
199*1119c2eaS猫头猫
200*1119c2eaS猫头猫    return (
201*1119c2eaS猫头猫        <View style={[styles.actionBase, defaultStyle, containerStyle]}>
202*1119c2eaS猫头猫            <FastImage
203*1119c2eaS猫头猫                style={[styles.leftImage, contentStyle]}
204*1119c2eaS猫头猫                uri={uri}
205*1119c2eaS猫头猫                emptySrc={fallbackImg}
206*1119c2eaS猫头猫            />
207*1119c2eaS猫头猫        </View>
208*1119c2eaS猫头猫    );
209*1119c2eaS猫头猫}
210*1119c2eaS猫头猫
211*1119c2eaS猫头猫interface IContentProps {
212*1119c2eaS猫头猫    title?: ReactNode;
213*1119c2eaS猫头猫    description?: ReactNode;
214*1119c2eaS猫头猫    containerStyle?: StyleProp<ViewStyle>;
215*1119c2eaS猫头猫}
216*1119c2eaS猫头猫
217*1119c2eaS猫头猫function Content(props: IContentProps) {
218*1119c2eaS猫头猫    const {title, description = null, containerStyle} = props;
219*1119c2eaS猫头猫
220*1119c2eaS猫头猫    let realTitle;
221*1119c2eaS猫头猫    let realDescription;
222*1119c2eaS猫头猫
223*1119c2eaS猫头猫    if (typeof title === 'string' || typeof title === 'number') {
224*1119c2eaS猫头猫        realTitle = <ThemeText numberOfLines={1}>{title}</ThemeText>;
225*1119c2eaS猫头猫    } else {
226*1119c2eaS猫头猫        realTitle = title;
227*1119c2eaS猫头猫    }
228*1119c2eaS猫头猫
229*1119c2eaS猫头猫    if (typeof description === 'string' || typeof description === 'number') {
230*1119c2eaS猫头猫        realDescription = (
231*1119c2eaS猫头猫            <ThemeText
232*1119c2eaS猫头猫                numberOfLines={1}
233*1119c2eaS猫头猫                fontSize="description"
234*1119c2eaS猫头猫                fontColor="secondary"
235*1119c2eaS猫头猫                style={styles.contentDesc}>
236*1119c2eaS猫头猫                {description}
237*1119c2eaS猫头猫            </ThemeText>
238*1119c2eaS猫头猫        );
239*1119c2eaS猫头猫    } else {
240*1119c2eaS猫头猫        realDescription = description;
241*1119c2eaS猫头猫    }
242*1119c2eaS猫头猫
243*1119c2eaS猫头猫    return (
244*1119c2eaS猫头猫        <View style={[styles.itemContentContainer, containerStyle]}>
245*1119c2eaS猫头猫            {realTitle}
246*1119c2eaS猫头猫            {realDescription}
247*1119c2eaS猫头猫        </View>
248*1119c2eaS猫头猫    );
24919dc08ecS猫头猫}
250e650bfb3S猫头猫
251e650bfb3S猫头猫const styles = StyleSheet.create({
252*1119c2eaS猫头猫    /** listitem */
253*1119c2eaS猫头猫    container: {
254*1119c2eaS猫头猫        width: '100%',
255*1119c2eaS猫头猫        flexDirection: 'row',
256*1119c2eaS猫头猫        alignItems: 'center',
257*1119c2eaS猫头猫    },
258*1119c2eaS猫头猫    /** left */
259*1119c2eaS猫头猫    actionBase: {
260*1119c2eaS猫头猫        height: '100%',
261*1119c2eaS猫头猫        flexShrink: 0,
262*1119c2eaS猫头猫        flexGrow: 0,
263*1119c2eaS猫头猫        flexBasis: 0,
264*1119c2eaS猫头猫        flexDirection: 'row',
265*1119c2eaS猫头猫        justifyContent: 'center',
266*1119c2eaS猫头猫        alignItems: 'center',
267*1119c2eaS猫头猫    },
268*1119c2eaS猫头猫
269*1119c2eaS猫头猫    leftImage: {
270*1119c2eaS猫头猫        width: rpx(80),
271*1119c2eaS猫头猫        height: rpx(80),
272*1119c2eaS猫头猫        borderRadius: rpx(16),
273*1119c2eaS猫头猫    },
274*1119c2eaS猫头猫    itemContentContainer: {
275*1119c2eaS猫头猫        flex: 1,
276*1119c2eaS猫头猫        height: '100%',
277*1119c2eaS猫头猫        justifyContent: 'center',
278*1119c2eaS猫头猫    },
279*1119c2eaS猫头猫    contentDesc: {
280*1119c2eaS猫头猫        marginTop: rpx(16),
28119dc08ecS猫头猫    },
28219dc08ecS猫头猫});
283*1119c2eaS猫头猫
284*1119c2eaS猫头猫ListItem.Size = Size;
285*1119c2eaS猫头猫ListItem.ListItemIcon = ListItemIcon;
286*1119c2eaS猫头猫ListItem.ListItemImage = ListItemImage;
287*1119c2eaS猫头猫ListItem.ListItemText = ListItemText;
288*1119c2eaS猫头猫ListItem.Content = Content;
289*1119c2eaS猫头猫
290*1119c2eaS猫头猫export default ListItem;
291