/** * Messages screen — список чатов в стиле референса. * * ┌ safe-area top * │ TabHeader (title зависит от connection state) * │ ─ FlatList (chat tiles) ─ * └ NavBar (external) * * Фильтры и search убраны — лист один поток; requests доступны через * NavBar → notifications tab. FAB composer'а тоже убран (чат-лист * просто отражает существующие беседы, создание новых — через tab * "New chat" в NavBar'е). */ import React, { useMemo } from 'react'; import { View, Text, FlatList } from 'react-native'; import { router } from 'expo-router'; import { Ionicons } from '@expo/vector-icons'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useStore } from '@/lib/store'; import { useConnectionStatus } from '@/hooks/useConnectionStatus'; import type { Contact, Message } from '@/lib/types'; import { TabHeader } from '@/components/TabHeader'; import { ChatTile } from '@/components/ChatTile'; export default function ChatsScreen() { const insets = useSafeAreaInsets(); const contacts = useStore(s => s.contacts); const messages = useStore(s => s.messages); const keyFile = useStore(s => s.keyFile); // Статус подключения: online / connecting / offline. // Название шапки и цвет pip'а на аватаре зависят от него. const connStatus = useConnectionStatus(); const headerTitle = connStatus === 'online' ? 'Messages' : connStatus === 'connecting' ? 'Connecting…' : 'Waiting for internet'; const dotColor = connStatus === 'online' ? '#3ba55d' : // green connStatus === 'connecting' ? '#f0b35a' : // amber '#f4212e'; // red const lastOf = (c: Contact): Message | null => { const msgs = messages[c.address]; return msgs && msgs.length ? msgs[msgs.length - 1] : null; }; // Сортировка по последней активности. Saved Messages (self-chat) всегда // закреплён сверху — это "Избранное", бессмысленно конкурировать с ним // по recency'и обычным чатам. const selfAddr = keyFile?.pub_key; const sorted = useMemo(() => { const saved = selfAddr ? contacts.find(c => c.address === selfAddr) : undefined; const rest = contacts .filter(c => c.address !== selfAddr) .map(c => ({ c, last: lastOf(c) })) .sort((a, b) => { const ka = a.last ? a.last.timestamp : a.c.addedAt / 1000; const kb = b.last ? b.last.timestamp : b.c.addedAt / 1000; return kb - ka; }) .map(x => x.c); return saved ? [saved, ...rest] : rest; }, [contacts, messages, selfAddr]); return ( c.address} renderItem={({ item }) => ( router.push(`/(app)/chats/${item.address}` as never)} /> )} contentContainerStyle={{ paddingBottom: 40, flexGrow: 1 }} showsVerticalScrollIndicator={false} /> {sorted.length === 0 && ( No chats yet Use the search tab in the navbar to add your first contact. )} ); }