react-native-debug-toolkit 3.1.4 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/README.md +88 -65
  2. package/README.zh-CN.md +87 -64
  3. package/bin/debug-toolkit.js +10 -2
  4. package/lib/commonjs/core/initialize.js +5 -3
  5. package/lib/commonjs/core/initialize.js.map +1 -1
  6. package/lib/commonjs/features/devConnect/DevConnectQrScanner.js +146 -0
  7. package/lib/commonjs/features/devConnect/DevConnectQrScanner.js.map +1 -0
  8. package/lib/commonjs/features/devConnect/DevConnectTab.js +426 -0
  9. package/lib/commonjs/features/devConnect/DevConnectTab.js.map +1 -0
  10. package/lib/commonjs/features/devConnect/cameraKit.js +54 -0
  11. package/lib/commonjs/features/devConnect/cameraKit.js.map +1 -0
  12. package/lib/commonjs/features/devConnect/devConnectPreferences.js +35 -0
  13. package/lib/commonjs/features/devConnect/devConnectPreferences.js.map +1 -0
  14. package/lib/commonjs/features/devConnect/devConnectUtils.js +53 -0
  15. package/lib/commonjs/features/devConnect/devConnectUtils.js.map +1 -0
  16. package/lib/commonjs/features/devConnect/index.js +92 -0
  17. package/lib/commonjs/features/devConnect/index.js.map +1 -0
  18. package/lib/commonjs/features/devConnect/platformDetect.js +30 -0
  19. package/lib/commonjs/features/devConnect/platformDetect.js.map +1 -0
  20. package/lib/commonjs/features/devConnect/types.js +2 -0
  21. package/lib/commonjs/features/devConnect/types.js.map +1 -0
  22. package/lib/commonjs/features/network/NetworkLogTab.js +7 -3
  23. package/lib/commonjs/features/network/NetworkLogTab.js.map +1 -1
  24. package/lib/commonjs/index.js +7 -0
  25. package/lib/commonjs/index.js.map +1 -1
  26. package/lib/commonjs/ui/DebugView.js +1 -0
  27. package/lib/commonjs/ui/DebugView.js.map +1 -1
  28. package/lib/commonjs/ui/panel/DebugPanel.js +0 -25
  29. package/lib/commonjs/ui/panel/DebugPanel.js.map +1 -1
  30. package/lib/commonjs/utils/DaemonClient.js +25 -1
  31. package/lib/commonjs/utils/DaemonClient.js.map +1 -1
  32. package/lib/commonjs/utils/debugPreferences.js +2 -1
  33. package/lib/commonjs/utils/debugPreferences.js.map +1 -1
  34. package/lib/commonjs/utils/deviceReport.js +1 -0
  35. package/lib/commonjs/utils/deviceReport.js.map +1 -1
  36. package/lib/module/core/initialize.js +5 -3
  37. package/lib/module/core/initialize.js.map +1 -1
  38. package/lib/module/features/devConnect/DevConnectQrScanner.js +141 -0
  39. package/lib/module/features/devConnect/DevConnectQrScanner.js.map +1 -0
  40. package/lib/module/features/devConnect/DevConnectTab.js +421 -0
  41. package/lib/module/features/devConnect/DevConnectTab.js.map +1 -0
  42. package/lib/module/features/devConnect/cameraKit.js +49 -0
  43. package/lib/module/features/devConnect/cameraKit.js.map +1 -0
  44. package/lib/module/features/devConnect/devConnectPreferences.js +29 -0
  45. package/lib/module/features/devConnect/devConnectPreferences.js.map +1 -0
  46. package/lib/module/features/devConnect/devConnectUtils.js +47 -0
  47. package/lib/module/features/devConnect/devConnectUtils.js.map +1 -0
  48. package/lib/module/features/devConnect/index.js +52 -0
  49. package/lib/module/features/devConnect/index.js.map +1 -0
  50. package/lib/module/features/devConnect/platformDetect.js +26 -0
  51. package/lib/module/features/devConnect/platformDetect.js.map +1 -0
  52. package/lib/module/features/devConnect/types.js +2 -0
  53. package/lib/module/features/devConnect/types.js.map +1 -0
  54. package/lib/module/features/network/NetworkLogTab.js +7 -3
  55. package/lib/module/features/network/NetworkLogTab.js.map +1 -1
  56. package/lib/module/index.js +1 -1
  57. package/lib/module/index.js.map +1 -1
  58. package/lib/module/ui/DebugView.js +1 -0
  59. package/lib/module/ui/DebugView.js.map +1 -1
  60. package/lib/module/ui/panel/DebugPanel.js +1 -26
  61. package/lib/module/ui/panel/DebugPanel.js.map +1 -1
  62. package/lib/module/utils/DaemonClient.js +25 -1
  63. package/lib/module/utils/DaemonClient.js.map +1 -1
  64. package/lib/module/utils/debugPreferences.js +2 -1
  65. package/lib/module/utils/debugPreferences.js.map +1 -1
  66. package/lib/module/utils/deviceReport.js +1 -0
  67. package/lib/module/utils/deviceReport.js.map +1 -1
  68. package/lib/typescript/src/core/initialize.d.ts +1 -0
  69. package/lib/typescript/src/core/initialize.d.ts.map +1 -1
  70. package/lib/typescript/src/features/devConnect/DevConnectQrScanner.d.ts +9 -0
  71. package/lib/typescript/src/features/devConnect/DevConnectQrScanner.d.ts.map +1 -0
  72. package/lib/typescript/src/features/devConnect/DevConnectTab.d.ts +5 -0
  73. package/lib/typescript/src/features/devConnect/DevConnectTab.d.ts.map +1 -0
  74. package/lib/typescript/src/features/devConnect/cameraKit.d.ts +47 -0
  75. package/lib/typescript/src/features/devConnect/cameraKit.d.ts.map +1 -0
  76. package/lib/typescript/src/features/devConnect/devConnectPreferences.d.ts +7 -0
  77. package/lib/typescript/src/features/devConnect/devConnectPreferences.d.ts.map +1 -0
  78. package/lib/typescript/src/features/devConnect/devConnectUtils.d.ts +12 -0
  79. package/lib/typescript/src/features/devConnect/devConnectUtils.d.ts.map +1 -0
  80. package/lib/typescript/src/features/devConnect/index.d.ts +7 -0
  81. package/lib/typescript/src/features/devConnect/index.d.ts.map +1 -0
  82. package/lib/typescript/src/features/devConnect/platformDetect.d.ts +2 -0
  83. package/lib/typescript/src/features/devConnect/platformDetect.d.ts.map +1 -0
  84. package/lib/typescript/src/features/devConnect/types.d.ts +7 -0
  85. package/lib/typescript/src/features/devConnect/types.d.ts.map +1 -0
  86. package/lib/typescript/src/features/network/NetworkLogTab.d.ts.map +1 -1
  87. package/lib/typescript/src/index.d.ts +2 -0
  88. package/lib/typescript/src/index.d.ts.map +1 -1
  89. package/lib/typescript/src/types/feature.d.ts +1 -1
  90. package/lib/typescript/src/types/feature.d.ts.map +1 -1
  91. package/lib/typescript/src/ui/DebugView.d.ts.map +1 -1
  92. package/lib/typescript/src/ui/panel/DebugPanel.d.ts.map +1 -1
  93. package/lib/typescript/src/utils/DaemonClient.d.ts +1 -0
  94. package/lib/typescript/src/utils/DaemonClient.d.ts.map +1 -1
  95. package/lib/typescript/src/utils/debugPreferences.d.ts +1 -0
  96. package/lib/typescript/src/utils/debugPreferences.d.ts.map +1 -1
  97. package/lib/typescript/src/utils/deviceReport.d.ts +6 -0
  98. package/lib/typescript/src/utils/deviceReport.d.ts.map +1 -1
  99. package/node/daemon/src/console/console.html +166 -27
  100. package/node/daemon/src/store.js +45 -6
  101. package/package.json +15 -3
  102. package/src/core/initialize.ts +7 -1
  103. package/src/features/devConnect/DevConnectQrScanner.tsx +122 -0
  104. package/src/features/devConnect/DevConnectTab.tsx +357 -0
  105. package/src/features/devConnect/cameraKit.ts +93 -0
  106. package/src/features/devConnect/devConnectPreferences.ts +33 -0
  107. package/src/features/devConnect/devConnectUtils.ts +59 -0
  108. package/src/features/devConnect/index.ts +64 -0
  109. package/src/features/devConnect/platformDetect.ts +26 -0
  110. package/src/features/devConnect/types.ts +6 -0
  111. package/src/features/network/NetworkLogTab.tsx +6 -3
  112. package/src/index.ts +2 -0
  113. package/src/types/feature.ts +2 -1
  114. package/src/ui/DebugView.tsx +1 -0
  115. package/src/ui/panel/DebugPanel.tsx +1 -23
  116. package/src/utils/DaemonClient.ts +26 -1
  117. package/src/utils/debugPreferences.ts +1 -0
  118. package/src/utils/deviceReport.ts +8 -1
  119. package/lib/commonjs/ui/panel/StreamingSettingsModal.js +0 -495
  120. package/lib/commonjs/ui/panel/StreamingSettingsModal.js.map +0 -1
  121. package/lib/module/ui/panel/StreamingSettingsModal.js +0 -490
  122. package/lib/module/ui/panel/StreamingSettingsModal.js.map +0 -1
  123. package/lib/typescript/src/ui/panel/StreamingSettingsModal.d.ts +0 -8
  124. package/lib/typescript/src/ui/panel/StreamingSettingsModal.d.ts.map +0 -1
  125. package/src/ui/panel/StreamingSettingsModal.tsx +0 -528
