Skip to content

Commit 8789b43

Browse files
authored
Merge pull request #78 from saigontechnology/feat/update_listconversationscreen_ui
feat: update list conversation ui
2 parents ad3c50a + a3935bb commit 8789b43

File tree

10 files changed

+334
-47
lines changed

10 files changed

+334
-47
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ npm install rn-firebase-chat
1313
- Using [npm](https://www.npmjs.com/#getting-started):
1414

1515
```sh
16-
npm install rn-firebase-chat @react-native-firebase/app @react-native-firebase/firestore @react-native-firebase/storage randomcolor react-native-aes-crypto react-native-gifted-chat react-native-keyboard-controller --save
16+
npm install rn-firebase-chat @react-native-firebase/app @react-native-firebase/firestore @react-native-firebase/storage randomcolor react-native-aes-crypto react-native-gifted-chat react-native-gesture-handler react-native-keyboard-controller --save
1717
```
1818

1919
- Using [Yarn](https://yarnpkg.com/):
2020

2121
```sh
22-
yarn add rn-firebase-chat @react-native-firebase/app @react-native-firebase/firestore @react-native-firebase/storage randomcolor react-native-aes-crypto react-native-gifted-chat react-native-keyboard-controller
22+
yarn add rn-firebase-chat @react-native-firebase/app @react-native-firebase/firestore @react-native-firebase/storage randomcolor react-native-aes-crypto react-native-gifted-chat react-native-gesture-handler react-native-keyboard-controller
2323
```
2424

2525
If you're using Expo, please follow the dedicated setup guide to configure `plugins` in your `app.config.ts` and add Firebase files for Android and iOS:

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
"react-native": "0.80.0",
8686
"react-native-aes-crypto": "^3.2.1",
8787
"react-native-builder-bob": "^0.40.12",
88+
"react-native-gesture-handler": "^2.28.0",
8889
"react-native-gifted-chat": "^2.8.1",
8990
"react-native-image-picker": "^8.2.1",
9091
"react-native-keyboard-controller": "^1.18.6",
@@ -107,6 +108,7 @@
107108
"react": "*",
108109
"react-native": "*",
109110
"react-native-aes-crypto": "*",
111+
"react-native-gesture-handler": "*",
110112
"react-native-gifted-chat": "*",
111113
"react-native-image-picker": "*",
112114
"react-native-keyboard-controller": "*",

src/asset/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const Images = {
1010
placeHolder: require('../images/place_holder.png'),
1111
playIcon: require('../images/play.png'),
1212
pauseWhiteIcon: require('../images/pause_white.png'),
13+
trash: require('../images/trash.png'),
1314
};
1415

1516
export default Images;

src/chat/ListConversationScreen.tsx

Lines changed: 154 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
import React, { useCallback, useMemo } from 'react';
2-
import { FlatList, StyleSheet, View } from 'react-native';
2+
import {
3+
FlatList,
4+
StyleSheet,
5+
View,
6+
Animated,
7+
TouchableOpacity,
8+
Image,
9+
StyleProp,
10+
ViewStyle,
11+
} from 'react-native';
12+
import { Swipeable } from 'react-native-gesture-handler';
313
import {
414
ConversationItem,
515
IConversationItemProps,
@@ -8,6 +18,7 @@ import type { ConversationProps } from '../interfaces';
818
import { useChatContext, useChatSelector } from '../hooks';
919
import { setConversation } from '../reducer';
1020
import { getListConversation } from '../reducer/selectors';
21+
import Images from '../asset';
1122

1223
type ListItem = {
1324
item: ConversationProps;
@@ -17,15 +28,27 @@ type ListItem = {
1728
export interface IListConversationProps {
1829
hasSearchBar?: boolean;
1930
onPress?: (conversation: ConversationProps) => void;
31+
onDelete?: (conversation: ConversationProps) => void;
2032
renderCustomItem?: ({ item, index }: ListItem) => React.JSX.Element | null;
2133
conversationItemProps?: Omit<IConversationItemProps, 'data' | 'onPress'>; // remove default prop 'data' and 'onPress'
34+
enableSwipeToDelete?: boolean;
35+
deleteButtonColor?: string;
36+
renderDeleteIcon?: () => React.ReactNode;
37+
containerStyle?: StyleProp<ViewStyle>;
38+
contentContainerStyle?: StyleProp<ViewStyle>;
2239
}
2340

2441
export const ListConversationScreen: React.FC<IListConversationProps> = ({
2542
// hasSearchBar,
2643
onPress,
44+
onDelete,
2745
renderCustomItem,
2846
conversationItemProps,
47+
enableSwipeToDelete = true,
48+
deleteButtonColor = '#FF3B30',
49+
renderDeleteIcon,
50+
containerStyle,
51+
contentContainerStyle,
2952
}) => {
3053
const { chatDispatch, userInfo } = useChatContext();
3154
const listConversation = useChatSelector(getListConversation);
@@ -43,33 +66,131 @@ export const ListConversationScreen: React.FC<IListConversationProps> = ({
4366
[chatDispatch, onPress]
4467
);
4568

69+
const handleDelete = useCallback(
70+
(item: ConversationProps) => {
71+
onDelete?.(item);
72+
},
73+
[onDelete]
74+
);
75+
76+
const renderRightActions = useCallback(
77+
(
78+
item: ConversationProps,
79+
progress: Animated.AnimatedInterpolation<number>,
80+
dragX: Animated.AnimatedInterpolation<number>
81+
) => {
82+
const translateX = dragX.interpolate({
83+
inputRange: [-100, 0],
84+
outputRange: [0, 100],
85+
extrapolate: 'clamp',
86+
});
87+
88+
const opacity = progress.interpolate({
89+
inputRange: [0, 1],
90+
outputRange: [0, 1],
91+
});
92+
93+
return (
94+
<Animated.View
95+
style={[
96+
styles.deleteAction,
97+
{
98+
transform: [{ translateX }],
99+
opacity,
100+
},
101+
]}
102+
>
103+
<TouchableOpacity
104+
style={[
105+
styles.deleteButton,
106+
{ backgroundColor: deleteButtonColor },
107+
]}
108+
onPress={() => handleDelete(item)}
109+
activeOpacity={0.7}
110+
>
111+
<Animated.View
112+
style={[
113+
styles.deleteContent,
114+
{
115+
transform: [
116+
{
117+
scale: progress.interpolate({
118+
inputRange: [0, 1],
119+
outputRange: [0.8, 1],
120+
}),
121+
},
122+
],
123+
},
124+
]}
125+
>
126+
{renderDeleteIcon ? (
127+
renderDeleteIcon()
128+
) : (
129+
<View style={styles.defaultDeleteIcon}>
130+
<Image
131+
source={Images.trash}
132+
style={styles.trashIcon}
133+
resizeMode="contain"
134+
/>
135+
</View>
136+
)}
137+
</Animated.View>
138+
</TouchableOpacity>
139+
</Animated.View>
140+
);
141+
},
142+
[deleteButtonColor, handleDelete, renderDeleteIcon]
143+
);
144+
46145
const renderItem = useCallback(
47146
({ item, index }: ListItem) => {
48-
if (renderCustomItem) return renderCustomItem({ item, index });
49-
return (
147+
const itemContent = renderCustomItem ? (
148+
renderCustomItem({ item, index })
149+
) : (
50150
<ConversationItem
51151
data={item}
52152
onPress={handleConversationPressed}
53153
{...(conversationItemProps || {})}
54154
userInfo={userInfo}
55155
/>
56156
);
157+
158+
if (!enableSwipeToDelete) {
159+
return itemContent;
160+
}
161+
162+
return (
163+
<Swipeable
164+
key={item.id}
165+
renderRightActions={(progress, dragX) =>
166+
renderRightActions(item, progress, dragX)
167+
}
168+
overshootRight={false}
169+
friction={2}
170+
enableTrackpadTwoFingerGesture
171+
>
172+
{itemContent}
173+
</Swipeable>
174+
);
57175
},
58176
[
59177
conversationItemProps,
60178
handleConversationPressed,
61179
renderCustomItem,
62180
userInfo,
181+
enableSwipeToDelete,
182+
renderRightActions,
63183
]
64184
);
65185

66186
return (
67-
<View style={styles.container}>
187+
<View style={[styles.container, containerStyle]}>
68188
<FlatList<ConversationProps>
69-
contentContainerStyle={styles.contentContainer}
70-
keyExtractor={(item, index) => index.toString()}
189+
contentContainerStyle={[contentContainerStyle]}
190+
keyExtractor={(item, index) => item.id || index.toString()}
71191
data={data}
72192
renderItem={renderItem}
193+
showsVerticalScrollIndicator={false}
73194
/>
74195
</View>
75196
);
@@ -78,8 +199,33 @@ export const ListConversationScreen: React.FC<IListConversationProps> = ({
78199
const styles = StyleSheet.create({
79200
container: {
80201
flex: 1,
202+
backgroundColor: 'white',
203+
},
204+
205+
deleteAction: {
206+
justifyContent: 'center',
207+
alignItems: 'flex-end',
208+
minWidth: 100,
209+
},
210+
deleteButton: {
211+
justifyContent: 'center',
212+
alignItems: 'center',
213+
paddingHorizontal: 24,
214+
height: '100%',
215+
minWidth: 100,
216+
},
217+
deleteContent: {
218+
justifyContent: 'center',
219+
alignItems: 'center',
220+
},
221+
defaultDeleteIcon: {
222+
width: 28,
223+
height: 28,
224+
justifyContent: 'center',
225+
alignItems: 'center',
81226
},
82-
contentContainer: {
83-
paddingTop: 15,
227+
trashIcon: {
228+
width: 28,
229+
height: 28,
84230
},
85231
});

0 commit comments

Comments
 (0)