react-native-inapp-inspector 2.3.9 → 2.3.11

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 (65) hide show
  1. package/dist/commonjs/components/Inspector/DebuggingTab.d.ts +3 -0
  2. package/dist/commonjs/components/Inspector/DebuggingTab.js +682 -0
  3. package/dist/commonjs/components/Inspector/MainScreen.js +2 -0
  4. package/dist/commonjs/components/Inspector/NetworkDetail.js +2 -1
  5. package/dist/commonjs/components/Inspector/NetworkFilterModal.d.ts +19 -0
  6. package/dist/commonjs/components/Inspector/NetworkFilterModal.js +648 -0
  7. package/dist/commonjs/components/Inspector/NetworkTab.js +89 -147
  8. package/dist/commonjs/components/Inspector/SettingsPanel.js +12 -0
  9. package/dist/commonjs/components/Inspector/TabBar.js +9 -0
  10. package/dist/commonjs/components/LogCard.js +5 -26
  11. package/dist/commonjs/components/NetworkIcons.d.ts +2 -0
  12. package/dist/commonjs/components/NetworkIcons.js +13 -1
  13. package/dist/commonjs/components/QRCodeView.d.ts +9 -0
  14. package/dist/commonjs/components/QRCodeView.js +79 -0
  15. package/dist/commonjs/constants/index.js +3 -0
  16. package/dist/commonjs/constants/version.d.ts +1 -1
  17. package/dist/commonjs/constants/version.js +1 -1
  18. package/dist/commonjs/helpers/qrGenerator.d.ts +2 -0
  19. package/dist/commonjs/helpers/qrGenerator.js +170 -0
  20. package/dist/commonjs/index.js +2 -0
  21. package/dist/commonjs/styles/index.d.ts +11 -0
  22. package/dist/commonjs/styles/index.js +20 -5
  23. package/dist/commonjs/types/enums.d.ts +5 -0
  24. package/dist/commonjs/types/enums.js +5 -0
  25. package/dist/esm/components/Inspector/DebuggingTab.d.ts +3 -0
  26. package/dist/esm/components/Inspector/DebuggingTab.js +642 -0
  27. package/dist/esm/components/Inspector/MainScreen.js +2 -0
  28. package/dist/esm/components/Inspector/NetworkDetail.js +2 -1
  29. package/dist/esm/components/Inspector/NetworkFilterModal.d.ts +19 -0
  30. package/dist/esm/components/Inspector/NetworkFilterModal.js +607 -0
  31. package/dist/esm/components/Inspector/NetworkTab.js +91 -149
  32. package/dist/esm/components/Inspector/SettingsPanel.js +13 -1
  33. package/dist/esm/components/Inspector/TabBar.js +10 -1
  34. package/dist/esm/components/LogCard.js +5 -26
  35. package/dist/esm/components/NetworkIcons.d.ts +2 -0
  36. package/dist/esm/components/NetworkIcons.js +10 -0
  37. package/dist/esm/components/QRCodeView.d.ts +9 -0
  38. package/dist/esm/components/QRCodeView.js +42 -0
  39. package/dist/esm/constants/index.js +3 -0
  40. package/dist/esm/constants/version.d.ts +1 -1
  41. package/dist/esm/constants/version.js +1 -1
  42. package/dist/esm/helpers/qrGenerator.d.ts +2 -0
  43. package/dist/esm/helpers/qrGenerator.js +167 -0
  44. package/dist/esm/index.js +2 -0
  45. package/dist/esm/styles/index.d.ts +11 -0
  46. package/dist/esm/styles/index.js +20 -5
  47. package/dist/esm/types/enums.d.ts +5 -0
  48. package/dist/esm/types/enums.js +5 -0
  49. package/package.json +2 -2
  50. package/src/components/Inspector/DebuggingTab.tsx +755 -0
  51. package/src/components/Inspector/MainScreen.tsx +2 -0
  52. package/src/components/Inspector/NetworkDetail.tsx +2 -1
  53. package/src/components/Inspector/NetworkFilterModal.tsx +710 -0
  54. package/src/components/Inspector/NetworkTab.tsx +127 -204
  55. package/src/components/Inspector/SettingsPanel.tsx +20 -0
  56. package/src/components/Inspector/TabBar.tsx +11 -0
  57. package/src/components/LogCard.tsx +5 -30
  58. package/src/components/NetworkIcons.tsx +66 -0
  59. package/src/components/QRCodeView.tsx +71 -0
  60. package/src/constants/index.ts +3 -0
  61. package/src/constants/version.ts +1 -1
  62. package/src/helpers/qrGenerator.ts +184 -0
  63. package/src/index.tsx +2 -0
  64. package/src/styles/index.ts +20 -5
  65. package/src/types/enums.ts +5 -0
