Files
life-echo/app-ios/components/chat/ConversationItem.tsx
penghanyuan 748f252c2f add ios app
2026-01-31 21:20:50 +01:00

132 lines
3.3 KiB
TypeScript

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
withTiming,
runOnJS,
} from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import { AppColors } from '@/constants/theme';
import { Conversation } from '@/data/mockData';
interface ConversationItemProps {
conversation: Conversation;
onPress: () => void;
}
export function ConversationItem({ conversation, onPress }: ConversationItemProps) {
const scale = useSharedValue(1);
const opacity = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
opacity: opacity.value,
}));
const tapGesture = Gesture.Tap()
.onBegin(() => {
scale.value = withSpring(0.97, { damping: 15, stiffness: 400 });
opacity.value = withTiming(0.8, { duration: 100 });
})
.onFinalize((_, success) => {
scale.value = withSpring(1, { damping: 15, stiffness: 400 });
opacity.value = withTiming(1, { duration: 150 });
if (success) {
runOnJS(onPress)();
}
});
return (
<GestureDetector gesture={tapGesture}>
<Animated.View style={[styles.container, animatedStyle]}>
<View style={styles.avatar}>
<Text style={styles.avatarEmoji}>{conversation.avatarEmoji}</Text>
</View>
<View style={styles.content}>
<Text style={styles.title} numberOfLines={1}>
{conversation.title}
</Text>
<Text style={styles.preview} numberOfLines={1}>
{conversation.lastMessage}
</Text>
</View>
<View style={styles.meta}>
<Text style={styles.timestamp}>{conversation.timestamp}</Text>
{conversation.unreadCount && conversation.unreadCount > 0 && (
<View style={styles.badge}>
<Text style={styles.badgeText}>{conversation.unreadCount}</Text>
</View>
)}
</View>
</Animated.View>
</GestureDetector>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 14,
paddingHorizontal: 20,
backgroundColor: AppColors.cream,
},
avatar: {
width: 56,
height: 56,
borderRadius: 14,
backgroundColor: AppColors.lavender,
alignItems: 'center',
justifyContent: 'center',
marginRight: 14,
shadowColor: AppColors.deepPurple,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.08,
shadowRadius: 8,
elevation: 2,
},
avatarEmoji: {
fontSize: 26,
},
content: {
flex: 1,
marginRight: 12,
},
title: {
fontSize: 17,
fontWeight: '500',
color: AppColors.deepPurple,
marginBottom: 4,
},
preview: {
fontSize: 14,
color: AppColors.slatePurple,
lineHeight: 20,
},
meta: {
alignItems: 'flex-end',
},
timestamp: {
fontSize: 12,
color: AppColors.slatePurple,
marginBottom: 6,
},
badge: {
width: 20,
height: 20,
borderRadius: 10,
backgroundColor: AppColors.mediumPurple,
alignItems: 'center',
justifyContent: 'center',
},
badgeText: {
fontSize: 12,
color: AppColors.white,
fontWeight: '500',
},
});