import { useEffect, useRef } from 'react'; import { useWindowDimensions, View } from 'react-native'; import { ConnectionBanner } from '@/components/ConnectionBanner'; import { ThemedView } from '@/components/ThemedView'; import { colors } from '@/theme/colors'; import { spacing } from '@/theme/spacing'; import { usePoseStream } from '@/hooks/usePoseStream'; import { useMatStore } from '@/stores/matStore'; import { type ConnectionStatus } from '@/types/sensing'; import { Alert, type Survivor } from '@/types/mat'; import { AlertList } from './AlertList'; import { MatWebView } from './MatWebView'; import { SurvivorCounter } from './SurvivorCounter'; import { useMatBridge } from './useMatBridge'; const isAlert = (value: unknown): value is Alert => { if (!value || typeof value !== 'object') { return false; } const record = value as Record; return typeof record.id === 'string' && typeof record.message === 'string'; }; const isSurvivor = (value: unknown): value is Survivor => { if (!value || typeof value !== 'object') { return false; } const record = value as Record; return typeof record.id === 'string' && typeof record.zone_id === 'string'; }; const resolveBannerState = (status: ConnectionStatus): 'connected' | 'simulated' | 'disconnected' => { if (status === 'connecting') { return 'disconnected'; } return status; }; export const MATScreen = () => { const { connectionStatus, lastFrame } = usePoseStream(); const { survivors, alerts, upsertSurvivor, addAlert, upsertEvent } = useMatStore((state) => ({ survivors: state.survivors, alerts: state.alerts, upsertSurvivor: state.upsertSurvivor, addAlert: state.addAlert, upsertEvent: state.upsertEvent, })); const { webViewRef, ready, onMessage, sendFrameUpdate, postEvent } = useMatBridge({ onSurvivorDetected: (survivor) => { if (isSurvivor(survivor)) { upsertSurvivor(survivor); } }, onAlertGenerated: (alert) => { if (isAlert(alert)) { addAlert(alert); } }, }); const seededRef = useRef(false); useEffect(() => { if (!ready || seededRef.current) { return; } const createEvent = postEvent('CREATE_EVENT'); createEvent({ type: 'earthquake', latitude: 37.7749, longitude: -122.4194, name: 'Training Scenario', }); const addZone = postEvent('ADD_ZONE'); addZone({ name: 'Zone A', zone_type: 'rectangle', x: 60, y: 60, width: 180, height: 120, }); addZone({ name: 'Zone B', zone_type: 'circle', center_x: 300, center_y: 170, radius: 60, }); upsertEvent({ event_id: 'training-scenario', disaster_type: 1, latitude: 37.7749, longitude: -122.4194, description: 'Training Scenario', }); seededRef.current = true; }, [postEvent, upsertEvent, ready]); useEffect(() => { if (ready && lastFrame) { sendFrameUpdate(lastFrame); } }, [lastFrame, ready, sendFrameUpdate]); const { height } = useWindowDimensions(); const webHeight = Math.max(240, Math.floor(height * 0.5)); return ( ); }; export default MATScreen;