react-native-inapp-inspector 2.3.17 → 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,20 +1,73 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Platform, ScrollView, Text, View, } from 'react-native';
|
|
1
|
+
import React, { useRef, useState } from 'react';
|
|
2
|
+
import { Platform, ScrollView, Text, TouchableOpacity, View, } from 'react-native';
|
|
3
3
|
import { useInspector } from './InspectorContext';
|
|
4
4
|
import styles from '../../styles';
|
|
5
5
|
import { AppColors } from '../../styles/AppColors';
|
|
6
6
|
import { AppFonts } from '../../styles/AppFonts';
|
|
7
7
|
import TouchableScale from '../TouchableScale';
|
|
8
|
-
import { SignalIcon, TerminalIcon, AnalyticsIcon, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, SmartphoneIcon, DatabaseIcon, QrCodeIcon, } from '../NetworkIcons';
|
|
8
|
+
import { SignalIcon, TerminalIcon, AnalyticsIcon, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, SmartphoneIcon, DatabaseIcon, QrCodeIcon, ScreencastIcon, ChevronIcon, } from '../NetworkIcons';
|
|
9
9
|
import { isReduxConnected } from '../../customHooks/reduxLogger';
|
|
10
10
|
import { isAnalyticsConnected } from '../../customHooks/analyticsLogger';
|
|
11
11
|
import { isLocalDebugEnvironment } from '../../helpers';
|
|
12
12
|
const TabBar = React.memo(() => {
|
|
13
|
-
const { activeTab, switchActiveTab, tabVisibility, logs, consoleLogs, analyticsEvents, crashRecords, lastReadApisCount, lastReadLogsCount, lastReadCrashesCount,
|
|
13
|
+
const { activeTab, switchActiveTab, tabVisibility, logs, consoleLogs, analyticsEvents, crashRecords, lastReadApisCount, lastReadLogsCount, lastReadCrashesCount, mediaCount, } = useInspector();
|
|
14
14
|
const isReduxAvail = isReduxConnected();
|
|
15
15
|
const isAnalyticsAvail = isAnalyticsConnected();
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const isMediaActive = activeTab === 'media';
|
|
17
|
+
const showMediaTab = (tabVisibility?.media ?? true) && mediaCount > 0;
|
|
18
|
+
const scrollViewRef = useRef(null);
|
|
19
|
+
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
20
|
+
const [canScrollRight, setCanScrollRight] = useState(true);
|
|
21
|
+
const scrollOffsetRef = useRef(0);
|
|
22
|
+
const handleScroll = (event) => {
|
|
23
|
+
const { contentOffset, layoutMeasurement, contentSize } = event.nativeEvent;
|
|
24
|
+
const x = contentOffset.x;
|
|
25
|
+
scrollOffsetRef.current = x;
|
|
26
|
+
const hasLeft = x > 8;
|
|
27
|
+
const hasRight = x < contentSize.width - layoutMeasurement.width - 8;
|
|
28
|
+
if (canScrollLeft !== hasLeft)
|
|
29
|
+
setCanScrollLeft(hasLeft);
|
|
30
|
+
if (canScrollRight !== hasRight)
|
|
31
|
+
setCanScrollRight(hasRight);
|
|
32
|
+
};
|
|
33
|
+
const scrollTabs = (offset) => {
|
|
34
|
+
scrollViewRef.current?.scrollTo({
|
|
35
|
+
x: Math.max(0, scrollOffsetRef.current + offset),
|
|
36
|
+
animated: true,
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
return (<View style={[
|
|
40
|
+
styles.tabBarContainer,
|
|
41
|
+
{
|
|
42
|
+
flexDirection: 'row',
|
|
43
|
+
alignItems: 'center',
|
|
44
|
+
paddingHorizontal: 0,
|
|
45
|
+
},
|
|
46
|
+
]}>
|
|
47
|
+
|
|
48
|
+
{canScrollLeft && (<TouchableOpacity onPress={() => scrollTabs(-160)} hitSlop={{ top: 6, bottom: 6, left: 6, right: 6 }} activeOpacity={0.7} style={{
|
|
49
|
+
paddingLeft: 6,
|
|
50
|
+
paddingRight: 2,
|
|
51
|
+
justifyContent: 'center',
|
|
52
|
+
alignItems: 'center',
|
|
53
|
+
}}>
|
|
54
|
+
<View style={{
|
|
55
|
+
width: 22,
|
|
56
|
+
height: 22,
|
|
57
|
+
borderRadius: 11,
|
|
58
|
+
backgroundColor: '#E5E7EB',
|
|
59
|
+
alignItems: 'center',
|
|
60
|
+
justifyContent: 'center',
|
|
61
|
+
}}>
|
|
62
|
+
<ChevronIcon direction="left" size={13} color={AppColors.purple}/>
|
|
63
|
+
</View>
|
|
64
|
+
</TouchableOpacity>)}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
<ScrollView ref={scrollViewRef} horizontal showsHorizontalScrollIndicator={false} onScroll={handleScroll} scrollEventThrottle={16} style={{ flex: 1 }} contentContainerStyle={{
|
|
68
|
+
paddingLeft: canScrollLeft ? 4 : 12,
|
|
69
|
+
paddingRight: showMediaTab ? 6 : 12,
|
|
70
|
+
}}>
|
|
18
71
|
{[
|
|
19
72
|
{
|
|
20
73
|
id: 1,
|
|
@@ -178,6 +231,82 @@ const TabBar = React.memo(() => {
|
|
|
178
231
|
</TouchableScale>);
|
|
179
232
|
})}
|
|
180
233
|
</ScrollView>
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
{canScrollRight && (<TouchableOpacity onPress={() => scrollTabs(160)} hitSlop={{ top: 6, bottom: 6, left: 6, right: 6 }} activeOpacity={0.7} style={{
|
|
237
|
+
paddingLeft: 2,
|
|
238
|
+
paddingRight: showMediaTab ? 4 : 8,
|
|
239
|
+
justifyContent: 'center',
|
|
240
|
+
alignItems: 'center',
|
|
241
|
+
}}>
|
|
242
|
+
<View style={{
|
|
243
|
+
width: 22,
|
|
244
|
+
height: 22,
|
|
245
|
+
borderRadius: 11,
|
|
246
|
+
backgroundColor: '#E5E7EB',
|
|
247
|
+
alignItems: 'center',
|
|
248
|
+
justifyContent: 'center',
|
|
249
|
+
}}>
|
|
250
|
+
<ChevronIcon direction="right" size={13} color={AppColors.purple}/>
|
|
251
|
+
</View>
|
|
252
|
+
</TouchableOpacity>)}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
{showMediaTab && (<View style={{
|
|
256
|
+
paddingLeft: 6,
|
|
257
|
+
paddingRight: 10,
|
|
258
|
+
borderLeftWidth: 1,
|
|
259
|
+
borderLeftColor: '#E5E7EB',
|
|
260
|
+
backgroundColor: '#ffffff',
|
|
261
|
+
justifyContent: 'center',
|
|
262
|
+
shadowColor: '#000000',
|
|
263
|
+
shadowOffset: { width: -3, height: 0 },
|
|
264
|
+
shadowOpacity: 0.12,
|
|
265
|
+
shadowRadius: 4,
|
|
266
|
+
elevation: 4,
|
|
267
|
+
zIndex: 10,
|
|
268
|
+
}}>
|
|
269
|
+
<TouchableScale key="media" onPress={() => {
|
|
270
|
+
switchActiveTab('media');
|
|
271
|
+
}} accessibilityRole="button" accessibilityLabel="Media Gallery" style={[
|
|
272
|
+
styles.contentTabButton,
|
|
273
|
+
{
|
|
274
|
+
marginRight: 0,
|
|
275
|
+
borderRadius: 8,
|
|
276
|
+
backgroundColor: isMediaActive ? AppColors.purple : '#eeeeee',
|
|
277
|
+
borderColor: isMediaActive ? AppColors.purple : '#E5E7EB',
|
|
278
|
+
borderWidth: 1,
|
|
279
|
+
paddingHorizontal: 10,
|
|
280
|
+
paddingVertical: 7,
|
|
281
|
+
alignItems: 'center',
|
|
282
|
+
justifyContent: 'center',
|
|
283
|
+
},
|
|
284
|
+
isMediaActive && styles.contentTabButtonActive,
|
|
285
|
+
]}>
|
|
286
|
+
<View style={{
|
|
287
|
+
position: 'relative',
|
|
288
|
+
alignItems: 'center',
|
|
289
|
+
justifyContent: 'center',
|
|
290
|
+
}}>
|
|
291
|
+
<ScreencastIcon color={isMediaActive ? AppColors.white : AppColors.grayText} size={15}/>
|
|
292
|
+
{mediaCount > 0 && (<View style={{
|
|
293
|
+
position: 'absolute',
|
|
294
|
+
top: -3,
|
|
295
|
+
right: -4,
|
|
296
|
+
width: 7,
|
|
297
|
+
height: 7,
|
|
298
|
+
borderRadius: 3.5,
|
|
299
|
+
backgroundColor: isMediaActive
|
|
300
|
+
? AppColors.emerald400
|
|
301
|
+
: AppColors.purple,
|
|
302
|
+
borderWidth: 1.2,
|
|
303
|
+
borderColor: isMediaActive
|
|
304
|
+
? AppColors.purple
|
|
305
|
+
: AppColors.white,
|
|
306
|
+
}}/>)}
|
|
307
|
+
</View>
|
|
308
|
+
</TouchableScale>
|
|
309
|
+
</View>)}
|
|
181
310
|
</View>);
|
|
182
311
|
});
|
|
183
312
|
export default TabBar;
|
|
@@ -141,7 +141,7 @@ const JsonViewer = React.memo(({ data, search, forceOpen, defaultExpandDepth = 1
|
|
|
141
141
|
return (<View style={[localStyles.container, fullHeight && { flex: 1 }]}>
|
|
142
142
|
|
|
143
143
|
{!hideTabs && (<View style={localStyles.toolbar}>
|
|
144
|
-
<SegmentedTabs tabs={[
|
|
144
|
+
<SegmentedTabs style={{ flex: 1, minWidth: 0, marginRight: 8 }} tabs={[
|
|
145
145
|
{
|
|
146
146
|
key: 'pretty',
|
|
147
147
|
label: t('network.jsonViewer.pretty'),
|
|
@@ -258,8 +258,9 @@ const localStyles = StyleSheet.create({
|
|
|
258
258
|
backgroundColor: AppColors.slate50,
|
|
259
259
|
borderBottomWidth: 1,
|
|
260
260
|
borderBottomColor: AppColors.slate200,
|
|
261
|
-
paddingHorizontal:
|
|
262
|
-
paddingVertical:
|
|
261
|
+
paddingHorizontal: 8,
|
|
262
|
+
paddingVertical: 6,
|
|
263
|
+
gap: 8,
|
|
263
264
|
},
|
|
264
265
|
contentWrapper: {
|
|
265
266
|
backgroundColor: AppColors.white,
|
|
@@ -151,3 +151,7 @@ export declare const PlayIcon: ({ color, size, }: IconProps) => React.JSX.Elemen
|
|
|
151
151
|
export declare const PauseIcon: ({ color, size, }: IconProps) => React.JSX.Element;
|
|
152
152
|
export declare const ImageIcon: ({ color, size, }: IconProps) => React.JSX.Element;
|
|
153
153
|
export declare const FilmIcon: ({ color, size, }: IconProps) => React.JSX.Element;
|
|
154
|
+
export declare const ScreencastIcon: ({ color, size, }: IconProps) => React.JSX.Element;
|
|
155
|
+
export declare const ListIcon: ({ color, size }: IconProps) => React.JSX.Element;
|
|
156
|
+
export declare const GridIcon: ({ color, size }: IconProps) => React.JSX.Element;
|
|
157
|
+
export declare const MinimizeWindowIcon: ({ color, size }: IconProps) => React.JSX.Element;
|
|
@@ -828,3 +828,24 @@ export const FilmIcon = ({ color = AppColors.white, size = 18, }) => (<Svg width
|
|
|
828
828
|
<Line x1="17" y1="17" x2="22" y2="17" stroke={color} strokeWidth="2"/>
|
|
829
829
|
<Line x1="17" y1="7" x2="22" y2="7" stroke={color} strokeWidth="2"/>
|
|
830
830
|
</Svg>);
|
|
831
|
+
export const ScreencastIcon = ({ color = AppColors.white, size = 18, }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
832
|
+
<Path d="M2 16.1A5 5 0 0 1 5.9 20M2 12.05A9 9 0 0 1 9.95 20M2 20h.01" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
|
833
|
+
<Path d="M2 8V6a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
|
834
|
+
</Svg>);
|
|
835
|
+
export const ListIcon = ({ color = AppColors.white, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
836
|
+
<Line x1="8" y1="6" x2="21" y2="6" stroke={color} strokeWidth="2" strokeLinecap="round"/>
|
|
837
|
+
<Line x1="8" y1="12" x2="21" y2="12" stroke={color} strokeWidth="2" strokeLinecap="round"/>
|
|
838
|
+
<Line x1="8" y1="18" x2="21" y2="18" stroke={color} strokeWidth="2" strokeLinecap="round"/>
|
|
839
|
+
<Circle cx="4" cy="6" r="1.5" fill={color}/>
|
|
840
|
+
<Circle cx="4" cy="12" r="1.5" fill={color}/>
|
|
841
|
+
<Circle cx="4" cy="18" r="1.5" fill={color}/>
|
|
842
|
+
</Svg>);
|
|
843
|
+
export const GridIcon = ({ color = AppColors.white, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
844
|
+
<Rect x="3" y="3" width="7" height="7" rx="1.5" stroke={color} strokeWidth="2"/>
|
|
845
|
+
<Rect x="14" y="3" width="7" height="7" rx="1.5" stroke={color} strokeWidth="2"/>
|
|
846
|
+
<Rect x="14" y="14" width="7" height="7" rx="1.5" stroke={color} strokeWidth="2"/>
|
|
847
|
+
<Rect x="3" y="14" width="7" height="7" rx="1.5" stroke={color} strokeWidth="2"/>
|
|
848
|
+
</Svg>);
|
|
849
|
+
export const MinimizeWindowIcon = ({ color = AppColors.white, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
850
|
+
<Path d="M4 14h6v6M20 10h-6V4M14 10l7-7M10 14l-7 7" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
|
851
|
+
</Svg>);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "2.3.
|
|
1
|
+
export declare const LIB_VERSION = "2.3.19";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LIB_VERSION = '2.3.
|
|
1
|
+
export const LIB_VERSION = '2.3.19';
|
|
@@ -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
|
"settings": {
|
|
60
62
|
"mainTitle": "Settings & Modules",
|
|
@@ -1109,14 +1111,30 @@
|
|
|
1109
1111
|
"allPurged": "All captured media purged",
|
|
1110
1112
|
"converting": "Converting...",
|
|
1111
1113
|
"convertToGif": "Convert to GIF",
|
|
1114
|
+
"playVideo": "Play Video",
|
|
1115
|
+
"playError": "Unable to play video",
|
|
1112
1116
|
"convertedSuccess": "Converted to Animated GIF successfully!",
|
|
1113
1117
|
"convertFailed": "Failed to convert to GIF",
|
|
1114
1118
|
"share": "Share",
|
|
1115
1119
|
"copyUri": "Copy URI",
|
|
1116
1120
|
"uriCopied": "File URI copied to clipboard",
|
|
1117
1121
|
"delete": "Delete",
|
|
1122
|
+
"deleteSelected": "Delete ({{count}})",
|
|
1123
|
+
"deleteSelectedTitle": "Delete Selected",
|
|
1124
|
+
"deleteSelectedMessage": "Are you sure you want to delete {{count}} selected media items?",
|
|
1125
|
+
"deletedCount": "Deleted {{count}} media items",
|
|
1118
1126
|
"deleteTitle": "Delete Media",
|
|
1119
1127
|
"deleteMessage": "Are you sure you want to delete {{filename}}?",
|
|
1120
|
-
"shareUnavailable": "Sharing not available on this device"
|
|
1128
|
+
"shareUnavailable": "Sharing not available on this device",
|
|
1129
|
+
"showingResults": "Showing {{count}} results",
|
|
1130
|
+
"showingFilteredResults": "Showing {{count}} of {{total}} results",
|
|
1131
|
+
"selectedOfResults": "Selected {{selected}} of {{total}} results",
|
|
1132
|
+
"minimize": "Minimize",
|
|
1133
|
+
"expand": "Expand Fullscreen",
|
|
1134
|
+
"collapse": "Exit Fullscreen",
|
|
1135
|
+
"speed": "Speed",
|
|
1136
|
+
"loop": "Loop",
|
|
1137
|
+
"pause": "Pause",
|
|
1138
|
+
"play": "Play"
|
|
1121
1139
|
}
|
|
1122
1140
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react';
|
|
2
|
-
import { Alert, Animated, PanResponder, Platform, UIManager, LogBox, } from 'react-native';
|
|
2
|
+
import { Alert, Animated, Easing, PanResponder, Platform, UIManager, LogBox, } from 'react-native';
|
|
3
3
|
import { NavigationContext } from '@react-navigation/native';
|
|
4
4
|
import { I18nextProvider, i18n } from './i18n';
|
|
5
5
|
import ErrorBoundary from './components/ErrorBoundary';
|
|
@@ -17,8 +17,9 @@ import { subscribeAnalyticsEvents, clearAnalyticsEvents, autoSetupAnalyticsLogge
|
|
|
17
17
|
import { getReduxState, subscribeReduxState, setReduxAutoRefresh, getLastActionForReducer, clearActionHistory, isReduxConnected, setReduxModuleEnabled, } from './customHooks/reduxLogger';
|
|
18
18
|
import { setPerformanceModuleEnabled } from './customHooks/performanceTracker';
|
|
19
19
|
import { setBundleModuleEnabled } from './customHooks/bundleAnalyzer';
|
|
20
|
-
import {
|
|
20
|
+
import { hideNativeFloatingButton, subscribeNativeFloatingButtonPress, subscribeNativeDeviceShake, isNativeModuleAvailable, } from './native/NativeInspector';
|
|
21
21
|
import { fetchRemoteConfigModuleStatus, } from './helpers/remoteConfig';
|
|
22
|
+
import { ScreenCapture } from './capture';
|
|
22
23
|
import { LIB_VERSION } from './constants';
|
|
23
24
|
import { toggleGlobalTheme } from './styles';
|
|
24
25
|
const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, environment, initialVisible = false, visible: controlledVisible, remoteConfig, }) => {
|
|
@@ -30,6 +31,11 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
30
31
|
const [modalAnimationType, setModalAnimationType] = useState('slide');
|
|
31
32
|
const [logs, setLogs] = useState([]);
|
|
32
33
|
const [visible, setVisible] = useState(controlledVisible ?? initialVisible ?? false);
|
|
34
|
+
const [isMinimized, setIsMinimized] = useState(false);
|
|
35
|
+
const minimizeInspector = useCallback(() => {
|
|
36
|
+
setIsMinimized(true);
|
|
37
|
+
setVisible(false);
|
|
38
|
+
}, []);
|
|
33
39
|
useEffect(() => {
|
|
34
40
|
if (controlledVisible !== undefined) {
|
|
35
41
|
setVisible(controlledVisible);
|
|
@@ -91,6 +97,24 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
91
97
|
const [lastReadLogsCount, setLastReadLogsCount] = useState(0);
|
|
92
98
|
const [lastReadApisCount, setLastReadApisCount] = useState(0);
|
|
93
99
|
const [lastReadCrashesCount, setLastReadCrashesCount] = useState(0);
|
|
100
|
+
const [mediaCount, setMediaCount] = useState(0);
|
|
101
|
+
const refreshMediaCount = useCallback(async () => {
|
|
102
|
+
try {
|
|
103
|
+
const items = await ScreenCapture.getMediaList();
|
|
104
|
+
const count = items ? items.length : 0;
|
|
105
|
+
setMediaCount(count);
|
|
106
|
+
return count;
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
setMediaCount(0);
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
}, []);
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
if (visible) {
|
|
115
|
+
refreshMediaCount();
|
|
116
|
+
}
|
|
117
|
+
}, [visible, refreshMediaCount]);
|
|
94
118
|
const [crashRecords, setCrashRecords] = useState(() => getCrashRecords());
|
|
95
119
|
const [selectedCrash, setSelectedCrash] = useState(null);
|
|
96
120
|
const [maxCrashLogs, setMaxCrashLogs] = useState(50);
|
|
@@ -171,6 +195,7 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
171
195
|
device: false,
|
|
172
196
|
storage: false,
|
|
173
197
|
debugging: false,
|
|
198
|
+
media: true,
|
|
174
199
|
});
|
|
175
200
|
const [maxNetworkLogs, setMaxNetworkLogs] = useState(250);
|
|
176
201
|
const [maxAnalyticsEventsLimit, setMaxAnalyticsEventsLimit] = useState(150);
|
|
@@ -225,6 +250,7 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
225
250
|
device: false,
|
|
226
251
|
storage: false,
|
|
227
252
|
debugging: false,
|
|
253
|
+
media: true,
|
|
228
254
|
});
|
|
229
255
|
setDefaultTab('apis');
|
|
230
256
|
setIsAutoRamLimitEnabled(true);
|
|
@@ -687,10 +713,11 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
687
713
|
const loop = Animated.loop(Animated.sequence([
|
|
688
714
|
Animated.timing(fabShineAnim, {
|
|
689
715
|
toValue: 1,
|
|
690
|
-
duration:
|
|
716
|
+
duration: 3200,
|
|
717
|
+
easing: Easing.inOut(Easing.ease),
|
|
691
718
|
useNativeDriver: false,
|
|
692
719
|
}),
|
|
693
|
-
Animated.delay(
|
|
720
|
+
Animated.delay(3500),
|
|
694
721
|
Animated.timing(fabShineAnim, {
|
|
695
722
|
toValue: 0,
|
|
696
723
|
duration: 0,
|
|
@@ -735,31 +762,10 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
735
762
|
const isNativeModule = useMemo(() => isNativeModuleAvailable(), []);
|
|
736
763
|
const useNativeFab = (Platform.OS === 'ios' || Platform.OS === 'android') && isNativeModule;
|
|
737
764
|
useEffect(() => {
|
|
738
|
-
if (
|
|
739
|
-
if (useNativeFab) {
|
|
740
|
-
hideNativeFloatingButton().catch(() => { });
|
|
741
|
-
}
|
|
742
|
-
return;
|
|
743
|
-
}
|
|
744
|
-
if (visible) {
|
|
765
|
+
if (useNativeFab) {
|
|
745
766
|
hideNativeFloatingButton().catch(() => { });
|
|
746
767
|
}
|
|
747
|
-
|
|
748
|
-
showNativeFloatingButton().catch(() => { });
|
|
749
|
-
setNativeFloatingButtonBadge(logs.length > 0 || analyticsEvents.length > 0).catch(() => { });
|
|
750
|
-
}
|
|
751
|
-
return () => {
|
|
752
|
-
if (useNativeFab) {
|
|
753
|
-
hideNativeFloatingButton().catch(() => { });
|
|
754
|
-
}
|
|
755
|
-
};
|
|
756
|
-
}, [
|
|
757
|
-
useNativeFab,
|
|
758
|
-
enabled,
|
|
759
|
-
visible,
|
|
760
|
-
logs.length,
|
|
761
|
-
analyticsEvents.length,
|
|
762
|
-
]);
|
|
768
|
+
}, [useNativeFab, visible]);
|
|
763
769
|
useEffect(() => {
|
|
764
770
|
if (!useNativeFab)
|
|
765
771
|
return;
|
|
@@ -1486,8 +1492,9 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
1486
1492
|
analytics: `${searchedLogs.filter(l => l.message.toLowerCase().includes('[analytics error]')).length}/${total}`,
|
|
1487
1493
|
};
|
|
1488
1494
|
}, [visibleConsoleLogs, logSearch]);
|
|
1489
|
-
|
|
1495
|
+
const closeModal = useCallback(() => {
|
|
1490
1496
|
setVisible(false);
|
|
1497
|
+
setIsMinimized(false);
|
|
1491
1498
|
setTimeout(() => {
|
|
1492
1499
|
setSelected(null);
|
|
1493
1500
|
setSelectedEvent(null);
|
|
@@ -1496,7 +1503,7 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
1496
1503
|
setSelectedReduxAction(null);
|
|
1497
1504
|
setSelectedCrash(null);
|
|
1498
1505
|
}, 300);
|
|
1499
|
-
}
|
|
1506
|
+
}, []);
|
|
1500
1507
|
function handleClearAll() {
|
|
1501
1508
|
clearNetworkLogs();
|
|
1502
1509
|
setLogs([]);
|
|
@@ -1633,6 +1640,9 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
1633
1640
|
visible,
|
|
1634
1641
|
setVisible,
|
|
1635
1642
|
closeModal,
|
|
1643
|
+
isMinimized,
|
|
1644
|
+
setIsMinimized,
|
|
1645
|
+
minimizeInspector,
|
|
1636
1646
|
isReady,
|
|
1637
1647
|
enabled,
|
|
1638
1648
|
isEnabled: enabled,
|
|
@@ -1650,6 +1660,8 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
1650
1660
|
toggleTabVisibility,
|
|
1651
1661
|
lastReadApisCount,
|
|
1652
1662
|
lastReadLogsCount,
|
|
1663
|
+
mediaCount,
|
|
1664
|
+
refreshMediaCount,
|
|
1653
1665
|
selected,
|
|
1654
1666
|
setSelected,
|
|
1655
1667
|
selectedEvent,
|
|
@@ -1815,6 +1827,8 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
1815
1827
|
toggleTabVisibility,
|
|
1816
1828
|
lastReadApisCount,
|
|
1817
1829
|
lastReadLogsCount,
|
|
1830
|
+
mediaCount,
|
|
1831
|
+
refreshMediaCount,
|
|
1818
1832
|
selected,
|
|
1819
1833
|
selectedEvent,
|
|
1820
1834
|
selectedLog,
|
|
@@ -1905,6 +1919,7 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
|
|
|
1905
1919
|
deviceFreeRamMb,
|
|
1906
1920
|
reduxAutoRefresh,
|
|
1907
1921
|
reduxExpandDepth,
|
|
1922
|
+
isMinimized,
|
|
1908
1923
|
]);
|
|
1909
1924
|
return (<InspectorContext.Provider value={contextValue}>
|
|
1910
1925
|
<MainScreen />
|
|
@@ -100,6 +100,7 @@ export interface RecordingOptions {
|
|
|
100
100
|
}
|
|
101
101
|
export interface RecordingResult {
|
|
102
102
|
uri: string;
|
|
103
|
+
thumbnailUri?: string;
|
|
103
104
|
format: 'mp4' | 'gif';
|
|
104
105
|
durationMs: number;
|
|
105
106
|
hasAudio: boolean;
|
|
@@ -118,6 +119,7 @@ export interface CapturedMediaItem {
|
|
|
118
119
|
type: 'image' | 'video' | 'gif';
|
|
119
120
|
format: string;
|
|
120
121
|
uri: string;
|
|
122
|
+
thumbnailUri?: string;
|
|
121
123
|
filename: string;
|
|
122
124
|
sizeBytes: number;
|
|
123
125
|
timestamp: number;
|
|
@@ -130,6 +132,7 @@ export declare const takeNativeScreenshot: (options?: ScreenshotOptions) => Prom
|
|
|
130
132
|
export declare const startNativeVideoRecording: (options?: RecordingOptions) => Promise<boolean>;
|
|
131
133
|
export declare const stopNativeVideoRecording: () => Promise<RecordingResult | null>;
|
|
132
134
|
export declare const isNativeRecordingActive: () => Promise<boolean>;
|
|
135
|
+
export declare const playNativeVideo: (videoUri: string) => Promise<boolean>;
|
|
133
136
|
export declare const convertNativeVideoToGif: (videoUri: string, options?: GifConversionOptions) => Promise<RecordingResult | null>;
|
|
134
137
|
export declare const fetchCapturedMediaList: () => Promise<CapturedMediaItem[]>;
|
|
135
138
|
export declare const deleteCapturedMediaFile: (uri: string) => Promise<boolean>;
|
|
@@ -317,6 +317,18 @@ export const isNativeRecordingActive = async () => {
|
|
|
317
317
|
return false;
|
|
318
318
|
}
|
|
319
319
|
};
|
|
320
|
+
export const playNativeVideo = async (videoUri) => {
|
|
321
|
+
if (!NativeModule || !NativeModule.playVideo) {
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
const result = await NativeModule.playVideo(videoUri);
|
|
326
|
+
return !!result;
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
};
|
|
320
332
|
export const convertNativeVideoToGif = async (videoUri, options) => {
|
|
321
333
|
if (!NativeModule || !NativeModule.convertToGif) {
|
|
322
334
|
return null;
|
|
@@ -20,6 +20,7 @@ export interface Spec extends TurboModule {
|
|
|
20
20
|
stopVideoRecording(): Promise<Object>;
|
|
21
21
|
isRecording(): Promise<boolean>;
|
|
22
22
|
convertToGif(videoUri: string, options: Object): Promise<Object>;
|
|
23
|
+
playVideo(videoUri: string): Promise<boolean>;
|
|
23
24
|
getCapturedMedia(): Promise<string>;
|
|
24
25
|
deleteCapturedMedia(uri: string): Promise<boolean>;
|
|
25
26
|
clearAllCapturedMedia(): Promise<boolean>;
|