react-native-inapp-inspector 2.0.5 → 2.0.6
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 +11 -0
- package/dist/commonjs/components/Inspector/AuditTab.d.ts +3 -0
- package/dist/commonjs/components/Inspector/AuditTab.js +741 -0
- package/dist/commonjs/components/Inspector/DeviceTab.d.ts +3 -0
- package/dist/commonjs/components/Inspector/DeviceTab.js +717 -0
- package/dist/commonjs/components/Inspector/InspectorHeader.js +28 -25
- package/dist/commonjs/components/Inspector/MainScreen.js +15 -2
- package/dist/commonjs/components/Inspector/NetworkDetail.js +15 -0
- package/dist/commonjs/components/Inspector/PerformanceHud.d.ts +7 -0
- package/dist/commonjs/components/Inspector/PerformanceHud.js +210 -0
- package/dist/commonjs/components/Inspector/PerformanceTab.js +30 -18
- package/dist/commonjs/components/Inspector/RequestReplayModal.d.ts +9 -0
- package/dist/commonjs/components/Inspector/RequestReplayModal.js +792 -0
- package/dist/commonjs/components/Inspector/RequestReplayView.d.ts +8 -0
- package/dist/commonjs/components/Inspector/RequestReplayView.js +871 -0
- package/dist/commonjs/components/Inspector/SettingsPanel.js +326 -15
- package/dist/commonjs/components/Inspector/StorageTab.d.ts +3 -0
- package/dist/commonjs/components/Inspector/StorageTab.js +610 -0
- package/dist/commonjs/components/Inspector/TabBar.js +23 -2
- package/dist/commonjs/components/NetworkIcons.d.ts +12 -0
- package/dist/commonjs/components/NetworkIcons.js +72 -3
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/storageInspector.d.ts +13 -0
- package/dist/commonjs/customHooks/storageInspector.js +179 -0
- package/dist/commonjs/helpers/deviceInfo.d.ts +4 -0
- package/dist/commonjs/helpers/deviceInfo.js +94 -0
- package/dist/commonjs/helpers/index.d.ts +2 -0
- package/dist/commonjs/helpers/index.js +12 -1
- package/dist/commonjs/helpers/packageAuditor.d.ts +5 -0
- package/dist/commonjs/helpers/packageAuditor.js +182 -0
- package/dist/commonjs/i18n/locales/en.json +3 -2
- package/dist/commonjs/index.d.ts +1 -0
- package/dist/commonjs/index.js +113 -9
- package/dist/commonjs/native/NativeInspector.d.ts +1 -0
- package/dist/commonjs/types/enums.d.ts +7 -0
- package/dist/commonjs/types/enums.js +7 -0
- package/dist/commonjs/types/interfaces.d.ts +73 -0
- package/dist/esm/components/Inspector/AuditTab.d.ts +3 -0
- package/dist/esm/components/Inspector/AuditTab.js +702 -0
- package/dist/esm/components/Inspector/DeviceTab.d.ts +3 -0
- package/dist/esm/components/Inspector/DeviceTab.js +678 -0
- package/dist/esm/components/Inspector/InspectorHeader.js +28 -25
- package/dist/esm/components/Inspector/MainScreen.js +15 -2
- package/dist/esm/components/Inspector/NetworkDetail.js +16 -1
- package/dist/esm/components/Inspector/PerformanceHud.d.ts +7 -0
- package/dist/esm/components/Inspector/PerformanceHud.js +170 -0
- package/dist/esm/components/Inspector/PerformanceTab.js +31 -19
- package/dist/esm/components/Inspector/RequestReplayModal.d.ts +9 -0
- package/dist/esm/components/Inspector/RequestReplayModal.js +752 -0
- package/dist/esm/components/Inspector/RequestReplayView.d.ts +8 -0
- package/dist/esm/components/Inspector/RequestReplayView.js +831 -0
- package/dist/esm/components/Inspector/SettingsPanel.js +327 -16
- package/dist/esm/components/Inspector/StorageTab.d.ts +3 -0
- package/dist/esm/components/Inspector/StorageTab.js +571 -0
- package/dist/esm/components/Inspector/TabBar.js +24 -3
- package/dist/esm/components/NetworkIcons.d.ts +12 -0
- package/dist/esm/components/NetworkIcons.js +57 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/storageInspector.d.ts +13 -0
- package/dist/esm/customHooks/storageInspector.js +170 -0
- package/dist/esm/helpers/deviceInfo.d.ts +4 -0
- package/dist/esm/helpers/deviceInfo.js +89 -0
- package/dist/esm/helpers/index.d.ts +2 -0
- package/dist/esm/helpers/index.js +10 -0
- package/dist/esm/helpers/packageAuditor.d.ts +5 -0
- package/dist/esm/helpers/packageAuditor.js +173 -0
- package/dist/esm/i18n/locales/en.json +3 -2
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +109 -8
- package/dist/esm/native/NativeInspector.d.ts +1 -0
- package/dist/esm/types/enums.d.ts +7 -0
- package/dist/esm/types/enums.js +7 -0
- package/dist/esm/types/interfaces.d.ts +73 -0
- package/ios/NetworkInspectorModule.mm +12 -5
- package/package.json +4 -1
|
@@ -14,7 +14,7 @@ import { getTelemetryConsentStatus } from '../../helpers/telemetry';
|
|
|
14
14
|
import { UpdateAvailableModal } from './UpdateAvailableModal';
|
|
15
15
|
import { WhiteBackNavigation, TrashIcon, SettingsIcon, CloseWhite, ClockIcon, SizeIcon, AppleIcon, AndroidIcon, NpmIcon, ResetIcon, } from '../NetworkIcons';
|
|
16
16
|
const InspectorHeader = React.memo(() => {
|
|
17
|
-
const { modalHeightPercent, appIcon, selected, setSelected, selectedEvent, setSelectedEvent, selectedLog, setSelectedLog, selectedReduxSlice, setSelectedReduxSlice, selectedReduxAction, setSelectedReduxAction, reduxState, reduxLastActionMap, showHeaderInfo, setShowHeaderInfo, updateAvailable, latestNpmVersion, clearAnim, activePulseAnim, unreadPulseAnim, runClearAllWithAnimation, settingsPage, setSettingsPage, resetToDefaults, closeModal, detailTitle, activeTab, environment, visible, selectedCrash, setSelectedCrash, } = useInspector();
|
|
17
|
+
const { modalHeightPercent, appIcon, selected, setSelected, selectedEvent, setSelectedEvent, selectedLog, setSelectedLog, selectedReduxSlice, setSelectedReduxSlice, selectedReduxAction, setSelectedReduxAction, reduxState, reduxLastActionMap, showHeaderInfo, setShowHeaderInfo, updateAvailable, latestNpmVersion, clearAnim, activePulseAnim, unreadPulseAnim, runClearAllWithAnimation, settingsPage, setSettingsPage, resetToDefaults, closeModal, detailTitle, activeTab, environment, visible, selectedCrash, setSelectedCrash, deviceInfo, } = useInspector();
|
|
18
18
|
const [showUpdateModal, setShowUpdateModal] = React.useState(false);
|
|
19
19
|
const [isTelemetryActive, setIsTelemetryActive] = React.useState(false);
|
|
20
20
|
const telemetryPulseAnim = React.useRef(new Animated.Value(1)).current;
|
|
@@ -264,38 +264,44 @@ const InspectorHeader = React.memo(() => {
|
|
|
264
264
|
</Pressable>)}
|
|
265
265
|
</View>
|
|
266
266
|
|
|
267
|
-
{/* OS & NPM Version
|
|
267
|
+
{/* OS & NPM Version Common Chip Bar */}
|
|
268
268
|
<View style={{
|
|
269
269
|
flexDirection: 'row',
|
|
270
270
|
alignItems: 'center',
|
|
271
271
|
gap: 5,
|
|
272
272
|
minWidth: 0,
|
|
273
273
|
}}>
|
|
274
|
+
{/* Unified Platform & Build Chip */}
|
|
274
275
|
<View style={{
|
|
275
276
|
flexDirection: 'row',
|
|
276
277
|
alignItems: 'center',
|
|
277
|
-
backgroundColor:
|
|
278
|
-
borderRadius:
|
|
279
|
-
paddingHorizontal: 6,
|
|
280
|
-
paddingVertical: 2,
|
|
281
|
-
gap: 4,
|
|
278
|
+
backgroundColor: 'rgba(255, 255, 255, 0.16)',
|
|
279
|
+
borderRadius: 6,
|
|
280
|
+
paddingHorizontal: 6.5,
|
|
281
|
+
paddingVertical: 2.5,
|
|
282
|
+
gap: 4.5,
|
|
282
283
|
borderWidth: 1,
|
|
283
|
-
borderColor:
|
|
284
|
+
borderColor: 'rgba(255, 255, 255, 0.28)',
|
|
284
285
|
flexShrink: 0,
|
|
285
286
|
}}>
|
|
286
|
-
{Platform.OS === 'ios' ? (<AppleIcon color=
|
|
287
|
+
{Platform.OS === 'ios' ? (<AppleIcon color="#FFFFFF" size={10.5}/>) : (<AndroidIcon color="#FFFFFF" size={10.5}/>)}
|
|
287
288
|
<Text style={{
|
|
288
|
-
fontFamily: AppFonts.
|
|
289
|
+
fontFamily: AppFonts.interBold,
|
|
289
290
|
fontSize: 9.5,
|
|
290
|
-
color:
|
|
291
|
+
color: '#FFFFFF',
|
|
291
292
|
letterSpacing: 0.1,
|
|
292
293
|
}} numberOfLines={1}>
|
|
293
294
|
{Platform.OS === 'ios'
|
|
294
|
-
? `iOS ${Platform.Version}
|
|
295
|
-
|
|
295
|
+
? `iOS ${String(deviceInfo?.osVersion || Platform.Version).replace(/^(ios\s*)+/i, '').trim()}${deviceInfo?.buildNumber || deviceInfo?.appVersion
|
|
296
|
+
? ` (${deviceInfo.buildNumber || deviceInfo.appVersion})`
|
|
297
|
+
: ''}`
|
|
298
|
+
: `Android ${String(deviceInfo?.osVersion || Platform.Version).replace(/^(android\s*)+/i, '').trim()}${deviceInfo?.buildNumber || deviceInfo?.appVersion
|
|
299
|
+
? ` (${deviceInfo.buildNumber || deviceInfo.appVersion})`
|
|
300
|
+
: ''}`}
|
|
296
301
|
</Text>
|
|
297
302
|
</View>
|
|
298
303
|
|
|
304
|
+
{/* Unified NPM Version Chip */}
|
|
299
305
|
<Pressable onPress={() => {
|
|
300
306
|
if (updateAvailable) {
|
|
301
307
|
setShowUpdateModal(true);
|
|
@@ -304,26 +310,23 @@ const InspectorHeader = React.memo(() => {
|
|
|
304
310
|
Linking.openURL('https://www.npmjs.com/package/react-native-inapp-inspector').catch(() => { });
|
|
305
311
|
}
|
|
306
312
|
}} style={{
|
|
307
|
-
backgroundColor: '
|
|
308
|
-
borderRadius:
|
|
309
|
-
paddingHorizontal: 6,
|
|
310
|
-
paddingVertical: 2,
|
|
313
|
+
backgroundColor: 'rgba(255, 255, 255, 0.16)',
|
|
314
|
+
borderRadius: 6,
|
|
315
|
+
paddingHorizontal: 6.5,
|
|
316
|
+
paddingVertical: 2.5,
|
|
311
317
|
flexDirection: 'row',
|
|
312
318
|
alignItems: 'center',
|
|
313
319
|
gap: 4,
|
|
320
|
+
borderWidth: 1,
|
|
321
|
+
borderColor: 'rgba(255, 255, 255, 0.28)',
|
|
314
322
|
flexShrink: 0,
|
|
315
|
-
shadowColor: '#000000',
|
|
316
|
-
shadowOffset: { width: 0, height: 1 },
|
|
317
|
-
shadowOpacity: 0.15,
|
|
318
|
-
shadowRadius: 2,
|
|
319
|
-
elevation: 2,
|
|
320
323
|
}}>
|
|
321
|
-
<NpmIcon size={11} color="#
|
|
324
|
+
<NpmIcon size={11} color="#FF6B6B"/>
|
|
322
325
|
<Text style={{
|
|
323
326
|
fontFamily: AppFonts.interBold,
|
|
324
327
|
fontSize: 9.5,
|
|
325
|
-
color: '#
|
|
326
|
-
letterSpacing: 0.
|
|
328
|
+
color: '#FFFFFF',
|
|
329
|
+
letterSpacing: 0.15,
|
|
327
330
|
}} numberOfLines={1}>
|
|
328
331
|
v{LIB_VERSION}
|
|
329
332
|
</Text>
|
|
@@ -17,6 +17,9 @@ import BundleTab from './BundleTab';
|
|
|
17
17
|
import PerformanceTab from './PerformanceTab';
|
|
18
18
|
import CrashTab from './CrashTab';
|
|
19
19
|
import CrashDetail from './CrashDetail';
|
|
20
|
+
import StorageTab from './StorageTab';
|
|
21
|
+
import DeviceTab from './DeviceTab';
|
|
22
|
+
import AuditTab from './AuditTab';
|
|
20
23
|
import SettingsPanel from './SettingsPanel';
|
|
21
24
|
import TelemetryConsentModal from './TelemetryConsentModal';
|
|
22
25
|
import NpmUpdateToast from './NpmUpdateToast';
|
|
@@ -24,8 +27,9 @@ import Toast from '../Toast';
|
|
|
24
27
|
import styles from '../../styles';
|
|
25
28
|
import { AppColors } from '../../styles/AppColors';
|
|
26
29
|
import NavigationTracker from './NavigationTracker';
|
|
30
|
+
import PerformanceHud from './PerformanceHud';
|
|
27
31
|
const MainScreen = () => {
|
|
28
|
-
const { visible, modalAnimationType, closeModal, modalHeightPercent, selected, selectedEvent, selectedLog, selectedReduxSlice, selectedReduxAction, selectedCrash, settingsPage, activeTab, isReady, isEnabled, useNativeFab, hasNavigationContext, setNavState, } = useInspector();
|
|
32
|
+
const { visible, setVisible, switchActiveTab, modalAnimationType, closeModal, modalHeightPercent, selected, selectedEvent, selectedLog, selectedReduxSlice, selectedReduxAction, selectedCrash, settingsPage, activeTab, isReady, isEnabled, isPerformanceHudEnabled, useNativeFab, hasNavigationContext, setNavState, } = useInspector();
|
|
29
33
|
const isDetailActive = (activeTab === 'apis' && selected != null) ||
|
|
30
34
|
(activeTab === 'analytics' && selectedEvent != null) ||
|
|
31
35
|
(activeTab === 'logs' && selectedLog != null) ||
|
|
@@ -66,10 +70,16 @@ const MainScreen = () => {
|
|
|
66
70
|
}).start();
|
|
67
71
|
}, [activeTab]);
|
|
68
72
|
return (<>
|
|
69
|
-
|
|
73
|
+
<View pointerEvents="box-none" style={StyleSheet.absoluteFillObject}>
|
|
74
|
+
{(Platform.OS === 'ios' || Platform.OS === 'android') &&
|
|
70
75
|
isEnabled &&
|
|
71
76
|
!visible &&
|
|
72
77
|
!useNativeFab && <FabLauncher />}
|
|
78
|
+
{isEnabled && !visible && isPerformanceHudEnabled && (<PerformanceHud visible={true} onPress={() => {
|
|
79
|
+
setVisible(true);
|
|
80
|
+
switchActiveTab('performance');
|
|
81
|
+
}}/>)}
|
|
82
|
+
</View>
|
|
73
83
|
<Modal visible={visible} animationType={modalAnimationType} transparent statusBarTranslucent={true}>
|
|
74
84
|
{visible && (<ErrorBoundary onClose={closeModal}>
|
|
75
85
|
<View style={styles.modalBackdrop}>
|
|
@@ -113,6 +123,9 @@ const MainScreen = () => {
|
|
|
113
123
|
{activeTab === 'logs' && <ConsoleTab />}
|
|
114
124
|
{activeTab === 'analytics' && <AnalyticsTab />}
|
|
115
125
|
{activeTab === 'redux' && <ReduxTab />}
|
|
126
|
+
{activeTab === 'storage' && <StorageTab />}
|
|
127
|
+
{activeTab === 'device' && <DeviceTab />}
|
|
128
|
+
{activeTab === 'audit' && <AuditTab />}
|
|
116
129
|
{activeTab === 'bundle' && <BundleTab />}
|
|
117
130
|
{activeTab === 'performance' && <PerformanceTab />}
|
|
118
131
|
{activeTab === 'crash' && <CrashTab />}
|
|
@@ -16,9 +16,11 @@ import { AppColors } from '../../styles/AppColors';
|
|
|
16
16
|
import { AppFonts } from '../../styles/AppFonts';
|
|
17
17
|
import { METHOD_COLORS } from '../../constants';
|
|
18
18
|
import { getStatusColor, getSize, formatDateTime, getFetchCommand, getCurlCommand, } from '../../helpers';
|
|
19
|
-
import { FailIcon, StatusIcon, HeadersIcon, RequestIcon, ResponseIcon, DownloadIcon, ClearIcon, SizeIcon, ExternalLinkIcon, ClockIcon, } from '../NetworkIcons';
|
|
19
|
+
import { FailIcon, StatusIcon, HeadersIcon, RequestIcon, ResponseIcon, DownloadIcon, ClearIcon, SizeIcon, ExternalLinkIcon, ClockIcon, ReplayIcon, } from '../NetworkIcons';
|
|
20
|
+
import RequestReplayView from './RequestReplayView';
|
|
20
21
|
const NetworkDetail = React.memo(() => {
|
|
21
22
|
const { t } = useTranslation();
|
|
23
|
+
const [isReplayScreenActive, setIsReplayScreenActive] = React.useState(false);
|
|
22
24
|
const { selected, detailDisplayUrl, apiDetailActiveTab, setApiDetailActiveTab, detailSearch, setDetailSearch, reqExpanded, setReqExpanded, resExpanded, setResExpanded, showReqDiff, setShowReqDiff, showResDiff, setShowResDiff, prevRequestData, prevResponseData, logRouteMapRef, } = useInspector();
|
|
23
25
|
const handleOpenUrl = () => {
|
|
24
26
|
Alert.alert(t('common.openInBrowser') || 'Open in Browser', `${t('common.openInBrowserPrompt') || 'Are you sure you want to open this URL in your external browser?'}\n\n${detailDisplayUrl}`, [
|
|
@@ -42,6 +44,9 @@ const NetworkDetail = React.memo(() => {
|
|
|
42
44
|
};
|
|
43
45
|
if (!selected)
|
|
44
46
|
return null;
|
|
47
|
+
if (isReplayScreenActive) {
|
|
48
|
+
return (<RequestReplayView request={selected} onBack={() => setIsReplayScreenActive(false)}/>);
|
|
49
|
+
}
|
|
45
50
|
return (<View style={{ flex: 1 }}>
|
|
46
51
|
{/* Non-scrollable details header */}
|
|
47
52
|
<View style={{ paddingHorizontal: 6, paddingTop: 4 }}>
|
|
@@ -247,6 +252,16 @@ const NetworkDetail = React.memo(() => {
|
|
|
247
252
|
</View>
|
|
248
253
|
|
|
249
254
|
<View style={styles.detailInfoRight}>
|
|
255
|
+
<TouchableScale style={[
|
|
256
|
+
styles.iconSquareBtn,
|
|
257
|
+
{
|
|
258
|
+
backgroundColor: `${AppColors.purple}15`,
|
|
259
|
+
borderColor: `${AppColors.purple}30`,
|
|
260
|
+
borderWidth: 1,
|
|
261
|
+
},
|
|
262
|
+
]} onPress={() => setIsReplayScreenActive(true)} accessible={true} accessibilityRole="button" accessibilityLabel="Edit & Resend Request" hitSlop={12}>
|
|
263
|
+
<ReplayIcon color={AppColors.purple} size={14}/>
|
|
264
|
+
</TouchableScale>
|
|
250
265
|
<TouchableScale style={[styles.iconSquareBtn, { backgroundColor: `${AppColors.sky600}15` }]} onPress={handleOpenUrl} hitSlop={12}>
|
|
251
266
|
<ExternalLinkIcon color={AppColors.sky600} size={14}/>
|
|
252
267
|
</TouchableScale>
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Animated, PanResponder, Platform, StyleSheet, Text, View, } from 'react-native';
|
|
3
|
+
import TouchableScale from '../TouchableScale';
|
|
4
|
+
import { AppColors } from '../../styles/AppColors';
|
|
5
|
+
import { AppFonts } from '../../styles/AppFonts';
|
|
6
|
+
import { getNativeDeviceMetrics } from '../../native/NativeInspector';
|
|
7
|
+
export const PerformanceHud = ({ visible, onPress, }) => {
|
|
8
|
+
const [fps, setFps] = useState(60);
|
|
9
|
+
const [ramMb, setRamMb] = useState(45);
|
|
10
|
+
// Pan / Drag positioning
|
|
11
|
+
const pan = useRef(new Animated.ValueXY({ x: 16, y: Platform.OS === 'ios' ? 56 : 36 })).current;
|
|
12
|
+
const panResponder = useRef(PanResponder.create({
|
|
13
|
+
onStartShouldSetPanResponder: () => false,
|
|
14
|
+
onMoveShouldSetPanResponder: (_, gestureState) => {
|
|
15
|
+
return Math.abs(gestureState.dx) > 4 || Math.abs(gestureState.dy) > 4;
|
|
16
|
+
},
|
|
17
|
+
onPanResponderGrant: () => {
|
|
18
|
+
pan.setOffset({
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
x: pan.x._value,
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
y: pan.y._value,
|
|
23
|
+
});
|
|
24
|
+
pan.setValue({ x: 0, y: 0 });
|
|
25
|
+
},
|
|
26
|
+
onPanResponderMove: Animated.event([null, { dx: pan.x, dy: pan.y }], {
|
|
27
|
+
useNativeDriver: false,
|
|
28
|
+
}),
|
|
29
|
+
onPanResponderRelease: () => {
|
|
30
|
+
pan.flattenOffset();
|
|
31
|
+
},
|
|
32
|
+
})).current;
|
|
33
|
+
// Real-time FPS Calculation via requestAnimationFrame
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (!visible)
|
|
36
|
+
return;
|
|
37
|
+
let frameCount = 0;
|
|
38
|
+
let lastTime = performance.now();
|
|
39
|
+
let animId;
|
|
40
|
+
const loop = (now) => {
|
|
41
|
+
frameCount++;
|
|
42
|
+
const elapsed = now - lastTime;
|
|
43
|
+
if (elapsed >= 500) {
|
|
44
|
+
const currentFps = Math.min(60, Math.round((frameCount * 1000) / elapsed));
|
|
45
|
+
setFps(currentFps);
|
|
46
|
+
frameCount = 0;
|
|
47
|
+
lastTime = now;
|
|
48
|
+
}
|
|
49
|
+
animId = requestAnimationFrame(loop);
|
|
50
|
+
};
|
|
51
|
+
animId = requestAnimationFrame(loop);
|
|
52
|
+
return () => {
|
|
53
|
+
cancelAnimationFrame(animId);
|
|
54
|
+
};
|
|
55
|
+
}, [visible]);
|
|
56
|
+
// Memory Metrics Polling
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (!visible)
|
|
59
|
+
return;
|
|
60
|
+
const interval = setInterval(async () => {
|
|
61
|
+
try {
|
|
62
|
+
const metrics = await getNativeDeviceMetrics();
|
|
63
|
+
if (metrics && metrics.residentMemory != null) {
|
|
64
|
+
const mb = metrics.residentMemory / (1024 * 1024);
|
|
65
|
+
setRamMb(Math.round(mb));
|
|
66
|
+
}
|
|
67
|
+
else if (metrics && metrics.usedRAM != null) {
|
|
68
|
+
const mb = metrics.usedRAM / (1024 * 1024);
|
|
69
|
+
setRamMb(Math.round(mb));
|
|
70
|
+
}
|
|
71
|
+
else if (typeof performance !== 'undefined' &&
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
performance.memory?.usedJSHeapSize) {
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
const mb = performance.memory.usedJSHeapSize / (1024 * 1024);
|
|
76
|
+
setRamMb(Math.round(mb));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Safe fallback
|
|
81
|
+
}
|
|
82
|
+
}, 1500);
|
|
83
|
+
return () => clearInterval(interval);
|
|
84
|
+
}, [visible]);
|
|
85
|
+
if (!visible)
|
|
86
|
+
return null;
|
|
87
|
+
const fpsColor = fps >= 55
|
|
88
|
+
? AppColors.greenColor
|
|
89
|
+
: fps >= 35
|
|
90
|
+
? AppColors.warningIconGold
|
|
91
|
+
: AppColors.errorColor;
|
|
92
|
+
return (<Animated.View {...panResponder.panHandlers} style={[
|
|
93
|
+
styles.hudContainer,
|
|
94
|
+
{
|
|
95
|
+
transform: pan.getTranslateTransform(),
|
|
96
|
+
},
|
|
97
|
+
]}>
|
|
98
|
+
<TouchableScale onPress={onPress} style={styles.hudInner}>
|
|
99
|
+
{/* FPS Indicator */}
|
|
100
|
+
<View style={styles.metricItem}>
|
|
101
|
+
<View style={[styles.statusDot, { backgroundColor: fpsColor }]}/>
|
|
102
|
+
<Text style={[styles.metricValue, { color: fpsColor }]}>{fps}</Text>
|
|
103
|
+
<Text style={styles.metricUnit}>FPS</Text>
|
|
104
|
+
</View>
|
|
105
|
+
|
|
106
|
+
<View style={styles.divider}/>
|
|
107
|
+
|
|
108
|
+
{/* RAM / Heap Indicator */}
|
|
109
|
+
<View style={styles.metricItem}>
|
|
110
|
+
<Text style={styles.metricIcon}>⚡</Text>
|
|
111
|
+
<Text style={styles.metricValue}>{ramMb}</Text>
|
|
112
|
+
<Text style={styles.metricUnit}>MB</Text>
|
|
113
|
+
</View>
|
|
114
|
+
</TouchableScale>
|
|
115
|
+
</Animated.View>);
|
|
116
|
+
};
|
|
117
|
+
const styles = StyleSheet.create({
|
|
118
|
+
hudContainer: {
|
|
119
|
+
position: 'absolute',
|
|
120
|
+
top: 0,
|
|
121
|
+
left: 0,
|
|
122
|
+
zIndex: 999998,
|
|
123
|
+
elevation: 999998,
|
|
124
|
+
},
|
|
125
|
+
hudInner: {
|
|
126
|
+
flexDirection: 'row',
|
|
127
|
+
alignItems: 'center',
|
|
128
|
+
backgroundColor: 'rgba(15, 23, 42, 0.88)',
|
|
129
|
+
borderRadius: 20,
|
|
130
|
+
borderWidth: 1,
|
|
131
|
+
borderColor: 'rgba(255, 255, 255, 0.18)',
|
|
132
|
+
paddingHorizontal: 10,
|
|
133
|
+
paddingVertical: 5,
|
|
134
|
+
gap: 8,
|
|
135
|
+
shadowColor: AppColors.black,
|
|
136
|
+
shadowOpacity: 0.35,
|
|
137
|
+
shadowRadius: 6,
|
|
138
|
+
shadowOffset: { width: 0, height: 2 },
|
|
139
|
+
},
|
|
140
|
+
metricItem: {
|
|
141
|
+
flexDirection: 'row',
|
|
142
|
+
alignItems: 'center',
|
|
143
|
+
gap: 4,
|
|
144
|
+
},
|
|
145
|
+
statusDot: {
|
|
146
|
+
width: 6,
|
|
147
|
+
height: 6,
|
|
148
|
+
borderRadius: 3,
|
|
149
|
+
},
|
|
150
|
+
metricIcon: {
|
|
151
|
+
fontSize: 10,
|
|
152
|
+
},
|
|
153
|
+
metricValue: {
|
|
154
|
+
fontFamily: AppFonts.interBold,
|
|
155
|
+
fontSize: 11.5,
|
|
156
|
+
color: AppColors.white,
|
|
157
|
+
},
|
|
158
|
+
metricUnit: {
|
|
159
|
+
fontFamily: AppFonts.interRegular,
|
|
160
|
+
fontSize: 9,
|
|
161
|
+
color: 'rgba(255, 255, 255, 0.65)',
|
|
162
|
+
letterSpacing: 0.2,
|
|
163
|
+
},
|
|
164
|
+
divider: {
|
|
165
|
+
width: 1,
|
|
166
|
+
height: 12,
|
|
167
|
+
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
export default PerformanceHud;
|
|
@@ -9,7 +9,7 @@ import { AppColors } from '../../styles/AppColors';
|
|
|
9
9
|
import { AppFonts } from '../../styles/AppFonts';
|
|
10
10
|
import { useTranslation } from '../../i18n';
|
|
11
11
|
import { getRuntimeDiagnostics } from '../../helpers';
|
|
12
|
-
import { SearchIcon, CircleXIcon, PerformanceIcon, BoltIcon, LightbulbIcon, } from '../NetworkIcons';
|
|
12
|
+
import { SearchIcon, CircleXIcon, PerformanceIcon, BoltIcon, LightbulbIcon, WarningTriangleIcon, MapIcon, AtomIcon, BrainIcon, GlobeIcon, SparklesIcon, } from '../NetworkIcons';
|
|
13
13
|
import { getPerformanceEvents, subscribePerformanceEvents, logPerformanceEvent, clearPerformanceEvents, } from '../../customHooks/performanceTracker';
|
|
14
14
|
import { startNativeFpsMonitoring, stopNativeFpsMonitoring, getNativeFpsMetrics, getNativeSystemMetrics, isNativeModuleAvailable, } from '../../native/NativeInspector';
|
|
15
15
|
const PerformanceTab = React.memo(() => {
|
|
@@ -373,24 +373,33 @@ const PerformanceTab = React.memo(() => {
|
|
|
373
373
|
<View style={perfStyles.categoryScrollWrapper}>
|
|
374
374
|
<ScrollView horizontal showsHorizontalScrollIndicator={false} style={perfStyles.categoryScrollView} contentContainerStyle={perfStyles.categoryScroll}>
|
|
375
375
|
{[
|
|
376
|
-
{ key: 'ALL', label: t('performance.catAll') },
|
|
377
|
-
{ key: 'JANKY', label: t('performance.catJanky') },
|
|
378
|
-
{ key: 'NAVIGATION', label: t('performance.catNavigation') },
|
|
379
|
-
{ key: 'RENDER', label: t('performance.catRender') },
|
|
380
|
-
{ key: 'MEMORY', label: t('performance.catMemory') },
|
|
381
|
-
{ key: 'IO', label: t('performance.catIo') },
|
|
376
|
+
{ key: 'ALL', label: t('performance.catAll'), icon: 'all' },
|
|
377
|
+
{ key: 'JANKY', label: t('performance.catJanky'), icon: 'janky' },
|
|
378
|
+
{ key: 'NAVIGATION', label: t('performance.catNavigation'), icon: 'nav' },
|
|
379
|
+
{ key: 'RENDER', label: t('performance.catRender'), icon: 'render' },
|
|
380
|
+
{ key: 'MEMORY', label: t('performance.catMemory'), icon: 'memory' },
|
|
381
|
+
{ key: 'IO', label: t('performance.catIo'), icon: 'io' },
|
|
382
382
|
].map(cat => {
|
|
383
383
|
const isSelected = filterCategory === cat.key;
|
|
384
|
+
const iconColor = isSelected ? AppColors.white : AppColors.grayText;
|
|
384
385
|
return (<TouchableScale key={cat.key} onPress={() => setFilterCategory(cat.key)} style={[
|
|
385
386
|
perfStyles.categoryChip,
|
|
386
387
|
isSelected && perfStyles.categoryChipActive,
|
|
387
388
|
]}>
|
|
388
|
-
<
|
|
389
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 5 }}>
|
|
390
|
+
{cat.icon === 'all' && <SparklesIcon size={12} color={iconColor}/>}
|
|
391
|
+
{cat.icon === 'janky' && <WarningTriangleIcon size={12} color={isSelected ? AppColors.white : AppColors.errorColor}/>}
|
|
392
|
+
{cat.icon === 'nav' && <MapIcon size={12} color={iconColor}/>}
|
|
393
|
+
{cat.icon === 'render' && <AtomIcon size={12} color={iconColor}/>}
|
|
394
|
+
{cat.icon === 'memory' && <BrainIcon size={12} color={iconColor}/>}
|
|
395
|
+
{cat.icon === 'io' && <GlobeIcon size={12} color={iconColor}/>}
|
|
396
|
+
<Text style={[
|
|
389
397
|
perfStyles.categoryChipText,
|
|
390
398
|
isSelected && perfStyles.categoryChipTextActive,
|
|
391
399
|
]}>
|
|
392
|
-
|
|
393
|
-
|
|
400
|
+
{cat.label}
|
|
401
|
+
</Text>
|
|
402
|
+
</View>
|
|
394
403
|
</TouchableScale>);
|
|
395
404
|
})}
|
|
396
405
|
</ScrollView>
|
|
@@ -401,13 +410,13 @@ const PerformanceTab = React.memo(() => {
|
|
|
401
410
|
{/* ── 1. REAL-TIME FPS SCORECARD & SMOOTH AREA GRAPH ── */}
|
|
402
411
|
<View style={perfStyles.heroCard}>
|
|
403
412
|
<View style={perfStyles.heroHeaderRow}>
|
|
404
|
-
<View style={{ flexDirection: 'row', alignItems: 'center', gap:
|
|
405
|
-
<PerformanceIcon color={AppColors.purple} size={
|
|
406
|
-
<View>
|
|
407
|
-
<Text style={perfStyles.heroTitle}>
|
|
413
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8, flex: 1 }}>
|
|
414
|
+
<PerformanceIcon color={AppColors.purple} size={18}/>
|
|
415
|
+
<View style={{ flex: 1 }}>
|
|
416
|
+
<Text style={perfStyles.heroTitle} numberOfLines={1}>
|
|
408
417
|
{t('performance.fpsAreaChartTitle')}
|
|
409
418
|
</Text>
|
|
410
|
-
<Text style={perfStyles.heroSubTitle}>
|
|
419
|
+
<Text style={perfStyles.heroSubTitle} numberOfLines={1}>
|
|
411
420
|
{t('performance.fpsAreaChartSub')}
|
|
412
421
|
</Text>
|
|
413
422
|
</View>
|
|
@@ -1122,18 +1131,21 @@ const perfStyles = StyleSheet.create({
|
|
|
1122
1131
|
color: AppColors.grayTextWeak,
|
|
1123
1132
|
},
|
|
1124
1133
|
fpsStatsGrid: {
|
|
1134
|
+
flex: 1,
|
|
1125
1135
|
flexDirection: 'row',
|
|
1126
1136
|
alignItems: 'center',
|
|
1127
|
-
|
|
1137
|
+
justifyContent: 'space-around',
|
|
1138
|
+
marginLeft: 8,
|
|
1128
1139
|
},
|
|
1129
1140
|
statItem: {
|
|
1130
1141
|
alignItems: 'center',
|
|
1131
|
-
|
|
1142
|
+
flex: 1,
|
|
1132
1143
|
},
|
|
1133
1144
|
statLabel: {
|
|
1134
|
-
fontFamily: AppFonts.
|
|
1135
|
-
fontSize:
|
|
1145
|
+
fontFamily: AppFonts.interMedium,
|
|
1146
|
+
fontSize: 9.5,
|
|
1136
1147
|
color: AppColors.grayTextWeak,
|
|
1148
|
+
textAlign: 'center',
|
|
1137
1149
|
},
|
|
1138
1150
|
statValue: {
|
|
1139
1151
|
fontFamily: AppFonts.interBold,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { NetworkLog } from '../../types';
|
|
3
|
+
interface RequestReplayModalProps {
|
|
4
|
+
visible: boolean;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
request: NetworkLog;
|
|
7
|
+
}
|
|
8
|
+
export declare const RequestReplayModal: React.FC<RequestReplayModalProps>;
|
|
9
|
+
export default RequestReplayModal;
|