import ChatSvg from "@/assets/icons/svg/chat.svg"; import FolderSvg from "@/assets/icons/svg/folder.svg"; import MoreSvg from "@/assets/icons/svg/more.svg"; import ReturnArrow from "@/assets/icons/svg/returnArrow.svg"; import YesSvg from "@/assets/icons/svg/yes.svg"; import { Message, Video } from "@/types/ask"; import { MaterialItem } from "@/types/personal-info"; import { TFunction } from "i18next"; import React from 'react'; import { FlatList, Image, Modal, Pressable, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { ThemedText } from "../ThemedText"; import TypewriterText from "./typewriterText"; import { mergeArrays } from "./utils"; import VideoPlayer from "./VideoPlayer"; interface RenderMessageProps { insets: { top: number }; item: Message; sessionId: string; setModalVisible: React.Dispatch>; modalVisible: { visible: boolean, data: Video | MaterialItem }; setModalDetailsVisible: React.Dispatch>; modalDetailsVisible: boolean; setSelectedImages: React.Dispatch>; selectedImages: string[]; t: TFunction; } const MessageItem = ({ t, insets, item, sessionId, setModalVisible, modalVisible, setModalDetailsVisible, modalDetailsVisible, setSelectedImages, selectedImages }: RenderMessageProps) => { const isUser = item.role === 'User'; const isVideo = (data: Video | MaterialItem): data is Video => { return 'video' in data; }; return ( {!isUser && } 0 || item.content.image_material_infos && item.content.image_material_infos.length > 0) ? '!rounded-t-3xl !rounded-b-2xl' : '!rounded-3xl'}`} > {!isUser ? sessionId ? item.content.text : : item.content.text } {(mergeArrays(item.content.image_material_infos || [], item.content.video_material_infos || [])?.length || 0 > 0) && ( {mergeArrays(item.content.image_material_infos || [], item.content.video_material_infos || [])?.slice(0, 3)?.map((image) => ( { setModalVisible({ visible: true, data: image }); }} style={{ width: '32%', aspectRatio: 1, marginBottom: 8, }} > ))} { ((item.content.video_material_infos?.length || 0) + (item.content.image_material_infos?.length || 0)) > 3 && { setModalDetailsVisible(true); }}> {((item.content.video_material_infos?.length || 0) + (item.content.image_material_infos?.length || 0))} } )} {/* {item.askAgain && item.askAgain.length > 0 && ( {item.askAgain.map((suggestion, index, array) => ( {suggestion.text} ))} )} */} { setModalVisible({ visible: false, data: {} as Video | MaterialItem }); }}> { setModalVisible({ visible: false, data: {} as Video | MaterialItem }) }} /> setModalVisible({ visible: false, data: {} as Video | MaterialItem })}> {isVideo(modalVisible.data) ? ( // 视频播放器 setModalVisible({ visible: false, data: {} as Video | MaterialItem })} > setModalVisible({ visible: false, data: {} as Video | MaterialItem })} /> ) : ( // 图片预览 setModalVisible({ visible: false, data: {} as Video | MaterialItem })} style={styles.imageContainer} > )} { setModalDetailsVisible(false); }} > setModalDetailsVisible(false)}> {t('ask.selectPhoto', { ns: 'ask' })} item.id} showsVerticalScrollIndicator={false} contentContainerStyle={detailsStyles.flatListContent} initialNumToRender={12} maxToRenderPerBatch={12} updateCellsBatchingPeriod={50} windowSize={10} removeClippedSubviews={true} renderItem={({ item }) => { return ( {selectedImages?.map((image, index) => { if (image === item.id || image === item.video?.id) { return index + 1 } })} console.log('Image load error:', error.nativeEvent.error)} onLoad={() => console.log('Image loaded successfully')} /> { setSelectedImages((prev) => { if (prev.includes(item?.id || item?.video?.id)) { return prev.filter((id) => id !== (item.id || item?.video?.id)); } else { return [...prev, item.id || item.video?.id]; } }); }} > {selectedImages.includes(item?.id || item?.video?.id) ? : ""} ); }} /> { // 如果用户没有选择 则为选择全部 if (selectedImages?.length < 0) { setSelectedImages(mergeArrays(item.content.image_material_infos || [], item.content.video_material_infos || [])?.map((item) => { return item.id || item.video?.id })) } setModalDetailsVisible(false) }} activeOpacity={0.8} > {t('ask.continueAsking', { ns: 'ask' })} ); }; export default MessageItem; const styles = StyleSheet.create({ imageGridContainer: { flexDirection: 'row', flexWrap: 'nowrap', width: '100%', marginTop: 8, }, video: { width: '100%', height: '100%', }, imageContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', width: '100%', maxHeight: '60%', }, fullWidthImage: { width: '100%', height: "54%", marginBottom: 8, }, gridImage: { aspectRatio: 1, marginBottom: 8, }, background: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(0, 0, 0, 0.5)', // 添加半透明黑色背景 }, centeredView: { flex: 1, justifyContent: 'center', alignItems: 'center', }, modalView: { borderRadius: 20, alignItems: 'center', height: '100%', width: "100%", justifyContent: 'center', alignSelf: 'center', }, container: { flex: 1, backgroundColor: '#f5f5f5', }, userAvatar: { width: 30, height: 30, borderRadius: 15, }, messageList: { padding: 16, }, messageBubble: { paddingHorizontal: 16, paddingVertical: 12, fontWeight: "600" }, userBubble: { alignSelf: 'flex-end', backgroundColor: '#FFB645', marginLeft: '20%', }, aiBubble: { alignSelf: 'flex-start', backgroundColor: '#fff', marginRight: '20%', borderWidth: 1, borderColor: '#e5e5ea', }, userText: { color: '#4C320C', fontSize: 16, }, aiText: { color: '#000', fontSize: 16, }, }); const detailsStyles = StyleSheet.create({ gridItemContainer: { flex: 1, // 使用 flex 布局使项目平均分配空间 maxWidth: '33.33%', // 每行最多4个项目 aspectRatio: 1, // 保持1:1的宽高比 }, flatListContent: { paddingBottom: 100, // 为底部按钮留出更多空间 paddingHorizontal: 8, // 添加水平内边距 paddingTop: 8, }, headerText: { fontSize: 20, fontWeight: 'bold', color: "#4C320C" }, container: { flex: 1, padding: 0, margin: 0, backgroundColor: '#fff', width: '100%', height: '100%', position: 'relative', }, imageNumber: { fontSize: 16, fontWeight: 'bold', color: '#fff', position: 'absolute', top: 10, left: 10, zIndex: 10, // 确保数字显示在图片上方 }, imageNumberText: { fontSize: 16, fontWeight: 'bold', color: '#fff', }, numberText: { position: 'absolute', top: 10, left: 10, width: 28, height: 28, borderRadius: 14, backgroundColor: 'rgba(0, 122, 255, 0.9)', // 使用半透明蓝色背景 justifyContent: 'center', alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 3.84, elevation: 5, }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 16, borderBottomWidth: 1, borderBottomColor: '#eee', }, gridItem: { flex: 1, // 填充父容器 overflow: 'hidden', backgroundColor: '#f5f5f5', borderWidth: 1, borderColor: '#eee', height: '100%', // 确保高度填满容器 position: 'relative', }, image: { width: '100%', height: '100%', resizeMode: 'cover', }, circleMarker: { position: 'absolute', top: 10, right: 10, width: 28, height: 28, borderRadius: 14, justifyContent: 'center', alignItems: 'center', borderWidth: 3, borderColor: '#fff', }, circleMarkerSelected: { backgroundColor: '#FFB645', }, markerText: { fontSize: 16, fontWeight: 'bold', color: '#000', }, footer: { position: 'absolute', bottom: 20, left: 0, right: 0, paddingHorizontal: 16, zIndex: 10, paddingVertical: 10, }, continueButton: { backgroundColor: '#E2793F', borderRadius: 32, padding: 16, alignItems: 'center', width: '100%', zIndex: 10, }, continueButtonText: { color: '#fff', fontSize: 18, fontWeight: 'bold', } });