/** * 聊天输入框组件 * 支持响应式布局(宽屏下居中显示) */ import React, { useMemo } from 'react'; import { View, TouchableOpacity, TextInput, ActivityIndicator, ScrollView, StyleSheet, Image as RNImage } from 'react-native'; import { MaterialCommunityIcons } from '@expo/vector-icons'; import { Text } from '../../../../components/common'; import { useAppColors } from '../../../../theme'; import { useChatScreenStyles } from './styles'; import { useBreakpointGTE } from '../../../../hooks/useResponsive'; import { ChatInputProps, GroupMessage, SenderInfo } from './types'; import { extractTextFromSegments } from '../../../../types/dto'; export const ChatInput: React.FC SenderInfo; }> = ({ inputText, onInputChange, onSend, onToggleEmoji, onToggleMore, activePanel, isComposerBusy, isMuted, isGroupChat, muteAll, replyingTo, onCancelReply, onFocus, restrictionHint, disableMore = false, pendingAttachments = [], onRemovePendingAttachment, currentUser, otherUser, getSenderInfo, }) => { const colors = useAppColors(); const styles = useChatScreenStyles(); const isDisabled = isGroupChat && isMuted; // 获取当前用户ID const currentUserId = currentUser?.id || ''; // 响应式布局 const isWideScreen = useBreakpointGTE('lg'); const inputContainerStyle = useMemo(() => ([ styles.inputContainer, isWideScreen ? { maxWidth: 900, alignSelf: 'center' as const, width: '100%' as const } : null, ]), [isWideScreen, styles.inputContainer]); const canSend = (!!inputText.trim() || pendingAttachments.length > 0) && !isComposerBusy && !isDisabled; // 回复预览组件 - 定义在内部以访问 styles const ReplyPreview: React.FC<{ replyingTo: GroupMessage; onCancel: () => void; }> = ({ replyingTo, onCancel }) => { const senderInfo = replyingTo.sender_id === currentUserId ? { nickname: '我', avatar: currentUser?.avatar } : isGroupChat ? getSenderInfo(replyingTo.sender_id) : { nickname: otherUser?.nickname || '对方', avatar: otherUser?.avatar }; return ( 回复 {senderInfo.nickname} {(() => { const segs = replyingTo.segments; const imgCount = segs?.filter(seg => seg.type === 'image').length ?? 0; const raw = extractTextFromSegments(segs); if (imgCount > 1) { const textPart = raw.replace(/\[图片\]/g, '').replace(/\s+/g, ' ').trim(); return textPart ? `${textPart} [${imgCount}张图片]` : `[${imgCount}张图片]`; } return raw; })()} ); }; return ( {/* 回复预览 */} {replyingTo && ( )} {/* 禁言提示 */} {isGroupChat && isMuted && ( {muteAll ? '全员禁言中,暂无法发送消息' : '你已被禁言,暂无法发送消息'} )} {!!restrictionHint && ( {restrictionHint} )} {pendingAttachments.length > 0 && ( {pendingAttachments.map(item => ( {!isDisabled && onRemovePendingAttachment ? ( onRemovePendingAttachment(item.id)} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }} > ) : null} ))} )} {canSend ? ( ) : isComposerBusy && !isDisabled ? ( ) : ( )} ); }; const attachmentStyles = StyleSheet.create({ stripScroll: { maxHeight: 88, marginBottom: 6, paddingHorizontal: 4, }, stripContent: { flexDirection: 'row', alignItems: 'center', paddingVertical: 4, }, thumbWrap: { position: 'relative', marginRight: 8, }, thumb: { width: 72, height: 72, borderRadius: 10, backgroundColor: '#E8EAED', }, removeBtn: { position: 'absolute', top: -6, right: -6, backgroundColor: '#FFF', borderRadius: 12, }, }); export default ChatInput;