Commit 804f4936 by tungnq

IMPORTANT: Xử lý cử chỉ vuốt trong swipe list của màn hộp thư đến

parent 00653950
...@@ -110,6 +110,41 @@ const styles = StyleSheet.create({ ...@@ -110,6 +110,41 @@ const styles = StyleSheet.create({
fontWeight: '600', fontWeight: '600',
fontFamily: R.fonts.fontMedium, fontFamily: R.fonts.fontMedium,
fontSize: R.fontsize.fontSizeContent, fontSize: R.fontsize.fontSizeContent,
},
swipeContainer: {
position: 'relative',
overflow: 'hidden',
},
deleteBackground: {
position: 'absolute',
right: 2.5,
top: 5,
bottom: 5,
width: 95,
backgroundColor: R.colors.red,
borderRadius:25,
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'column',
},
deleteButton: {
width: 100,
height: '100%',
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'column',
},
deleteIcon: {
width: 24,
height: 24,
tintColor: R.colors.white,
marginBottom: 4,
},
deleteText: {
color: R.colors.white,
fontSize: R.fontsize.fontSizeContent,
fontFamily: R.fonts.fontMedium,
fontWeight: '600',
} }
}) })
......
import React from 'react'; import React, {useState, useRef} from 'react';
import { import {
Text, Text,
View, View,
...@@ -7,6 +7,9 @@ import { ...@@ -7,6 +7,9 @@ import {
Image, Image,
ActivityIndicator, ActivityIndicator,
RefreshControl, RefreshControl,
Animated,
PanResponder,
Dimensions,
} from 'react-native'; } from 'react-native';
import styles from './style'; import styles from './style';
import FAB from '../../components/FAB/fab'; import FAB from '../../components/FAB/fab';
...@@ -19,6 +22,15 @@ const EmailHomeView = props => { ...@@ -19,6 +22,15 @@ const EmailHomeView = props => {
const {groupedEmails, loading, onEmailPress, onRefresh, formatEmailDate} = props; const {groupedEmails, loading, onEmailPress, onRefresh, formatEmailDate} = props;
const navigation = useNavigation(); const navigation = useNavigation();
const screenWidth = Dimensions.get('window').width;
const [localGroupedEmails, setLocalGroupedEmails] = useState(groupedEmails);
const [swipedEmailId, setSwipedEmailId] = useState(null);
// Update local state when props change
React.useEffect(() => {
setLocalGroupedEmails(groupedEmails);
}, [groupedEmails]);
if (loading) { if (loading) {
return ( return (
...@@ -29,60 +41,173 @@ const EmailHomeView = props => { ...@@ -29,60 +41,173 @@ const EmailHomeView = props => {
); );
} }
const renderEmailItem = ({item}) => ( const SwipeableEmailItem = ({item, onDelete}) => {
<TouchableOpacity const translateX = useRef(new Animated.Value(0)).current;
style={[styles.emailItem, !item.isRead && styles.unreadEmail]} const deleteThreshold = screenWidth * 0.3;
onPress={() => navigation.navigate(SCREENNAME.DETAILEMAIL)}>
<View style={styles.avatarContainer}>
<View style={styles.avatar}>
<Text style={styles.avatarText}>
{item.sender.charAt(0).toUpperCase()}
</Text>
</View>
</View>
<View style={styles.emailContent}> // Reset position when another email is swiped
<View style={styles.emailHeader}> React.useEffect(() => {
<Text style={[styles.senderName, !item.isRead && styles.unreadText]}> if (swipedEmailId !== null && swipedEmailId !== item.id) {
{item.sender} Animated.spring(translateX, {
</Text> toValue: 0,
</View> useNativeDriver: true,
}).start();
<Text }
style={[styles.emailSubject, !item.isRead && styles.unreadText]} }, [swipedEmailId]);
numberOfLines={1}>
{item.subject} const panResponder = PanResponder.create({
</Text> onMoveShouldSetPanResponder: (evt, gestureState) => {
// console.log('gestureState', gestureState);
<Text const moveX = Math.abs(gestureState.dx);
style={[styles.emailPreview, !item.isRead && styles.unreadEmail]} console.log('moveX', moveX);
numberOfLines={2}> const isSwipingLeft = moveX < deleteThreshold;
{item.preview} console.log('isSwipingLeft', isSwipingLeft);
</Text> return isSwipingLeft;
</View> },
onPanResponderMove: (evt, gestureState) => {
console.log('gestureState', gestureState.dx);
if (gestureState.dx > -100 && gestureState.dx < 0 ) {
translateX.setValue(-100);
}else if(gestureState.dx >0){
translateX.setValue(0);
}
},
// onPanResponderRelease: (evt, gestureState) => {
// console.log('deleteThreshold', -deleteThreshold);
// if (gestureState.dx < -deleteThreshold) {
// // Show delete button
// Animated.timing(translateX, {
// toValue: -100,
// duration: 300,
// useNativeDriver: true,
// }).start();
// setSwipedEmailId(item.id);
// }
// else {
// Animated.spring(translateX, {
// toValue: 0,
// useNativeDriver: true,
// }).start(() => {
// setSwipedEmailId(null);
// });
// }
// },
});
const deleteOpacity = translateX.interpolate({
inputRange: [-deleteThreshold, 0],
outputRange: [1, 0],
extrapolate: 'clamp',
});
const handleDeletePress = () => {
// Delete immediately without animation
onDelete(item.id);
setSwipedEmailId(null);
};
const handleCancelPress = () => {
// Snap back to original position
Animated.spring(translateX, {
toValue: 0,
useNativeDriver: true,
}).start(() => {
setSwipedEmailId(null);
});
};
return (
<View style={styles.swipeContainer}>
{/* Delete background */}
<Animated.View style={[styles.deleteBackground, {opacity: deleteOpacity}]}>
<TouchableOpacity
style={styles.deleteButton}
onPress={handleDeletePress}
>
<Image source={R.images.icDelete} style={styles.deleteIcon} />
<Text style={styles.deleteText}>Xóa</Text>
</TouchableOpacity>
</Animated.View>
{/* Email item */}
<Animated.View
style={[{transform: [{translateX}]}]}
{...panResponder.panHandlers}>
<TouchableOpacity
style={[styles.emailItem, !item.isRead && styles.unreadEmail]}
onPress={() => navigation.navigate(SCREENNAME.DETAILEMAIL)}>
<View style={styles.avatarContainer}>
<View style={styles.avatar}>
<Text style={styles.avatarText}>
{item.sender.charAt(0).toUpperCase()}
</Text>
</View>
</View>
<View style={styles.emailContent}>
<View style={styles.emailHeader}>
<Text style={[styles.senderName, !item.isRead && styles.unreadText]}>
{item.sender}
</Text>
</View>
<Text
style={[styles.emailSubject, !item.isRead && styles.unreadText]}
numberOfLines={1}>
{item.subject}
</Text>
<Text
style={[styles.emailPreview, !item.isRead && styles.unreadEmail]}
numberOfLines={2}>
{item.preview}
</Text>
</View>
<View <View
style={{ style={{
justifyContent: 'center', justifyContent: 'center',
alignItems: 'flex-end', alignItems: 'flex-end',
position: 'absolute', position: 'absolute',
right: 15, right: 15,
top: 10, top: 10,
}}> }}>
<Text style={styles.emailDate}> <Text style={styles.emailDate}>
{`${item.date.getDate().toString().padStart(2, '0')}/${( {`${item.date.getDate().toString().padStart(2, '0')}/${(
item.date.getMonth() + 1 item.date.getMonth() + 1
) )
.toString() .toString()
.padStart(2, '0')}/${item.date.getFullYear()}`} .padStart(2, '0')}/${item.date.getFullYear()}`}
</Text> </Text>
{item.hasAttachment && ( {item.hasAttachment && (
<View style={styles.attachmentIndicator}> <View style={styles.attachmentIndicator}>
<Text style={styles.attachmentCount}>2</Text> <Text style={styles.attachmentCount}>2</Text>
</View> </View>
)} )}
</View>
</TouchableOpacity>
</Animated.View>
</View> </View>
</TouchableOpacity> );
};
const handleDeleteEmail = (emailId) => {
// Remove email from local state temporarily
const updatedGroupedEmails = {};
Object.keys(localGroupedEmails).forEach(dateKey => {
const filteredEmails = localGroupedEmails[dateKey].filter(email => email.id !== emailId);
if (filteredEmails.length > 0) {
updatedGroupedEmails[dateKey] = filteredEmails;
}
});
setLocalGroupedEmails(updatedGroupedEmails);
};
const renderEmailItem = ({item}) => (
<SwipeableEmailItem item={item} onDelete={handleDeleteEmail} />
); );
const renderDateSection = (dateLabel, emailsForDate) => ( const renderDateSection = (dateLabel, emailsForDate) => (
...@@ -98,10 +223,10 @@ const EmailHomeView = props => { ...@@ -98,10 +223,10 @@ const EmailHomeView = props => {
<View style={styles.container}> <View style={styles.container}>
<View style={styles.body}> <View style={styles.body}>
<FlatList <FlatList
data={Object.keys(groupedEmails)} data={Object.keys(localGroupedEmails)}
keyExtractor={item => item} keyExtractor={item => item}
renderItem={({item: dateLabel}) => renderItem={({item: dateLabel}) =>
renderDateSection(dateLabel, groupedEmails[dateLabel]) renderDateSection(dateLabel, localGroupedEmails[dateLabel])
} }
refreshControl={ refreshControl={
<RefreshControl <RefreshControl
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment