react-native-inapp-inspector 2.3.18 → 2.3.19
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.
- package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +47 -0
- package/dist/commonjs/capture.d.ts +2 -0
- package/dist/commonjs/capture.js +3 -0
- package/dist/commonjs/components/EmptyState.d.ts +1 -0
- package/dist/commonjs/components/EmptyState.js +2 -2
- package/dist/commonjs/components/Inspector/FabLauncher.js +494 -39
- package/dist/commonjs/components/Inspector/InspectorHeader.js +45 -26
- package/dist/commonjs/components/Inspector/MainScreen.js +4 -3
- package/dist/commonjs/components/Inspector/MediaGalleryTab.js +418 -13
- package/dist/commonjs/components/Inspector/MediaPreviewModal.js +376 -88
- package/dist/commonjs/components/Inspector/NetworkDetail.js +49 -63
- package/dist/commonjs/components/Inspector/SettingsPanel.js +499 -119
- package/dist/commonjs/components/Inspector/TabBar.js +166 -4
- package/dist/commonjs/components/JsonViewer.js +4 -3
- package/dist/commonjs/components/NetworkIcons.d.ts +4 -0
- package/dist/commonjs/components/NetworkIcons.js +26 -1
- package/dist/commonjs/components/SegmentedTabs.js +1 -0
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/i18n/locales/en.json +20 -2
- package/dist/commonjs/index.js +45 -30
- package/dist/commonjs/native/NativeInspector.d.ts +3 -0
- package/dist/commonjs/native/NativeInspector.js +14 -1
- package/dist/commonjs/native/NativeNetworkInspector.d.ts +1 -0
- package/dist/commonjs/styles/AppColors.js +78 -78
- package/dist/commonjs/types/enums.d.ts +2 -0
- package/dist/commonjs/types/enums.js +2 -0
- package/dist/commonjs/types/interfaces.d.ts +5 -0
- package/dist/esm/capture.d.ts +2 -0
- package/dist/esm/capture.js +4 -1
- package/dist/esm/components/EmptyState.d.ts +1 -0
- package/dist/esm/components/EmptyState.js +2 -2
- package/dist/esm/components/Inspector/FabLauncher.js +462 -40
- package/dist/esm/components/Inspector/InspectorHeader.js +46 -27
- package/dist/esm/components/Inspector/MainScreen.js +4 -3
- package/dist/esm/components/Inspector/MediaGalleryTab.js +419 -14
- package/dist/esm/components/Inspector/MediaPreviewModal.js +379 -91
- package/dist/esm/components/Inspector/NetworkDetail.js +49 -63
- package/dist/esm/components/Inspector/SettingsPanel.js +500 -120
- package/dist/esm/components/Inspector/TabBar.js +135 -6
- package/dist/esm/components/JsonViewer.js +4 -3
- package/dist/esm/components/NetworkIcons.d.ts +4 -0
- package/dist/esm/components/NetworkIcons.js +21 -0
- package/dist/esm/components/SegmentedTabs.js +1 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/i18n/locales/en.json +20 -2
- package/dist/esm/index.js +44 -29
- package/dist/esm/native/NativeInspector.d.ts +3 -0
- package/dist/esm/native/NativeInspector.js +12 -0
- package/dist/esm/native/NativeNetworkInspector.d.ts +1 -0
- package/dist/esm/styles/AppColors.js +78 -78
- package/dist/esm/types/enums.d.ts +2 -0
- package/dist/esm/types/enums.js +2 -0
- package/dist/esm/types/interfaces.d.ts +5 -0
- package/ios/NetworkInspectorModule.mm +241 -136
- package/package.json +1 -1
- package/react-native-inapp-inspector.podspec +1 -1
- package/src/capture.ts +8 -0
- package/src/components/EmptyState.tsx +3 -1
- package/src/components/Inspector/FabLauncher.tsx +562 -52
- package/src/components/Inspector/InspectorHeader.tsx +60 -22
- package/src/components/Inspector/MainScreen.tsx +3 -2
- package/src/components/Inspector/MediaGalleryTab.tsx +502 -28
- package/src/components/Inspector/MediaPreviewModal.tsx +465 -117
- package/src/components/Inspector/NetworkDetail.tsx +80 -97
- package/src/components/Inspector/SettingsPanel.tsx +708 -152
- package/src/components/Inspector/TabBar.tsx +174 -6
- package/src/components/JsonViewer.tsx +4 -2
- package/src/components/NetworkIcons.tsx +56 -0
- package/src/components/SegmentedTabs.tsx +1 -0
- package/src/constants/version.ts +1 -1
- package/src/i18n/locales/en.json +20 -4
- package/src/index.tsx +46 -31
- package/src/native/NativeInspector.ts +17 -0
- package/src/native/NativeNetworkInspector.ts +1 -0
- package/src/styles/AppColors.ts +80 -80
- package/src/types/enums.ts +2 -0
- package/src/types/interfaces.ts +5 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, {useRef, useState} from 'react';
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
NativeScrollEvent,
|
|
4
|
+
NativeSyntheticEvent,
|
|
4
5
|
Platform,
|
|
5
6
|
ScrollView,
|
|
6
7
|
Text,
|
|
@@ -23,11 +24,12 @@ import {
|
|
|
23
24
|
SmartphoneIcon,
|
|
24
25
|
DatabaseIcon,
|
|
25
26
|
QrCodeIcon,
|
|
27
|
+
ScreencastIcon,
|
|
28
|
+
ChevronIcon,
|
|
26
29
|
} from '../NetworkIcons';
|
|
27
30
|
|
|
28
31
|
import {isReduxConnected} from '../../customHooks/reduxLogger';
|
|
29
32
|
import {isAnalyticsConnected} from '../../customHooks/analyticsLogger';
|
|
30
|
-
import {triggerNativeHaptic} from '../../native/NativeInspector';
|
|
31
33
|
import {isLocalDebugEnvironment} from '../../helpers';
|
|
32
34
|
|
|
33
35
|
const TabBar = React.memo(() => {
|
|
@@ -42,18 +44,85 @@ const TabBar = React.memo(() => {
|
|
|
42
44
|
lastReadApisCount,
|
|
43
45
|
lastReadLogsCount,
|
|
44
46
|
lastReadCrashesCount,
|
|
45
|
-
|
|
47
|
+
mediaCount,
|
|
46
48
|
} = useInspector();
|
|
47
49
|
|
|
48
50
|
const isReduxAvail = isReduxConnected();
|
|
49
51
|
const isAnalyticsAvail = isAnalyticsConnected();
|
|
50
52
|
|
|
53
|
+
const isMediaActive = activeTab === 'media';
|
|
54
|
+
const showMediaTab = (tabVisibility?.media ?? true) && mediaCount > 0;
|
|
55
|
+
|
|
56
|
+
const scrollViewRef = useRef<ScrollView>(null);
|
|
57
|
+
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
58
|
+
const [canScrollRight, setCanScrollRight] = useState(true);
|
|
59
|
+
const scrollOffsetRef = useRef(0);
|
|
60
|
+
|
|
61
|
+
const handleScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
62
|
+
const {contentOffset, layoutMeasurement, contentSize} = event.nativeEvent;
|
|
63
|
+
const x = contentOffset.x;
|
|
64
|
+
scrollOffsetRef.current = x;
|
|
65
|
+
const hasLeft = x > 8;
|
|
66
|
+
const hasRight = x < contentSize.width - layoutMeasurement.width - 8;
|
|
67
|
+
if (canScrollLeft !== hasLeft) setCanScrollLeft(hasLeft);
|
|
68
|
+
if (canScrollRight !== hasRight) setCanScrollRight(hasRight);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const scrollTabs = (offset: number) => {
|
|
72
|
+
scrollViewRef.current?.scrollTo({
|
|
73
|
+
x: Math.max(0, scrollOffsetRef.current + offset),
|
|
74
|
+
animated: true,
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
|
|
51
78
|
return (
|
|
52
|
-
<View
|
|
79
|
+
<View
|
|
80
|
+
style={[
|
|
81
|
+
styles.tabBarContainer,
|
|
82
|
+
{
|
|
83
|
+
flexDirection: 'row',
|
|
84
|
+
alignItems: 'center',
|
|
85
|
+
paddingHorizontal: 0,
|
|
86
|
+
},
|
|
87
|
+
]}>
|
|
88
|
+
{/* Scroll Left Arrow Icon — Initially hidden until scrolled */}
|
|
89
|
+
{canScrollLeft && (
|
|
90
|
+
<TouchableOpacity
|
|
91
|
+
onPress={() => scrollTabs(-160)}
|
|
92
|
+
hitSlop={{top: 6, bottom: 6, left: 6, right: 6}}
|
|
93
|
+
activeOpacity={0.7}
|
|
94
|
+
style={{
|
|
95
|
+
paddingLeft: 6,
|
|
96
|
+
paddingRight: 2,
|
|
97
|
+
justifyContent: 'center',
|
|
98
|
+
alignItems: 'center',
|
|
99
|
+
}}>
|
|
100
|
+
<View
|
|
101
|
+
style={{
|
|
102
|
+
width: 22,
|
|
103
|
+
height: 22,
|
|
104
|
+
borderRadius: 11,
|
|
105
|
+
backgroundColor: '#E5E7EB',
|
|
106
|
+
alignItems: 'center',
|
|
107
|
+
justifyContent: 'center',
|
|
108
|
+
}}>
|
|
109
|
+
<ChevronIcon direction="left" size={13} color={AppColors.purple} />
|
|
110
|
+
</View>
|
|
111
|
+
</TouchableOpacity>
|
|
112
|
+
)}
|
|
113
|
+
|
|
114
|
+
{/* Scrollable Main Tabs (#1 - #10) */}
|
|
53
115
|
<ScrollView
|
|
116
|
+
ref={scrollViewRef}
|
|
54
117
|
horizontal
|
|
55
118
|
showsHorizontalScrollIndicator={false}
|
|
56
|
-
|
|
119
|
+
onScroll={handleScroll}
|
|
120
|
+
scrollEventThrottle={16}
|
|
121
|
+
style={{flex: 1}}
|
|
122
|
+
contentContainerStyle={{
|
|
123
|
+
paddingLeft: canScrollLeft ? 4 : 12,
|
|
124
|
+
paddingRight: showMediaTab ? 6 : 12,
|
|
125
|
+
}}>
|
|
57
126
|
{(
|
|
58
127
|
[
|
|
59
128
|
{
|
|
@@ -256,6 +325,105 @@ const TabBar = React.memo(() => {
|
|
|
256
325
|
);
|
|
257
326
|
})}
|
|
258
327
|
</ScrollView>
|
|
328
|
+
|
|
329
|
+
{/* Scroll Right Arrow Icon */}
|
|
330
|
+
{canScrollRight && (
|
|
331
|
+
<TouchableOpacity
|
|
332
|
+
onPress={() => scrollTabs(160)}
|
|
333
|
+
hitSlop={{top: 6, bottom: 6, left: 6, right: 6}}
|
|
334
|
+
activeOpacity={0.7}
|
|
335
|
+
style={{
|
|
336
|
+
paddingLeft: 2,
|
|
337
|
+
paddingRight: showMediaTab ? 4 : 8,
|
|
338
|
+
justifyContent: 'center',
|
|
339
|
+
alignItems: 'center',
|
|
340
|
+
}}>
|
|
341
|
+
<View
|
|
342
|
+
style={{
|
|
343
|
+
width: 22,
|
|
344
|
+
height: 22,
|
|
345
|
+
borderRadius: 11,
|
|
346
|
+
backgroundColor: '#E5E7EB',
|
|
347
|
+
alignItems: 'center',
|
|
348
|
+
justifyContent: 'center',
|
|
349
|
+
}}>
|
|
350
|
+
<ChevronIcon direction="right" size={13} color={AppColors.purple} />
|
|
351
|
+
</View>
|
|
352
|
+
</TouchableOpacity>
|
|
353
|
+
)}
|
|
354
|
+
|
|
355
|
+
{/* Sticky Right Screencast Tab — Visible only when mediaCount > 0 */}
|
|
356
|
+
{showMediaTab && (
|
|
357
|
+
<View
|
|
358
|
+
style={{
|
|
359
|
+
paddingLeft: 6,
|
|
360
|
+
paddingRight: 10,
|
|
361
|
+
borderLeftWidth: 1,
|
|
362
|
+
borderLeftColor: '#E5E7EB',
|
|
363
|
+
backgroundColor: '#ffffff',
|
|
364
|
+
justifyContent: 'center',
|
|
365
|
+
shadowColor: '#000000',
|
|
366
|
+
shadowOffset: {width: -3, height: 0},
|
|
367
|
+
shadowOpacity: 0.12,
|
|
368
|
+
shadowRadius: 4,
|
|
369
|
+
elevation: 4,
|
|
370
|
+
zIndex: 10,
|
|
371
|
+
}}>
|
|
372
|
+
<TouchableScale
|
|
373
|
+
key="media"
|
|
374
|
+
onPress={() => {
|
|
375
|
+
switchActiveTab('media');
|
|
376
|
+
}}
|
|
377
|
+
accessibilityRole="button"
|
|
378
|
+
accessibilityLabel="Media Gallery"
|
|
379
|
+
style={[
|
|
380
|
+
styles.contentTabButton,
|
|
381
|
+
{
|
|
382
|
+
marginRight: 0,
|
|
383
|
+
borderRadius: 8,
|
|
384
|
+
backgroundColor: isMediaActive ? AppColors.purple : '#eeeeee',
|
|
385
|
+
borderColor: isMediaActive ? AppColors.purple : '#E5E7EB',
|
|
386
|
+
borderWidth: 1,
|
|
387
|
+
paddingHorizontal: 10,
|
|
388
|
+
paddingVertical: 7,
|
|
389
|
+
alignItems: 'center',
|
|
390
|
+
justifyContent: 'center',
|
|
391
|
+
},
|
|
392
|
+
isMediaActive && styles.contentTabButtonActive,
|
|
393
|
+
]}>
|
|
394
|
+
<View
|
|
395
|
+
style={{
|
|
396
|
+
position: 'relative',
|
|
397
|
+
alignItems: 'center',
|
|
398
|
+
justifyContent: 'center',
|
|
399
|
+
}}>
|
|
400
|
+
<ScreencastIcon
|
|
401
|
+
color={isMediaActive ? AppColors.white : AppColors.grayText}
|
|
402
|
+
size={15}
|
|
403
|
+
/>
|
|
404
|
+
{mediaCount > 0 && (
|
|
405
|
+
<View
|
|
406
|
+
style={{
|
|
407
|
+
position: 'absolute',
|
|
408
|
+
top: -3,
|
|
409
|
+
right: -4,
|
|
410
|
+
width: 7,
|
|
411
|
+
height: 7,
|
|
412
|
+
borderRadius: 3.5,
|
|
413
|
+
backgroundColor: isMediaActive
|
|
414
|
+
? AppColors.emerald400
|
|
415
|
+
: AppColors.purple,
|
|
416
|
+
borderWidth: 1.2,
|
|
417
|
+
borderColor: isMediaActive
|
|
418
|
+
? AppColors.purple
|
|
419
|
+
: AppColors.white,
|
|
420
|
+
}}
|
|
421
|
+
/>
|
|
422
|
+
)}
|
|
423
|
+
</View>
|
|
424
|
+
</TouchableScale>
|
|
425
|
+
</View>
|
|
426
|
+
)}
|
|
259
427
|
</View>
|
|
260
428
|
);
|
|
261
429
|
});
|
|
@@ -242,6 +242,7 @@ const JsonViewer = React.memo(({
|
|
|
242
242
|
{!hideTabs && (
|
|
243
243
|
<View style={localStyles.toolbar}>
|
|
244
244
|
<SegmentedTabs
|
|
245
|
+
style={{flex: 1, minWidth: 0, marginRight: 8}}
|
|
245
246
|
tabs={[
|
|
246
247
|
{
|
|
247
248
|
key: 'pretty',
|
|
@@ -445,8 +446,9 @@ const localStyles = StyleSheet.create({
|
|
|
445
446
|
backgroundColor: AppColors.slate50,
|
|
446
447
|
borderBottomWidth: 1,
|
|
447
448
|
borderBottomColor: AppColors.slate200,
|
|
448
|
-
paddingHorizontal:
|
|
449
|
-
paddingVertical:
|
|
449
|
+
paddingHorizontal: 8,
|
|
450
|
+
paddingVertical: 6,
|
|
451
|
+
gap: 8,
|
|
450
452
|
},
|
|
451
453
|
contentWrapper: {
|
|
452
454
|
backgroundColor: AppColors.white,
|
|
@@ -2596,4 +2596,60 @@ export const FilmIcon = ({
|
|
|
2596
2596
|
</Svg>
|
|
2597
2597
|
);
|
|
2598
2598
|
|
|
2599
|
+
export const ScreencastIcon = ({
|
|
2600
|
+
color = AppColors.white,
|
|
2601
|
+
size = 18,
|
|
2602
|
+
}: IconProps) => (
|
|
2603
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
2604
|
+
<Path
|
|
2605
|
+
d="M2 16.1A5 5 0 0 1 5.9 20M2 12.05A9 9 0 0 1 9.95 20M2 20h.01"
|
|
2606
|
+
stroke={color}
|
|
2607
|
+
strokeWidth="2"
|
|
2608
|
+
strokeLinecap="round"
|
|
2609
|
+
strokeLinejoin="round"
|
|
2610
|
+
/>
|
|
2611
|
+
<Path
|
|
2612
|
+
d="M2 8V6a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6"
|
|
2613
|
+
stroke={color}
|
|
2614
|
+
strokeWidth="2"
|
|
2615
|
+
strokeLinecap="round"
|
|
2616
|
+
strokeLinejoin="round"
|
|
2617
|
+
/>
|
|
2618
|
+
</Svg>
|
|
2619
|
+
);
|
|
2620
|
+
|
|
2621
|
+
export const ListIcon = ({color = AppColors.white, size = 14}: IconProps) => (
|
|
2622
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
2623
|
+
<Line x1="8" y1="6" x2="21" y2="6" stroke={color} strokeWidth="2" strokeLinecap="round" />
|
|
2624
|
+
<Line x1="8" y1="12" x2="21" y2="12" stroke={color} strokeWidth="2" strokeLinecap="round" />
|
|
2625
|
+
<Line x1="8" y1="18" x2="21" y2="18" stroke={color} strokeWidth="2" strokeLinecap="round" />
|
|
2626
|
+
<Circle cx="4" cy="6" r="1.5" fill={color} />
|
|
2627
|
+
<Circle cx="4" cy="12" r="1.5" fill={color} />
|
|
2628
|
+
<Circle cx="4" cy="18" r="1.5" fill={color} />
|
|
2629
|
+
</Svg>
|
|
2630
|
+
);
|
|
2631
|
+
|
|
2632
|
+
export const GridIcon = ({color = AppColors.white, size = 14}: IconProps) => (
|
|
2633
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
2634
|
+
<Rect x="3" y="3" width="7" height="7" rx="1.5" stroke={color} strokeWidth="2" />
|
|
2635
|
+
<Rect x="14" y="3" width="7" height="7" rx="1.5" stroke={color} strokeWidth="2" />
|
|
2636
|
+
<Rect x="14" y="14" width="7" height="7" rx="1.5" stroke={color} strokeWidth="2" />
|
|
2637
|
+
<Rect x="3" y="14" width="7" height="7" rx="1.5" stroke={color} strokeWidth="2" />
|
|
2638
|
+
</Svg>
|
|
2639
|
+
);
|
|
2640
|
+
|
|
2641
|
+
export const MinimizeWindowIcon = ({color = AppColors.white, size = 14}: IconProps) => (
|
|
2642
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
2643
|
+
<Path
|
|
2644
|
+
d="M4 14h6v6M20 10h-6V4M14 10l7-7M10 14l-7 7"
|
|
2645
|
+
stroke={color}
|
|
2646
|
+
strokeWidth="2"
|
|
2647
|
+
strokeLinecap="round"
|
|
2648
|
+
strokeLinejoin="round"
|
|
2649
|
+
/>
|
|
2650
|
+
</Svg>
|
|
2651
|
+
);
|
|
2652
|
+
|
|
2653
|
+
|
|
2654
|
+
|
|
2599
2655
|
|
package/src/constants/version.ts
CHANGED
package/src/i18n/locales/en.json
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
"viewOnNpm": "View on NPM",
|
|
17
17
|
"later": "Later",
|
|
18
18
|
"source": "SOURCE",
|
|
19
|
+
"minimize": "Minimize",
|
|
20
|
+
"tapToExpand": "Tap to expand",
|
|
19
21
|
"open": "Open",
|
|
20
22
|
"openInBrowser": "Open in Browser",
|
|
21
23
|
"openInBrowserPrompt": "Are you sure you want to open this URL in your external browser?"
|
|
@@ -54,7 +56,7 @@
|
|
|
54
56
|
"crash": "Crash",
|
|
55
57
|
"device": "Device",
|
|
56
58
|
"storage": "Storage",
|
|
57
|
-
"media": "
|
|
59
|
+
"media": "Screencast"
|
|
58
60
|
},
|
|
59
61
|
|
|
60
62
|
"settings": {
|
|
@@ -203,7 +205,6 @@
|
|
|
203
205
|
"purgedSuccess": "Media storage purged"
|
|
204
206
|
},
|
|
205
207
|
"general": {
|
|
206
|
-
|
|
207
208
|
"darkMode": "Dark Mode Theme",
|
|
208
209
|
"darkModeDescription": "Toggle sleek dark aesthetic or light contrast",
|
|
209
210
|
"modalHeight": "Inspector Window Height",
|
|
@@ -1111,15 +1112,30 @@
|
|
|
1111
1112
|
"allPurged": "All captured media purged",
|
|
1112
1113
|
"converting": "Converting...",
|
|
1113
1114
|
"convertToGif": "Convert to GIF",
|
|
1115
|
+
"playVideo": "Play Video",
|
|
1116
|
+
"playError": "Unable to play video",
|
|
1114
1117
|
"convertedSuccess": "Converted to Animated GIF successfully!",
|
|
1115
1118
|
"convertFailed": "Failed to convert to GIF",
|
|
1116
1119
|
"share": "Share",
|
|
1117
1120
|
"copyUri": "Copy URI",
|
|
1118
1121
|
"uriCopied": "File URI copied to clipboard",
|
|
1119
1122
|
"delete": "Delete",
|
|
1123
|
+
"deleteSelected": "Delete ({{count}})",
|
|
1124
|
+
"deleteSelectedTitle": "Delete Selected",
|
|
1125
|
+
"deleteSelectedMessage": "Are you sure you want to delete {{count}} selected media items?",
|
|
1126
|
+
"deletedCount": "Deleted {{count}} media items",
|
|
1120
1127
|
"deleteTitle": "Delete Media",
|
|
1121
1128
|
"deleteMessage": "Are you sure you want to delete {{filename}}?",
|
|
1122
|
-
"shareUnavailable": "Sharing not available on this device"
|
|
1129
|
+
"shareUnavailable": "Sharing not available on this device",
|
|
1130
|
+
"showingResults": "Showing {{count}} results",
|
|
1131
|
+
"showingFilteredResults": "Showing {{count}} of {{total}} results",
|
|
1132
|
+
"selectedOfResults": "Selected {{selected}} of {{total}} results",
|
|
1133
|
+
"minimize": "Minimize",
|
|
1134
|
+
"expand": "Expand Fullscreen",
|
|
1135
|
+
"collapse": "Exit Fullscreen",
|
|
1136
|
+
"speed": "Speed",
|
|
1137
|
+
"loop": "Loop",
|
|
1138
|
+
"pause": "Pause",
|
|
1139
|
+
"play": "Play"
|
|
1123
1140
|
}
|
|
1124
1141
|
}
|
|
1125
|
-
|
package/src/index.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import React, {useEffect, useMemo, useRef, useState, useCallback} from 'react';
|
|
|
2
2
|
import {
|
|
3
3
|
Alert,
|
|
4
4
|
Animated,
|
|
5
|
+
Easing,
|
|
5
6
|
PanResponder,
|
|
6
7
|
Platform,
|
|
7
8
|
UIManager,
|
|
@@ -130,6 +131,7 @@ import {
|
|
|
130
131
|
fetchRemoteConfigModuleStatus,
|
|
131
132
|
isFirebaseRemoteConfigAvailable,
|
|
132
133
|
} from './helpers/remoteConfig';
|
|
134
|
+
import {ScreenCapture} from './capture';
|
|
133
135
|
|
|
134
136
|
// Constants
|
|
135
137
|
import {
|
|
@@ -184,6 +186,12 @@ const NetworkInspector = ({
|
|
|
184
186
|
const [visible, setVisible] = useState<boolean>(
|
|
185
187
|
controlledVisible ?? initialVisible ?? false,
|
|
186
188
|
);
|
|
189
|
+
const [isMinimized, setIsMinimized] = useState<boolean>(false);
|
|
190
|
+
|
|
191
|
+
const minimizeInspector = useCallback(() => {
|
|
192
|
+
setIsMinimized(true);
|
|
193
|
+
setVisible(false);
|
|
194
|
+
}, []);
|
|
187
195
|
|
|
188
196
|
useEffect(() => {
|
|
189
197
|
if (controlledVisible !== undefined) {
|
|
@@ -267,6 +275,25 @@ const NetworkInspector = ({
|
|
|
267
275
|
const [lastReadLogsCount, setLastReadLogsCount] = useState(0);
|
|
268
276
|
const [lastReadApisCount, setLastReadApisCount] = useState(0);
|
|
269
277
|
const [lastReadCrashesCount, setLastReadCrashesCount] = useState(0);
|
|
278
|
+
const [mediaCount, setMediaCount] = useState(0);
|
|
279
|
+
|
|
280
|
+
const refreshMediaCount = useCallback(async () => {
|
|
281
|
+
try {
|
|
282
|
+
const items = await ScreenCapture.getMediaList();
|
|
283
|
+
const count = items ? items.length : 0;
|
|
284
|
+
setMediaCount(count);
|
|
285
|
+
return count;
|
|
286
|
+
} catch {
|
|
287
|
+
setMediaCount(0);
|
|
288
|
+
return 0;
|
|
289
|
+
}
|
|
290
|
+
}, []);
|
|
291
|
+
|
|
292
|
+
useEffect(() => {
|
|
293
|
+
if (visible) {
|
|
294
|
+
refreshMediaCount();
|
|
295
|
+
}
|
|
296
|
+
}, [visible, refreshMediaCount]);
|
|
270
297
|
|
|
271
298
|
// ─── Crash state ───────────────────────────────────────────────────────────
|
|
272
299
|
const [crashRecords, setCrashRecords] = useState<CrashRecord[]>(() =>
|
|
@@ -375,6 +402,7 @@ const NetworkInspector = ({
|
|
|
375
402
|
device: false,
|
|
376
403
|
storage: false,
|
|
377
404
|
debugging: false,
|
|
405
|
+
media: true,
|
|
378
406
|
});
|
|
379
407
|
|
|
380
408
|
const [maxNetworkLogs, setMaxNetworkLogs] = useState<number>(250);
|
|
@@ -438,6 +466,7 @@ const NetworkInspector = ({
|
|
|
438
466
|
device: false,
|
|
439
467
|
storage: false,
|
|
440
468
|
debugging: false,
|
|
469
|
+
media: true,
|
|
441
470
|
});
|
|
442
471
|
|
|
443
472
|
setDefaultTab('apis');
|
|
@@ -930,10 +959,11 @@ const NetworkInspector = ({
|
|
|
930
959
|
Animated.sequence([
|
|
931
960
|
Animated.timing(fabShineAnim, {
|
|
932
961
|
toValue: 1,
|
|
933
|
-
duration:
|
|
962
|
+
duration: 3200,
|
|
963
|
+
easing: Easing.inOut(Easing.ease),
|
|
934
964
|
useNativeDriver: false,
|
|
935
965
|
}),
|
|
936
|
-
Animated.delay(
|
|
966
|
+
Animated.delay(3500),
|
|
937
967
|
Animated.timing(fabShineAnim, {
|
|
938
968
|
toValue: 0,
|
|
939
969
|
duration: 0,
|
|
@@ -989,36 +1019,12 @@ const NetworkInspector = ({
|
|
|
989
1019
|
|
|
990
1020
|
|
|
991
1021
|
|
|
992
|
-
//
|
|
1022
|
+
// Always hide legacy native circular button in favor of the React Native music-player dock
|
|
993
1023
|
useEffect(() => {
|
|
994
|
-
if (
|
|
995
|
-
if (useNativeFab) {
|
|
996
|
-
hideNativeFloatingButton().catch(() => {});
|
|
997
|
-
}
|
|
998
|
-
return;
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
if (visible) {
|
|
1024
|
+
if (useNativeFab) {
|
|
1002
1025
|
hideNativeFloatingButton().catch(() => {});
|
|
1003
|
-
} else {
|
|
1004
|
-
showNativeFloatingButton().catch(() => {});
|
|
1005
|
-
setNativeFloatingButtonBadge(
|
|
1006
|
-
logs.length > 0 || analyticsEvents.length > 0,
|
|
1007
|
-
).catch(() => {});
|
|
1008
1026
|
}
|
|
1009
|
-
|
|
1010
|
-
return () => {
|
|
1011
|
-
if (useNativeFab) {
|
|
1012
|
-
hideNativeFloatingButton().catch(() => {});
|
|
1013
|
-
}
|
|
1014
|
-
};
|
|
1015
|
-
}, [
|
|
1016
|
-
useNativeFab,
|
|
1017
|
-
enabled,
|
|
1018
|
-
visible,
|
|
1019
|
-
logs.length,
|
|
1020
|
-
analyticsEvents.length,
|
|
1021
|
-
]);
|
|
1027
|
+
}, [useNativeFab, visible]);
|
|
1022
1028
|
|
|
1023
1029
|
// Subscribe to native UI-thread floating button tap events
|
|
1024
1030
|
useEffect(() => {
|
|
@@ -1874,8 +1880,9 @@ const NetworkInspector = ({
|
|
|
1874
1880
|
};
|
|
1875
1881
|
}, [visibleConsoleLogs, logSearch]);
|
|
1876
1882
|
|
|
1877
|
-
|
|
1883
|
+
const closeModal = useCallback(() => {
|
|
1878
1884
|
setVisible(false);
|
|
1885
|
+
setIsMinimized(false);
|
|
1879
1886
|
setTimeout(() => {
|
|
1880
1887
|
setSelected(null);
|
|
1881
1888
|
setSelectedEvent(null);
|
|
@@ -1884,7 +1891,7 @@ const NetworkInspector = ({
|
|
|
1884
1891
|
setSelectedReduxAction(null);
|
|
1885
1892
|
setSelectedCrash(null);
|
|
1886
1893
|
}, 300);
|
|
1887
|
-
}
|
|
1894
|
+
}, []);
|
|
1888
1895
|
|
|
1889
1896
|
function handleClearAll() {
|
|
1890
1897
|
clearNetworkLogs();
|
|
@@ -2049,6 +2056,9 @@ const NetworkInspector = ({
|
|
|
2049
2056
|
visible,
|
|
2050
2057
|
setVisible,
|
|
2051
2058
|
closeModal,
|
|
2059
|
+
isMinimized,
|
|
2060
|
+
setIsMinimized,
|
|
2061
|
+
minimizeInspector,
|
|
2052
2062
|
isReady,
|
|
2053
2063
|
enabled,
|
|
2054
2064
|
isEnabled: enabled,
|
|
@@ -2068,6 +2078,8 @@ const NetworkInspector = ({
|
|
|
2068
2078
|
toggleTabVisibility,
|
|
2069
2079
|
lastReadApisCount,
|
|
2070
2080
|
lastReadLogsCount,
|
|
2081
|
+
mediaCount,
|
|
2082
|
+
refreshMediaCount,
|
|
2071
2083
|
|
|
2072
2084
|
// ─── Selection / header state ───────────────────────────────────────
|
|
2073
2085
|
selected,
|
|
@@ -2252,6 +2264,8 @@ const NetworkInspector = ({
|
|
|
2252
2264
|
toggleTabVisibility,
|
|
2253
2265
|
lastReadApisCount,
|
|
2254
2266
|
lastReadLogsCount,
|
|
2267
|
+
mediaCount,
|
|
2268
|
+
refreshMediaCount,
|
|
2255
2269
|
selected,
|
|
2256
2270
|
selectedEvent,
|
|
2257
2271
|
selectedLog,
|
|
@@ -2342,6 +2356,7 @@ const NetworkInspector = ({
|
|
|
2342
2356
|
deviceFreeRamMb,
|
|
2343
2357
|
reduxAutoRefresh,
|
|
2344
2358
|
reduxExpandDepth,
|
|
2359
|
+
isMinimized,
|
|
2345
2360
|
],
|
|
2346
2361
|
);
|
|
2347
2362
|
|
|
@@ -468,6 +468,7 @@ export interface RecordingOptions {
|
|
|
468
468
|
|
|
469
469
|
export interface RecordingResult {
|
|
470
470
|
uri: string;
|
|
471
|
+
thumbnailUri?: string;
|
|
471
472
|
format: 'mp4' | 'gif';
|
|
472
473
|
durationMs: number;
|
|
473
474
|
hasAudio: boolean;
|
|
@@ -488,6 +489,7 @@ export interface CapturedMediaItem {
|
|
|
488
489
|
type: 'image' | 'video' | 'gif';
|
|
489
490
|
format: string;
|
|
490
491
|
uri: string;
|
|
492
|
+
thumbnailUri?: string;
|
|
491
493
|
filename: string;
|
|
492
494
|
sizeBytes: number;
|
|
493
495
|
timestamp: number;
|
|
@@ -561,6 +563,21 @@ export const isNativeRecordingActive = async (): Promise<boolean> => {
|
|
|
561
563
|
}
|
|
562
564
|
};
|
|
563
565
|
|
|
566
|
+
/**
|
|
567
|
+
* Plays a recorded video file using the native system media player.
|
|
568
|
+
*/
|
|
569
|
+
export const playNativeVideo = async (videoUri: string): Promise<boolean> => {
|
|
570
|
+
if (!NativeModule || !NativeModule.playVideo) {
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
573
|
+
try {
|
|
574
|
+
const result = await NativeModule.playVideo(videoUri);
|
|
575
|
+
return !!result;
|
|
576
|
+
} catch {
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
|
|
564
581
|
/**
|
|
565
582
|
* Converts a recorded MP4 video to an animated GIF.
|
|
566
583
|
*/
|
|
@@ -22,6 +22,7 @@ export interface Spec extends TurboModule {
|
|
|
22
22
|
stopVideoRecording(): Promise<Object>;
|
|
23
23
|
isRecording(): Promise<boolean>;
|
|
24
24
|
convertToGif(videoUri: string, options: Object): Promise<Object>;
|
|
25
|
+
playVideo(videoUri: string): Promise<boolean>;
|
|
25
26
|
getCapturedMedia(): Promise<string>;
|
|
26
27
|
deleteCapturedMedia(uri: string): Promise<boolean>;
|
|
27
28
|
clearAllCapturedMedia(): Promise<boolean>;
|