xref: /MusicFree/src/components/base/listItem.tsx (revision e01046d9be7f61fcd5e29f2c916d36029515b016)
11119c2eaS猫头猫import React, {ReactNode} from 'react';
21119c2eaS猫头猫import {
31119c2eaS猫头猫    StyleProp,
41119c2eaS猫头猫    StyleSheet,
51119c2eaS猫头猫    TextProps,
61119c2eaS猫头猫    TextStyle,
71119c2eaS猫头猫    TouchableHighlight,
81119c2eaS猫头猫    TouchableOpacity,
91119c2eaS猫头猫    View,
101119c2eaS猫头猫    ViewStyle,
111119c2eaS猫头猫} from 'react-native';
1219dc08ecS猫头猫import rpx from '@/utils/rpx';
131119c2eaS猫头猫import useColors from '@/hooks/useColors';
141119c2eaS猫头猫import ThemeText from './themeText';
151119c2eaS猫头猫import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
161119c2eaS猫头猫import {
171119c2eaS猫头猫    fontSizeConst,
181119c2eaS猫头猫    fontWeightConst,
191119c2eaS猫头猫    iconSizeConst,
201119c2eaS猫头猫} from '@/constants/uiConst';
211119c2eaS猫头猫import FastImage from './fastImage';
221119c2eaS猫头猫import {ImageStyle} from 'react-native-fast-image';
2319dc08ecS猫头猫
241119c2eaS猫头猫interface IListItemProps {
251119c2eaS猫头猫    // 是否有左右边距
261119c2eaS猫头猫    withHorizonalPadding?: boolean;
271119c2eaS猫头猫    // 左边距
281119c2eaS猫头猫    leftPadding?: number;
291119c2eaS猫头猫    // 右边距
301119c2eaS猫头猫    rightPadding?: number;
311119c2eaS猫头猫    // height:
321119c2eaS猫头猫    style?: StyleProp<ViewStyle>;
331119c2eaS猫头猫    // 高度类型
34*e01046d9S猫头猫    heightType?: 'big' | 'small' | 'smallest' | 'normal' | 'none';
351119c2eaS猫头猫    children?: ReactNode;
361119c2eaS猫头猫    onPress?: () => void;
371119c2eaS猫头猫    onLongPress?: () => void;
381119c2eaS猫头猫}
391119c2eaS猫头猫
401119c2eaS猫头猫const defaultPadding = rpx(24);
411119c2eaS猫头猫const defaultActionWidth = rpx(80);
421119c2eaS猫头猫
431119c2eaS猫头猫const Size = {
441119c2eaS猫头猫    big: rpx(120),
451119c2eaS猫头猫    normal: rpx(108),
461119c2eaS猫头猫    small: rpx(96),
47*e01046d9S猫头猫    smallest: rpx(72),
481119c2eaS猫头猫    none: undefined,
491119c2eaS猫头猫};
501119c2eaS猫头猫
511119c2eaS猫头猫function ListItem(props: IListItemProps) {
521119c2eaS猫头猫    const {
531119c2eaS猫头猫        withHorizonalPadding,
541119c2eaS猫头猫        leftPadding = defaultPadding,
551119c2eaS猫头猫        rightPadding = defaultPadding,
561119c2eaS猫头猫        style,
571119c2eaS猫头猫        heightType = 'normal',
581119c2eaS猫头猫        children,
591119c2eaS猫头猫        onPress,
601119c2eaS猫头猫        onLongPress,
611119c2eaS猫头猫    } = props;
621119c2eaS猫头猫
631119c2eaS猫头猫    const defaultStyle: StyleProp<ViewStyle> = {
641119c2eaS猫头猫        paddingLeft: withHorizonalPadding ? leftPadding : 0,
651119c2eaS猫头猫        paddingRight: withHorizonalPadding ? rightPadding : 0,
661119c2eaS猫头猫        height: Size[heightType],
671119c2eaS猫头猫    };
681119c2eaS猫头猫
691119c2eaS猫头猫    const colors = useColors();
701119c2eaS猫头猫
711119c2eaS猫头猫    return (
721119c2eaS猫头猫        <TouchableHighlight
731119c2eaS猫头猫            style={styles.container}
741119c2eaS猫头猫            underlayColor={colors.listActive}
751119c2eaS猫头猫            onPress={onPress}
761119c2eaS猫头猫            onLongPress={onLongPress}>
771119c2eaS猫头猫            <View style={[styles.container, defaultStyle, style]}>
781119c2eaS猫头猫                {children}
791119c2eaS猫头猫            </View>
801119c2eaS猫头猫        </TouchableHighlight>
811119c2eaS猫头猫    );
821119c2eaS猫头猫}
831119c2eaS猫头猫
841119c2eaS猫头猫interface IListItemTextProps {
851119c2eaS猫头猫    children?: number | string;
861119c2eaS猫头猫    fontSize?: keyof typeof fontSizeConst;
871119c2eaS猫头猫    fontWeight?: keyof typeof fontWeightConst;
881119c2eaS猫头猫    width?: number;
891119c2eaS猫头猫    position?: 'left' | 'right' | 'none';
901119c2eaS猫头猫    fixedWidth?: boolean;
911119c2eaS猫头猫    containerStyle?: StyleProp<ViewStyle>;
921119c2eaS猫头猫    contentStyle?: StyleProp<TextStyle>;
931119c2eaS猫头猫    contentProps?: TextProps;
941119c2eaS猫头猫}
951119c2eaS猫头猫
961119c2eaS猫头猫function ListItemText(props: IListItemTextProps) {
971119c2eaS猫头猫    const {
981119c2eaS猫头猫        children,
991119c2eaS猫头猫        fontSize,
1001119c2eaS猫头猫        fontWeight,
1011119c2eaS猫头猫        position = 'left',
1021119c2eaS猫头猫        fixedWidth,
1031119c2eaS猫头猫        width,
1041119c2eaS猫头猫        containerStyle,
1051119c2eaS猫头猫        contentStyle,
1061119c2eaS猫头猫        contentProps = {},
1071119c2eaS猫头猫    } = props;
1081119c2eaS猫头猫
1091119c2eaS猫头猫    const defaultStyle: StyleProp<ViewStyle> = {
1101119c2eaS猫头猫        marginRight: position === 'left' ? defaultPadding : 0,
1111119c2eaS猫头猫        marginLeft: position === 'right' ? defaultPadding : 0,
1121119c2eaS猫头猫        width: fixedWidth ? width ?? defaultActionWidth : undefined,
1131119c2eaS猫头猫        flexBasis: fixedWidth ? width ?? defaultActionWidth : undefined,
1141119c2eaS猫头猫    };
1151119c2eaS猫头猫
1161119c2eaS猫头猫    return (
1171119c2eaS猫头猫        <View style={[styles.actionBase, defaultStyle, containerStyle]}>
1181119c2eaS猫头猫            <ThemeText
1191119c2eaS猫头猫                fontSize={fontSize}
1201119c2eaS猫头猫                style={contentStyle}
1211119c2eaS猫头猫                fontWeight={fontWeight}
1221119c2eaS猫头猫                {...contentProps}>
1231119c2eaS猫头猫                {children}
1241119c2eaS猫头猫            </ThemeText>
1251119c2eaS猫头猫        </View>
1261119c2eaS猫头猫    );
1271119c2eaS猫头猫}
1281119c2eaS猫头猫
1291119c2eaS猫头猫interface IListItemIconProps {
1301119c2eaS猫头猫    icon: string;
1311119c2eaS猫头猫    iconSize?: number;
1321119c2eaS猫头猫    width?: number;
1331119c2eaS猫头猫    position?: 'left' | 'right' | 'none';
1341119c2eaS猫头猫    fixedWidth?: boolean;
1351119c2eaS猫头猫    containerStyle?: StyleProp<ViewStyle>;
1361119c2eaS猫头猫    contentStyle?: StyleProp<TextStyle>;
1371119c2eaS猫头猫    onPress?: () => void;
1381119c2eaS猫头猫}
1391119c2eaS猫头猫
1401119c2eaS猫头猫function ListItemIcon(props: IListItemIconProps) {
1411119c2eaS猫头猫    const {
1421119c2eaS猫头猫        icon,
1431119c2eaS猫头猫        iconSize = iconSizeConst.normal,
1441119c2eaS猫头猫        position = 'left',
1451119c2eaS猫头猫        fixedWidth,
1461119c2eaS猫头猫        width,
1471119c2eaS猫头猫        containerStyle,
1481119c2eaS猫头猫        contentStyle,
1491119c2eaS猫头猫        onPress,
1501119c2eaS猫头猫    } = props;
1511119c2eaS猫头猫
1526cfecf1cS猫头猫    const colors = useColors();
1536cfecf1cS猫头猫
1541119c2eaS猫头猫    const defaultStyle: StyleProp<ViewStyle> = {
1551119c2eaS猫头猫        marginRight: position === 'left' ? defaultPadding : 0,
1561119c2eaS猫头猫        marginLeft: position === 'right' ? defaultPadding : 0,
1571119c2eaS猫头猫        width: fixedWidth ? width ?? defaultActionWidth : undefined,
1581119c2eaS猫头猫        flexBasis: fixedWidth ? width ?? defaultActionWidth : undefined,
1591119c2eaS猫头猫    };
1601119c2eaS猫头猫
1611119c2eaS猫头猫    const innerContent = (
1621119c2eaS猫头猫        <View style={[styles.actionBase, defaultStyle, containerStyle]}>
1636cfecf1cS猫头猫            <Icon
1646cfecf1cS猫头猫                name={icon}
1656cfecf1cS猫头猫                size={iconSize}
1666cfecf1cS猫头猫                style={contentStyle}
1676cfecf1cS猫头猫                color={colors.text}
1686cfecf1cS猫头猫            />
1691119c2eaS猫头猫        </View>
1701119c2eaS猫头猫    );
1711119c2eaS猫头猫
1721119c2eaS猫头猫    return onPress ? (
1731119c2eaS猫头猫        <TouchableOpacity onPress={onPress}>{innerContent}</TouchableOpacity>
1741119c2eaS猫头猫    ) : (
1751119c2eaS猫头猫        innerContent
1761119c2eaS猫头猫    );
1771119c2eaS猫头猫}
1781119c2eaS猫头猫
1791119c2eaS猫头猫interface IListItemImageProps {
1801119c2eaS猫头猫    uri?: string;
1811119c2eaS猫头猫    fallbackImg?: number;
1821119c2eaS猫头猫    imageSize?: number;
1831119c2eaS猫头猫    width?: number;
1841119c2eaS猫头猫    position?: 'left' | 'right';
1851119c2eaS猫头猫    fixedWidth?: boolean;
1861119c2eaS猫头猫    containerStyle?: StyleProp<ViewStyle>;
1871119c2eaS猫头猫    contentStyle?: StyleProp<ImageStyle>;
1881119c2eaS猫头猫}
1891119c2eaS猫头猫
1901119c2eaS猫头猫function ListItemImage(props: IListItemImageProps) {
1911119c2eaS猫头猫    const {
1921119c2eaS猫头猫        uri,
1931119c2eaS猫头猫        fallbackImg,
1941119c2eaS猫头猫        position = 'left',
1951119c2eaS猫头猫        fixedWidth,
1961119c2eaS猫头猫        width,
1971119c2eaS猫头猫        containerStyle,
1981119c2eaS猫头猫        contentStyle,
1991119c2eaS猫头猫    } = props;
2001119c2eaS猫头猫
2011119c2eaS猫头猫    const defaultStyle: StyleProp<ViewStyle> = {
2021119c2eaS猫头猫        marginRight: position === 'left' ? defaultPadding : 0,
2031119c2eaS猫头猫        marginLeft: position === 'right' ? defaultPadding : 0,
2041119c2eaS猫头猫        width: fixedWidth ? width ?? defaultActionWidth : undefined,
2051119c2eaS猫头猫        flexBasis: fixedWidth ? width ?? defaultActionWidth : undefined,
2061119c2eaS猫头猫    };
2071119c2eaS猫头猫
2081119c2eaS猫头猫    return (
2091119c2eaS猫头猫        <View style={[styles.actionBase, defaultStyle, containerStyle]}>
2101119c2eaS猫头猫            <FastImage
2111119c2eaS猫头猫                style={[styles.leftImage, contentStyle]}
2121119c2eaS猫头猫                uri={uri}
2131119c2eaS猫头猫                emptySrc={fallbackImg}
2141119c2eaS猫头猫            />
2151119c2eaS猫头猫        </View>
2161119c2eaS猫头猫    );
2171119c2eaS猫头猫}
2181119c2eaS猫头猫
2191119c2eaS猫头猫interface IContentProps {
2201119c2eaS猫头猫    title?: ReactNode;
2216cfecf1cS猫头猫    children?: ReactNode;
2221119c2eaS猫头猫    description?: ReactNode;
2231119c2eaS猫头猫    containerStyle?: StyleProp<ViewStyle>;
2241119c2eaS猫头猫}
2251119c2eaS猫头猫
2261119c2eaS猫头猫function Content(props: IContentProps) {
2276cfecf1cS猫头猫    const {
2286cfecf1cS猫头猫        children,
2296cfecf1cS猫头猫        title = children,
2306cfecf1cS猫头猫        description = null,
2316cfecf1cS猫头猫        containerStyle,
2326cfecf1cS猫头猫    } = props;
2331119c2eaS猫头猫
2341119c2eaS猫头猫    let realTitle;
2351119c2eaS猫头猫    let realDescription;
2361119c2eaS猫头猫
2371119c2eaS猫头猫    if (typeof title === 'string' || typeof title === 'number') {
2381119c2eaS猫头猫        realTitle = <ThemeText numberOfLines={1}>{title}</ThemeText>;
2391119c2eaS猫头猫    } else {
2401119c2eaS猫头猫        realTitle = title;
2411119c2eaS猫头猫    }
2421119c2eaS猫头猫
2431119c2eaS猫头猫    if (typeof description === 'string' || typeof description === 'number') {
2441119c2eaS猫头猫        realDescription = (
2451119c2eaS猫头猫            <ThemeText
2461119c2eaS猫头猫                numberOfLines={1}
2471119c2eaS猫头猫                fontSize="description"
248277c5280S猫头猫                fontColor="textSecondary"
2491119c2eaS猫头猫                style={styles.contentDesc}>
2501119c2eaS猫头猫                {description}
2511119c2eaS猫头猫            </ThemeText>
2521119c2eaS猫头猫        );
2531119c2eaS猫头猫    } else {
2541119c2eaS猫头猫        realDescription = description;
2551119c2eaS猫头猫    }
2561119c2eaS猫头猫
2571119c2eaS猫头猫    return (
2581119c2eaS猫头猫        <View style={[styles.itemContentContainer, containerStyle]}>
2591119c2eaS猫头猫            {realTitle}
2601119c2eaS猫头猫            {realDescription}
2611119c2eaS猫头猫        </View>
2621119c2eaS猫头猫    );
26319dc08ecS猫头猫}
264e650bfb3S猫头猫
265*e01046d9S猫头猫export function ListItemHeader(props: {children?: ReactNode}) {
266*e01046d9S猫头猫    const {children} = props;
267*e01046d9S猫头猫    return (
268*e01046d9S猫头猫        <ListItem
269*e01046d9S猫头猫            withHorizonalPadding
270*e01046d9S猫头猫            heightType="smallest"
271*e01046d9S猫头猫            style={styles.listItemHeader}>
272*e01046d9S猫头猫            {typeof children === 'string' ? (
273*e01046d9S猫头猫                <ThemeText
274*e01046d9S猫头猫                    fontSize="subTitle"
275*e01046d9S猫头猫                    fontColor="textSecondary"
276*e01046d9S猫头猫                    fontWeight="bold">
277*e01046d9S猫头猫                    {children}
278*e01046d9S猫头猫                </ThemeText>
279*e01046d9S猫头猫            ) : (
280*e01046d9S猫头猫                children
281*e01046d9S猫头猫            )}
282*e01046d9S猫头猫        </ListItem>
283*e01046d9S猫头猫    );
284*e01046d9S猫头猫}
285*e01046d9S猫头猫
286e650bfb3S猫头猫const styles = StyleSheet.create({
2871119c2eaS猫头猫    /** listitem */
2881119c2eaS猫头猫    container: {
2891119c2eaS猫头猫        width: '100%',
2901119c2eaS猫头猫        flexDirection: 'row',
2911119c2eaS猫头猫        alignItems: 'center',
2921119c2eaS猫头猫    },
2931119c2eaS猫头猫    /** left */
2941119c2eaS猫头猫    actionBase: {
2951119c2eaS猫头猫        height: '100%',
2961119c2eaS猫头猫        flexShrink: 0,
2971119c2eaS猫头猫        flexGrow: 0,
2981119c2eaS猫头猫        flexBasis: 0,
2991119c2eaS猫头猫        flexDirection: 'row',
3001119c2eaS猫头猫        justifyContent: 'center',
3011119c2eaS猫头猫        alignItems: 'center',
3021119c2eaS猫头猫    },
3031119c2eaS猫头猫
3041119c2eaS猫头猫    leftImage: {
3051119c2eaS猫头猫        width: rpx(80),
3061119c2eaS猫头猫        height: rpx(80),
3071119c2eaS猫头猫        borderRadius: rpx(16),
3081119c2eaS猫头猫    },
3091119c2eaS猫头猫    itemContentContainer: {
3101119c2eaS猫头猫        flex: 1,
3111119c2eaS猫头猫        height: '100%',
3121119c2eaS猫头猫        justifyContent: 'center',
3131119c2eaS猫头猫    },
3141119c2eaS猫头猫    contentDesc: {
3151119c2eaS猫头猫        marginTop: rpx(16),
31619dc08ecS猫头猫    },
317*e01046d9S猫头猫
318*e01046d9S猫头猫    listItemHeader: {
319*e01046d9S猫头猫        marginTop: rpx(20),
320*e01046d9S猫头猫    },
32119dc08ecS猫头猫});
3221119c2eaS猫头猫
3231119c2eaS猫头猫ListItem.Size = Size;
3241119c2eaS猫头猫ListItem.ListItemIcon = ListItemIcon;
3251119c2eaS猫头猫ListItem.ListItemImage = ListItemImage;
3261119c2eaS猫头猫ListItem.ListItemText = ListItemText;
3271119c2eaS猫头猫ListItem.Content = Content;
3281119c2eaS猫头猫
3291119c2eaS猫头猫export default ListItem;
330