BlueWallet/components/ListItem.tsx

200 lines
5.9 KiB
TypeScript
Raw Normal View History

2024-01-14 23:33:10 +01:00
import React, { useMemo } from 'react';
2024-05-20 11:54:13 +02:00
import { ActivityIndicator, I18nManager, Pressable, PressableProps, StyleSheet, Switch, TouchableOpacity } from 'react-native';
2024-06-12 19:30:01 +02:00
import { Avatar, ListItem as RNElementsListItem, Button } from '@rneui/themed'; // Replace with actual import paths
2024-05-20 11:54:13 +02:00
2023-12-16 22:44:35 +01:00
import { useTheme } from './themes';
// Update the type for the props
interface ListItemProps {
2024-06-12 19:30:01 +02:00
swipeable?: boolean;
2023-12-19 16:33:33 +01:00
rightIcon?: any;
2024-05-27 04:03:35 +02:00
leftAvatar?: React.JSX.Element;
2023-12-16 22:44:35 +01:00
containerStyle?: object;
Component?: typeof React.Component | typeof PressableWrapper;
bottomDivider?: boolean;
topDivider?: boolean;
testID?: string;
onPress?: () => void;
onLongPress?: () => void;
2024-06-12 19:30:01 +02:00
onDeletePressed?: () => void;
2023-12-16 22:44:35 +01:00
disabled?: boolean;
switch?: object; // Define more specific type if needed
2023-12-19 16:33:33 +01:00
leftIcon?: any; // Define more specific type if needed
2023-12-16 22:44:35 +01:00
title: string;
subtitle?: string;
subtitleNumberOfLines?: number;
rightTitle?: string;
rightTitleStyle?: object;
isLoading?: boolean;
chevron?: boolean;
checkmark?: boolean;
2024-05-27 04:03:35 +02:00
subtitleProps?: object;
2024-06-12 19:30:01 +02:00
swipeableLeftContent?: React.ReactNode;
swipeableRightContent?: React.ReactNode;
2023-12-16 22:44:35 +01:00
}
export class PressableWrapper extends React.Component<PressableProps> {
render() {
return <Pressable {...this.props} />;
}
}
export class TouchableOpacityWrapper extends React.Component {
render() {
return <TouchableOpacity {...this.props} />;
}
}
2024-06-12 19:30:01 +02:00
// Define Swipeable Button Components
const DefaultRightContent: React.FC<{ reset: () => void; onDeletePressed?: () => void }> = ({ reset, onDeletePressed }) => (
<Button
title="Delete"
onPress={() => {
reset();
onDeletePressed?.();
}}
icon={{ name: 'delete', color: 'white' }}
buttonStyle={styles.rightButton}
/>
);
2023-12-16 22:44:35 +01:00
2024-06-12 19:30:01 +02:00
const styles = StyleSheet.create({
rightButton: {
minHeight: '100%',
backgroundColor: 'red',
},
});
2024-01-14 23:33:10 +01:00
2024-06-12 19:30:01 +02:00
const ListItem: React.FC<ListItemProps> = React.memo(
({
swipeable = false,
Component = TouchableOpacityWrapper,
rightIcon,
leftAvatar,
containerStyle,
bottomDivider = true,
topDivider = false,
testID,
onPress,
onLongPress,
onDeletePressed,
disabled,
switch: switchProps,
leftIcon,
title,
subtitle,
subtitleNumberOfLines,
rightTitle,
rightTitleStyle,
isLoading,
chevron,
checkmark,
swipeableLeftContent,
swipeableRightContent,
}: ListItemProps) => {
const { colors } = useTheme();
const stylesHook = StyleSheet.create({
title: {
color: disabled ? colors.buttonDisabledTextColor : colors.foregroundColor,
fontSize: 16,
fontWeight: '500',
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
},
subtitle: {
flexWrap: 'wrap',
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
color: colors.alternativeTextColor,
fontWeight: '400',
fontSize: 14,
},
rightTitleContainer: {
flex: 1,
},
containerStyle: {
backgroundColor: colors.background,
},
});
const memoizedSwitchProps = useMemo(() => {
return switchProps ? { ...switchProps } : undefined;
}, [switchProps]);
const renderContent = () => (
<>
{leftIcon && <Avatar icon={leftIcon} />}
{leftAvatar && leftAvatar}
<RNElementsListItem.Content>
<RNElementsListItem.Title style={stylesHook.title} numberOfLines={0} accessible={switchProps === undefined}>
{title}
2023-12-16 22:44:35 +01:00
</RNElementsListItem.Title>
2024-06-12 19:30:01 +02:00
{subtitle && (
<RNElementsListItem.Subtitle
numberOfLines={subtitleNumberOfLines ?? 1}
accessible={switchProps === undefined}
style={stylesHook.subtitle}
>
{subtitle}
</RNElementsListItem.Subtitle>
)}
2023-12-16 22:44:35 +01:00
</RNElementsListItem.Content>
2024-06-12 19:30:01 +02:00
{rightTitle && (
<RNElementsListItem.Content right style={stylesHook.rightTitleContainer}>
<RNElementsListItem.Title style={rightTitleStyle} numberOfLines={0} right>
{rightTitle}
</RNElementsListItem.Title>
</RNElementsListItem.Content>
)}
{isLoading ? (
<ActivityIndicator />
) : (
<>
{chevron && <RNElementsListItem.Chevron iconStyle={{ transform: [{ scaleX: I18nManager.isRTL ? -1 : 1 }] }} />}
{rightIcon && <Avatar icon={rightIcon} />}
{switchProps && <Switch {...memoizedSwitchProps} accessibilityLabel={title} accessible accessibilityRole="switch" />}
{checkmark && <RNElementsListItem.CheckBox iconType="octaicon" checkedColor="#0070FF" checkedIcon="check" checked />}
</>
)}
</>
);
if (swipeable && !Component) {
console.warn('Component prop is required when swipeable is true.');
return null;
}
return swipeable ? (
<RNElementsListItem.Swipeable
containerStyle={containerStyle ?? stylesHook.containerStyle}
Component={Component}
bottomDivider={bottomDivider}
topDivider={topDivider}
testID={testID}
onPress={onPress}
onLongPress={onLongPress}
disabled={disabled}
leftContent={swipeableLeftContent}
rightContent={swipeableRightContent ?? <DefaultRightContent reset={() => {}} onDeletePressed={onDeletePressed} />}
accessible={switchProps === undefined}
>
{renderContent()}
</RNElementsListItem.Swipeable>
) : (
<RNElementsListItem
containerStyle={containerStyle ?? stylesHook.containerStyle}
Component={Component}
bottomDivider={bottomDivider}
topDivider={topDivider}
testID={testID}
onPress={onPress}
onLongPress={onLongPress}
disabled={disabled}
accessible={switchProps === undefined}
>
{renderContent()}
</RNElementsListItem>
);
},
);
2023-12-16 22:44:35 +01:00
export default ListItem;