import React, { useCallback, useMemo } from "react"; import { ActivityIndicator, FlatList, View } from "react-native"; import { Message } from "../../types"; import { MessageBubble } from "./MessageBubble"; import { TypingIndicator } from "./TypingIndicator"; import { stopPlayback, playAudio } from "../../services/audio"; interface MessageListProps { messages: Message[]; isTyping?: boolean; onDeleteMessage?: (id: string) => void; onLoadMore?: () => void; hasMore?: boolean; } export function MessageList({ messages, isTyping, onDeleteMessage, onLoadMore, hasMore }: MessageListProps) { // Inverted FlatList renders bottom-up — newest messages at the bottom (visually), // which means we reverse the data so index 0 = newest = rendered at bottom. const invertedData = useMemo(() => [...messages].reverse(), [messages]); // Play from a voice message and auto-chain all consecutive assistant voice messages after it const handlePlayVoice = useCallback(async (messageId: string) => { const idx = messages.findIndex((m) => m.id === messageId); if (idx === -1) return; const chain: Message[] = []; for (let i = idx; i < messages.length; i++) { const m = messages[i]; if (m.role === "assistant" && m.type === "voice" && m.audioUri) { chain.push(m); } else if (i > idx) { break; } } if (chain.length === 0) return; await stopPlayback(); for (const m of chain) { playAudio(m.audioUri!); } }, [messages]); return ( item.id} renderItem={({ item }) => ( )} onEndReached={hasMore ? onLoadMore : undefined} onEndReachedThreshold={0.5} contentContainerStyle={{ paddingVertical: 12 }} showsVerticalScrollIndicator={false} ListHeaderComponent={ <> {isTyping && } } ListFooterComponent={ hasMore ? ( ) : null } /> ); }