281 lines
10 KiB
TypeScript
281 lines
10 KiB
TypeScript
import React from 'react';
|
|
import {StyleSheet, Button} from 'react-native';
|
|
import {ThemedText} from '@/components/themed-text';
|
|
import {ThemedView} from '@/components/themed-view';
|
|
import {BLE_UUIDS, PROTOCOL_VERSION, useBleExplorer} from '@/ble';
|
|
import ParallaxScrollView from '@/components/parallax-scroll-view';
|
|
import {IconSymbol} from '@/components/ui/icon-symbol';
|
|
|
|
|
|
export default function TabTwoScreen() {
|
|
const {
|
|
isScanning,
|
|
isConnected,
|
|
connectedDevice,
|
|
deviceInfo,
|
|
version,
|
|
isActivated,
|
|
transferProgress,
|
|
discoveredDevices,
|
|
loading,
|
|
error,
|
|
startScan,
|
|
stopScan,
|
|
connectToDevice,
|
|
disconnectDevice,
|
|
queryActivationStatus,
|
|
queryDeviceVersion,
|
|
requestDeviceInfo,
|
|
updateActivationTime,
|
|
sendIdentityCheck,
|
|
transferMedia,
|
|
} = useBleExplorer();
|
|
|
|
|
|
return (
|
|
<ParallaxScrollView
|
|
headerBackgroundColor={{light: '#D0D0D0', dark: '#353636'}}
|
|
headerImage={
|
|
<IconSymbol
|
|
size={310}
|
|
color="#808080"
|
|
name="paperplane.fill"
|
|
style={styles.headerImage}
|
|
/>
|
|
}>
|
|
<ThemedView style={styles.titleContainer}>
|
|
<ThemedText type="title">BLE Explorer</ThemedText>
|
|
</ThemedView>
|
|
|
|
{/* Connection Status */}
|
|
<ThemedView style={styles.section}>
|
|
<ThemedText type="subtitle">Connection Status</ThemedText>
|
|
<ThemedText>Scanning: {isScanning ? 'Yes' : 'No'}</ThemedText>
|
|
<ThemedText>Connected: {isConnected ? 'Yes' : 'No'}</ThemedText>
|
|
<ThemedText>Device: {connectedDevice?.name || 'None'}</ThemedText>
|
|
{error && <ThemedText style={styles.errorText}>Error: {error}</ThemedText>}
|
|
</ThemedView>
|
|
|
|
{/* Discovered Devices */}
|
|
<ThemedView style={styles.section}>
|
|
<ThemedText type="subtitle">Discovered Devices</ThemedText>
|
|
<ThemedText style={styles.deviceCount}>Total devices
|
|
found: {discoveredDevices.length}</ThemedText>
|
|
{discoveredDevices.length === 0 ? (
|
|
<ThemedText>No devices discovered yet. Start scanning to find devices.</ThemedText>
|
|
) : (
|
|
<ThemedView style={{gap: 8}}>
|
|
{discoveredDevices.map((item) => (
|
|
<ThemedView
|
|
key={item.id}
|
|
style={[styles.deviceItem, item.connected && styles.connectedDevice]}
|
|
lightColor="#eee"
|
|
darkColor="#2a2a2a"
|
|
>
|
|
<ThemedView style={styles.deviceInfo} lightColor="transparent"
|
|
darkColor="transparent">
|
|
<ThemedText style={item.connected && styles.connectedDeviceText}>
|
|
{item.name || 'Unknown Device'}
|
|
</ThemedText>
|
|
<ThemedText style={styles.deviceId}>{item.id}</ThemedText>
|
|
{item.serviceUUIDs && item.serviceUUIDs.length > 0 && (
|
|
<ThemedText style={styles.serviceUuids}>
|
|
Services: {item.serviceUUIDs.join(', ')}
|
|
</ThemedText>
|
|
)}
|
|
{item.connected && (
|
|
<ThemedText style={styles.connectionStatus}>Connected</ThemedText>
|
|
)}
|
|
</ThemedView>
|
|
<Button
|
|
title={loading.connecting ? 'Connecting...' : (item.connected ? 'Connected' : 'Connect')}
|
|
onPress={() => connectToDevice(item)}
|
|
disabled={isConnected || loading.connecting || item.connected}
|
|
/>
|
|
</ThemedView>
|
|
))}
|
|
</ThemedView>
|
|
)}
|
|
</ThemedView>
|
|
|
|
{/* Device Info */}
|
|
<ThemedView style={styles.section}>
|
|
<ThemedText type="subtitle">Device Information</ThemedText>
|
|
<ThemedText>Activated: {isActivated ? 'Yes' : 'No'}</ThemedText>
|
|
<ThemedText>Version: {version || 'Unknown'}</ThemedText>
|
|
{deviceInfo && (
|
|
<>
|
|
<ThemedText>Name: {deviceInfo.devname}</ThemedText>
|
|
<ThemedText>Total Space: {deviceInfo.allspace} KB</ThemedText>
|
|
<ThemedText>Free Space: {deviceInfo.freespace} KB</ThemedText>
|
|
<ThemedText>Brand: {deviceInfo.brand}</ThemedText>
|
|
</>
|
|
)}
|
|
</ThemedView>
|
|
|
|
{/* Transfer Status */}
|
|
<ThemedView style={styles.section}>
|
|
<ThemedText type="subtitle">File Transfer</ThemedText>
|
|
<ThemedText>Converting: {loading.converting ? 'Yes' : 'No'}</ThemedText>
|
|
<ThemedText>Transferring: {loading.transferring ? 'Yes' : 'No'}</ThemedText>
|
|
<ThemedText>Progress: {transferProgress}%</ThemedText>
|
|
</ThemedView>
|
|
|
|
{/* Control Buttons */}
|
|
<ThemedView style={styles.section}>
|
|
<ThemedText type="subtitle">Controls</ThemedText>
|
|
<ThemedView style={styles.buttonRow}>
|
|
<Button title={isScanning ? 'Stop Scan' : 'Start Scan'}
|
|
onPress={isScanning ? stopScan : startScan}/>
|
|
<Button
|
|
title="Disconnect"
|
|
onPress={disconnectDevice}
|
|
disabled={!isConnected}
|
|
/>
|
|
</ThemedView>
|
|
|
|
<ThemedView style={styles.buttonRow}>
|
|
<Button
|
|
title={loading.querying ? 'Querying...' : 'Query Activation'}
|
|
onPress={queryActivationStatus}
|
|
disabled={!isConnected || loading.querying}
|
|
/>
|
|
<Button title={loading.querying ? 'Querying...' : 'Query Version'}
|
|
onPress={queryDeviceVersion} disabled={!isConnected || loading.querying}/>
|
|
</ThemedView>
|
|
|
|
<ThemedView style={styles.buttonRow}>
|
|
<Button
|
|
title={loading.querying ? 'Querying...' : 'Device Info'}
|
|
onPress={requestDeviceInfo}
|
|
disabled={!isConnected || loading.querying}
|
|
/>
|
|
<Button title="Update Time" onPress={updateActivationTime} disabled={!isConnected}/>
|
|
</ThemedView>
|
|
|
|
<ThemedView style={styles.buttonRow}>
|
|
<Button title="Identity Check (Valid)" onPress={() => sendIdentityCheck()}
|
|
disabled={!isConnected}/>
|
|
<Button title="Identity Check (Invalid)" onPress={() => sendIdentityCheck()}
|
|
disabled={!isConnected}/>
|
|
</ThemedView>
|
|
|
|
<ThemedView style={styles.buttonRow}>
|
|
<Button
|
|
title={loading.transferring ? 'Transferring...' : 'Transfer File'}
|
|
onPress={transferMedia}
|
|
disabled={!isConnected || loading.transferring}
|
|
/>
|
|
</ThemedView>
|
|
</ThemedView>
|
|
|
|
{/* Protocol Info - Available in both modes */}
|
|
<ThemedView style={styles.section}>
|
|
<ThemedText type="subtitle">Protocol Information</ThemedText>
|
|
<ThemedText>Version: {PROTOCOL_VERSION}</ThemedText>
|
|
<ThemedText>Service UUID: {BLE_UUIDS.SERVICE}</ThemedText>
|
|
<ThemedText>Write UUID: {BLE_UUIDS.WRITE_CHARACTERISTIC}</ThemedText>
|
|
<ThemedText>Read UUID: {BLE_UUIDS.READ_CHARACTERISTIC}</ThemedText>
|
|
</ThemedView>
|
|
</ParallaxScrollView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
headerImage: {
|
|
color: '#808080',
|
|
bottom: -90,
|
|
left: -35,
|
|
position: 'absolute',
|
|
},
|
|
titleContainer: {
|
|
flexDirection: 'row',
|
|
gap: 8,
|
|
},
|
|
section: {
|
|
gap: 8,
|
|
marginBottom: 8,
|
|
},
|
|
buttonRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
marginBottom: 8,
|
|
gap: 8,
|
|
},
|
|
logHeader: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
marginBottom: 8,
|
|
},
|
|
logContainer: {
|
|
maxHeight: 200,
|
|
padding: 8,
|
|
borderRadius: 4,
|
|
},
|
|
logText: {
|
|
fontSize: 12,
|
|
marginBottom: 2,
|
|
},
|
|
deviceItem: {
|
|
padding: 12,
|
|
marginBottom: 8,
|
|
borderRadius: 8,
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
},
|
|
deviceInfo: {
|
|
flex: 1,
|
|
marginRight: 12,
|
|
},
|
|
deviceId: {
|
|
fontSize: 12,
|
|
opacity: 0.7,
|
|
},
|
|
deviceCount: {
|
|
fontSize: 14,
|
|
opacity: 0.8,
|
|
marginTop: 4,
|
|
marginBottom: 8,
|
|
fontWeight: '500',
|
|
},
|
|
serviceUuids: {
|
|
fontSize: 11,
|
|
opacity: 0.6,
|
|
marginTop: 2,
|
|
fontStyle: 'italic',
|
|
},
|
|
connectionStatus: {
|
|
fontSize: 12,
|
|
fontWeight: 'bold',
|
|
marginTop: 4,
|
|
},
|
|
connectedDevice: {
|
|
borderWidth: 1,
|
|
borderColor: '#4CAF50',
|
|
},
|
|
connectedDeviceText: {
|
|
fontWeight: 'bold',
|
|
},
|
|
errorText: {
|
|
marginTop: 8,
|
|
fontWeight: 'bold',
|
|
},
|
|
modeSwitchContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginVertical: 12,
|
|
},
|
|
modeLabel: {
|
|
fontSize: 16,
|
|
marginHorizontal: 8,
|
|
},
|
|
modeDescription: {
|
|
fontSize: 12,
|
|
opacity: 0.7,
|
|
marginTop: 8,
|
|
},
|
|
});
|