TriloopTem_App/app/(tabs)/control.tsx
2026-06-06 22:13:00 +08:00

151 lines
5.1 KiB
TypeScript

import React, { useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, ScrollView, ActivityIndicator } from 'react-native';
import { router } from 'expo-router';
import { DeviceStatusBar } from '../../src/components/DeviceStatusBar';
import { ParamForm } from '../../src/components/ParamForm';
import { useDevice } from '../../src/hooks/useDevice';
import { useDeviceStore } from '../../src/stores/deviceStore';
import { useDataStore } from '../../src/stores/dataStore';
export default function ControlScreen() {
const { busy, connected, deviceStatus, setup, startContinuous, startSingle, stop } = useDevice();
const frame = useDataStore((s) => s.currentFrame);
const [configDirty, setConfigDirty] = useState(false);
const handleSetup = async () => {
await setup();
setConfigDirty(false);
};
if (!connected) {
return (
<View style={styles.notConnected}>
<Text style={styles.notConnectedText}></Text>
<TouchableOpacity style={styles.connectBtn} onPress={() => router.replace('/connect')}>
<Text style={styles.connectBtnText}></Text>
</TouchableOpacity>
</View>
);
}
const running = deviceStatus === 'running';
const canStart = !running && !busy;
const canStop = (running || deviceStatus === 'single') && !busy;
return (
<View style={styles.container}>
<DeviceStatusBar />
{/* Control buttons */}
<View style={styles.ctrlRow}>
<TouchableOpacity
style={[styles.ctrlBtn, styles.btnStart, !canStart && styles.btnDisabled]}
onPress={startContinuous}
disabled={!canStart}
>
{busy ? <ActivityIndicator color="#fff" size="small" /> : <Text style={styles.ctrlText}></Text>}
</TouchableOpacity>
<TouchableOpacity
style={[styles.ctrlBtn, styles.btnSingle, !canStart && styles.btnDisabled]}
onPress={startSingle}
disabled={!canStart}
>
<Text style={styles.ctrlText}></Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.ctrlBtn, styles.btnStop, !canStop && styles.btnDisabled]}
onPress={stop}
disabled={!canStop}
>
<Text style={styles.ctrlText}></Text>
</TouchableOpacity>
</View>
{/* Last frame info */}
{frame && (
<View style={styles.frameInfo}>
<Text style={styles.frameText}>
#{frame.frameId} {frame.meta ? frame.accNum : '--'} {frame.meta?.channelNum ?? '-'}
</Text>
<Text style={styles.frameText}>
: {frame.meta?.current ?? '--'} : {frame.meta?.temperature ?? '--'}
</Text>
</View>
)}
{/* Param form */}
<ScrollView style={styles.formScroll} keyboardShouldPersistTaps="handled">
<View style={styles.formHeader}>
<Text style={styles.formTitle}></Text>
{configDirty && <Text style={styles.dirtyBadge}></Text>}
</View>
<ParamForm onAnyChange={() => setConfigDirty(true)} />
<TouchableOpacity
style={[styles.setupBtn, busy && styles.btnDisabled]}
onPress={handleSetup}
disabled={busy}
>
{busy ? <ActivityIndicator color="#fff" /> : <Text style={styles.setupBtnText}> </Text>}
</TouchableOpacity>
<View style={{ height: 24 }} />
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#0d0d0d' },
notConnected: { flex: 1, justifyContent: 'center', alignItems: 'center', gap: 16, backgroundColor: '#0d0d0d' },
notConnectedText: { color: '#666', fontSize: 16 },
connectBtn: { backgroundColor: '#4a9eff', borderRadius: 8, paddingVertical: 10, paddingHorizontal: 24 },
connectBtnText: { color: '#fff', fontWeight: '600' },
ctrlRow: { flexDirection: 'row', gap: 10, padding: 12 },
ctrlBtn: {
flex: 1,
paddingVertical: 12,
borderRadius: 8,
alignItems: 'center',
justifyContent: 'center',
},
btnStart: { backgroundColor: '#1a5c2a' },
btnSingle: { backgroundColor: '#1a3a5c' },
btnStop: { backgroundColor: '#5c1a1a' },
btnDisabled: { opacity: 0.4 },
ctrlText: { color: '#fff', fontWeight: '700', fontSize: 14 },
frameInfo: {
marginHorizontal: 12,
backgroundColor: '#181818',
borderRadius: 8,
padding: 8,
marginBottom: 8,
},
frameText: { color: '#888', fontSize: 11, fontFamily: 'monospace' },
formScroll: { flex: 1 },
formHeader: {
flexDirection: 'row',
alignItems: 'center',
gap: 10,
paddingHorizontal: 14,
paddingVertical: 8,
},
formTitle: { color: '#4a9eff', fontSize: 13, fontWeight: '600' },
dirtyBadge: {
backgroundColor: '#5c3a0a',
color: '#ffaa00',
fontSize: 10,
paddingHorizontal: 6,
paddingVertical: 2,
borderRadius: 4,
},
setupBtn: {
margin: 14,
backgroundColor: '#4a9eff',
borderRadius: 10,
paddingVertical: 12,
alignItems: 'center',
},
setupBtnText: { color: '#fff', fontWeight: '700', fontSize: 15, letterSpacing: 2 },
});