@@ -1,528 +0,0 @@
1
- import React, { useCallback, useEffect, useRef, useState } from 'react';
2
- import {
3
- KeyboardAvoidingView,
4
- Modal,
5
- Platform,
6
- ScrollView,
7
- View,
8
- Text,
9
- TextInput,
10
- TouchableOpacity,
11
- StyleSheet,
12
- Pressable,
13
- } from 'react-native';
14
- import { Colors } from '../theme/colors';
15
- import {
16
- daemonClient,
17
- type DaemonConnectionMode,
18
- type DaemonSettings,
19
- buildDeviceDaemonEndpoint,
20
- normalizeDaemonSettings,
21
- getDefaultDaemonEndpoint,
22
- } from '../../utils/DaemonClient';
23
-
24
- interface StreamingSettingsModalProps {
25
- visible: boolean;
26
- onClose: () => void;
27
- }
28
-
29
- type SyncUiState = 'idle' | 'connecting' | 'connected' | 'retrying' | 'failed' | 'running';
30
-
31
- const CONNECTION_TIMEOUT_MS = 2000;
32
-
33
- function formatConnectionFailure(): string {
34
- return 'Cannot reach desktop. Try /health in phone browser.';
35
- }
36
-
37
- export function StreamingSettingsModal({ visible, onClose }: StreamingSettingsModalProps) {
38
- const inputRef = useRef<TextInput>(null);
39
- const [mode, setMode] = useState<DaemonConnectionMode>('simulator');
40
- const [deviceHost, setDeviceHost] = useState('');
41
- const [streaming, setStreaming] = useState(daemonClient.isConnected());
42
- const [syncState, setSyncState] = useState<SyncUiState>(daemonClient.isConnected() ? 'running' : 'idle');
43
- const [message, setMessage] = useState<string | null>(null);
44
- const [sending, setSending] = useState(false);
45
-
46
- const handleDeviceHostChange = useCallback((value: string) => {
47
- setDeviceHost(value);
48
- if (syncState === 'failed') {
49
- setSyncState('idle');
50
- }
51
- setMessage(null);
52
- }, [syncState]);
53
-
54
- const detectDeviceHost = useCallback(async () => {
55
- setMessage('Enter your Mac IP, or open /health on the phone browser to verify reachability.');
56
- }, []);
57
-
58
- useEffect(() => {
59
- if (visible) {
60
- const settings = daemonClient.getSettings();
61
- setMode(settings.mode);
62
- setDeviceHost(settings.deviceHost);
63
- }
64
- }, [visible]);
65
-
66
- useEffect(() => {
67
- const active = daemonClient.isConnected();
68
- setStreaming(active);
69
- setSyncState(active ? 'running' : 'idle');
70
- }, [visible]);
71
-
72
- const getSettings = useCallback((): DaemonSettings => ({
73
- mode,
74
- endpoint: '',
75
- deviceHost,
76
- token: '',
77
- }), [deviceHost, mode]);
78
-
79
- const validateSettings = useCallback((): boolean => {
80
- if (mode === 'device' && !deviceHost.trim()) {
81
- setMessage('Enter your Mac IP first.');
82
- return false;
83
- }
84
- return true;
85
- }, [deviceHost, mode]);
86
-
87
- const handleModeChange = useCallback((nextMode: DaemonConnectionMode) => {
88
- setMode(nextMode);
89
- }, []);
90
-
91
- const toggleLiveSync = useCallback(async () => {
92
- if (streaming) {
93
- daemonClient.disconnect();
94
- daemonClient.setStreamingEnabled(false);
95
- setStreaming(false);
96
- setSyncState('idle');
97
- setMessage(null);
98
- return;
99
- }
100
-
101
- if (!validateSettings()) {
102
- return;
103
- }
104
-
105
- const settings = getSettings();
106
- const daemonOptions = normalizeDaemonSettings(settings);
107
- setMessage('Checking desktop connection...');
108
- setSyncState('connecting');
109
- daemonClient.configure(settings);
110
-
111
- const connection = await daemonClient.checkConnection({
112
- ...daemonOptions,
113
- timeoutMs: CONNECTION_TIMEOUT_MS,
114
- });
115
- if (!connection.ok) {
116
- setStreaming(false);
117
- setSyncState('failed');
118
- setMessage(formatConnectionFailure());
119
- return;
120
- }
121
-
122
- daemonClient.setStreamingEnabled(true);
123
- daemonClient.connect({
124
- ...daemonOptions,
125
- timeoutMs: 3000,
126
- onStatus: (status) => {
127
- if (status.state === 'connected') {
128
- setSyncState('connected');
129
- setMessage(null);
130
- } else if (status.state === 'retrying') {
131
- setSyncState('retrying');
132
- setMessage('Desktop not reachable. Retrying...');
133
- } else if (status.state === 'failed') {
134
- setStreaming(false);
135
- setSyncState('failed');
136
- setMessage(
137
- status.reason === 'auth'
138
- ? 'Desktop token rejected.'
139
- : 'Desktop not reachable after multiple retries.',
140
- );
141
- } else {
142
- setSyncState('connecting');
143
- }
144
- },
145
- });
146
- setStreaming(true);
147
- }, [getSettings, streaming, validateSettings]);
148
-
149
- const sendOnce = useCallback(async () => {
150
- if (!validateSettings()) {
151
- return;
152
- }
153
-
154
- const settings = getSettings();
155
- const daemonOptions = normalizeDaemonSettings(settings);
156
- setSending(true);
157
- setMessage('Checking desktop connection...');
158
- daemonClient.configure(settings);
159
-
160
- try {
161
- const connection = await daemonClient.checkConnection({
162
- ...daemonOptions,
163
- timeoutMs: CONNECTION_TIMEOUT_MS,
164
- });
165
- if (!connection.ok) {
166
- setMessage(formatConnectionFailure());
167
- return;
168
- }
169
-
170
- setMessage('Sending logs...');
171
- const result = await daemonClient.reportOnce({
172
- ...daemonOptions,
173
- timeoutMs: 2000,
174
- });
175
-
176
- if (result.ok) {
177
- const totalLogs = Object.values(result.logCount ?? {}).reduce((total, count) => total + count, 0);
178
- setMessage(`Sent ${totalLogs} logs.`);
179
- } else {
180
- setMessage(result.error ? `Send failed: ${result.error}` : 'Send failed.');
181
- }
182
- } finally {
183
- setSending(false);
184
- }
185
- }, [getSettings, validateSettings]);
186
-
187
- const target = mode === 'device'
188
- ? buildDeviceDaemonEndpoint(deviceHost) || 'Enter Mac IP'
189
- : getDefaultDaemonEndpoint();
190
- const canConnect = mode === 'simulator' || Boolean(deviceHost.trim());
191
- const connecting = !streaming && syncState === 'connecting';
192
- const busy = sending || connecting;
193
- const statusTitle = sending
194
- ? 'Checking'
195
- : connecting
196
- ? 'Checking'
197
- : streaming && syncState === 'connected'
198
- ? 'Live sync connected'
199
- : streaming && syncState === 'retrying'
200
- ? 'Retrying desktop sync'
201
- : syncState === 'failed'
202
- ? 'Failed'
203
- : streaming
204
- ? 'Live sync running'
205
- : mode === 'device' && !deviceHost.trim()
206
- ? 'Enter Mac IP'
207
- : 'Ready';
208
-
209
- return (
210
- <Modal visible={visible} transparent animationType="fade" onRequestClose={onClose}>
211
- <KeyboardAvoidingView
212
- style={styles.keyboardAvoiding}
213
- behavior={Platform.OS === 'ios' ? 'padding' : undefined}
214
- >
215
- <Pressable style={styles.backdrop} onPress={onClose}>
216
- <Pressable style={styles.sheet} onPress={(e) => e.stopPropagation()}>
217
- <View style={styles.handle} />
218
-
219
- <View style={styles.header}>
220
- <Text style={styles.title}>Desktop Logs</Text>
221
- <TouchableOpacity onPress={onClose} style={styles.closeButton} activeOpacity={0.7}>
222
- <Text style={styles.closeButtonText}>Close</Text>
223
- </TouchableOpacity>
224
- </View>
225
-
226
- <ScrollView
227
- keyboardShouldPersistTaps="handled"
228
- showsVerticalScrollIndicator={false}
229
- contentContainerStyle={styles.scrollContent}
230
- >
231
- <View style={styles.statusCard}>
232
- <View style={[styles.statusDot, streaming ? styles.dotActive : styles.dotInactive]} />
233
- <View style={styles.statusCopy}>
234
- <Text style={styles.statusTitle}>{statusTitle}</Text>
235
- <Text style={styles.statusTarget} numberOfLines={1}>{target}</Text>
236
- </View>
237
- </View>
238
-
239
- <View style={styles.section}>
240
- <Text style={styles.label}>Connection</Text>
241
- <View style={styles.segment}>
242
- <TouchableOpacity
243
- style={[styles.segmentButton, mode === 'simulator' && styles.segmentButtonActive]}
244
- onPress={() => handleModeChange('simulator')}
245
- disabled={streaming}
246
- activeOpacity={0.7}
247
- >
248
- <Text style={[styles.segmentText, mode === 'simulator' && styles.segmentTextActive]}>
249
- Simulator
250
- </Text>
251
- </TouchableOpacity>
252
- <TouchableOpacity
253
- style={[styles.segmentButton, mode === 'device' && styles.segmentButtonActive]}
254
- onPress={() => handleModeChange('device')}
255
- disabled={streaming}
256
- activeOpacity={0.7}
257
- >
258
- <Text style={[styles.segmentText, mode === 'device' && styles.segmentTextActive]}>
259
- Real device
260
- </Text>
261
- </TouchableOpacity>
262
- </View>
263
- </View>
264
-
265
- {mode === 'device' ? (
266
- <View style={styles.section}>
267
- <View style={styles.inputRow}>
268
- <Text style={styles.inputLabel}>Mac IP</Text>
269
- <TextInput
270
- ref={inputRef}
271
- style={styles.input}
272
- value={deviceHost}
273
- onChangeText={handleDeviceHostChange}
274
- placeholder="192.168.1.10"
275
- placeholderTextColor={Colors.textLight}
276
- autoCapitalize="none"
277
- autoCorrect={false}
278
- keyboardType="numbers-and-punctuation"
279
- returnKeyType="done"
280
- onSubmitEditing={() => inputRef.current?.blur()}
281
- editable={!streaming}
282
- />
283
- <TouchableOpacity
284
- style={[styles.detectButton, (streaming || busy) && styles.buttonDisabled]}
285
- onPress={detectDeviceHost}
286
- disabled={streaming || busy}
287
- activeOpacity={0.7}
288
- >
289
- <Text style={styles.detectButtonText}>?</Text>
290
- </TouchableOpacity>
291
- </View>
292
- </View>
293
- ) : null}
294
-
295
- {message ? <Text style={styles.message}>{message}</Text> : null}
296
-
297
- <View style={styles.actions}>
298
- <TouchableOpacity
299
- style={[styles.primaryButton, (!canConnect || busy) && styles.buttonDisabled]}
300
- onPress={toggleLiveSync}
301
- disabled={!canConnect || busy}
302
- activeOpacity={0.75}
303
- >
304
- <Text style={styles.primaryButtonText}>
305
- {streaming ? 'Stop Live Sync' : busy ? 'Checking...' : 'Start Live Sync'}
306
- </Text>
307
- </TouchableOpacity>
308
- <TouchableOpacity
309
- style={[styles.secondaryButton, (!canConnect || busy) && styles.buttonDisabled]}
310
- onPress={sendOnce}
311
- disabled={!canConnect || busy}
312
- activeOpacity={0.75}
313
- >
314
- <Text style={styles.secondaryButtonText}>{sending ? 'Sending...' : 'Send Once'}</Text>
315
- </TouchableOpacity>
316
- </View>
317
- </ScrollView>
318
- </Pressable>
319
- </Pressable>
320
- </KeyboardAvoidingView>
321
- </Modal>
322
- );
323
- }
324
-
325
- const styles = StyleSheet.create({
326
- keyboardAvoiding: {
327
- flex: 1,
328
- },
329
- backdrop: {
330
- flex: 1,
331
- backgroundColor: 'rgba(0,0,0,0.4)',
332
- justifyContent: 'flex-end',
333
- },
334
- sheet: {
335
- backgroundColor: Colors.surface,
336
- borderTopLeftRadius: 20,
337
- borderTopRightRadius: 20,
338
- paddingHorizontal: 20,
339
- paddingTop: 12,
340
- paddingBottom: 20,
341
- maxHeight: '82%',
342
- },
343
- handle: {
344
- width: 40,
345
- height: 4,
346
- borderRadius: 2,
347
- backgroundColor: Colors.textLight,
348
- alignSelf: 'center',
349
- marginBottom: 16,
350
- },
351
- header: {
352
- flexDirection: 'row',
353
- alignItems: 'center',
354
- justifyContent: 'space-between',
355
- marginBottom: 14,
356
- },
357
- title: {
358
- fontSize: 18,
359
- fontWeight: '600',
360
- color: Colors.text,
361
- },
362
- closeButton: {
363
- paddingHorizontal: 4,
364
- paddingVertical: 4,
365
- },
366
- closeButtonText: {
367
- fontSize: 14,
368
- fontWeight: '500',
369
- color: Colors.primary,
370
- },
371
- scrollContent: {
372
- paddingBottom: 4,
373
- },
374
- statusCard: {
375
- flexDirection: 'row',
376
- alignItems: 'center',
377
- gap: 10,
378
- padding: 12,
379
- borderRadius: 8,
380
- backgroundColor: Colors.background,
381
- borderWidth: 1,
382
- borderColor: Colors.border,
383
- marginBottom: 16,
384
- },
385
- statusCopy: {
386
- flex: 1,
387
- },
388
- statusTitle: {
389
- fontSize: 14,
390
- fontWeight: '600',
391
- color: Colors.text,
392
- },
393
- statusTarget: {
394
- marginTop: 2,
395
- fontSize: 12,
396
- color: Colors.textLight,
397
- fontFamily: 'Courier',
398
- },
399
- section: {
400
- marginBottom: 14,
401
- },
402
- label: {
403
- fontSize: 13,
404
- fontWeight: '500',
405
- color: Colors.textSecondary,
406
- marginBottom: 6,
407
- },
408
- segment: {
409
- flexDirection: 'row',
410
- padding: 3,
411
- borderRadius: 10,
412
- backgroundColor: Colors.background,
413
- borderWidth: 1,
414
- borderColor: Colors.border,
415
- },
416
- segmentButton: {
417
- flex: 1,
418
- alignItems: 'center',
419
- paddingVertical: 9,
420
- borderRadius: 7,
421
- },
422
- segmentButtonActive: {
423
- backgroundColor: Colors.surface,
424
- borderWidth: 1,
425
- borderColor: Colors.primary,
426
- },
427
- segmentText: {
428
- fontSize: 13,
429
- fontWeight: '500',
430
- color: Colors.textSecondary,
431
- },
432
- segmentTextActive: {
433
- color: Colors.primary,
434
- fontWeight: '600',
435
- },
436
- inputRow: {
437
- flexDirection: 'row',
438
- alignItems: 'center',
439
- gap: 8,
440
- },
441
- inputLabel: {
442
- width: 50,
443
- fontSize: 13,
444
- fontWeight: '600',
445
- color: Colors.textSecondary,
446
- },
447
- input: {
448
- flex: 1,
449
- backgroundColor: Colors.background,
450
- borderWidth: 1,
451
- borderColor: Colors.border,
452
- borderRadius: 8,
453
- paddingHorizontal: 12,
454
- paddingVertical: 10,
455
- fontSize: 14,
456
- color: Colors.text,
457
- fontFamily: 'Courier',
458
- },
459
- detectButton: {
460
- minWidth: 68,
461
- alignItems: 'center',
462
- justifyContent: 'center',
463
- paddingHorizontal: 10,
464
- paddingVertical: 10,
465
- borderRadius: 8,
466
- backgroundColor: Colors.surface,
467
- borderWidth: 1,
468
- borderColor: Colors.primary,
469
- },
470
- detectButtonText: {
471
- color: Colors.primary,
472
- fontSize: 13,
473
- fontWeight: '600',
474
- },
475
- statusDot: {
476
- width: 8,
477
- height: 8,
478
- borderRadius: 4,
479
- },
480
- dotActive: {
481
- backgroundColor: Colors.success,
482
- },
483
- dotInactive: {
484
- backgroundColor: Colors.textLight,
485
- },
486
- message: {
487
- fontSize: 12,
488
- lineHeight: 17,
489
- color: Colors.textSecondary,
490
- marginBottom: 12,
491
- },
492
- actions: {
493
- flexDirection: 'row',
494
- gap: 10,
495
- marginTop: 4,
496
- },
497
- primaryButton: {
498
- flex: 1,
499
- alignItems: 'center',
500
- justifyContent: 'center',
501
- paddingVertical: 11,
502
- borderRadius: 10,
503
- backgroundColor: Colors.primary,
504
- },
505
- primaryButtonText: {
506
- color: '#fff',
507
- fontSize: 14,
508
- fontWeight: '600',
509
- },
510
- secondaryButton: {
511
- flex: 1,
512
- alignItems: 'center',
513
- justifyContent: 'center',
514
- paddingVertical: 11,
515
- borderRadius: 10,
516
- backgroundColor: Colors.background,
517
- borderWidth: 1,
518
- borderColor: Colors.border,
519
- },
520
- secondaryButtonText: {
521
- color: Colors.primary,
522
- fontSize: 14,
523
- fontWeight: '600',
524
- },
525
- buttonDisabled: {
526
- opacity: 0.5,
527
- },
528
- });