@@ -0,0 +1,755 @@
1
+ import React, {useState, useEffect, useMemo, useCallback} from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ ScrollView,
6
+ StyleSheet,
7
+ TextInput,
8
+ TouchableOpacity,
9
+ NativeModules,
10
+ Platform,
11
+ Share,
12
+ } from 'react-native';
13
+ import {useInspector} from './InspectorContext';
14
+ import {AppColors} from '../../styles/AppColors';
15
+ import {AppFonts} from '../../styles/AppFonts';
16
+ import QRCodeView from '../QRCodeView';
17
+ import TouchableScale from '../TouchableScale';
18
+ import CopyButton from '../CopyButton';
19
+ import {copyToClipboard} from '../../helpers';
20
+ import {showToast} from '../../helpers/toast';
21
+ import {useTranslation} from '../../i18n';
22
+ import {
23
+ BoltIcon,
24
+ GlobeIcon,
25
+ ClockIcon,
26
+ CircleCheckIcon,
27
+ CircleXIcon,
28
+ SmartphoneIcon,
29
+ PackageIcon,
30
+ TerminalIcon,
31
+ ExternalLinkIcon,
32
+ RepeatIcon,
33
+ ShieldAlertIcon,
34
+ } from '../NetworkIcons';
35
+
36
+ interface PortStatus {
37
+ port: number;
38
+ status: 'checking' | 'active' | 'inactive';
39
+ latencyMs?: number;
40
+ }
41
+
42
+ const COMMON_PORTS = [8081, 8082, 8083, 19000];
43
+
44
+ export const DebuggingTab: React.FC = () => {
45
+ const {t} = useTranslation();
46
+
47
+ // Auto-detect host IP and initial port from NativeModules.SourceCode.scriptURL
48
+ const detectedConfig = useMemo(() => {
49
+ const scriptURL = NativeModules.SourceCode?.scriptURL || '';
50
+ let host = 'localhost';
51
+ let port = 8081;
52
+
53
+ try {
54
+ if (scriptURL.includes('://')) {
55
+ const urlWithoutScheme = scriptURL.split('://')[1];
56
+ const hostAndPort = urlWithoutScheme.split('/')[0];
57
+ if (hostAndPort.includes(':')) {
58
+ const parts = hostAndPort.split(':');
59
+ host = parts[0];
60
+ const parsedPort = parseInt(parts[1], 10);
61
+ if (!isNaN(parsedPort)) port = parsedPort;
62
+ } else {
63
+ host = hostAndPort;
64
+ }
65
+ }
66
+ } catch {}
67
+
68
+ return {host, port, scriptURL};
69
+ }, []);
70
+
71
+ const [hostIp, setHostIp] = useState<string>(() => {
72
+ // If localhost or 127.0.0.1 or 10.0.2.2, default to 192.168.1.1 or detected host
73
+ if (
74
+ detectedConfig.host === 'localhost' ||
75
+ detectedConfig.host === '127.0.0.1' ||
76
+ detectedConfig.host === '10.0.2.2'
77
+ ) {
78
+ return '192.168.1.15';
79
+ }
80
+ return detectedConfig.host;
81
+ });
82
+
83
+ const [selectedPort, setSelectedPort] = useState<number>(detectedConfig.port);
84
+ const [apkPath, setApkPath] = useState<string>('app-debug.apk');
85
+ const [activeQrTab, setActiveQrTab] = useState<'metro' | 'apk' | 'host'>('metro');
86
+ const [isAutoDetecting, setIsAutoDetecting] = useState<boolean>(false);
87
+ const [portsStatus, setPortsStatus] = useState<Record<number, PortStatus>>({});
88
+
89
+ // Auto-probe ports on mount
90
+ const probePorts = useCallback(async () => {
91
+ setIsAutoDetecting(true);
92
+ const results: Record<number, PortStatus> = {};
93
+
94
+ for (const p of COMMON_PORTS) {
95
+ results[p] = {port: p, status: 'checking'};
96
+ }
97
+ setPortsStatus({...results});
98
+
99
+ let foundActivePort: number | null = null;
100
+
101
+ for (const p of COMMON_PORTS) {
102
+ const startTime = Date.now();
103
+ try {
104
+ const controller = new AbortController();
105
+ const timeoutId = setTimeout(() => controller.abort(), 1500);
106
+ // Ping /status endpoint of Metro Bundler
107
+ const res = await fetch(`http://localhost:${p}/status`, {
108
+ signal: controller.signal,
109
+ });
110
+ clearTimeout(timeoutId);
111
+ const text = await res.text();
112
+ const latency = Date.now() - startTime;
113
+
114
+ if (res.ok && text.includes('packager-status:running')) {
115
+ results[p] = {port: p, status: 'active', latencyMs: latency};
116
+ if (!foundActivePort) foundActivePort = p;
117
+ } else {
118
+ results[p] = {port: p, status: 'inactive'};
119
+ }
120
+ } catch {
121
+ results[p] = {port: p, status: 'inactive'};
122
+ }
123
+ setPortsStatus({...results});
124
+ }
125
+
126
+ if (foundActivePort) {
127
+ setSelectedPort(foundActivePort);
128
+ showToast(`Detected Metro running on Port ${foundActivePort}!`);
129
+ }
130
+
131
+ setIsAutoDetecting(false);
132
+ }, []);
133
+
134
+ useEffect(() => {
135
+ probePorts();
136
+ }, [probePorts]);
137
+
138
+ // Construct target URLs for QR codes
139
+ const metroBundleUrl = `http://${hostIp}:${selectedPort}/index.bundle?platform=android&dev=true`;
140
+ const apkDownloadUrl = `http://${hostIp}:${selectedPort}/${apkPath}`;
141
+ const devSettingsHost = `${hostIp}:${selectedPort}`;
142
+
143
+ const currentQrValue = useMemo(() => {
144
+ if (activeQrTab === 'apk') return apkDownloadUrl;
145
+ if (activeQrTab === 'host') return devSettingsHost;
146
+ return metroBundleUrl;
147
+ }, [activeQrTab, apkDownloadUrl, devSettingsHost, metroBundleUrl]);
148
+
149
+ const activePortInfo = portsStatus[selectedPort];
150
+
151
+ return (
152
+ <ScrollView
153
+ style={styles.container}
154
+ contentContainerStyle={styles.content}
155
+ showsVerticalScrollIndicator={false}>
156
+ {/* ─── Top Live Server Status Banner ────────────────────────────── */}
157
+ <View style={styles.serverCard}>
158
+ <View style={styles.serverCardTop}>
159
+ <View style={styles.serverStatusLeft}>
160
+ <View
161
+ style={[
162
+ styles.statusDot,
163
+ {
164
+ backgroundColor:
165
+ activePortInfo?.status === 'active'
166
+ ? AppColors.greenColor
167
+ : activePortInfo?.status === 'checking'
168
+ ? AppColors.warningIconGold
169
+ : AppColors.errorColor,
170
+ },
171
+ ]}
172
+ />
173
+ <View>
174
+ <View style={{flexDirection: 'row', alignItems: 'center', gap: 6}}>
175
+ <Text style={styles.serverTitle}>Metro Dev Server</Text>
176
+ <View style={styles.portPill}>
177
+ <Text style={styles.portPillText}>Port {selectedPort}</Text>
178
+ </View>
179
+ </View>
180
+ <Text style={styles.serverSubtitle}>
181
+ {activePortInfo?.status === 'active'
182
+ ? `🟢 Active & Bundling (${activePortInfo.latencyMs}ms)`
183
+ : activePortInfo?.status === 'checking'
184
+ ? '🟡 Probing Metro Ports...'
185
+ : '🔴 Standby / Select active port'}
186
+ </Text>
187
+ </View>
188
+ </View>
189
+
190
+ <TouchableScale
191
+ onPress={probePorts}
192
+ style={styles.scanBtn}
193
+ hitSlop={8}>
194
+ <RepeatIcon size={12} color={AppColors.purple} />
195
+ <Text style={styles.scanBtnText}>Re-scan</Text>
196
+ </TouchableScale>
197
+ </View>
198
+
199
+ {/* Port Selector Chips */}
200
+ <View style={styles.portsRow}>
201
+ {COMMON_PORTS.map(p => {
202
+ const isSelected = selectedPort === p;
203
+ const pInfo = portsStatus[p];
204
+ const isActive = pInfo?.status === 'active';
205
+ return (
206
+ <TouchableOpacity
207
+ key={p}
208
+ activeOpacity={0.7}
209
+ onPress={() => setSelectedPort(p)}
210
+ style={[
211
+ styles.portChip,
212
+ isSelected && styles.portChipSelected,
213
+ isActive && {borderColor: AppColors.greenColor},
214
+ ]}>
215
+ <View
216
+ style={[
217
+ styles.portMiniDot,
218
+ {
219
+ backgroundColor: isActive
220
+ ? AppColors.greenColor
221
+ : AppColors.grayTextWeak,
222
+ },
223
+ ]}
224
+ />
225
+ <Text
226
+ style={[
227
+ styles.portChipText,
228
+ isSelected && styles.portChipTextSelected,
229
+ ]}>
230
+ {p}
231
+ </Text>
232
+ {isActive && (
233
+ <View style={styles.liveBadge}>
234
+ <Text style={styles.liveBadgeText}>LIVE</Text>
235
+ </View>
236
+ )}
237
+ </TouchableOpacity>
238
+ );
239
+ })}
240
+ </View>
241
+ </View>
242
+
243
+ {/* ─── Host IP Configuration Card ───────────────────────────────── */}
244
+ <View style={styles.card}>
245
+ <View style={styles.cardHeader}>
246
+ <Text style={styles.cardTitle}>HOST IP & BUNDLE LOCATION</Text>
247
+ <TouchableOpacity
248
+ onPress={() => {
249
+ if (
250
+ detectedConfig.host !== 'localhost' &&
251
+ detectedConfig.host !== '127.0.0.1' &&
252
+ detectedConfig.host !== '10.0.2.2'
253
+ ) {
254
+ setHostIp(detectedConfig.host);
255
+ showToast(`Reset to detected IP: ${detectedConfig.host}`);
256
+ }
257
+ }}>
258
+ <Text style={styles.headerActionText}>Reset to Detected</Text>
259
+ </TouchableOpacity>
260
+ </View>
261
+
262
+ <View style={styles.inputContainer}>
263
+ <Text style={styles.inputPrefix}>http://</Text>
264
+ <TextInput
265
+ style={styles.input}
266
+ value={hostIp}
267
+ onChangeText={setHostIp}
268
+ placeholder="192.168.1.15"
269
+ placeholderTextColor={AppColors.grayTextWeak}
270
+ autoCapitalize="none"
271
+ autoCorrect={false}
272
+ />
273
+ <Text style={styles.inputSuffix}>:{selectedPort}</Text>
274
+ </View>
275
+ <Text style={styles.inputHint}>
276
+ 💡 Ensure your physical Android device and Mac are connected to the same Wi-Fi network.
277
+ </Text>
278
+ </View>
279
+
280
+ {/* ─── Interactive QR Code Generator Card ──────────────────────── */}
281
+ <View style={styles.qrCard}>
282
+ {/* Mode Selector Tabs */}
283
+ <View style={styles.qrTabsRow}>
284
+ <TouchableOpacity
285
+ activeOpacity={0.7}
286
+ onPress={() => setActiveQrTab('metro')}
287
+ style={[
288
+ styles.qrTab,
289
+ activeQrTab === 'metro' && styles.qrTabActive,
290
+ ]}>
291
+ <BoltIcon
292
+ size={13}
293
+ color={activeQrTab === 'metro' ? AppColors.white : AppColors.grayText}
294
+ />
295
+ <Text
296
+ style={[
297
+ styles.qrTabText,
298
+ activeQrTab === 'metro' && styles.qrTabTextActive,
299
+ ]}>
300
+ Metro Live Reload
301
+ </Text>
302
+ </TouchableOpacity>
303
+
304
+ <TouchableOpacity
305
+ activeOpacity={0.7}
306
+ onPress={() => setActiveQrTab('apk')}
307
+ style={[
308
+ styles.qrTab,
309
+ activeQrTab === 'apk' && styles.qrTabActive,
310
+ ]}>
311
+ <PackageIcon
312
+ size={13}
313
+ color={activeQrTab === 'apk' ? AppColors.white : AppColors.grayText}
314
+ />
315
+ <Text
316
+ style={[
317
+ styles.qrTabText,
318
+ activeQrTab === 'apk' && styles.qrTabTextActive,
319
+ ]}>
320
+ Install Debug APK
321
+ </Text>
322
+ </TouchableOpacity>
323
+
324
+ <TouchableOpacity
325
+ activeOpacity={0.7}
326
+ onPress={() => setActiveQrTab('host')}
327
+ style={[
328
+ styles.qrTab,
329
+ activeQrTab === 'host' && styles.qrTabActive,
330
+ ]}>
331
+ <SmartphoneIcon
332
+ size={13}
333
+ color={activeQrTab === 'host' ? AppColors.white : AppColors.grayText}
334
+ />
335
+ <Text
336
+ style={[
337
+ styles.qrTabText,
338
+ activeQrTab === 'host' && styles.qrTabTextActive,
339
+ ]}>
340
+ Dev Host Info
341
+ </Text>
342
+ </TouchableOpacity>
343
+ </View>
344
+
345
+ {/* QR Code Container */}
346
+ <View style={styles.qrWrapper}>
347
+ <QRCodeView
348
+ value={currentQrValue}
349
+ size={190}
350
+ color={AppColors.primaryBlack}
351
+ backgroundColor={AppColors.white}
352
+ />
353
+
354
+ <View style={styles.qrInfoBox}>
355
+ <Text style={styles.qrTargetTitle}>
356
+ {activeQrTab === 'apk'
357
+ ? '📦 Direct APK Download URL'
358
+ : activeQrTab === 'host'
359
+ ? '📱 Dev Settings Bundle Host'
360
+ : '⚡ Live Metro Fast-Refresh Endpoint'}
361
+ </Text>
362
+ <Text style={styles.qrTargetUrl} numberOfLines={2} ellipsizeMode="middle">
363
+ {currentQrValue}
364
+ </Text>
365
+ </View>
366
+ </View>
367
+
368
+ {/* Quick Action Row */}
369
+ <View style={styles.qrActionsRow}>
370
+ <TouchableScale
371
+ onPress={() => copyToClipboard(currentQrValue, 'QR Link')}
372
+ style={styles.actionBtn}>
373
+ <Text style={styles.actionBtnText}>Copy Link</Text>
374
+ </TouchableScale>
375
+
376
+ <TouchableScale
377
+ onPress={() => {
378
+ Share.share({
379
+ message: currentQrValue,
380
+ title: 'Metro Debug Link',
381
+ });
382
+ }}
383
+ style={[styles.actionBtn, styles.actionBtnPrimary]}>
384
+ <Text style={styles.actionBtnPrimaryText}>Share to Device</Text>
385
+ </TouchableScale>
386
+ </View>
387
+ </View>
388
+
389
+ {/* ─── Bare React Native Multi-Device Setup Guide ───────────────── */}
390
+ <View style={styles.guideCard}>
391
+ <Text style={styles.guideHeading}>📱 HOW TO CONNECT ANDROID DEVICE:</Text>
392
+
393
+ <View style={styles.stepRow}>
394
+ <View style={styles.stepNumberBadge}>
395
+ <Text style={styles.stepNumberText}>1</Text>
396
+ </View>
397
+ <View style={{flex: 1}}>
398
+ <Text style={styles.stepTitle}>Connect to Same Wi-Fi</Text>
399
+ <Text style={styles.stepDesc}>
400
+ Make sure your Android phone is connected to the same Wi-Fi router or Mac Mobile Hotspot.
401
+ </Text>
402
+ </View>
403
+ </View>
404
+
405
+ <View style={styles.stepRow}>
406
+ <View style={styles.stepNumberBadge}>
407
+ <Text style={styles.stepNumberText}>2</Text>
408
+ </View>
409
+ <View style={{flex: 1}}>
410
+ <Text style={styles.stepTitle}>Scan to Install / Connect</Text>
411
+ <Text style={styles.stepDesc}>
412
+ Open Android Camera or browser, scan the QR code above to download the APK or connect Metro.
413
+ </Text>
414
+ </View>
415
+ </View>
416
+
417
+ <View style={styles.stepRow}>
418
+ <View style={styles.stepNumberBadge}>
419
+ <Text style={styles.stepNumberText}>3</Text>
420
+ </View>
421
+ <View style={{flex: 1}}>
422
+ <Text style={styles.stepTitle}>Simultaneous Live Fast-Refresh ⚡</Text>
423
+ <Text style={styles.stepDesc}>
424
+ Any changes saved in VS Code will immediately update <Text style={{fontWeight: '700'}}>both the iOS Simulator and physical Android phone</Text> in real-time!
425
+ </Text>
426
+ </View>
427
+ </View>
428
+ </View>
429
+ </ScrollView>
430
+ );
431
+ };
432
+
433
+ const styles = StyleSheet.create({
434
+ container: {
435
+ flex: 1,
436
+ backgroundColor: AppColors.contentBg,
437
+ },
438
+ content: {
439
+ padding: 12,
440
+ gap: 12,
441
+ paddingBottom: 40,
442
+ },
443
+ serverCard: {
444
+ backgroundColor: AppColors.primaryLight,
445
+ borderRadius: 14,
446
+ padding: 14,
447
+ borderWidth: 1,
448
+ borderColor: AppColors.grayBorderSecondary,
449
+ shadowColor: AppColors.black,
450
+ shadowOffset: {width: 0, height: 2},
451
+ shadowOpacity: 0.05,
452
+ shadowRadius: 4,
453
+ elevation: 2,
454
+ gap: 12,
455
+ },
456
+ serverCardTop: {
457
+ flexDirection: 'row',
458
+ alignItems: 'center',
459
+ justifyContent: 'space-between',
460
+ },
461
+ serverStatusLeft: {
462
+ flexDirection: 'row',
463
+ alignItems: 'center',
464
+ gap: 10,
465
+ flex: 1,
466
+ },
467
+ statusDot: {
468
+ width: 12,
469
+ height: 12,
470
+ borderRadius: 6,
471
+ },
472
+ serverTitle: {
473
+ fontFamily: AppFonts.interBold,
474
+ fontSize: 15,
475
+ color: AppColors.primaryBlack,
476
+ },
477
+ serverSubtitle: {
478
+ fontFamily: AppFonts.interMedium,
479
+ fontSize: 11,
480
+ color: AppColors.grayText,
481
+ marginTop: 2,
482
+ },
483
+ portPill: {
484
+ backgroundColor: `${AppColors.purple}18`,
485
+ paddingHorizontal: 6,
486
+ paddingVertical: 2,
487
+ borderRadius: 6,
488
+ },
489
+ portPillText: {
490
+ fontFamily: AppFonts.interBold,
491
+ fontSize: 10,
492
+ color: AppColors.purple,
493
+ },
494
+ scanBtn: {
495
+ flexDirection: 'row',
496
+ alignItems: 'center',
497
+ gap: 4,
498
+ paddingHorizontal: 8,
499
+ paddingVertical: 4,
500
+ borderRadius: 6,
501
+ backgroundColor: `${AppColors.purple}14`,
502
+ borderWidth: 1,
503
+ borderColor: `${AppColors.purple}30`,
504
+ },
505
+ scanBtnText: {
506
+ fontFamily: AppFonts.interBold,
507
+ fontSize: 11,
508
+ color: AppColors.purple,
509
+ },
510
+ portsRow: {
511
+ flexDirection: 'row',
512
+ gap: 8,
513
+ },
514
+ portChip: {
515
+ flex: 1,
516
+ flexDirection: 'row',
517
+ alignItems: 'center',
518
+ justifyContent: 'center',
519
+ gap: 4,
520
+ paddingVertical: 7,
521
+ borderRadius: 8,
522
+ backgroundColor: AppColors.grayBackground,
523
+ borderWidth: 1,
524
+ borderColor: AppColors.grayBorderSecondary,
525
+ },
526
+ portChipSelected: {
527
+ backgroundColor: `${AppColors.purple}18`,
528
+ borderColor: AppColors.purple,
529
+ },
530
+ portMiniDot: {
531
+ width: 5,
532
+ height: 5,
533
+ borderRadius: 2.5,
534
+ },
535
+ portChipText: {
536
+ fontFamily: AppFonts.interBold,
537
+ fontSize: 11,
538
+ color: AppColors.grayTextStrong,
539
+ },
540
+ portChipTextSelected: {
541
+ color: AppColors.purple,
542
+ },
543
+ liveBadge: {
544
+ backgroundColor: AppColors.greenColor,
545
+ paddingHorizontal: 3,
546
+ paddingVertical: 0.5,
547
+ borderRadius: 3,
548
+ },
549
+ liveBadgeText: {
550
+ fontFamily: AppFonts.interBold,
551
+ fontSize: 7.5,
552
+ color: AppColors.white,
553
+ },
554
+ card: {
555
+ backgroundColor: AppColors.primaryLight,
556
+ borderRadius: 14,
557
+ padding: 14,
558
+ borderWidth: 1,
559
+ borderColor: AppColors.grayBorderSecondary,
560
+ shadowColor: AppColors.black,
561
+ shadowOffset: {width: 0, height: 2},
562
+ shadowOpacity: 0.05,
563
+ shadowRadius: 4,
564
+ elevation: 2,
565
+ gap: 8,
566
+ },
567
+ cardHeader: {
568
+ flexDirection: 'row',
569
+ alignItems: 'center',
570
+ justifyContent: 'space-between',
571
+ },
572
+ cardTitle: {
573
+ fontFamily: AppFonts.interBold,
574
+ fontSize: 11,
575
+ color: AppColors.grayTextWeak,
576
+ letterSpacing: 0.6,
577
+ },
578
+ headerActionText: {
579
+ fontFamily: AppFonts.interBold,
580
+ fontSize: 11,
581
+ color: AppColors.purple,
582
+ },
583
+ inputContainer: {
584
+ flexDirection: 'row',
585
+ alignItems: 'center',
586
+ backgroundColor: AppColors.grayBackground,
587
+ borderRadius: 10,
588
+ borderWidth: 1,
589
+ borderColor: AppColors.grayBorderSecondary,
590
+ paddingHorizontal: 10,
591
+ height: 40,
592
+ },
593
+ inputPrefix: {
594
+ fontFamily: AppFonts.interMedium,
595
+ fontSize: 12.5,
596
+ color: AppColors.grayTextWeak,
597
+ },
598
+ input: {
599
+ flex: 1,
600
+ fontFamily: AppFonts.interBold,
601
+ fontSize: 13,
602
+ color: AppColors.primaryBlack,
603
+ paddingVertical: 0,
604
+ },
605
+ inputSuffix: {
606
+ fontFamily: AppFonts.interBold,
607
+ fontSize: 12.5,
608
+ color: AppColors.purple,
609
+ },
610
+ inputHint: {
611
+ fontFamily: AppFonts.interRegular,
612
+ fontSize: 11,
613
+ color: AppColors.grayTextWeak,
614
+ lineHeight: 15,
615
+ },
616
+ qrCard: {
617
+ backgroundColor: AppColors.primaryLight,
618
+ borderRadius: 14,
619
+ padding: 14,
620
+ borderWidth: 1,
621
+ borderColor: AppColors.grayBorderSecondary,
622
+ shadowColor: AppColors.black,
623
+ shadowOffset: {width: 0, height: 2},
624
+ shadowOpacity: 0.05,
625
+ shadowRadius: 4,
626
+ elevation: 2,
627
+ alignItems: 'center',
628
+ gap: 14,
629
+ },
630
+ qrTabsRow: {
631
+ flexDirection: 'row',
632
+ backgroundColor: AppColors.grayBackground,
633
+ borderRadius: 10,
634
+ padding: 3,
635
+ width: '100%',
636
+ gap: 4,
637
+ },
638
+ qrTab: {
639
+ flex: 1,
640
+ flexDirection: 'row',
641
+ alignItems: 'center',
642
+ justifyContent: 'center',
643
+ gap: 4,
644
+ paddingVertical: 7,
645
+ borderRadius: 8,
646
+ },
647
+ qrTabActive: {
648
+ backgroundColor: AppColors.purple,
649
+ },
650
+ qrTabText: {
651
+ fontFamily: AppFonts.interMedium,
652
+ fontSize: 11,
653
+ color: AppColors.grayText,
654
+ },
655
+ qrTabTextActive: {
656
+ color: AppColors.white,
657
+ fontFamily: AppFonts.interBold,
658
+ },
659
+ qrWrapper: {
660
+ alignItems: 'center',
661
+ gap: 12,
662
+ },
663
+ qrInfoBox: {
664
+ alignItems: 'center',
665
+ maxWidth: 280,
666
+ gap: 2,
667
+ },
668
+ qrTargetTitle: {
669
+ fontFamily: AppFonts.interBold,
670
+ fontSize: 11.5,
671
+ color: AppColors.primaryBlack,
672
+ },
673
+ qrTargetUrl: {
674
+ fontFamily: AppFonts.interRegular,
675
+ fontSize: 10.5,
676
+ color: AppColors.skyBlue,
677
+ textAlign: 'center',
678
+ },
679
+ qrActionsRow: {
680
+ flexDirection: 'row',
681
+ gap: 10,
682
+ width: '100%',
683
+ },
684
+ actionBtn: {
685
+ flex: 1,
686
+ paddingVertical: 10,
687
+ borderRadius: 10,
688
+ borderWidth: 1,
689
+ borderColor: AppColors.grayBorderSecondary,
690
+ backgroundColor: AppColors.grayBackground,
691
+ alignItems: 'center',
692
+ justifyContent: 'center',
693
+ },
694
+ actionBtnText: {
695
+ fontFamily: AppFonts.interBold,
696
+ fontSize: 12,
697
+ color: AppColors.grayTextStrong,
698
+ },
699
+ actionBtnPrimary: {
700
+ backgroundColor: AppColors.purple,
701
+ borderColor: AppColors.purple,
702
+ },
703
+ actionBtnPrimaryText: {
704
+ fontFamily: AppFonts.interBold,
705
+ fontSize: 12,
706
+ color: AppColors.white,
707
+ },
708
+ guideCard: {
709
+ backgroundColor: AppColors.primaryLight,
710
+ borderRadius: 14,
711
+ padding: 14,
712
+ borderWidth: 1,
713
+ borderColor: AppColors.grayBorderSecondary,
714
+ gap: 10,
715
+ },
716
+ guideHeading: {
717
+ fontFamily: AppFonts.interBold,
718
+ fontSize: 11,
719
+ color: AppColors.grayTextWeak,
720
+ letterSpacing: 0.6,
721
+ },
722
+ stepRow: {
723
+ flexDirection: 'row',
724
+ alignItems: 'flex-start',
725
+ gap: 10,
726
+ },
727
+ stepNumberBadge: {
728
+ width: 22,
729
+ height: 22,
730
+ borderRadius: 11,
731
+ backgroundColor: `${AppColors.purple}18`,
732
+ alignItems: 'center',
733
+ justifyContent: 'center',
734
+ marginTop: 1,
735
+ },
736
+ stepNumberText: {
737
+ fontFamily: AppFonts.interBold,
738
+ fontSize: 11,
739
+ color: AppColors.purple,
740
+ },
741
+ stepTitle: {
742
+ fontFamily: AppFonts.interBold,
743
+ fontSize: 12.5,
744
+ color: AppColors.primaryBlack,
745
+ },
746
+ stepDesc: {
747
+ fontFamily: AppFonts.interRegular,
748
+ fontSize: 11,
749
+ color: AppColors.grayText,
750
+ lineHeight: 16,
751
+ marginTop: 1,
752
+ },
753
+ });
754
+
755
+ export default DebuggingTab;