import { Colors } from '@/constants/Colors'; import { useColorScheme } from '@/hooks/useColorScheme'; import { Ionicons } from '@expo/vector-icons'; import { BlurView } from 'expo-blur'; import { Image } from 'expo-image'; import React from 'react'; import { ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'; import QuickChips from './QuickChips'; import { QuickChip, SelectedImage } from './types'; interface ChatComposerProps { input: string; onInputChange: (text: string) => void; onSend: () => void; onPickImages: () => void; onCancelRequest: () => void; selectedImages: SelectedImage[]; onRemoveImage: (id: string) => void; onPreviewImage: (uri: string) => void; isSending: boolean; isStreaming: boolean; chips: QuickChip[]; } const ChatComposer: React.FC = ({ input, onInputChange, onSend, onPickImages, onCancelRequest, selectedImages, onRemoveImage, onPreviewImage, isSending, isStreaming, chips }) => { const colorScheme = useColorScheme(); const theme = Colors[colorScheme ?? 'light']; const hasContent = input.trim() || selectedImages.length > 0; const isActive = isSending || isStreaming; return ( {/* 快捷操作按钮 */} {/* 选中的图片预览 */} {selectedImages.length > 0 && ( {selectedImages.map((img) => ( onPreviewImage(img.localUri)} style={styles.imageThumb} > {/* 上传进度 */} {img.progress > 0 && img.progress < 1 && ( {Math.round(img.progress * 100)}% )} {/* 上传错误 */} {img.error && ( {/* 重试上传逻辑 */ }} style={styles.imageRetryBtn} > )} {/* 删除按钮 */} onRemoveImage(img.id)} style={styles.imageRemoveBtn} > ))} )} {/* 输入区域 */} {isActive ? ( ) : ( )} ); }; const styles = StyleSheet.create({ composerWrap: { paddingTop: 8, paddingHorizontal: 10, borderTopWidth: 0, }, imagesRow: { maxHeight: 92, marginBottom: 8, }, imagesRowContent: { gap: 8, paddingHorizontal: 6, }, imageThumbWrap: { width: 72, height: 72, borderRadius: 12, overflow: 'hidden', position: 'relative', backgroundColor: 'rgba(122,90,248,0.08)', }, imageThumb: { width: '100%', height: '100%', }, imageRemoveBtn: { position: 'absolute', right: 4, top: 4, width: 20, height: 20, borderRadius: 10, alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgba(0,0,0,0.45)', }, imageProgressOverlay: { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.35)', alignItems: 'center', justifyContent: 'center', }, imageProgressText: { color: '#fff', fontWeight: '700', fontSize: 12, }, imageErrorOverlay: { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, backgroundColor: 'rgba(255,0,0,0.35)', alignItems: 'center', justifyContent: 'center', }, imageRetryBtn: { width: 24, height: 24, borderRadius: 12, alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgba(0,0,0,0.6)', }, inputRow: { flexDirection: 'row', alignItems: 'center', padding: 8, }, mediaBtn: { width: 40, height: 40, borderRadius: 12, alignItems: 'center', justifyContent: 'center', marginRight: 6, }, input: { flex: 1, fontSize: 15, maxHeight: 120, minHeight: 40, paddingHorizontal: 8, paddingVertical: 6, textAlignVertical: 'center', }, sendBtn: { width: 40, height: 40, borderRadius: 20, alignItems: 'center', justifyContent: 'center', }, }); export default ChatComposer;