187 lines
4.9 KiB
TypeScript
187 lines
4.9 KiB
TypeScript
import { ChatBubble, TimeSeparator, TypingIndicator } from '@/components/chat/ChatBubble';
|
|
import { ChatInput } from '@/components/chat/ChatInput';
|
|
import { AppColors } from '@/constants/theme';
|
|
import {
|
|
getCurrentTimeString,
|
|
getRandomAIResponse,
|
|
Message,
|
|
mockConversations,
|
|
mockMessages,
|
|
} from '@/data/mockData';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { router, useLocalSearchParams } from 'expo-router';
|
|
import React, { useEffect, useRef, useState } from 'react';
|
|
import {
|
|
KeyboardAvoidingView,
|
|
Platform,
|
|
ScrollView,
|
|
StyleSheet,
|
|
Text,
|
|
TouchableOpacity,
|
|
View,
|
|
} from 'react-native';
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
|
|
export default function ChatDetailScreen() {
|
|
const { id } = useLocalSearchParams<{ id: string }>();
|
|
const scrollViewRef = useRef<ScrollView>(null);
|
|
|
|
const [messages, setMessages] = useState<Message[]>(mockMessages);
|
|
const [isTyping, setIsTyping] = useState(false);
|
|
|
|
// Find conversation info
|
|
const conversation = mockConversations.find(c => c.id === id) || mockConversations[0];
|
|
|
|
// Scroll to bottom when messages change
|
|
useEffect(() => {
|
|
setTimeout(() => {
|
|
scrollViewRef.current?.scrollToEnd({ animated: true });
|
|
}, 100);
|
|
}, [messages, isTyping]);
|
|
|
|
const handleSendMessage = (text: string) => {
|
|
// Add user message
|
|
const userMessage: Message = {
|
|
id: `m${Date.now()}`,
|
|
conversationId: id || '1',
|
|
senderType: 'user',
|
|
contentType: 'text',
|
|
content: text,
|
|
timestamp: getCurrentTimeString(),
|
|
};
|
|
|
|
setMessages(prev => [...prev, userMessage]);
|
|
|
|
// Simulate AI typing
|
|
setTimeout(() => {
|
|
setIsTyping(true);
|
|
}, 500);
|
|
|
|
// Add AI response after delay
|
|
setTimeout(() => {
|
|
setIsTyping(false);
|
|
const aiMessage: Message = {
|
|
id: `m${Date.now() + 1}`,
|
|
conversationId: id || '1',
|
|
senderType: 'ai',
|
|
contentType: 'text',
|
|
content: getRandomAIResponse(),
|
|
timestamp: getCurrentTimeString(),
|
|
};
|
|
setMessages(prev => [...prev, aiMessage]);
|
|
}, 1500 + Math.random() * 1000);
|
|
};
|
|
|
|
const handleBack = () => {
|
|
router.back();
|
|
};
|
|
|
|
return (
|
|
<SafeAreaView style={styles.container} edges={['top']}>
|
|
{/* Header */}
|
|
<View style={styles.header}>
|
|
<TouchableOpacity
|
|
style={styles.backButton}
|
|
onPress={handleBack}
|
|
activeOpacity={0.7}
|
|
>
|
|
<Ionicons name="chevron-back" size={24} color={AppColors.white} />
|
|
</TouchableOpacity>
|
|
|
|
<View style={styles.headerTitleArea}>
|
|
<Text style={styles.headerTitle}>{conversation.title}</Text>
|
|
<Text style={styles.headerStatus}>在线</Text>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Messages */}
|
|
<KeyboardAvoidingView
|
|
style={styles.messageContainer}
|
|
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
|
keyboardVerticalOffset={0}
|
|
>
|
|
<ScrollView
|
|
ref={scrollViewRef}
|
|
style={styles.messageList}
|
|
contentContainerStyle={styles.messageListContent}
|
|
showsVerticalScrollIndicator={false}
|
|
keyboardShouldPersistTaps="handled"
|
|
>
|
|
<TimeSeparator time="今天 14:30" />
|
|
|
|
{messages.map((message) => (
|
|
<ChatBubble key={message.id} message={message} />
|
|
))}
|
|
|
|
{isTyping && <TypingIndicator />}
|
|
</ScrollView>
|
|
|
|
{/* Input Area */}
|
|
<ChatInput
|
|
onSendMessage={handleSendMessage}
|
|
onVoicePress={() => {
|
|
// Voice input placeholder
|
|
console.log('Voice input pressed');
|
|
}}
|
|
onEmojiPress={() => {
|
|
// Emoji picker placeholder
|
|
console.log('Emoji picker pressed');
|
|
}}
|
|
onMorePress={() => {
|
|
// More options placeholder
|
|
console.log('More options pressed');
|
|
}}
|
|
/>
|
|
</KeyboardAvoidingView>
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: AppColors.mediumPurple,
|
|
},
|
|
header: {
|
|
height: 62,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
paddingHorizontal: 16,
|
|
backgroundColor: AppColors.mediumPurple,
|
|
},
|
|
backButton: {
|
|
width: 40,
|
|
height: 40,
|
|
borderRadius: 12,
|
|
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
},
|
|
headerTitleArea: {
|
|
flex: 1,
|
|
alignItems: 'center',
|
|
marginRight: 40, // Balance the back button
|
|
},
|
|
headerTitle: {
|
|
fontSize: 18,
|
|
fontWeight: '600',
|
|
color: AppColors.white,
|
|
},
|
|
headerStatus: {
|
|
fontSize: 12,
|
|
color: 'rgba(255, 255, 255, 0.8)',
|
|
marginTop: 2,
|
|
},
|
|
messageContainer: {
|
|
flex: 1,
|
|
backgroundColor: AppColors.cream,
|
|
},
|
|
messageList: {
|
|
flex: 1,
|
|
backgroundColor: AppColors.cream,
|
|
},
|
|
messageListContent: {
|
|
paddingVertical: 16,
|
|
},
|
|
});
|