import { Pressable, StyleSheet, View } from 'react-native'; import { memo, useCallback, useState } from 'react'; import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'; import { StatusDot } from '@/components/StatusDot'; import { ModeBadge } from '@/components/ModeBadge'; import { ThemedText } from '@/components/ThemedText'; import { formatConfidence, formatRssi } from '@/utils/formatters'; import { colors, spacing } from '@/theme'; import type { ConnectionStatus } from '@/types/sensing'; type LiveMode = 'LIVE' | 'SIM' | 'RSSI'; type LiveHUDProps = { rssi?: number; connectionStatus: ConnectionStatus; fps: number; confidence: number; personCount: number; mode: LiveMode; }; const statusTextMap: Record = { connected: 'Connected', simulated: 'Simulated', connecting: 'Connecting', disconnected: 'Disconnected', }; const statusDotStatusMap: Record = { connected: 'connected', simulated: 'simulated', connecting: 'connecting', disconnected: 'disconnected', }; export const LiveHUD = memo( ({ rssi, connectionStatus, fps, confidence, personCount, mode }: LiveHUDProps) => { const [panelVisible, setPanelVisible] = useState(true); const panelAlpha = useSharedValue(1); const togglePanel = useCallback(() => { const next = !panelVisible; setPanelVisible(next); panelAlpha.value = withTiming(next ? 1 : 0, { duration: 220 }); }, [panelAlpha, panelVisible]); const animatedPanelStyle = useAnimatedStyle(() => ({ opacity: panelAlpha.value, })); const statusText = statusTextMap[connectionStatus]; return ( {/* App title */} WiFi-DensePose {/* Status + FPS */} {statusText} {fps > 0 && ( {fps} FPS )} {/* Bottom panel */} RSSI {formatRssi(rssi)} Confidence {formatConfidence(confidence)} People: {personCount} ); }, ); const styles = StyleSheet.create({ topLeft: { position: 'absolute', top: spacing.md, left: spacing.md, }, appTitle: { color: colors.textPrimary, }, topRight: { position: 'absolute', top: spacing.md, right: spacing.md, alignItems: 'flex-end', gap: 4, }, row: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, }, statusText: { color: colors.textPrimary, }, bottomPanel: { position: 'absolute', left: spacing.sm, right: spacing.sm, bottom: spacing.sm, minHeight: 72, borderRadius: 12, backgroundColor: 'rgba(10,14,26,0.72)', borderWidth: 1, borderColor: 'rgba(50,184,198,0.35)', paddingHorizontal: spacing.md, paddingVertical: spacing.sm, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, bottomCell: { flex: 1, alignItems: 'center', }, bottomCellRight: { flex: 1, alignItems: 'flex-end', }, bigValue: { color: colors.accent, marginTop: 2, marginBottom: 2, }, metaText: { color: colors.textPrimary, marginBottom: 4, }, }); LiveHUD.displayName = 'LiveHUD';