/** * Main app tab layout. * Redirects to welcome if no key found. */ import React, { useEffect } from 'react'; import { Tabs, router } from 'expo-router'; import { Ionicons } from '@expo/vector-icons'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useStore } from '@/lib/store'; import { useBalance } from '@/hooks/useBalance'; import { useContacts } from '@/hooks/useContacts'; import { useWellKnownContracts } from '@/hooks/useWellKnownContracts'; import { getWSClient } from '@/lib/ws'; const C_ACCENT = '#7db5ff'; const C_MUTED = '#98a7c2'; const C_BG = '#111a2b'; const C_BORDER = '#1c2840'; export default function AppLayout() { const keyFile = useStore(s => s.keyFile); const requests = useStore(s => s.requests); const insets = useSafeAreaInsets(); useBalance(); useContacts(); useWellKnownContracts(); // auto-discover canonical system contracts from node // Arm the WS client with this user's Ed25519 keypair. The client signs the // server's auth nonce on every (re)connect so scoped subscriptions // (addr:, inbox:) are accepted. Without this the // server would still accept global topic subs but reject scoped ones. useEffect(() => { const ws = getWSClient(); if (keyFile) { ws.setAuthCreds({ pubKey: keyFile.pub_key, privKey: keyFile.priv_key }); } else { ws.setAuthCreds(null); } }, [keyFile]); useEffect(() => { if (keyFile === null) { const t = setTimeout(() => { if (!useStore.getState().keyFile) router.replace('/'); }, 300); return () => clearTimeout(t); } }, [keyFile]); // Tab bar layout math: // icon (22) + gap (4) + label (~13) = ~39px of content // We add a 12px visual margin above, and pad the bottom by the larger of // the platform safe-area inset or 10px so the bar never sits flush on the // home indicator. const BAR_CONTENT_HEIGHT = 52; const bottomPad = Math.max(insets.bottom, 10); return ( ( ), tabBarBadge: requests.length > 0 ? requests.length : undefined, tabBarBadgeStyle: { backgroundColor: C_ACCENT, fontSize: 10 }, }} /> ( ), }} /> ( ), }} /> {/* Non-tab screens — hidden from tab bar */} ); }