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;
|