import React, { useState, useEffect, useRef } from 'react'; import { View, Text, TextInput, TouchableOpacity, StyleSheet, ScrollView, Linking, ActivityIndicator, KeyboardAvoidingView, Platform, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { router } from 'expo-router'; import { useConnectionStore } from '../src/stores/connectionStore'; import { useDevice } from '../src/hooks/useDevice'; const LOG_MAX = 60; export default function ConnectScreen() { const { host, port, status, lastError, setHost, setPort } = useConnectionStore(); const { connect, disconnect } = useDevice(); const [logs, setLogs] = useState(['Ready.']); const [portStr, setPortStr] = useState(String(port)); const prevStatusRef = useRef(status); const addLog = (msg: string) => { setLogs((prev) => [`[${new Date().toLocaleTimeString()}] ${msg}`, ...prev].slice(0, LOG_MAX)); }; useEffect(() => { const prev = prevStatusRef.current; prevStatusRef.current = status; if (status === prev) return; if (status === 'connected') { addLog('连接成功 ✓'); router.push('/(tabs)/control'); } else if (status === 'error') { addLog(`错误: ${lastError}`); } else if (status === 'reconnecting') { addLog('断线,正在重连...'); } }, [status, lastError]); const handleConnect = () => { const p = parseInt(portStr, 10); if (!host || isNaN(p)) { addLog('请检查 IP 和端口'); return; } setPort(p); addLog(`正在连接 ${host}:${p} ...`); connect(); }; const handleDisconnect = () => { disconnect(); addLog('已断开连接'); }; const isConnecting = status === 'connecting' || status === 'reconnecting'; const isConnected = status === 'connected'; return ( {/* ── Brand ── */} TEM Receiver 瞬变电磁接收机上位机 {/* ── Setup guide ── */} 连接步骤 1 手机连接设备 WiFi 热点 Linking.openSettings()}> 设置 → 2 确认参数,点击连接 {/* ── Inputs ── */} 连接参数 IP 地址 端 口 {/* ── Action ── */} {!isConnected ? ( {isConnecting ? : 连 接 设 备} ) : ( 已连接 router.push('/(tabs)/control')} activeOpacity={0.8}> 进入控制台 → 断开 )} {/* ── Log terminal ── */} ● 连接日志 {logs.map((l, i) => ( {l} ))} ); } const S = StyleSheet.create({ safe: { flex: 1, backgroundColor: '#090912' }, flex: { flex: 1 }, scroll: { flex: 1 }, scrollContent: { padding: 20, paddingBottom: 40 }, // Brand brand: { alignItems: 'center', marginBottom: 28, marginTop: 8 }, brandIcon: { fontSize: 36, color: '#4a9eff', marginBottom: 8 }, title: { color: '#e4e4f0', fontSize: 26, fontWeight: '700', letterSpacing: 1 }, subtitle: { color: '#4a4a6a', fontSize: 12, marginTop: 4, letterSpacing: 0.5 }, // Card card: { backgroundColor: '#111120', borderRadius: 14, borderWidth: 1, borderColor: '#22223a', padding: 16, marginBottom: 12, }, cardLabel: { color: '#4a4a6a', fontSize: 10, fontWeight: '600', letterSpacing: 1.5, marginBottom: 12, textTransform: 'uppercase' }, // Steps stepRow: { flexDirection: 'row', alignItems: 'center', gap: 10, marginBottom: 8 }, stepBadge: { width: 20, height: 20, borderRadius: 10, backgroundColor: '#1a2a44', justifyContent: 'center', alignItems: 'center' }, stepNum: { color: '#4a9eff', fontSize: 11, fontWeight: '700' }, stepText: { color: '#8888aa', fontSize: 13, flex: 1 }, linkBtn: { backgroundColor: '#0d2040', borderRadius: 6, paddingHorizontal: 10, paddingVertical: 4, borderWidth: 1, borderColor: '#1a3a66' }, linkBtnText: { color: '#4a9eff', fontSize: 11, fontWeight: '600' }, // Inputs inputRow: { flexDirection: 'row', alignItems: 'center', gap: 12 }, inputDivider: { height: StyleSheet.hairlineWidth, backgroundColor: '#1e1e30', marginVertical: 10 }, inputLabel: { color: '#5a5a7a', fontSize: 12, width: 54, letterSpacing: 0.3 }, input: { flex: 1, color: '#d0d0e8', fontSize: 15, fontWeight: '500', paddingVertical: 6, borderBottomWidth: 1, borderBottomColor: '#2a2a48', }, // Connect button connectBtn: { backgroundColor: '#1a3a6e', borderRadius: 14, paddingVertical: 16, alignItems: 'center', marginBottom: 12, borderWidth: 1, borderColor: '#4a9eff', marginTop: 4, }, connectBtnBusy: { borderColor: '#2a4a7a', backgroundColor: '#0f1f3a' }, connectBtnText: { color: '#4a9eff', fontSize: 16, fontWeight: '700', letterSpacing: 3 }, // Connected state connectedBox: { flexDirection: 'row', alignItems: 'center', gap: 10, marginBottom: 12, marginTop: 4 }, connectedLeft: { flexDirection: 'row', alignItems: 'center', gap: 6 }, greenDot: { width: 8, height: 8, borderRadius: 4, backgroundColor: '#3ddc84' }, connectedText: { color: '#3ddc84', fontWeight: '700', fontSize: 13 }, goBtn: { flex: 1, backgroundColor: '#0d2820', borderRadius: 10, paddingVertical: 11, alignItems: 'center', borderWidth: 1, borderColor: '#1a4a30' }, goBtnText: { color: '#3ddc84', fontWeight: '600', fontSize: 13 }, disconnectBtn: { backgroundColor: '#2a0d12', borderRadius: 10, paddingVertical: 11, paddingHorizontal: 14, borderWidth: 1, borderColor: '#4a1a22' }, disconnectBtnText: { color: '#ff5c6e', fontSize: 13, fontWeight: '600' }, // Terminal log terminal: { backgroundColor: '#08080f', borderRadius: 12, borderWidth: 1, borderColor: '#1a1a28', overflow: 'hidden', minHeight: 120 }, terminalHeader: { color: '#3ddc84', fontSize: 10, fontWeight: '700', letterSpacing: 1.5, paddingHorizontal: 14, paddingTop: 10, paddingBottom: 6, borderBottomWidth: 1, borderBottomColor: '#141422' }, terminalBody: { padding: 12 }, terminalLine: { color: '#3a3a5a', fontSize: 10, fontFamily: Platform.OS === 'ios' ? 'Courier' : 'monospace', marginBottom: 3, lineHeight: 16 }, terminalLineLatest: { color: '#6a6a9a' }, });