2025-07-16 19:51:30 +08:00

224 lines
7.2 KiB
TypeScript

import ReturnArrow from "@/assets/icons/svg/returnArrow.svg";
import Chat from "@/components/ask/chat";
import AskHello from "@/components/ask/hello";
import SendMessage from "@/components/ask/send";
import { ThemedText } from "@/components/ThemedText";
import { fetchApi } from "@/lib/server-api-util";
import { Message } from "@/types/ask";
import { router, useLocalSearchParams } from "expo-router";
import React, { useEffect, useRef, useState } from 'react';
import {
Animated,
KeyboardAvoidingView,
Platform,
ScrollView,
StyleSheet,
TouchableOpacity,
View
} from 'react-native';
import { useSafeAreaInsets } from "react-native-safe-area-context";
export default function AskScreen() {
const insets = useSafeAreaInsets();
const scrollViewRef = useRef<ScrollView>(null);
const [isHello, setIsHello] = useState(true);
const [conversationId, setConversationId] = useState<string | null>(null);
const [userMessages, setUserMessages] = useState<Message[]>([]);
// 选择图片
const [selectedImages, setSelectedImages] = useState<string[]>([]);
// 动画值
const fadeAnim = useRef(new Animated.Value(1)).current;
const fadeAnimChat = useRef(new Animated.Value(0)).current;
const { sessionId, newSession } = useLocalSearchParams<{
sessionId: string;
newSession: string;
}>();
// 处理滚动到底部
useEffect(() => {
if (scrollViewRef.current && !isHello) {
scrollViewRef.current.scrollToEnd({ animated: true });
}
}, [userMessages, isHello]);
// 处理路由参数
useEffect(() => {
if (sessionId) {
setConversationId(sessionId);
setIsHello(false);
fetchApi<Message[]>(`/chats/${sessionId}/message-history`).then((res) => {
setUserMessages(res);
});
}
// if (newSession) {
// setIsHello(false);
// createNewConversation();
// }
}, [sessionId]);
// 动画效果
useEffect(() => {
if (isHello) {
// 显示欢迎页,隐藏聊天页
Animated.parallel([
Animated.timing(fadeAnim, {
toValue: 1,
duration: 300,
useNativeDriver: true,
}),
Animated.timing(fadeAnimChat, {
toValue: 0,
duration: 300,
useNativeDriver: true,
})
]).start();
} else {
// 显示聊天页,隐藏欢迎页
Animated.parallel([
Animated.timing(fadeAnim, {
toValue: 0,
duration: 1000,
useNativeDriver: true,
}),
Animated.timing(fadeAnimChat, {
toValue: 1,
duration: 1000,
useNativeDriver: true,
})
]).start();
}
}, [isHello, fadeAnim, fadeAnimChat]);
return (
<View style={[styles.container, { paddingTop: insets.top }]}>
{/* 导航栏 */}
<View style={[styles.navbar, isHello && styles.hiddenNavbar]}>
<TouchableOpacity
style={styles.backButton}
onPress={() => router.push('/memo-list')}
>
<ReturnArrow />
</TouchableOpacity>
<ThemedText style={styles.title}>MemoWake</ThemedText>
<View style={styles.placeholder} />
</View>
<KeyboardAvoidingView
style={styles.keyboardAvoidingView}
behavior={Platform.OS === "ios" ? "padding" : "height"}
keyboardVerticalOffset={Platform.OS === "ios" ? 0 : 0}
enabled={!isHello}
>
<View style={styles.contentContainer}>
{/* 欢迎页面 */}
<Animated.View
style={[
styles.absoluteView,
{
opacity: fadeAnim,
// 使用 pointerEvents 控制交互
pointerEvents: isHello ? 'auto' : 'none',
zIndex: 1
}
]}
>
<AskHello />
</Animated.View>
{/* 聊天页面 */}
<Animated.View
style={[
styles.absoluteView,
{
opacity: fadeAnimChat,
// 使用 pointerEvents 控制交互
pointerEvents: isHello ? 'none' : 'auto',
zIndex: 0
}
]}
>
<Chat userMessages={userMessages} sessionId={sessionId} setSelectedImages={setSelectedImages} selectedImages={selectedImages} />
</Animated.View>
</View>
{/* 输入框 */}
<View style={styles.inputContainer}>
<SendMessage
setIsHello={setIsHello}
setUserMessages={setUserMessages}
setConversationId={setConversationId}
conversationId={conversationId}
selectedImages={selectedImages}
setSelectedImages={setSelectedImages}
/>
</View>
</KeyboardAvoidingView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
navbar: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingVertical: 16,
paddingHorizontal: 16,
backgroundColor: 'white',
// 使用 border 替代阴影
borderBottomWidth: 1,
borderBottomColor: 'rgba(0,0,0,0.1)',
// 如果需要更柔和的边缘,可以添加一个微妙的阴影
elevation: 1, // Android
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.1,
shadowRadius: 1,
},
hiddenNavbar: {
shadowOpacity: 0,
elevation: 0,
},
backButton: {
padding: 8,
marginRight: 8,
},
title: {
fontSize: 20,
fontWeight: '600',
textAlign: 'center',
flex: 1,
},
placeholder: {
width: 40,
},
// 更新 keyboardAvoidingView 和 contentContainer 样式
keyboardAvoidingView: {
flex: 1,
},
contentContainer: {
flex: 1,
justifyContent: 'center',
paddingBottom: 20,
},
absoluteView: {
position: 'absolute', // 保持绝对定位
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'white',
},
inputContainer: {
padding: 16,
paddingBottom: 24,
backgroundColor: 'white',
borderTopWidth: 1,
borderTopColor: '#f0f0f0',
},
});