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