xref: /MusicFree/src/components/base/listItem.tsx (revision 1fa77b042dffea2ad8db31c1b15672ed8f3755cf)
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