import { MessageBubble } from '@/components/chat/MessageBubble'; import { TypingIndicator } from '@/components/chat/TypingIndicator'; import { ChatMessage } from '@/store/useAppStore'; import { findLastAssistantId, shouldShowTypingIndicator } from '@/utils/chatSelectors'; import React, { useEffect, useRef } from 'react'; import { FlatList, StyleSheet } from 'react-native'; import Animated, { FadeInDown } from 'react-native-reanimated'; interface MessageListProps { messages: ChatMessage[]; isStreaming: boolean; onEdit: (id: string) => void; onDelete: (id: string) => void; onRegenerate: () => void; } interface MessageRowProps { message: ChatMessage; delayed: boolean; isStreaming: boolean; isLastAssistant: boolean; onEdit: (id: string) => void; onDelete: (id: string) => void; onRegenerate: () => void; } // Memoized so that a streamed token only re-renders (and re-parses the Markdown of) // the message that changed, not the whole conversation. const MessageRow = React.memo(function MessageRow({ message, delayed, isStreaming, isLastAssistant, onEdit, onDelete, onRegenerate, }: MessageRowProps) { return ( onEdit(message.id)} onRegenerate={onRegenerate} onDelete={() => onDelete(message.id)} isStreaming={isStreaming} isLastAssistant={isLastAssistant} /> ); }); export function MessageList({ messages, isStreaming, onEdit, onDelete, onRegenerate }: MessageListProps) { const flatListRef = useRef(null); const lastAssistantId = findLastAssistantId(messages); const lastContentLength = messages[messages.length - 1]?.content?.length; useEffect(() => { if (messages.length > 0 && flatListRef.current) { setTimeout(() => { flatListRef.current?.scrollToEnd({ animated: !isStreaming }); }, 100); } }, [messages.length, lastContentLength, isStreaming]); return ( <> item.id} renderItem={({ item, index }) => ( messages.length - 4} isStreaming={isStreaming} isLastAssistant={item.id === lastAssistantId} onEdit={onEdit} onDelete={onDelete} onRegenerate={onRegenerate} /> )} contentContainerStyle={styles.listContent} /> {shouldShowTypingIndicator(messages, isStreaming) && } ); } const styles = StyleSheet.create({ listContent: { paddingTop: 16, paddingBottom: 24, }, });