import { ActivityIndicator, FlatList, Pressable, RefreshControl, Text, View, } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; import { toast } from "sonner-native"; import { toUserMessage } from "@/lib/errors"; import { particlePath } from "@/lib/particle-path"; import { useNetwork, useNetworks } from "@/hooks/use-networks"; import { useStreamParticles } from "@/hooks/use-stream-particles"; import type { RootStackScreenProps } from "@/navigation/types"; import { StreamCard } from "./StreamCard"; export function StreamListScreen({ route, navigation, }: RootStackScreenProps<"StreamList">) { const { networkId } = route.params; const network = useNetwork(networkId); // Re-fetching the network list is the closest stand-in for a hard refresh — // Firestore subscriptions are already realtime, so pull-to-refresh mainly // reassures the user and re-tries network metadata. const { refetch: refetchNetworks, isRefetching: isRefetchingNetworks } = useNetworks(); const path = particlePath(networkId, []); // v1: only show open streams. Closed streams are reachable on desktop — // an "Archived" surface is a follow-up (PRD §20). const { streams, isLoading, error } = useStreamParticles(path, { status: "open", }); return (
navigation.goBack()} /> {error ? ( ) : isLoading && streams.length === 0 ? ( ) : streams.length === 0 ? ( ) : ( s.id} contentContainerClassName="p-3 gap-2 pb-24" refreshControl={ refetchNetworks()} /> } renderItem={({ item }) => ( navigation.navigate("StreamView", { networkId, streamId: item.id, }) } /> )} /> )} { // Real compose flow lands in step 5. toast("New stream — coming soon"); }} /> ); } function Header({ title, onBack, }: { title: string; onBack: () => void; }) { return ( {title} ); } function LoadingState() { return ( ); } function EmptyState() { return ( No streams yet. Tap the button below to start one — voice, video, or text. ); } function ErrorState({ message }: { message: string }) { return ( {message} Streams reconnect automatically once the network is back. ); } function ComposeFab({ onPress }: { onPress: () => void }) { return ( + ); }