11import 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' ;
313import {
414 ConversationItem ,
515 IConversationItemProps ,
@@ -8,6 +18,7 @@ import type { ConversationProps } from '../interfaces';
818import { useChatContext , useChatSelector } from '../hooks' ;
919import { setConversation } from '../reducer' ;
1020import { getListConversation } from '../reducer/selectors' ;
21+ import Images from '../asset' ;
1122
1223type ListItem = {
1324 item : ConversationProps ;
@@ -17,15 +28,27 @@ type ListItem = {
1728export 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
2441export 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> = ({
78199const 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