import { useThemeColor } from '@/hooks/useThemeColor'; import { ChatMessage } from '@/store/useAppStore'; import { Bot, User } from 'lucide-react-native'; import React, { useState } from 'react'; import { StyleSheet, Text, useWindowDimensions, View } from 'react-native'; import { MessageActions } from './MessageActions'; import { MessageContent } from './MessageContent'; interface MessageBubbleProps { message: ChatMessage; onEdit?: () => void; onRegenerate?: () => void; onDelete?: () => void; isStreaming?: boolean; isLastAssistant?: boolean; } function Avatar({ isUser }: { isUser: boolean }) { const colors = useThemeColor(); const Icon = isUser ? User : Bot; return ( ); } function BubbleRow({ message, showingStreaming }: { message: ChatMessage; showingStreaming: boolean }) { const { width } = useWindowDimensions(); const colors = useThemeColor(); const isUser = message.role === 'user'; const maxWidth = width > 768 ? '70%' : '85%'; return ( {!isUser && } {isUser && } ); } /** Timestamp + edited badge. */ function BubbleMeta({ message }: { message: ChatMessage }) { const colors = useThemeColor(); const isUser = message.role === 'user'; return ( {!isUser && } {new Date(message.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} {message.isEdited ? ' ยท edited' : ''} ); } export function MessageBubble({ message, onEdit, onRegenerate, onDelete, isStreaming, isLastAssistant, }: MessageBubbleProps) { const isUser = message.role === 'user'; const [showActions, setShowActions] = useState(false); const showingStreaming = !!isStreaming && !!isLastAssistant; const actionsVisible = (!isUser || showActions) && message.content.length > 0; return ( isUser && setShowActions(true)} style={styles.outerWrap} > {actionsVisible && ( )} ); } const styles = StyleSheet.create({ outerWrap: { width: '100%', marginBottom: 12, }, container: { width: '100%', paddingHorizontal: 16, flexDirection: 'row', alignItems: 'flex-end', gap: 8, }, containerUser: { justifyContent: 'flex-end', }, containerAssistant: { justifyContent: 'flex-start', }, avatar: { width: 32, height: 32, borderRadius: 16, alignItems: 'center', justifyContent: 'center', marginBottom: 2, }, bubble: { paddingHorizontal: 16, paddingVertical: 12, borderRadius: 20, // CRITICAL FOR MARKDOWN IN FLEX ROW: flexShrink: 1, }, bubbleUser: { borderBottomRightRadius: 6, }, bubbleAssistant: { borderBottomLeftRadius: 6, }, metaRow: { flexDirection: 'row', paddingHorizontal: 16, marginTop: 4, gap: 8, }, metaRowUser: { justifyContent: 'flex-end', paddingRight: 56, }, metaRowAssistant: { justifyContent: 'flex-start', }, timestamp: { fontSize: 11, fontWeight: '500', }, });