react-native-inapp-inspector 2.0.0 → 2.0.2
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/README.md +10 -0
- package/android/.gradle/8.9/checksums/checksums.lock +0 -0
- package/android/.gradle/8.9/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.9/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.9/gc.properties +0 -0
- package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
- package/android/.gradle/9.2.0/fileChanges/last-build.bin +0 -0
- package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/9.2.0/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/build/reports/problems/problems-report.html +659 -0
- package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +33 -24
- package/dist/commonjs/components/ConsoleLogCard.js +5 -5
- package/dist/commonjs/components/EndOfListFooter.js +1 -1
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +19 -71
- package/dist/commonjs/components/Inspector/BundleTab.js +670 -188
- package/dist/commonjs/components/Inspector/ConsoleTab.js +109 -98
- package/dist/commonjs/components/Inspector/CrashTab.js +2 -1
- package/dist/commonjs/components/Inspector/InspectorHeader.js +102 -19
- package/dist/commonjs/components/Inspector/MainScreen.js +151 -17
- package/dist/commonjs/components/Inspector/NetworkTab.js +104 -20
- package/dist/commonjs/components/Inspector/SettingsPanel.js +1111 -1385
- package/dist/commonjs/components/Inspector/TabBar.js +3 -4
- package/dist/commonjs/components/Inspector/TelemetryConsentModal.d.ts +3 -0
- package/dist/commonjs/components/Inspector/TelemetryConsentModal.js +212 -0
- package/dist/commonjs/components/JsonViewer.js +9 -4
- package/dist/commonjs/components/LogCard.js +31 -1
- package/dist/commonjs/components/LogSyntaxHighlighter.d.ts +16 -0
- package/dist/commonjs/components/LogSyntaxHighlighter.js +130 -0
- package/dist/commonjs/components/NetworkIcons.d.ts +2 -0
- package/dist/commonjs/components/NetworkIcons.js +10 -1
- package/dist/commonjs/components/Slider.d.ts +13 -0
- package/dist/commonjs/components/Slider.js +261 -0
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/analyticsLogger.js +1 -1
- package/dist/commonjs/customHooks/crashHandler.js +1 -1
- package/dist/commonjs/helpers/index.d.ts +2 -0
- package/dist/commonjs/helpers/index.js +16 -0
- package/dist/commonjs/helpers/searchQueryParser.d.ts +6 -0
- package/dist/commonjs/helpers/searchQueryParser.js +236 -0
- package/dist/commonjs/helpers/settingsStore.js +13 -13
- package/dist/commonjs/helpers/telemetry.d.ts +99 -0
- package/dist/commonjs/helpers/telemetry.js +398 -0
- package/dist/commonjs/index.d.ts +2 -0
- package/dist/commonjs/index.js +30 -21
- package/dist/commonjs/native/NativeInspector.d.ts +5 -0
- package/dist/commonjs/native/NativeInspector.js +3 -2
- package/dist/commonjs/styles/index.js +35 -35
- package/dist/esm/components/ConsoleLogCard.js +5 -5
- package/dist/esm/components/EndOfListFooter.js +2 -2
- package/dist/esm/components/Inspector/AnalyticsTab.js +21 -73
- package/dist/esm/components/Inspector/BundleTab.js +670 -188
- package/dist/esm/components/Inspector/ConsoleTab.js +110 -99
- package/dist/esm/components/Inspector/CrashTab.js +2 -1
- package/dist/esm/components/Inspector/InspectorHeader.js +103 -20
- package/dist/esm/components/Inspector/MainScreen.js +119 -18
- package/dist/esm/components/Inspector/NetworkTab.js +105 -21
- package/dist/esm/components/Inspector/SettingsPanel.js +1114 -1388
- package/dist/esm/components/Inspector/TabBar.js +4 -5
- package/dist/esm/components/Inspector/TelemetryConsentModal.d.ts +3 -0
- package/dist/esm/components/Inspector/TelemetryConsentModal.js +175 -0
- package/dist/esm/components/JsonViewer.js +9 -4
- package/dist/esm/components/LogCard.js +32 -2
- package/dist/esm/components/LogSyntaxHighlighter.d.ts +16 -0
- package/dist/esm/components/LogSyntaxHighlighter.js +123 -0
- package/dist/esm/components/NetworkIcons.d.ts +2 -0
- package/dist/esm/components/NetworkIcons.js +7 -0
- package/dist/esm/components/Slider.d.ts +13 -0
- package/dist/esm/components/Slider.js +222 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/analyticsLogger.js +1 -1
- package/dist/esm/customHooks/crashHandler.js +1 -1
- package/dist/esm/helpers/index.d.ts +2 -0
- package/dist/esm/helpers/index.js +2 -0
- package/dist/esm/helpers/searchQueryParser.d.ts +6 -0
- package/dist/esm/helpers/searchQueryParser.js +233 -0
- package/dist/esm/helpers/settingsStore.js +13 -13
- package/dist/esm/helpers/telemetry.d.ts +99 -0
- package/dist/esm/helpers/telemetry.js +380 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +20 -21
- package/dist/esm/native/NativeInspector.d.ts +5 -0
- package/dist/esm/native/NativeInspector.js +3 -2
- package/dist/esm/styles/index.js +35 -35
- package/ios/{NetworkInspectorModule.m → NetworkInspectorModule.mm} +193 -97
- package/package.json +2 -2
|
@@ -74,7 +74,11 @@ const PackageLogoRenderer = ({ name, size = 28 }) => {
|
|
|
74
74
|
if (lowerName.includes('screens') || lowerName.includes('software-mansion')) {
|
|
75
75
|
return (<View style={[
|
|
76
76
|
bundleStyles.pkgLogoWrap,
|
|
77
|
-
{
|
|
77
|
+
{
|
|
78
|
+
width: size,
|
|
79
|
+
height: size,
|
|
80
|
+
backgroundColor: AppColors.reanimatedNavy,
|
|
81
|
+
},
|
|
78
82
|
]}>
|
|
79
83
|
<Svg width={size - 8} height={size - 8} viewBox="0 0 100 100" fill="none">
|
|
80
84
|
<Path d="M50 15 L88 35 L50 55 L12 35 Z" fill={AppColors.sky400}/>
|
|
@@ -126,7 +130,12 @@ const PackageLogoRenderer = ({ name, size = 28 }) => {
|
|
|
126
130
|
</View>);
|
|
127
131
|
};
|
|
128
132
|
const BundleCategoryIcon = ({ type, size = 16, color = AppColors.purple }) => {
|
|
129
|
-
const stroke = {
|
|
133
|
+
const stroke = {
|
|
134
|
+
stroke: color,
|
|
135
|
+
strokeWidth: 1.7,
|
|
136
|
+
strokeLinecap: 'round',
|
|
137
|
+
strokeLinejoin: 'round',
|
|
138
|
+
};
|
|
130
139
|
const renderGlyph = () => {
|
|
131
140
|
switch (type) {
|
|
132
141
|
case 'folder':
|
|
@@ -337,7 +346,9 @@ export const downloadBundleFile = async (file, scriptURL) => {
|
|
|
337
346
|
// Path: ${file.path}
|
|
338
347
|
// Category: ${file.category.toUpperCase()}
|
|
339
348
|
// Size: ${file.sizeKb} KB
|
|
340
|
-
// Status: ${file.status === 'optimal'
|
|
349
|
+
// Status: ${file.status === 'optimal'
|
|
350
|
+
? 'Active in Dependency Graph'
|
|
351
|
+
: 'Not consumed / Static'}
|
|
341
352
|
// Meta: ${file.meta}
|
|
342
353
|
// ─────────────────────────────────────────────────────────────
|
|
343
354
|
|
|
@@ -379,10 +390,9 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, expandedFolder
|
|
|
379
390
|
const indentLeft = level * 16 + 10;
|
|
380
391
|
if (node.isFolder) {
|
|
381
392
|
return (<View style={bundleStyles.treeFolderBlock}>
|
|
382
|
-
<TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={`Folder ${node.name}, ${node.fileCount} ${node.fileCount === 1 ? 'file' : 'files'}, ${node.sizeKb >= 1024
|
|
383
|
-
|
|
384
|
-
{ paddingLeft: indentLeft }
|
|
385
|
-
]}>
|
|
393
|
+
<TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={`Folder ${node.name}, ${node.fileCount} ${node.fileCount === 1 ? 'file' : 'files'}, ${node.sizeKb >= 1024
|
|
394
|
+
? `${(node.sizeKb / 1024).toFixed(2)} MB`
|
|
395
|
+
: `${node.sizeKb} KB`}`} accessibilityState={{ expanded: isExpanded }} accessibilityHint="Double tap to expand or collapse folder" onPress={() => toggleFolder(node.fullPath)} style={[bundleStyles.treeFolderRow, { paddingLeft: indentLeft }]}>
|
|
386
396
|
<View style={bundleStyles.treeRowLeft}>
|
|
387
397
|
<Text style={bundleStyles.treeChevron}>
|
|
388
398
|
{isCollapsed ? '▸' : '▾'}
|
|
@@ -391,7 +401,8 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, expandedFolder
|
|
|
391
401
|
<HighlightText text={node.name + '/'} search={search} style={bundleStyles.treeFolderName} highlightStyle={bundleStyles.searchHighlight}/>
|
|
392
402
|
<View style={bundleStyles.treeCountBadge}>
|
|
393
403
|
<Text style={bundleStyles.treeCountBadgeText}>
|
|
394
|
-
{node.fileCount}
|
|
404
|
+
{node.fileCount}{' '}
|
|
405
|
+
{node.fileCount === 1 ? t('bundle.file') : t('bundle.files')}
|
|
395
406
|
</Text>
|
|
396
407
|
</View>
|
|
397
408
|
</View>
|
|
@@ -399,7 +410,9 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, expandedFolder
|
|
|
399
410
|
<View style={bundleStyles.treeRowRight}>
|
|
400
411
|
<Text style={bundleStyles.treeFolderSize}>
|
|
401
412
|
{node.sizeKb >= 1024
|
|
402
|
-
? t('bundle.fileSizeMb', {
|
|
413
|
+
? t('bundle.fileSizeMb', {
|
|
414
|
+
size: (node.sizeKb / 1024).toFixed(2),
|
|
415
|
+
})
|
|
403
416
|
: t('bundle.fileSizeKb', { size: node.sizeKb })}
|
|
404
417
|
</Text>
|
|
405
418
|
<CopyButton value={() => ({
|
|
@@ -438,13 +451,18 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, expandedFolder
|
|
|
438
451
|
<HighlightText text={file.name} search={search} style={bundleStyles.treeFileName} highlightStyle={bundleStyles.searchHighlight}/>
|
|
439
452
|
|
|
440
453
|
{isUnused && (<View style={bundleStyles.treeUnusedPill}>
|
|
441
|
-
<Text style={bundleStyles.treeUnusedPillText}>
|
|
454
|
+
<Text style={bundleStyles.treeUnusedPillText}>
|
|
455
|
+
{t('bundle.notConsumed')}
|
|
456
|
+
</Text>
|
|
442
457
|
</View>)}
|
|
443
458
|
</View>
|
|
444
459
|
|
|
445
460
|
<View style={bundleStyles.treeRowRight}>
|
|
446
461
|
<View style={bundleStyles.treeFileSizeGroup}>
|
|
447
|
-
<Text style={[
|
|
462
|
+
<Text style={[
|
|
463
|
+
bundleStyles.treeFileSizeText,
|
|
464
|
+
isUnused && { color: AppColors.red600 },
|
|
465
|
+
]}>
|
|
448
466
|
{file.sizeKb >= 1024
|
|
449
467
|
? t('bundle.fileSizeMb', { size: (file.sizeKb / 1024).toFixed(2) })
|
|
450
468
|
: t('bundle.fileSizeKb', { size: file.sizeKb })}
|
|
@@ -467,17 +485,41 @@ const CATEGORY_TABS = [
|
|
|
467
485
|
{ key: 'UNUSED', labelKey: 'bundle.catUnused', iconType: 'ban' },
|
|
468
486
|
{ key: 'CONSUMED', labelKey: 'bundle.catConsumed', iconType: 'bolt' },
|
|
469
487
|
{ key: 'image', labelKey: 'bundle.catImages', iconType: 'image' },
|
|
470
|
-
{
|
|
471
|
-
|
|
488
|
+
{
|
|
489
|
+
key: 'typescript',
|
|
490
|
+
labelKey: 'bundle.catTypescript',
|
|
491
|
+
iconType: 'typescript',
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
key: 'javascript',
|
|
495
|
+
labelKey: 'bundle.catJavascript',
|
|
496
|
+
iconType: 'javascript',
|
|
497
|
+
},
|
|
472
498
|
{ key: 'font', labelKey: 'bundle.catFonts', iconType: 'font' },
|
|
473
499
|
{ key: 'json', labelKey: 'bundle.catJson', iconType: 'json' },
|
|
474
500
|
];
|
|
475
501
|
const CATEGORY_COLORS = {
|
|
476
|
-
image: {
|
|
477
|
-
|
|
478
|
-
|
|
502
|
+
image: {
|
|
503
|
+
label: 'Images & Media',
|
|
504
|
+
color: AppColors.pink500,
|
|
505
|
+
bg: AppColors.pink100,
|
|
506
|
+
},
|
|
507
|
+
typescript: {
|
|
508
|
+
label: 'TypeScript',
|
|
509
|
+
color: AppColors.sky500,
|
|
510
|
+
bg: AppColors.sky100,
|
|
511
|
+
},
|
|
512
|
+
javascript: {
|
|
513
|
+
label: 'JavaScript',
|
|
514
|
+
color: AppColors.indigo500,
|
|
515
|
+
bg: AppColors.indigo50,
|
|
516
|
+
},
|
|
479
517
|
font: { label: 'Fonts', color: AppColors.purple500, bg: AppColors.purple100 },
|
|
480
|
-
json: {
|
|
518
|
+
json: {
|
|
519
|
+
label: 'JSON / Data',
|
|
520
|
+
color: AppColors.emerald500,
|
|
521
|
+
bg: AppColors.emerald100,
|
|
522
|
+
},
|
|
481
523
|
};
|
|
482
524
|
const BundleTab = React.memo(() => {
|
|
483
525
|
const { t } = useTranslation();
|
|
@@ -524,8 +566,13 @@ const BundleTab = React.memo(() => {
|
|
|
524
566
|
const bundlePackages = useMemo(() => (analysis ? analysis.packages : []), [analysis]);
|
|
525
567
|
// Comprehensive bundle summary (full Metro bundle calculation e.g. 6.0 MB)
|
|
526
568
|
const summary = useMemo(() => {
|
|
527
|
-
const totalKb = analysis?.totalDevKb ||
|
|
528
|
-
|
|
569
|
+
const totalKb = analysis?.totalDevKb ||
|
|
570
|
+
(analysis?.totalDevBytes
|
|
571
|
+
? Math.round(analysis.totalDevBytes / 1024)
|
|
572
|
+
: 6144);
|
|
573
|
+
const totalMb = analysis?.totalDevMb
|
|
574
|
+
? analysis.totalDevMb.toFixed(2)
|
|
575
|
+
: (totalKb / 1024).toFixed(2);
|
|
529
576
|
const nodeModulesKb = analysis?.splitUp?.nodeModules?.kb || Math.round(totalKb * 0.52);
|
|
530
577
|
const nodeModulesPct = analysis?.splitUp?.nodeModules?.pct || 52.0;
|
|
531
578
|
const metroKb = analysis?.splitUp?.metroDevOverhead?.kb || Math.round(totalKb * 0.21);
|
|
@@ -576,7 +623,9 @@ const BundleTab = React.memo(() => {
|
|
|
576
623
|
iconType: 'image',
|
|
577
624
|
title: 'Images & Static Media',
|
|
578
625
|
targetTab: 'media',
|
|
579
|
-
count: bundleFiles.filter(f => f.category === 'image' ||
|
|
626
|
+
count: bundleFiles.filter(f => f.category === 'image' ||
|
|
627
|
+
f.category === 'font' ||
|
|
628
|
+
f.category === 'json').length || 3,
|
|
580
629
|
sizeKb: assetsMediaKb,
|
|
581
630
|
sizeMb: (assetsMediaKb / 1024).toFixed(2),
|
|
582
631
|
pct: assetsMediaPct,
|
|
@@ -760,7 +809,7 @@ const BundleTab = React.memo(() => {
|
|
|
760
809
|
</TouchableScale>);
|
|
761
810
|
})}
|
|
762
811
|
</ScrollView>
|
|
763
|
-
<TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={isAnalyzing ?
|
|
812
|
+
<TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={isAnalyzing ? 'Analyzing Metro bundle' : 'Reload bundle analysis'} accessibilityHint="Re-probes Metro dev server and refreshes bundle statistics" onPress={refreshAnalysis} style={bundleStyles.reloadButton} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
|
|
764
813
|
{isAnalyzing ? (<ActivityIndicator size="small" color={AppColors.brandPurple}/>) : (<RefreshCcwIcon color={AppColors.brandPurple} size={14}/>)}
|
|
765
814
|
</TouchableScale>
|
|
766
815
|
</View>
|
|
@@ -769,7 +818,6 @@ const BundleTab = React.memo(() => {
|
|
|
769
818
|
{/* ── 1. TAB: OVERVIEW & TREEMAP ───────────────────────────────────────── */}
|
|
770
819
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
771
820
|
{activeSubTab === 'overview' && (<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
|
|
772
|
-
|
|
773
821
|
{/* Hero Overview Card */}
|
|
774
822
|
<View style={bundleStyles.heroCard}>
|
|
775
823
|
<View style={bundleStyles.heroTopRow}>
|
|
@@ -777,7 +825,9 @@ const BundleTab = React.memo(() => {
|
|
|
777
825
|
<PackageIcon color={AppColors.brandPurple} size={24}/>
|
|
778
826
|
</View>
|
|
779
827
|
<View style={{ flex: 1 }}>
|
|
780
|
-
<Text style={bundleStyles.heroTitle}>
|
|
828
|
+
<Text style={bundleStyles.heroTitle}>
|
|
829
|
+
{t('bundle.heroTitle')}
|
|
830
|
+
</Text>
|
|
781
831
|
{analysis?.isLive && analysis.scriptURL ? (<View style={{ marginTop: 4, gap: 4 }}>
|
|
782
832
|
<Text style={bundleStyles.heroSubtitle}>
|
|
783
833
|
{t('bundle.heroSubtitle')}
|
|
@@ -796,7 +846,11 @@ const BundleTab = React.memo(() => {
|
|
|
796
846
|
justifyContent: 'space-between',
|
|
797
847
|
marginBottom: 3,
|
|
798
848
|
}}>
|
|
799
|
-
<View style={{
|
|
849
|
+
<View style={{
|
|
850
|
+
flexDirection: 'row',
|
|
851
|
+
alignItems: 'center',
|
|
852
|
+
gap: 4,
|
|
853
|
+
}}>
|
|
800
854
|
<ExternalLinkIcon color={AppColors.skyBlue} size={11}/>
|
|
801
855
|
<Text style={{
|
|
802
856
|
fontFamily: AppFonts.interBold,
|
|
@@ -836,7 +890,9 @@ const BundleTab = React.memo(() => {
|
|
|
836
890
|
{/* 4-Stat Metric Grid */}
|
|
837
891
|
<View style={bundleStyles.metricsGrid}>
|
|
838
892
|
<View style={bundleStyles.metricBox}>
|
|
839
|
-
<Text style={bundleStyles.metricLabel}>
|
|
893
|
+
<Text style={bundleStyles.metricLabel}>
|
|
894
|
+
{t('bundle.devBundleSize')}
|
|
895
|
+
</Text>
|
|
840
896
|
<Text style={bundleStyles.metricValue}>
|
|
841
897
|
{t('bundle.mbValue', {
|
|
842
898
|
size: analysis ? analysis.totalDevMb : summary.totalMb,
|
|
@@ -853,8 +909,13 @@ const BundleTab = React.memo(() => {
|
|
|
853
909
|
</View>
|
|
854
910
|
|
|
855
911
|
<View style={bundleStyles.metricBox}>
|
|
856
|
-
<Text style={bundleStyles.metricLabel}>
|
|
857
|
-
|
|
912
|
+
<Text style={bundleStyles.metricLabel}>
|
|
913
|
+
{t('bundle.imagesMedia')}
|
|
914
|
+
</Text>
|
|
915
|
+
<Text style={[
|
|
916
|
+
bundleStyles.metricValue,
|
|
917
|
+
{ color: AppColors.pink500 },
|
|
918
|
+
]}>
|
|
858
919
|
{t('bundle.fileSizeKb', { size: summary.images.kb })}
|
|
859
920
|
</Text>
|
|
860
921
|
<Text style={bundleStyles.metricHint}>
|
|
@@ -863,9 +924,13 @@ const BundleTab = React.memo(() => {
|
|
|
863
924
|
</View>
|
|
864
925
|
|
|
865
926
|
<View style={bundleStyles.metricBox}>
|
|
866
|
-
<Text style={bundleStyles.metricLabel}>
|
|
927
|
+
<Text style={bundleStyles.metricLabel}>
|
|
928
|
+
{t('bundle.tsJsSource')}
|
|
929
|
+
</Text>
|
|
867
930
|
<Text style={[bundleStyles.metricValue, { color: AppColors.sky500 }]}>
|
|
868
|
-
{t('bundle.fileSizeKb', {
|
|
931
|
+
{t('bundle.fileSizeKb', {
|
|
932
|
+
size: summary.ts.kb + summary.js.kb,
|
|
933
|
+
})}
|
|
869
934
|
</Text>
|
|
870
935
|
<Text style={bundleStyles.metricHint}>
|
|
871
936
|
{t('bundle.pctOfTrackedAssets', {
|
|
@@ -875,11 +940,22 @@ const BundleTab = React.memo(() => {
|
|
|
875
940
|
</View>
|
|
876
941
|
|
|
877
942
|
<View style={bundleStyles.metricBox}>
|
|
878
|
-
<Text style={bundleStyles.metricLabel}>
|
|
879
|
-
|
|
943
|
+
<Text style={bundleStyles.metricLabel}>
|
|
944
|
+
{t('bundle.jsEngine')}
|
|
945
|
+
</Text>
|
|
946
|
+
<View style={{
|
|
947
|
+
flexDirection: 'row',
|
|
948
|
+
alignItems: 'center',
|
|
949
|
+
gap: 5,
|
|
950
|
+
marginTop: 2,
|
|
951
|
+
}}>
|
|
880
952
|
<View style={[
|
|
881
953
|
bundleStyles.statusIndicator,
|
|
882
|
-
{
|
|
954
|
+
{
|
|
955
|
+
backgroundColor: isHermes
|
|
956
|
+
? AppColors.greenColor
|
|
957
|
+
: AppColors.darkOrange,
|
|
958
|
+
},
|
|
883
959
|
]}/>
|
|
884
960
|
<Text style={bundleStyles.metricValue}>
|
|
885
961
|
{isHermes ? 'Hermes' : 'JSC'}
|
|
@@ -894,7 +970,12 @@ const BundleTab = React.memo(() => {
|
|
|
894
970
|
|
|
895
971
|
{/* Live analysis unavailable warning */}
|
|
896
972
|
{analysis && !analysis.isLive && (<View style={bundleStyles.liveWarningCard}>
|
|
897
|
-
<View style={{
|
|
973
|
+
<View style={{
|
|
974
|
+
flexDirection: 'row',
|
|
975
|
+
alignItems: 'center',
|
|
976
|
+
gap: 6,
|
|
977
|
+
flex: 1,
|
|
978
|
+
}}>
|
|
898
979
|
<CircleAlertIcon color={AppColors.amber700} size={16}/>
|
|
899
980
|
<View style={{ flex: 1 }}>
|
|
900
981
|
<Text style={bundleStyles.liveWarningTitle}>
|
|
@@ -907,13 +988,13 @@ const BundleTab = React.memo(() => {
|
|
|
907
988
|
</View>
|
|
908
989
|
</View>)}
|
|
909
990
|
|
|
910
|
-
|
|
911
|
-
|
|
912
991
|
{/* Visual Type Distribution Ratio Bar */}
|
|
913
992
|
<View style={bundleStyles.sectionCard}>
|
|
914
993
|
<View style={bundleStyles.sectionHeaderRow}>
|
|
915
|
-
<View>
|
|
916
|
-
<Text style={bundleStyles.sectionTitle}>
|
|
994
|
+
<View style={{ flex: 1, paddingRight: 4 }}>
|
|
995
|
+
<Text style={bundleStyles.sectionTitle}>
|
|
996
|
+
{t('bundle.treemapTitle')}
|
|
997
|
+
</Text>
|
|
917
998
|
<Text style={bundleStyles.sectionSub}>
|
|
918
999
|
{t('bundle.treemapSub', { mb: summary.totalMb })}
|
|
919
1000
|
</Text>
|
|
@@ -921,19 +1002,44 @@ const BundleTab = React.memo(() => {
|
|
|
921
1002
|
<CopyButton value={() => ({
|
|
922
1003
|
totalMb: summary.totalMb,
|
|
923
1004
|
totalKb: summary.totalKb,
|
|
924
|
-
nodeModules: {
|
|
1005
|
+
nodeModules: {
|
|
1006
|
+
kb: summary.nodeModulesKb,
|
|
1007
|
+
pct: summary.nodeModulesPct,
|
|
1008
|
+
},
|
|
925
1009
|
metroRuntime: { kb: summary.metroKb, pct: summary.metroPct },
|
|
926
|
-
appSource: {
|
|
927
|
-
|
|
1010
|
+
appSource: {
|
|
1011
|
+
kb: summary.appSourceKb,
|
|
1012
|
+
pct: summary.appSourcePct,
|
|
1013
|
+
},
|
|
1014
|
+
assetsMedia: {
|
|
1015
|
+
kb: summary.assetsMediaKb,
|
|
1016
|
+
pct: summary.assetsMediaPct,
|
|
1017
|
+
},
|
|
928
1018
|
})} label={t('bundle.treemapJson')}/>
|
|
929
1019
|
</View>
|
|
930
1020
|
|
|
931
1021
|
{/* Stacked Colored Bar for Full 6.0 MB Bundle */}
|
|
932
1022
|
<View style={bundleStyles.treemapBar}>
|
|
933
|
-
<View style={{
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1023
|
+
<View style={{
|
|
1024
|
+
flex: summary.nodeModulesPct,
|
|
1025
|
+
backgroundColor: AppColors.indigo500,
|
|
1026
|
+
height: 16,
|
|
1027
|
+
}}/>
|
|
1028
|
+
<View style={{
|
|
1029
|
+
flex: summary.metroPct,
|
|
1030
|
+
backgroundColor: AppColors.amber500,
|
|
1031
|
+
height: 16,
|
|
1032
|
+
}}/>
|
|
1033
|
+
<View style={{
|
|
1034
|
+
flex: summary.appSourcePct,
|
|
1035
|
+
backgroundColor: AppColors.sky500,
|
|
1036
|
+
height: 16,
|
|
1037
|
+
}}/>
|
|
1038
|
+
<View style={{
|
|
1039
|
+
flex: summary.assetsMediaPct,
|
|
1040
|
+
backgroundColor: AppColors.pink500,
|
|
1041
|
+
height: 16,
|
|
1042
|
+
}}/>
|
|
937
1043
|
</View>
|
|
938
1044
|
|
|
939
1045
|
{/* Legend Grid */}
|
|
@@ -945,7 +1051,8 @@ const BundleTab = React.memo(() => {
|
|
|
945
1051
|
<Text style={bundleStyles.legendVal}>
|
|
946
1052
|
{summary.nodeModulesKb >= 1024
|
|
947
1053
|
? `${(summary.nodeModulesKb / 1024).toFixed(1)} MB`
|
|
948
|
-
: `${summary.nodeModulesKb} KB`}
|
|
1054
|
+
: `${summary.nodeModulesKb} KB`}{' '}
|
|
1055
|
+
({summary.nodeModulesPct}%)
|
|
949
1056
|
</Text>
|
|
950
1057
|
</Text>
|
|
951
1058
|
</View>
|
|
@@ -956,7 +1063,8 @@ const BundleTab = React.memo(() => {
|
|
|
956
1063
|
<Text style={bundleStyles.legendVal}>
|
|
957
1064
|
{summary.metroKb >= 1024
|
|
958
1065
|
? `${(summary.metroKb / 1024).toFixed(1)} MB`
|
|
959
|
-
: `${summary.metroKb} KB`}
|
|
1066
|
+
: `${summary.metroKb} KB`}{' '}
|
|
1067
|
+
({summary.metroPct}%)
|
|
960
1068
|
</Text>
|
|
961
1069
|
</Text>
|
|
962
1070
|
</View>
|
|
@@ -967,7 +1075,8 @@ const BundleTab = React.memo(() => {
|
|
|
967
1075
|
<Text style={bundleStyles.legendVal}>
|
|
968
1076
|
{summary.appSourceKb >= 1024
|
|
969
1077
|
? `${(summary.appSourceKb / 1024).toFixed(1)} MB`
|
|
970
|
-
: `${summary.appSourceKb} KB`}
|
|
1078
|
+
: `${summary.appSourceKb} KB`}{' '}
|
|
1079
|
+
({summary.appSourcePct}%)
|
|
971
1080
|
</Text>
|
|
972
1081
|
</Text>
|
|
973
1082
|
</View>
|
|
@@ -978,7 +1087,8 @@ const BundleTab = React.memo(() => {
|
|
|
978
1087
|
<Text style={bundleStyles.legendVal}>
|
|
979
1088
|
{summary.assetsMediaKb >= 1024
|
|
980
1089
|
? `${(summary.assetsMediaKb / 1024).toFixed(1)} MB`
|
|
981
|
-
: `${summary.assetsMediaKb} KB`}
|
|
1090
|
+
: `${summary.assetsMediaKb} KB`}{' '}
|
|
1091
|
+
({summary.assetsMediaPct}%)
|
|
982
1092
|
</Text>
|
|
983
1093
|
</Text>
|
|
984
1094
|
</View>
|
|
@@ -988,10 +1098,12 @@ const BundleTab = React.memo(() => {
|
|
|
988
1098
|
{/* Detailed Category Footprint Cards */}
|
|
989
1099
|
<View style={bundleStyles.sectionCard}>
|
|
990
1100
|
<View style={bundleStyles.sectionHeaderRow}>
|
|
991
|
-
<Text style={bundleStyles.sectionTitle}>
|
|
1101
|
+
<Text style={bundleStyles.sectionTitle}>
|
|
1102
|
+
{t('bundle.categoryBreakdown')}
|
|
1103
|
+
</Text>
|
|
992
1104
|
<CopyButton value={() => summary} label={t('bundle.categoriesJson')}/>
|
|
993
1105
|
</View>
|
|
994
|
-
|
|
1106
|
+
|
|
995
1107
|
{summary.categories.map((cat, cIdx) => (<Pressable key={cIdx} accessible={true} accessibilityRole="button" accessibilityLabel={`${cat.title}, ${cat.sizeKb >= 1024 ? `${cat.sizeMb} MB` : `${cat.sizeKb} KB`}, ${cat.pct}% of bundle`} accessibilityHint={`Double tap to view ${cat.title} details`} style={({ pressed }) => [
|
|
996
1108
|
bundleStyles.catRowCard,
|
|
997
1109
|
pressed && { opacity: 0.85, transform: [{ scale: 0.99 }] },
|
|
@@ -999,25 +1111,42 @@ const BundleTab = React.memo(() => {
|
|
|
999
1111
|
<View style={bundleStyles.catRowTop}>
|
|
1000
1112
|
<View style={[
|
|
1001
1113
|
bundleStyles.catIconBox,
|
|
1002
|
-
{
|
|
1114
|
+
{
|
|
1115
|
+
backgroundColor: `${cat.color}15`,
|
|
1116
|
+
borderColor: `${cat.color}30`,
|
|
1117
|
+
},
|
|
1003
1118
|
]}>
|
|
1004
1119
|
<BundleCategoryIcon type={cat.iconType} size={18} color={cat.color}/>
|
|
1005
1120
|
</View>
|
|
1006
1121
|
|
|
1007
1122
|
<View style={bundleStyles.catRowTitleWrap}>
|
|
1008
|
-
<View style={{
|
|
1123
|
+
<View style={{
|
|
1124
|
+
flexDirection: 'row',
|
|
1125
|
+
alignItems: 'center',
|
|
1126
|
+
justifyContent: 'space-between',
|
|
1127
|
+
gap: 6,
|
|
1128
|
+
}}>
|
|
1009
1129
|
<Text style={bundleStyles.catRowTitle} numberOfLines={1}>
|
|
1010
1130
|
{cat.title}
|
|
1011
1131
|
</Text>
|
|
1012
|
-
<View style={{
|
|
1132
|
+
<View style={{
|
|
1133
|
+
flexDirection: 'row',
|
|
1134
|
+
alignItems: 'center',
|
|
1135
|
+
gap: 6,
|
|
1136
|
+
}}>
|
|
1013
1137
|
<Text style={bundleStyles.catRowSize}>
|
|
1014
|
-
{cat.sizeKb >= 1024
|
|
1138
|
+
{cat.sizeKb >= 1024
|
|
1139
|
+
? `${cat.sizeMb} MB`
|
|
1140
|
+
: `${cat.sizeKb} KB`}
|
|
1015
1141
|
</Text>
|
|
1016
1142
|
<View style={[
|
|
1017
1143
|
bundleStyles.catPctPill,
|
|
1018
1144
|
{ backgroundColor: `${cat.color}18` },
|
|
1019
1145
|
]}>
|
|
1020
|
-
<Text style={[
|
|
1146
|
+
<Text style={[
|
|
1147
|
+
bundleStyles.catPctText,
|
|
1148
|
+
{ color: cat.color },
|
|
1149
|
+
]}>
|
|
1021
1150
|
{cat.pct}%
|
|
1022
1151
|
</Text>
|
|
1023
1152
|
</View>
|
|
@@ -1068,20 +1197,43 @@ const BundleTab = React.memo(() => {
|
|
|
1068
1197
|
{/* 4-Pill Chip Breakdown */}
|
|
1069
1198
|
<View style={bundleStyles.totalFormulaGrid}>
|
|
1070
1199
|
<View style={bundleStyles.totalChip}>
|
|
1071
|
-
<View style={[
|
|
1072
|
-
|
|
1200
|
+
<View style={[
|
|
1201
|
+
bundleStyles.totalDot,
|
|
1202
|
+
{ backgroundColor: AppColors.indigo500 },
|
|
1203
|
+
]}/>
|
|
1204
|
+
<Text style={bundleStyles.totalChipText}>
|
|
1205
|
+
NPM: {(summary.nodeModulesKb / 1024).toFixed(1)}M (
|
|
1206
|
+
{summary.nodeModulesPct}%)
|
|
1207
|
+
</Text>
|
|
1073
1208
|
</View>
|
|
1074
1209
|
<View style={bundleStyles.totalChip}>
|
|
1075
|
-
<View style={[
|
|
1076
|
-
|
|
1210
|
+
<View style={[
|
|
1211
|
+
bundleStyles.totalDot,
|
|
1212
|
+
{ backgroundColor: AppColors.amber500 },
|
|
1213
|
+
]}/>
|
|
1214
|
+
<Text style={bundleStyles.totalChipText}>
|
|
1215
|
+
Metro: {(summary.metroKb / 1024).toFixed(1)}M (
|
|
1216
|
+
{summary.metroPct}%)
|
|
1217
|
+
</Text>
|
|
1077
1218
|
</View>
|
|
1078
1219
|
<View style={bundleStyles.totalChip}>
|
|
1079
|
-
<View style={[
|
|
1080
|
-
|
|
1220
|
+
<View style={[
|
|
1221
|
+
bundleStyles.totalDot,
|
|
1222
|
+
{ backgroundColor: AppColors.sky500 },
|
|
1223
|
+
]}/>
|
|
1224
|
+
<Text style={bundleStyles.totalChipText}>
|
|
1225
|
+
Source: {(summary.appSourceKb / 1024).toFixed(1)}M (
|
|
1226
|
+
{summary.appSourcePct}%)
|
|
1227
|
+
</Text>
|
|
1081
1228
|
</View>
|
|
1082
1229
|
<View style={bundleStyles.totalChip}>
|
|
1083
|
-
<View style={[
|
|
1084
|
-
|
|
1230
|
+
<View style={[
|
|
1231
|
+
bundleStyles.totalDot,
|
|
1232
|
+
{ backgroundColor: AppColors.pink500 },
|
|
1233
|
+
]}/>
|
|
1234
|
+
<Text style={bundleStyles.totalChipText}>
|
|
1235
|
+
Media: {summary.assetsMediaKb}K ({summary.assetsMediaPct}%)
|
|
1236
|
+
</Text>
|
|
1085
1237
|
</View>
|
|
1086
1238
|
</View>
|
|
1087
1239
|
</View>
|
|
@@ -1090,10 +1242,13 @@ const BundleTab = React.memo(() => {
|
|
|
1090
1242
|
{/* Detailed Subsystem Architecture Split-up */}
|
|
1091
1243
|
<View style={bundleStyles.sectionCard}>
|
|
1092
1244
|
<View style={bundleStyles.sectionHeaderRow}>
|
|
1093
|
-
<View>
|
|
1094
|
-
<Text style={bundleStyles.sectionTitle}>
|
|
1245
|
+
<View style={{ flex: 1, paddingRight: 4 }}>
|
|
1246
|
+
<Text style={bundleStyles.sectionTitle}>
|
|
1247
|
+
Bundle Subsystem Breakdown
|
|
1248
|
+
</Text>
|
|
1095
1249
|
<Text style={bundleStyles.sectionSub}>
|
|
1096
|
-
Granular analysis of packages, application source, engine
|
|
1250
|
+
Granular analysis of packages, application source, engine
|
|
1251
|
+
runtime & assets
|
|
1097
1252
|
</Text>
|
|
1098
1253
|
</View>
|
|
1099
1254
|
<CopyButton value={() => ({
|
|
@@ -1102,8 +1257,11 @@ const BundleTab = React.memo(() => {
|
|
|
1102
1257
|
hermesEngine: isHermes ? 'Hermes (Bytecode)' : 'JSC (Source)',
|
|
1103
1258
|
jsDevKb: summary.totalKb,
|
|
1104
1259
|
jsHermesReleaseKb: Math.round(summary.totalKb * 0.38),
|
|
1105
|
-
appSourceFiles: bundleFiles.filter(f => f.category === 'typescript' ||
|
|
1106
|
-
|
|
1260
|
+
appSourceFiles: bundleFiles.filter(f => f.category === 'typescript' ||
|
|
1261
|
+
f.category === 'javascript').length,
|
|
1262
|
+
mediaAssets: bundleFiles.filter(f => f.category === 'image' ||
|
|
1263
|
+
f.category === 'font' ||
|
|
1264
|
+
f.category === 'json').length,
|
|
1107
1265
|
})} label="Subsystem Split JSON"/>
|
|
1108
1266
|
</View>
|
|
1109
1267
|
|
|
@@ -1112,28 +1270,51 @@ const BundleTab = React.memo(() => {
|
|
|
1112
1270
|
<View style={bundleStyles.subsystemHeader}>
|
|
1113
1271
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
|
|
1114
1272
|
<BundleCategoryIcon type="deps" size={16} color={AppColors.indigo500}/>
|
|
1115
|
-
<Text style={bundleStyles.subsystemTitle}>
|
|
1273
|
+
<Text style={bundleStyles.subsystemTitle}>
|
|
1274
|
+
NPM & Third-Party Dependencies
|
|
1275
|
+
</Text>
|
|
1116
1276
|
</View>
|
|
1117
|
-
<View style={[
|
|
1118
|
-
|
|
1119
|
-
|
|
1277
|
+
<View style={[
|
|
1278
|
+
bundleStyles.subsystemBadge,
|
|
1279
|
+
{ backgroundColor: `${AppColors.indigo500}18` },
|
|
1280
|
+
]}>
|
|
1281
|
+
<Text style={[
|
|
1282
|
+
bundleStyles.subsystemBadgeText,
|
|
1283
|
+
{ color: AppColors.indigo500 },
|
|
1284
|
+
]}>
|
|
1285
|
+
{(summary.nodeModulesKb / 1024).toFixed(1)} MB •{' '}
|
|
1286
|
+
{summary.nodeModulesPct}%
|
|
1120
1287
|
</Text>
|
|
1121
1288
|
</View>
|
|
1122
1289
|
</View>
|
|
1123
1290
|
<View style={bundleStyles.subsystemGrid}>
|
|
1124
1291
|
<View style={bundleStyles.subsystemItem}>
|
|
1125
1292
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1126
|
-
Direct:
|
|
1293
|
+
Direct:{' '}
|
|
1294
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1295
|
+
{bundlePackages.filter(p => p.type === 'direct').length ||
|
|
1296
|
+
12}{' '}
|
|
1297
|
+
pkgs
|
|
1298
|
+
</Text>
|
|
1127
1299
|
</Text>
|
|
1128
1300
|
</View>
|
|
1129
1301
|
<View style={bundleStyles.subsystemItem}>
|
|
1130
1302
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1131
|
-
Transitive:
|
|
1303
|
+
Transitive:{' '}
|
|
1304
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1305
|
+
{bundlePackages.filter(p => p.type !== 'direct').length ||
|
|
1306
|
+
41}{' '}
|
|
1307
|
+
pkgs
|
|
1308
|
+
</Text>
|
|
1132
1309
|
</Text>
|
|
1133
1310
|
</View>
|
|
1134
1311
|
<View style={bundleStyles.subsystemItem}>
|
|
1135
1312
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1136
|
-
Top Package:
|
|
1313
|
+
Top Package:{' '}
|
|
1314
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1315
|
+
{bundlePackages[0]?.name || 'react-native'} (
|
|
1316
|
+
{bundlePackages[0]?.sizeKb || 1240} KB)
|
|
1317
|
+
</Text>
|
|
1137
1318
|
</Text>
|
|
1138
1319
|
</View>
|
|
1139
1320
|
</View>
|
|
@@ -1144,28 +1325,50 @@ const BundleTab = React.memo(() => {
|
|
|
1144
1325
|
<View style={bundleStyles.subsystemHeader}>
|
|
1145
1326
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
|
|
1146
1327
|
<BundleCategoryIcon type="source" size={16} color={AppColors.sky500}/>
|
|
1147
|
-
<Text style={bundleStyles.subsystemTitle}>
|
|
1328
|
+
<Text style={bundleStyles.subsystemTitle}>
|
|
1329
|
+
Application Source Code
|
|
1330
|
+
</Text>
|
|
1148
1331
|
</View>
|
|
1149
|
-
<View style={[
|
|
1150
|
-
|
|
1151
|
-
|
|
1332
|
+
<View style={[
|
|
1333
|
+
bundleStyles.subsystemBadge,
|
|
1334
|
+
{ backgroundColor: `${AppColors.sky500}18` },
|
|
1335
|
+
]}>
|
|
1336
|
+
<Text style={[
|
|
1337
|
+
bundleStyles.subsystemBadgeText,
|
|
1338
|
+
{ color: AppColors.sky500 },
|
|
1339
|
+
]}>
|
|
1340
|
+
{(summary.appSourceKb / 1024).toFixed(1)} MB •{' '}
|
|
1341
|
+
{summary.appSourcePct}%
|
|
1152
1342
|
</Text>
|
|
1153
1343
|
</View>
|
|
1154
1344
|
</View>
|
|
1155
1345
|
<View style={bundleStyles.subsystemGrid}>
|
|
1156
1346
|
<View style={bundleStyles.subsystemItem}>
|
|
1157
1347
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1158
|
-
TypeScript/TSX:
|
|
1348
|
+
TypeScript/TSX:{' '}
|
|
1349
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1350
|
+
{bundleFiles.filter(f => f.category === 'typescript')
|
|
1351
|
+
.length || 14}{' '}
|
|
1352
|
+
files
|
|
1353
|
+
</Text>
|
|
1159
1354
|
</Text>
|
|
1160
1355
|
</View>
|
|
1161
1356
|
<View style={bundleStyles.subsystemItem}>
|
|
1162
1357
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1163
|
-
JavaScript/JSX:
|
|
1358
|
+
JavaScript/JSX:{' '}
|
|
1359
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1360
|
+
{bundleFiles.filter(f => f.category === 'javascript')
|
|
1361
|
+
.length || 3}{' '}
|
|
1362
|
+
files
|
|
1363
|
+
</Text>
|
|
1164
1364
|
</Text>
|
|
1165
1365
|
</View>
|
|
1166
1366
|
<View style={bundleStyles.subsystemItem}>
|
|
1167
1367
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1168
|
-
Tracked Modules:
|
|
1368
|
+
Tracked Modules:{' '}
|
|
1369
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1370
|
+
{bundleFiles.length || 18} files
|
|
1371
|
+
</Text>
|
|
1169
1372
|
</Text>
|
|
1170
1373
|
</View>
|
|
1171
1374
|
</View>
|
|
@@ -1176,10 +1379,18 @@ const BundleTab = React.memo(() => {
|
|
|
1176
1379
|
<View style={bundleStyles.subsystemHeader}>
|
|
1177
1380
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
|
|
1178
1381
|
<BundleCategoryIcon type="bolt" size={16} color={AppColors.emerald600}/>
|
|
1179
|
-
<Text style={bundleStyles.subsystemTitle}>
|
|
1382
|
+
<Text style={bundleStyles.subsystemTitle}>
|
|
1383
|
+
Hermes Bytecode Engine
|
|
1384
|
+
</Text>
|
|
1180
1385
|
</View>
|
|
1181
|
-
<View style={[
|
|
1182
|
-
|
|
1386
|
+
<View style={[
|
|
1387
|
+
bundleStyles.subsystemBadge,
|
|
1388
|
+
{ backgroundColor: `${AppColors.emerald500}18` },
|
|
1389
|
+
]}>
|
|
1390
|
+
<Text style={[
|
|
1391
|
+
bundleStyles.subsystemBadgeText,
|
|
1392
|
+
{ color: AppColors.emerald700 },
|
|
1393
|
+
]}>
|
|
1183
1394
|
~62% AOT Compression
|
|
1184
1395
|
</Text>
|
|
1185
1396
|
</View>
|
|
@@ -1187,17 +1398,26 @@ const BundleTab = React.memo(() => {
|
|
|
1187
1398
|
<View style={bundleStyles.subsystemGrid}>
|
|
1188
1399
|
<View style={bundleStyles.subsystemItem}>
|
|
1189
1400
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1190
|
-
Dev JS Size:
|
|
1401
|
+
Dev JS Size:{' '}
|
|
1402
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1403
|
+
{summary.totalMb} MB
|
|
1404
|
+
</Text>
|
|
1191
1405
|
</Text>
|
|
1192
1406
|
</View>
|
|
1193
1407
|
<View style={bundleStyles.subsystemItem}>
|
|
1194
1408
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1195
|
-
Hermes Bytecode:
|
|
1409
|
+
Hermes Bytecode:{' '}
|
|
1410
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1411
|
+
{((summary.totalKb * 0.38) / 1024).toFixed(2)} MB
|
|
1412
|
+
</Text>
|
|
1196
1413
|
</Text>
|
|
1197
1414
|
</View>
|
|
1198
1415
|
<View style={bundleStyles.subsystemItem}>
|
|
1199
1416
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1200
|
-
Execution:
|
|
1417
|
+
Execution:{' '}
|
|
1418
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1419
|
+
{isHermes ? 'Hermes JSI Direct' : 'JSC Standard'}
|
|
1420
|
+
</Text>
|
|
1201
1421
|
</Text>
|
|
1202
1422
|
</View>
|
|
1203
1423
|
</View>
|
|
@@ -1208,10 +1428,18 @@ const BundleTab = React.memo(() => {
|
|
|
1208
1428
|
<View style={bundleStyles.subsystemHeader}>
|
|
1209
1429
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
|
|
1210
1430
|
<BundleCategoryIcon type="media" size={16} color={AppColors.pink500}/>
|
|
1211
|
-
<Text style={bundleStyles.subsystemTitle}>
|
|
1431
|
+
<Text style={bundleStyles.subsystemTitle}>
|
|
1432
|
+
Images, Fonts & Static Assets
|
|
1433
|
+
</Text>
|
|
1212
1434
|
</View>
|
|
1213
|
-
<View style={[
|
|
1214
|
-
|
|
1435
|
+
<View style={[
|
|
1436
|
+
bundleStyles.subsystemBadge,
|
|
1437
|
+
{ backgroundColor: `${AppColors.pink500}18` },
|
|
1438
|
+
]}>
|
|
1439
|
+
<Text style={[
|
|
1440
|
+
bundleStyles.subsystemBadgeText,
|
|
1441
|
+
{ color: AppColors.pink500 },
|
|
1442
|
+
]}>
|
|
1215
1443
|
{summary.assetsMediaKb} KB • {summary.assetsMediaPct}%
|
|
1216
1444
|
</Text>
|
|
1217
1445
|
</View>
|
|
@@ -1219,17 +1447,32 @@ const BundleTab = React.memo(() => {
|
|
|
1219
1447
|
<View style={bundleStyles.subsystemGrid}>
|
|
1220
1448
|
<View style={bundleStyles.subsystemItem}>
|
|
1221
1449
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1222
|
-
Images & Icons:
|
|
1450
|
+
Images & Icons:{' '}
|
|
1451
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1452
|
+
{bundleFiles.filter(f => f.category === 'image').length ||
|
|
1453
|
+
2}{' '}
|
|
1454
|
+
assets
|
|
1455
|
+
</Text>
|
|
1223
1456
|
</Text>
|
|
1224
1457
|
</View>
|
|
1225
1458
|
<View style={bundleStyles.subsystemItem}>
|
|
1226
1459
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1227
|
-
JSON Data:
|
|
1460
|
+
JSON Data:{' '}
|
|
1461
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1462
|
+
{bundleFiles.filter(f => f.category === 'json').length ||
|
|
1463
|
+
1}{' '}
|
|
1464
|
+
files
|
|
1465
|
+
</Text>
|
|
1228
1466
|
</Text>
|
|
1229
1467
|
</View>
|
|
1230
1468
|
<View style={bundleStyles.subsystemItem}>
|
|
1231
1469
|
<Text style={bundleStyles.subsystemItemText}>
|
|
1232
|
-
Custom Fonts:
|
|
1470
|
+
Custom Fonts:{' '}
|
|
1471
|
+
<Text style={bundleStyles.subsystemItemVal}>
|
|
1472
|
+
{bundleFiles.filter(f => f.category === 'font').length ||
|
|
1473
|
+
0}{' '}
|
|
1474
|
+
fonts
|
|
1475
|
+
</Text>
|
|
1233
1476
|
</Text>
|
|
1234
1477
|
</View>
|
|
1235
1478
|
</View>
|
|
@@ -1241,13 +1484,24 @@ const BundleTab = React.memo(() => {
|
|
|
1241
1484
|
{/* ── 2. TAB: PRODUCTION BUILDS & PLATFORMS ───────────────────────────── */}
|
|
1242
1485
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1243
1486
|
{activeSubTab === 'production' && (<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
|
|
1244
|
-
|
|
1245
1487
|
{/* Platform Segmented Switcher (Horizontally Scrollable) */}
|
|
1246
1488
|
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={bundleStyles.prodPlatformScroll}>
|
|
1247
1489
|
{[
|
|
1248
|
-
{
|
|
1249
|
-
|
|
1250
|
-
|
|
1490
|
+
{
|
|
1491
|
+
key: 'ios',
|
|
1492
|
+
label: 'iOS App (.ipa)',
|
|
1493
|
+
badge: `${analysis?.production.ios.totalDownloadMb || 111.9} MB`,
|
|
1494
|
+
},
|
|
1495
|
+
{
|
|
1496
|
+
key: 'androidAab',
|
|
1497
|
+
label: 'Android AAB (.aab)',
|
|
1498
|
+
badge: `${analysis?.production.androidAab.totalDownloadMb || 38.5} MB`,
|
|
1499
|
+
},
|
|
1500
|
+
{
|
|
1501
|
+
key: 'androidApk',
|
|
1502
|
+
label: 'Universal APK (.apk)',
|
|
1503
|
+
badge: `${analysis?.production.androidApk.totalInstallMb || 364.0} MB`,
|
|
1504
|
+
},
|
|
1251
1505
|
].map(tab => {
|
|
1252
1506
|
const isSelected = prodPlatform === tab.key;
|
|
1253
1507
|
return (<TouchableScale key={tab.key} accessible={true} accessibilityRole="tab" accessibilityLabel={`${tab.label}, ${tab.badge}`} accessibilityState={{ selected: isSelected }} accessibilityHint={`Switches production estimate to ${tab.label}`} onPress={() => setProdPlatform(tab.key)} style={[
|
|
@@ -1304,31 +1558,51 @@ const BundleTab = React.memo(() => {
|
|
|
1304
1558
|
<View style={bundleStyles.metricsGrid}>
|
|
1305
1559
|
<View style={bundleStyles.metricBox}>
|
|
1306
1560
|
<Text style={bundleStyles.metricLabel}>INSTALL SIZE</Text>
|
|
1307
|
-
<Text style={[
|
|
1561
|
+
<Text style={[
|
|
1562
|
+
bundleStyles.metricValue,
|
|
1563
|
+
{ color: AppColors.purple },
|
|
1564
|
+
]}>
|
|
1308
1565
|
{analysis.production[prodPlatform].totalInstallMb} MB
|
|
1309
1566
|
</Text>
|
|
1310
|
-
<Text style={bundleStyles.metricHint}>
|
|
1567
|
+
<Text style={bundleStyles.metricHint}>
|
|
1568
|
+
On-device uncompressed footprint
|
|
1569
|
+
</Text>
|
|
1311
1570
|
</View>
|
|
1312
1571
|
|
|
1313
1572
|
<View style={bundleStyles.metricBox}>
|
|
1314
1573
|
<Text style={bundleStyles.metricLabel}>DOWNLOAD SIZE</Text>
|
|
1315
|
-
<Text style={[
|
|
1574
|
+
<Text style={[
|
|
1575
|
+
bundleStyles.metricValue,
|
|
1576
|
+
{ color: AppColors.emerald600 },
|
|
1577
|
+
]}>
|
|
1316
1578
|
~{analysis.production[prodPlatform].totalDownloadMb} MB
|
|
1317
1579
|
</Text>
|
|
1318
|
-
<Text style={bundleStyles.metricHint}>
|
|
1580
|
+
<Text style={bundleStyles.metricHint}>
|
|
1581
|
+
Store network transfer payload
|
|
1582
|
+
</Text>
|
|
1319
1583
|
</View>
|
|
1320
1584
|
|
|
1321
1585
|
<View style={bundleStyles.metricBox}>
|
|
1322
1586
|
<Text style={bundleStyles.metricLabel}>COMPRESSION</Text>
|
|
1323
|
-
<Text style={[
|
|
1587
|
+
<Text style={[
|
|
1588
|
+
bundleStyles.metricValue,
|
|
1589
|
+
{ color: AppColors.sky500 },
|
|
1590
|
+
]}>
|
|
1324
1591
|
{analysis.production[prodPlatform].compressionRatioPct}%
|
|
1325
1592
|
</Text>
|
|
1326
|
-
<Text style={bundleStyles.metricHint}>
|
|
1593
|
+
<Text style={bundleStyles.metricHint}>
|
|
1594
|
+
Bytecode & asset ratio
|
|
1595
|
+
</Text>
|
|
1327
1596
|
</View>
|
|
1328
1597
|
|
|
1329
1598
|
<View style={bundleStyles.metricBox}>
|
|
1330
|
-
<Text style={bundleStyles.metricLabel}>
|
|
1331
|
-
|
|
1599
|
+
<Text style={bundleStyles.metricLabel}>
|
|
1600
|
+
FORMAT ARCHITECTURE
|
|
1601
|
+
</Text>
|
|
1602
|
+
<Text style={[
|
|
1603
|
+
bundleStyles.metricValue,
|
|
1604
|
+
{ color: AppColors.amber700 },
|
|
1605
|
+
]}>
|
|
1332
1606
|
{prodPlatform === 'ios'
|
|
1333
1607
|
? 'Mach-O 64-bit'
|
|
1334
1608
|
: prodPlatform === 'androidAab'
|
|
@@ -1349,10 +1623,13 @@ const BundleTab = React.memo(() => {
|
|
|
1349
1623
|
{/* Component Breakdown Cards */}
|
|
1350
1624
|
{analysis && (<View style={bundleStyles.sectionCard}>
|
|
1351
1625
|
<View style={bundleStyles.sectionHeaderRow}>
|
|
1352
|
-
<View>
|
|
1353
|
-
<Text style={bundleStyles.sectionTitle}>
|
|
1626
|
+
<View style={{ flex: 1, paddingRight: 4 }}>
|
|
1627
|
+
<Text style={bundleStyles.sectionTitle}>
|
|
1628
|
+
Binary Component Architecture
|
|
1629
|
+
</Text>
|
|
1354
1630
|
<Text style={bundleStyles.sectionSub}>
|
|
1355
|
-
Compiled native libraries, runtime bytecodes, assets, and
|
|
1631
|
+
Compiled native libraries, runtime bytecodes, assets, and
|
|
1632
|
+
signature blocks
|
|
1356
1633
|
</Text>
|
|
1357
1634
|
</View>
|
|
1358
1635
|
<CopyButton value={() => analysis.production[prodPlatform].components} label="Components JSON"/>
|
|
@@ -1370,26 +1647,29 @@ const BundleTab = React.memo(() => {
|
|
|
1370
1647
|
{/* Production Binary Legend */}
|
|
1371
1648
|
<View style={[bundleStyles.legendGrid, { marginBottom: 12 }]}>
|
|
1372
1649
|
{analysis.production[prodPlatform].components.map((comp, cIdx) => (<View key={cIdx} style={bundleStyles.legendItem}>
|
|
1373
|
-
|
|
1650
|
+
<View style={{
|
|
1374
1651
|
width: 8,
|
|
1375
1652
|
height: 8,
|
|
1376
1653
|
borderRadius: 4,
|
|
1377
1654
|
backgroundColor: comp.color,
|
|
1378
1655
|
}}/>
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1656
|
+
<Text style={bundleStyles.legendText} numberOfLines={1}>
|
|
1657
|
+
{comp.name}{' '}
|
|
1658
|
+
<Text style={bundleStyles.legendVal}>
|
|
1659
|
+
{comp.sizeMb} MB ({comp.pct}%)
|
|
1660
|
+
</Text>
|
|
1383
1661
|
</Text>
|
|
1384
|
-
</
|
|
1385
|
-
</View>))}
|
|
1662
|
+
</View>))}
|
|
1386
1663
|
</View>
|
|
1387
1664
|
|
|
1388
1665
|
{analysis.production[prodPlatform].components.map((comp, idx) => (<View key={idx} style={bundleStyles.catRowCard}>
|
|
1389
1666
|
<View style={bundleStyles.catRowTop}>
|
|
1390
1667
|
<View style={[
|
|
1391
1668
|
bundleStyles.catIconBox,
|
|
1392
|
-
{
|
|
1669
|
+
{
|
|
1670
|
+
backgroundColor: `${comp.color}15`,
|
|
1671
|
+
borderColor: `${comp.color}30`,
|
|
1672
|
+
},
|
|
1393
1673
|
]}>
|
|
1394
1674
|
<BundleCategoryIcon type={comp.category === 'native'
|
|
1395
1675
|
? 'source'
|
|
@@ -1403,17 +1683,31 @@ const BundleTab = React.memo(() => {
|
|
|
1403
1683
|
</View>
|
|
1404
1684
|
|
|
1405
1685
|
<View style={bundleStyles.catRowTitleWrap}>
|
|
1406
|
-
<View style={{
|
|
1686
|
+
<View style={{
|
|
1687
|
+
flexDirection: 'row',
|
|
1688
|
+
alignItems: 'center',
|
|
1689
|
+
justifyContent: 'space-between',
|
|
1690
|
+
gap: 6,
|
|
1691
|
+
}}>
|
|
1407
1692
|
<Text style={bundleStyles.catRowTitle} numberOfLines={1}>
|
|
1408
1693
|
{comp.name}
|
|
1409
1694
|
</Text>
|
|
1410
|
-
<View style={{
|
|
1411
|
-
|
|
1695
|
+
<View style={{
|
|
1696
|
+
flexDirection: 'row',
|
|
1697
|
+
alignItems: 'center',
|
|
1698
|
+
gap: 6,
|
|
1699
|
+
}}>
|
|
1700
|
+
<Text style={bundleStyles.catRowSize}>
|
|
1701
|
+
{comp.sizeMb} MB
|
|
1702
|
+
</Text>
|
|
1412
1703
|
<View style={[
|
|
1413
1704
|
bundleStyles.catPctPill,
|
|
1414
1705
|
{ backgroundColor: `${comp.color}18` },
|
|
1415
1706
|
]}>
|
|
1416
|
-
<Text style={[
|
|
1707
|
+
<Text style={[
|
|
1708
|
+
bundleStyles.catPctText,
|
|
1709
|
+
{ color: comp.color },
|
|
1710
|
+
]}>
|
|
1417
1711
|
{comp.pct}%
|
|
1418
1712
|
</Text>
|
|
1419
1713
|
</View>
|
|
@@ -1433,9 +1727,16 @@ const BundleTab = React.memo(() => {
|
|
|
1433
1727
|
]}/>
|
|
1434
1728
|
</View>
|
|
1435
1729
|
|
|
1436
|
-
{comp.advice ? (<View style={[
|
|
1730
|
+
{comp.advice ? (<View style={[
|
|
1731
|
+
bundleStyles.adviceBadge,
|
|
1732
|
+
bundleStyles.adviceOptimal,
|
|
1733
|
+
{ marginTop: 6 },
|
|
1734
|
+
]}>
|
|
1437
1735
|
<LightbulbIcon color={AppColors.emerald700} size={13}/>
|
|
1438
|
-
<Text style={[
|
|
1736
|
+
<Text style={[
|
|
1737
|
+
bundleStyles.adviceText,
|
|
1738
|
+
{ color: AppColors.emerald700, flex: 1, marginLeft: 4 },
|
|
1739
|
+
]}>
|
|
1439
1740
|
{comp.advice}
|
|
1440
1741
|
</Text>
|
|
1441
1742
|
</View>) : null}
|
|
@@ -1470,21 +1771,33 @@ const BundleTab = React.memo(() => {
|
|
|
1470
1771
|
{/* Platform Metric Grid Chips */}
|
|
1471
1772
|
<View style={bundleStyles.totalFormulaGrid}>
|
|
1472
1773
|
<View style={bundleStyles.totalChip}>
|
|
1473
|
-
<View style={[
|
|
1774
|
+
<View style={[
|
|
1775
|
+
bundleStyles.totalDot,
|
|
1776
|
+
{ backgroundColor: AppColors.purple },
|
|
1777
|
+
]}/>
|
|
1474
1778
|
<Text style={bundleStyles.totalChipText}>
|
|
1475
|
-
Install:
|
|
1779
|
+
Install:{' '}
|
|
1780
|
+
{analysis.production[prodPlatform].totalInstallMb} MB
|
|
1476
1781
|
</Text>
|
|
1477
1782
|
</View>
|
|
1478
1783
|
<View style={bundleStyles.totalChip}>
|
|
1479
|
-
<View style={[
|
|
1784
|
+
<View style={[
|
|
1785
|
+
bundleStyles.totalDot,
|
|
1786
|
+
{ backgroundColor: AppColors.sky500 },
|
|
1787
|
+
]}/>
|
|
1480
1788
|
<Text style={bundleStyles.totalChipText}>
|
|
1481
|
-
Download: ~
|
|
1789
|
+
Download: ~
|
|
1790
|
+
{analysis.production[prodPlatform].totalDownloadMb} MB
|
|
1482
1791
|
</Text>
|
|
1483
1792
|
</View>
|
|
1484
1793
|
<View style={bundleStyles.totalChip}>
|
|
1485
|
-
<View style={[
|
|
1794
|
+
<View style={[
|
|
1795
|
+
bundleStyles.totalDot,
|
|
1796
|
+
{ backgroundColor: AppColors.emerald500 },
|
|
1797
|
+
]}/>
|
|
1486
1798
|
<Text style={bundleStyles.totalChipText}>
|
|
1487
|
-
Compression:
|
|
1799
|
+
Compression:{' '}
|
|
1800
|
+
{analysis.production[prodPlatform].compressionRatioPct}%
|
|
1488
1801
|
</Text>
|
|
1489
1802
|
</View>
|
|
1490
1803
|
</View>
|
|
@@ -1521,8 +1834,16 @@ const BundleTab = React.memo(() => {
|
|
|
1521
1834
|
return (<TouchableScale key={tab.key} accessible={true} accessibilityRole="button" accessibilityLabel={`Filter by ${t(tab.labelKey)}, ${count} items`} accessibilityState={{ selected: isActive }} accessibilityHint={`Filters files list to ${t(tab.labelKey)}`} onPress={() => setActiveCategory(tab.key)} style={[
|
|
1522
1835
|
bundleStyles.catPill,
|
|
1523
1836
|
isActive && bundleStyles.catPillActive,
|
|
1524
|
-
tab.key === 'UNUSED' &&
|
|
1525
|
-
|
|
1837
|
+
tab.key === 'UNUSED' &&
|
|
1838
|
+
isActive && {
|
|
1839
|
+
backgroundColor: AppColors.red500,
|
|
1840
|
+
borderColor: AppColors.red600,
|
|
1841
|
+
},
|
|
1842
|
+
tab.key === 'CONSUMED' &&
|
|
1843
|
+
isActive && {
|
|
1844
|
+
backgroundColor: AppColors.emerald600,
|
|
1845
|
+
borderColor: AppColors.emerald700,
|
|
1846
|
+
},
|
|
1526
1847
|
]}>
|
|
1527
1848
|
<BundleCategoryIcon type={tab.iconType} size={12} color={isActive ? AppColors.white : AppColors.grayTextStrong}/>
|
|
1528
1849
|
<Text style={[
|
|
@@ -1538,7 +1859,6 @@ const BundleTab = React.memo(() => {
|
|
|
1538
1859
|
|
|
1539
1860
|
{/* Files List / Tree Content */}
|
|
1540
1861
|
<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
|
|
1541
|
-
|
|
1542
1862
|
{/* View Mode Toggle Header Bar */}
|
|
1543
1863
|
<View style={bundleStyles.treeHeaderRow}>
|
|
1544
1864
|
<View style={bundleStyles.viewModeToggleGroup}>
|
|
@@ -1548,7 +1868,8 @@ const BundleTab = React.memo(() => {
|
|
|
1548
1868
|
]}>
|
|
1549
1869
|
<Text style={[
|
|
1550
1870
|
bundleStyles.viewModeBtnText,
|
|
1551
|
-
filesViewMode === 'tree' &&
|
|
1871
|
+
filesViewMode === 'tree' &&
|
|
1872
|
+
bundleStyles.viewModeBtnTextActive,
|
|
1552
1873
|
]}>
|
|
1553
1874
|
{t('bundle.treeView')}
|
|
1554
1875
|
</Text>
|
|
@@ -1559,7 +1880,8 @@ const BundleTab = React.memo(() => {
|
|
|
1559
1880
|
]}>
|
|
1560
1881
|
<Text style={[
|
|
1561
1882
|
bundleStyles.viewModeBtnText,
|
|
1562
|
-
filesViewMode === 'list' &&
|
|
1883
|
+
filesViewMode === 'list' &&
|
|
1884
|
+
bundleStyles.viewModeBtnTextActive,
|
|
1563
1885
|
]}>
|
|
1564
1886
|
{t('bundle.flatList')}
|
|
1565
1887
|
</Text>
|
|
@@ -1568,11 +1890,17 @@ const BundleTab = React.memo(() => {
|
|
|
1568
1890
|
|
|
1569
1891
|
{filesViewMode === 'tree' ? (<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
1570
1892
|
<TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Expand all folders" onPress={expandAllFolders}>
|
|
1571
|
-
<Text style={bundleStyles.treeActionLink}>
|
|
1893
|
+
<Text style={bundleStyles.treeActionLink}>
|
|
1894
|
+
{t('bundle.expand')}
|
|
1895
|
+
</Text>
|
|
1572
1896
|
</TouchableScale>
|
|
1573
|
-
<Text style={{ color: AppColors.grayTextWeak, fontSize: 11 }}
|
|
1897
|
+
<Text style={{ color: AppColors.grayTextWeak, fontSize: 11 }}>
|
|
1898
|
+
•
|
|
1899
|
+
</Text>
|
|
1574
1900
|
<TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Collapse all folders" onPress={collapseAllFolders}>
|
|
1575
|
-
<Text style={bundleStyles.treeActionLink}>
|
|
1901
|
+
<Text style={bundleStyles.treeActionLink}>
|
|
1902
|
+
{t('bundle.collapse')}
|
|
1903
|
+
</Text>
|
|
1576
1904
|
</TouchableScale>
|
|
1577
1905
|
</View>) : (<Text style={bundleStyles.listHeaderCount}>
|
|
1578
1906
|
{t('bundle.showingFilesOf', {
|
|
@@ -1589,9 +1917,13 @@ const BundleTab = React.memo(() => {
|
|
|
1589
1917
|
/* ── MODE 2: FLAT LIST VIEW ── */
|
|
1590
1918
|
filteredFiles.map((file, index) => {
|
|
1591
1919
|
const categoryMeta = CATEGORY_COLORS[file.category] || CATEGORY_COLORS.typescript;
|
|
1592
|
-
const pctOfTotal = ((file.sizeKb / summary.totalKb) *
|
|
1920
|
+
const pctOfTotal = ((file.sizeKb / summary.totalKb) *
|
|
1921
|
+
100).toFixed(1);
|
|
1593
1922
|
const isUnused = file.isConsumed === false;
|
|
1594
|
-
return (<View key={file.id} style={[
|
|
1923
|
+
return (<View key={file.id} style={[
|
|
1924
|
+
bundleStyles.fileCard,
|
|
1925
|
+
isUnused && bundleStyles.treeFileCardUnused,
|
|
1926
|
+
]}>
|
|
1595
1927
|
<View style={bundleStyles.fileCardTop}>
|
|
1596
1928
|
<View style={bundleStyles.sNoBadge}>
|
|
1597
1929
|
<Text style={bundleStyles.sNoText}>#{index + 1}</Text>
|
|
@@ -1600,25 +1932,45 @@ const BundleTab = React.memo(() => {
|
|
|
1600
1932
|
<MediaPreviewThumbnail file={file}/>
|
|
1601
1933
|
|
|
1602
1934
|
<View style={{ flex: 1, paddingHorizontal: 4 }}>
|
|
1603
|
-
<View style={{
|
|
1935
|
+
<View style={{
|
|
1936
|
+
flexDirection: 'row',
|
|
1937
|
+
alignItems: 'center',
|
|
1938
|
+
gap: 6,
|
|
1939
|
+
flexWrap: 'wrap',
|
|
1940
|
+
}}>
|
|
1604
1941
|
<HighlightText text={file.name} search={search} style={bundleStyles.fileName} highlightStyle={bundleStyles.searchHighlight}/>
|
|
1605
1942
|
{isUnused ? (<View style={bundleStyles.unusedBadge}>
|
|
1606
|
-
<Text style={bundleStyles.unusedBadgeText}>
|
|
1943
|
+
<Text style={bundleStyles.unusedBadgeText}>
|
|
1944
|
+
{t('bundle.notConsumed')}
|
|
1945
|
+
</Text>
|
|
1607
1946
|
</View>) : (<View style={bundleStyles.consumedBadge}>
|
|
1608
|
-
<Text style={bundleStyles.consumedBadgeText}>
|
|
1947
|
+
<Text style={bundleStyles.consumedBadgeText}>
|
|
1948
|
+
{t('bundle.consumed')}
|
|
1949
|
+
</Text>
|
|
1609
1950
|
</View>)}
|
|
1610
1951
|
</View>
|
|
1611
1952
|
<HighlightText text={file.path} search={search} style={bundleStyles.filePath} highlightStyle={bundleStyles.searchHighlight} numberOfLines={1}/>
|
|
1612
1953
|
</View>
|
|
1613
1954
|
|
|
1614
|
-
<View style={{
|
|
1955
|
+
<View style={{
|
|
1956
|
+
flexDirection: 'row',
|
|
1957
|
+
alignItems: 'center',
|
|
1958
|
+
gap: 6,
|
|
1959
|
+
}}>
|
|
1615
1960
|
<View style={bundleStyles.fileSizeBox}>
|
|
1616
|
-
<Text style={[
|
|
1961
|
+
<Text style={[
|
|
1962
|
+
bundleStyles.fileSizeKb,
|
|
1963
|
+
isUnused && { color: AppColors.amber800Warm },
|
|
1964
|
+
]}>
|
|
1617
1965
|
{file.sizeKb >= 1024
|
|
1618
|
-
? t('bundle.fileSizeMb', {
|
|
1966
|
+
? t('bundle.fileSizeMb', {
|
|
1967
|
+
size: (file.sizeKb / 1024).toFixed(2),
|
|
1968
|
+
})
|
|
1619
1969
|
: t('bundle.fileSizeKb', { size: file.sizeKb })}
|
|
1620
1970
|
</Text>
|
|
1621
|
-
<Text style={bundleStyles.filePercent}>
|
|
1971
|
+
<Text style={bundleStyles.filePercent}>
|
|
1972
|
+
{pctOfTotal}%
|
|
1973
|
+
</Text>
|
|
1622
1974
|
</View>
|
|
1623
1975
|
<TouchableScale onPress={() => downloadBundleFile(file, analysis?.scriptURL)} style={bundleStyles.downloadFileBtn} hitSlop={8}>
|
|
1624
1976
|
<DownloadIcon size={14} color={AppColors.sky500}/>
|
|
@@ -1632,7 +1984,9 @@ const BundleTab = React.memo(() => {
|
|
|
1632
1984
|
bundleStyles.fileProgressBar,
|
|
1633
1985
|
{
|
|
1634
1986
|
width: `${Math.min(100, Math.max(4, Number(pctOfTotal) * 4))}%`,
|
|
1635
|
-
backgroundColor: isUnused
|
|
1987
|
+
backgroundColor: isUnused
|
|
1988
|
+
? AppColors.red500
|
|
1989
|
+
: categoryMeta.color,
|
|
1636
1990
|
},
|
|
1637
1991
|
]}/>
|
|
1638
1992
|
</View>
|
|
@@ -1691,7 +2045,6 @@ const BundleTab = React.memo(() => {
|
|
|
1691
2045
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1692
2046
|
{activeSubTab === 'packages' && (<View style={{ flex: 1 }}>
|
|
1693
2047
|
<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
|
|
1694
|
-
|
|
1695
2048
|
<View style={bundleStyles.filterContainer}>
|
|
1696
2049
|
<View style={bundleStyles.searchRow}>
|
|
1697
2050
|
<SearchIcon color={AppColors.grayTextWeak} size={15}/>
|
|
@@ -1704,14 +2057,25 @@ const BundleTab = React.memo(() => {
|
|
|
1704
2057
|
</View>
|
|
1705
2058
|
|
|
1706
2059
|
<Text style={bundleStyles.listHeaderCount}>
|
|
1707
|
-
{t('bundle.showingDependencies', {
|
|
2060
|
+
{t('bundle.showingDependencies', {
|
|
2061
|
+
count: filteredPackages.length,
|
|
2062
|
+
})}
|
|
1708
2063
|
</Text>
|
|
1709
2064
|
|
|
1710
2065
|
{filteredPackages.map((pkg, index) => {
|
|
1711
|
-
const cleanInstalledVersion = pkg.version
|
|
1712
|
-
|
|
2066
|
+
const cleanInstalledVersion = pkg.version
|
|
2067
|
+
? pkg.version.replace(/^\^/, '')
|
|
2068
|
+
: '';
|
|
2069
|
+
const hasUpdate = !!pkg.latestVersion &&
|
|
2070
|
+
!!cleanInstalledVersion &&
|
|
1713
2071
|
pkg.latestVersion !== cleanInstalledVersion;
|
|
1714
|
-
return (<View key={pkg.id} style={[
|
|
2072
|
+
return (<View key={pkg.id} style={[
|
|
2073
|
+
bundleStyles.fileCard,
|
|
2074
|
+
pkg.isDeprecated && {
|
|
2075
|
+
borderColor: AppColors.errorBorder,
|
|
2076
|
+
backgroundColor: AppColors.errorCardBg,
|
|
2077
|
+
},
|
|
2078
|
+
]}>
|
|
1715
2079
|
{/* Header Row: #s.no + Logo + Package Name + Version Pill + Update/Deprecated Badges + Size & Copy */}
|
|
1716
2080
|
<View style={bundleStyles.fileCardTop}>
|
|
1717
2081
|
<View style={bundleStyles.sNoBadge}>
|
|
@@ -1721,12 +2085,19 @@ const BundleTab = React.memo(() => {
|
|
|
1721
2085
|
<PackageLogoRenderer name={pkg.name} color={pkg.color} size={28}/>
|
|
1722
2086
|
|
|
1723
2087
|
<View style={{ flex: 1, paddingHorizontal: 4 }}>
|
|
1724
|
-
<View style={{
|
|
2088
|
+
<View style={{
|
|
2089
|
+
flexDirection: 'row',
|
|
2090
|
+
alignItems: 'center',
|
|
2091
|
+
gap: 6,
|
|
2092
|
+
flexWrap: 'wrap',
|
|
2093
|
+
}}>
|
|
1725
2094
|
<HighlightText text={pkg.name} search={search} style={bundleStyles.fileName} highlightStyle={bundleStyles.searchHighlight}/>
|
|
1726
2095
|
<View style={bundleStyles.versionPill}>
|
|
1727
2096
|
<Text style={bundleStyles.versionPillText}>
|
|
1728
2097
|
{cleanInstalledVersion
|
|
1729
|
-
? t('bundle.versionPrefix', {
|
|
2098
|
+
? t('bundle.versionPrefix', {
|
|
2099
|
+
version: cleanInstalledVersion,
|
|
2100
|
+
})
|
|
1730
2101
|
: t('bundle.bundled')}
|
|
1731
2102
|
</Text>
|
|
1732
2103
|
</View>
|
|
@@ -1737,34 +2108,72 @@ const BundleTab = React.memo(() => {
|
|
|
1737
2108
|
</Text>
|
|
1738
2109
|
</View>) : hasUpdate ? (<View style={bundleStyles.updateBadge}>
|
|
1739
2110
|
<Text style={bundleStyles.updateBadgeText}>
|
|
1740
|
-
{t('bundle.updateAvailable', {
|
|
2111
|
+
{t('bundle.updateAvailable', {
|
|
2112
|
+
version: pkg.latestVersion,
|
|
2113
|
+
})}
|
|
1741
2114
|
</Text>
|
|
1742
|
-
</View>) : cleanInstalledVersion ? (<View style={[
|
|
1743
|
-
|
|
2115
|
+
</View>) : cleanInstalledVersion ? (<View style={[
|
|
2116
|
+
bundleStyles.updateBadge,
|
|
2117
|
+
{
|
|
2118
|
+
backgroundColor: AppColors.gray100,
|
|
2119
|
+
borderColor: AppColors.gray200,
|
|
2120
|
+
},
|
|
2121
|
+
]}>
|
|
2122
|
+
<Text style={[
|
|
2123
|
+
bundleStyles.updateBadgeText,
|
|
2124
|
+
{ color: AppColors.gray600 },
|
|
2125
|
+
]}>
|
|
1744
2126
|
{t('bundle.upToDate')}
|
|
1745
2127
|
</Text>
|
|
1746
|
-
</View>) : (<View style={[
|
|
1747
|
-
|
|
2128
|
+
</View>) : (<View style={[
|
|
2129
|
+
bundleStyles.updateBadge,
|
|
2130
|
+
{
|
|
2131
|
+
backgroundColor: AppColors.gray100,
|
|
2132
|
+
borderColor: AppColors.gray200,
|
|
2133
|
+
},
|
|
2134
|
+
]}>
|
|
2135
|
+
<Text style={[
|
|
2136
|
+
bundleStyles.updateBadgeText,
|
|
2137
|
+
{ color: AppColors.gray600 },
|
|
2138
|
+
]}>
|
|
1748
2139
|
{t('bundle.bundledBadge')}
|
|
1749
2140
|
</Text>
|
|
1750
2141
|
</View>)}
|
|
1751
2142
|
</View>
|
|
1752
2143
|
</View>
|
|
1753
2144
|
|
|
1754
|
-
<View style={{
|
|
2145
|
+
<View style={{
|
|
2146
|
+
flexDirection: 'row',
|
|
2147
|
+
alignItems: 'center',
|
|
2148
|
+
gap: 6,
|
|
2149
|
+
}}>
|
|
1755
2150
|
<View style={bundleStyles.fileSizeBox}>
|
|
1756
2151
|
<Text style={bundleStyles.fileSizeKb}>
|
|
1757
2152
|
{t('bundle.fileSizeKb', { size: pkg.sizeKb })}
|
|
1758
2153
|
</Text>
|
|
1759
|
-
<Text style={bundleStyles.filePercent}>
|
|
2154
|
+
<Text style={bundleStyles.filePercent}>
|
|
2155
|
+
{pkg.percentage}%
|
|
2156
|
+
</Text>
|
|
1760
2157
|
</View>
|
|
1761
2158
|
<CopyButton value={() => pkg} label={t('bundle.packageDetailsJson')}/>
|
|
1762
2159
|
</View>
|
|
1763
2160
|
</View>
|
|
1764
2161
|
|
|
1765
2162
|
{/* Subtitle Row: Category Chip + Description */}
|
|
1766
|
-
<View style={{
|
|
1767
|
-
|
|
2163
|
+
<View style={{
|
|
2164
|
+
flexDirection: 'row',
|
|
2165
|
+
alignItems: 'center',
|
|
2166
|
+
gap: 6,
|
|
2167
|
+
marginTop: 4,
|
|
2168
|
+
marginBottom: 2,
|
|
2169
|
+
}}>
|
|
2170
|
+
<View style={[
|
|
2171
|
+
bundleStyles.pkgBadge,
|
|
2172
|
+
{
|
|
2173
|
+
backgroundColor: `${pkg.color}1F`,
|
|
2174
|
+
borderColor: `${pkg.color}4D`,
|
|
2175
|
+
},
|
|
2176
|
+
]}>
|
|
1768
2177
|
<Text style={[bundleStyles.pkgBadgeText, { color: pkg.color }]}>
|
|
1769
2178
|
{pkg.category.toUpperCase()}
|
|
1770
2179
|
</Text>
|
|
@@ -1776,7 +2185,11 @@ const BundleTab = React.memo(() => {
|
|
|
1776
2185
|
|
|
1777
2186
|
{/* Deprecation Warning Banner if deprecated */}
|
|
1778
2187
|
{pkg.isDeprecated && pkg.deprecationReason && (<View style={bundleStyles.deprecationBox}>
|
|
1779
|
-
<View style={{
|
|
2188
|
+
<View style={{
|
|
2189
|
+
flexDirection: 'row',
|
|
2190
|
+
alignItems: 'center',
|
|
2191
|
+
gap: 5,
|
|
2192
|
+
}}>
|
|
1780
2193
|
<CircleAlertIcon color={AppColors.errorColor} size={12}/>
|
|
1781
2194
|
<Text style={bundleStyles.deprecationText}>
|
|
1782
2195
|
{pkg.deprecationReason}
|
|
@@ -1787,19 +2200,39 @@ const BundleTab = React.memo(() => {
|
|
|
1787
2200
|
<View style={bundleStyles.fileProgressTrack}>
|
|
1788
2201
|
<View style={[
|
|
1789
2202
|
bundleStyles.fileProgressBar,
|
|
1790
|
-
{
|
|
2203
|
+
{
|
|
2204
|
+
width: `${pkg.percentage * 2}%`,
|
|
2205
|
+
backgroundColor: pkg.isDeprecated
|
|
2206
|
+
? AppColors.red500
|
|
2207
|
+
: pkg.color,
|
|
2208
|
+
},
|
|
1791
2209
|
]}/>
|
|
1792
2210
|
</View>
|
|
1793
2211
|
|
|
1794
2212
|
{/* Footer Row: Type Tag + Last Active + NPM Link Button */}
|
|
1795
|
-
<View style={{
|
|
1796
|
-
|
|
2213
|
+
<View style={{
|
|
2214
|
+
flexDirection: 'row',
|
|
2215
|
+
justifyContent: 'space-between',
|
|
2216
|
+
alignItems: 'center',
|
|
2217
|
+
marginTop: 3,
|
|
2218
|
+
}}>
|
|
2219
|
+
<View style={{
|
|
2220
|
+
flexDirection: 'row',
|
|
2221
|
+
alignItems: 'center',
|
|
2222
|
+
gap: 8,
|
|
2223
|
+
}}>
|
|
1797
2224
|
<View style={bundleStyles.typeTag}>
|
|
1798
2225
|
<Text style={bundleStyles.typeTagText}>
|
|
1799
|
-
{pkg.type === 'direct'
|
|
2226
|
+
{pkg.type === 'direct'
|
|
2227
|
+
? t('bundle.direct')
|
|
2228
|
+
: t('bundle.transitive')}
|
|
1800
2229
|
</Text>
|
|
1801
2230
|
</View>
|
|
1802
|
-
{pkg.lastActive && (<View style={{
|
|
2231
|
+
{pkg.lastActive && (<View style={{
|
|
2232
|
+
flexDirection: 'row',
|
|
2233
|
+
alignItems: 'center',
|
|
2234
|
+
gap: 4,
|
|
2235
|
+
}}>
|
|
1803
2236
|
<ClockIcon color={AppColors.grayTextWeak} size={11}/>
|
|
1804
2237
|
<Text style={bundleStyles.lastActiveText}>
|
|
1805
2238
|
{pkg.lastActive}
|
|
@@ -1807,15 +2240,22 @@ const BundleTab = React.memo(() => {
|
|
|
1807
2240
|
</View>)}
|
|
1808
2241
|
</View>
|
|
1809
2242
|
|
|
1810
|
-
<View style={{
|
|
2243
|
+
<View style={{
|
|
2244
|
+
flexDirection: 'row',
|
|
2245
|
+
alignItems: 'center',
|
|
2246
|
+
gap: 8,
|
|
2247
|
+
}}>
|
|
1811
2248
|
<Text style={bundleStyles.fileMetaText}>
|
|
1812
2249
|
{t('bundle.minified', { size: pkg.sizeKb })}
|
|
1813
2250
|
</Text>
|
|
1814
2251
|
<TouchableScale accessible={true} accessibilityRole="link" accessibilityLabel={`Open ${pkg.name} on NPM`} accessibilityHint="Opens NPM package page in browser" onPress={() => {
|
|
1815
|
-
const url = pkg.npmUrl ||
|
|
2252
|
+
const url = pkg.npmUrl ||
|
|
2253
|
+
`https://www.npmjs.com/package/${pkg.name}`;
|
|
1816
2254
|
Linking.openURL(url).catch(() => { });
|
|
1817
2255
|
}} style={bundleStyles.npmLinkBtn}>
|
|
1818
|
-
<Text style={bundleStyles.npmLinkText}>
|
|
2256
|
+
<Text style={bundleStyles.npmLinkText}>
|
|
2257
|
+
{t('bundle.npmLink')}
|
|
2258
|
+
</Text>
|
|
1819
2259
|
</TouchableScale>
|
|
1820
2260
|
</View>
|
|
1821
2261
|
</View>
|
|
@@ -1828,7 +2268,9 @@ const BundleTab = React.memo(() => {
|
|
|
1828
2268
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
|
|
1829
2269
|
<PackageIcon color={AppColors.purple} size={14}/>
|
|
1830
2270
|
<Text style={bundleStyles.footerTitle}>
|
|
1831
|
-
{t('bundle.dependenciesCount', {
|
|
2271
|
+
{t('bundle.dependenciesCount', {
|
|
2272
|
+
count: filteredPackages.length,
|
|
2273
|
+
})}
|
|
1832
2274
|
</Text>
|
|
1833
2275
|
</View>
|
|
1834
2276
|
<Text style={bundleStyles.footerSizeVal}>
|
|
@@ -1845,22 +2287,36 @@ const BundleTab = React.memo(() => {
|
|
|
1845
2287
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1846
2288
|
{activeSubTab === 'media' && (<View style={{ flex: 1 }}>
|
|
1847
2289
|
<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
|
|
1848
|
-
|
|
1849
2290
|
<View style={bundleStyles.tipsCard}>
|
|
1850
|
-
<View style={{
|
|
2291
|
+
<View style={{
|
|
2292
|
+
flexDirection: 'row',
|
|
2293
|
+
alignItems: 'center',
|
|
2294
|
+
justifyContent: 'space-between',
|
|
2295
|
+
marginBottom: 8,
|
|
2296
|
+
}}>
|
|
1851
2297
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
|
|
1852
2298
|
<StorageIcon color={AppColors.purple} size={18}/>
|
|
1853
|
-
<Text style={bundleStyles.tipsHeading}>
|
|
2299
|
+
<Text style={bundleStyles.tipsHeading}>
|
|
2300
|
+
{t('bundle.mediaAuditorTitle')}
|
|
2301
|
+
</Text>
|
|
1854
2302
|
</View>
|
|
1855
2303
|
<CopyButton value={() => mediaFiles} label={t('bundle.mediaAssetsJson')}/>
|
|
1856
2304
|
</View>
|
|
1857
2305
|
<Text style={bundleStyles.tipDesc}>
|
|
1858
2306
|
{t('bundle.mediaAuditorPrefix')}{' '}
|
|
1859
|
-
<Text style={{
|
|
2307
|
+
<Text style={{
|
|
2308
|
+
fontFamily: AppFonts.interBold,
|
|
2309
|
+
color: AppColors.purple,
|
|
2310
|
+
}}>
|
|
1860
2311
|
{summary.images.pct + summary.fonts.pct}%
|
|
1861
2312
|
</Text>{' '}
|
|
1862
|
-
{t('bundle.mediaAuditorMid', {
|
|
1863
|
-
|
|
2313
|
+
{t('bundle.mediaAuditorMid', {
|
|
2314
|
+
kb: summary.images.kb + summary.fonts.kb,
|
|
2315
|
+
})}{' '}
|
|
2316
|
+
<Text style={{
|
|
2317
|
+
fontFamily: AppFonts.interBold,
|
|
2318
|
+
color: AppColors.emerald700,
|
|
2319
|
+
}}>
|
|
1864
2320
|
{t('bundle.mediaSavings', { size: 540 })}
|
|
1865
2321
|
</Text>{' '}
|
|
1866
2322
|
{t('bundle.mediaAuditorSuffix')}
|
|
@@ -1884,7 +2340,11 @@ const BundleTab = React.memo(() => {
|
|
|
1884
2340
|
<Text style={bundleStyles.filePath}>{file.path}</Text>
|
|
1885
2341
|
</View>
|
|
1886
2342
|
|
|
1887
|
-
<View style={{
|
|
2343
|
+
<View style={{
|
|
2344
|
+
flexDirection: 'row',
|
|
2345
|
+
alignItems: 'center',
|
|
2346
|
+
gap: 6,
|
|
2347
|
+
}}>
|
|
1888
2348
|
<View style={bundleStyles.fileSizeBox}>
|
|
1889
2349
|
<Text style={bundleStyles.fileSizeKb}>
|
|
1890
2350
|
{t('bundle.fileSizeKb', { size: file.sizeKb })}
|
|
@@ -1942,12 +2402,18 @@ const BundleTab = React.memo(() => {
|
|
|
1942
2402
|
{/* ── 5. TAB: OPTIMIZER CHECKLIST ─────────────────────────────────────── */}
|
|
1943
2403
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1944
2404
|
{activeSubTab === 'optimizer' && (<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
|
|
1945
|
-
|
|
1946
2405
|
<View style={bundleStyles.tipsCard}>
|
|
1947
|
-
<View style={{
|
|
2406
|
+
<View style={{
|
|
2407
|
+
flexDirection: 'row',
|
|
2408
|
+
alignItems: 'center',
|
|
2409
|
+
justifyContent: 'space-between',
|
|
2410
|
+
marginBottom: 12,
|
|
2411
|
+
}}>
|
|
1948
2412
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
|
|
1949
2413
|
<CircleAlertIcon color={AppColors.purple} size={18}/>
|
|
1950
|
-
<Text style={bundleStyles.tipsHeading}>
|
|
2414
|
+
<Text style={bundleStyles.tipsHeading}>
|
|
2415
|
+
{t('bundle.optimizerTitle')}
|
|
2416
|
+
</Text>
|
|
1951
2417
|
</View>
|
|
1952
2418
|
<CopyButton value={() => [
|
|
1953
2419
|
t('bundle.optTip1Title'),
|
|
@@ -1974,8 +2440,12 @@ const BundleTab = React.memo(() => {
|
|
|
1974
2440
|
desc: isHermes
|
|
1975
2441
|
? t('bundle.optTip2DescActive')
|
|
1976
2442
|
: t('bundle.optTip2DescInactive'),
|
|
1977
|
-
badge: isHermes
|
|
1978
|
-
|
|
2443
|
+
badge: isHermes
|
|
2444
|
+
? t('bundle.active')
|
|
2445
|
+
: t('bundle.actionRequired'),
|
|
2446
|
+
badgeColor: isHermes
|
|
2447
|
+
? AppColors.emerald500
|
|
2448
|
+
: AppColors.amber500,
|
|
1979
2449
|
},
|
|
1980
2450
|
{
|
|
1981
2451
|
iconType: 'font',
|
|
@@ -2011,8 +2481,17 @@ const BundleTab = React.memo(() => {
|
|
|
2011
2481
|
<Text style={bundleStyles.tipTitle}>{tip.title}</Text>
|
|
2012
2482
|
</View>
|
|
2013
2483
|
<View style={bundleStyles.tipActionWrap}>
|
|
2014
|
-
<View style={[
|
|
2015
|
-
|
|
2484
|
+
<View style={[
|
|
2485
|
+
bundleStyles.impactBadge,
|
|
2486
|
+
{
|
|
2487
|
+
backgroundColor: `${tip.badgeColor}18`,
|
|
2488
|
+
borderColor: `${tip.badgeColor}40`,
|
|
2489
|
+
},
|
|
2490
|
+
]}>
|
|
2491
|
+
<Text style={[
|
|
2492
|
+
bundleStyles.impactBadgeText,
|
|
2493
|
+
{ color: tip.badgeColor },
|
|
2494
|
+
]}>
|
|
2016
2495
|
{tip.badge}
|
|
2017
2496
|
</Text>
|
|
2018
2497
|
</View>
|
|
@@ -2235,12 +2714,14 @@ const bundleStyles = StyleSheet.create({
|
|
|
2235
2714
|
padding: 14,
|
|
2236
2715
|
borderWidth: 1,
|
|
2237
2716
|
borderColor: AppColors.dividerColor,
|
|
2717
|
+
overflow: 'hidden',
|
|
2238
2718
|
},
|
|
2239
2719
|
sectionHeaderRow: {
|
|
2240
2720
|
flexDirection: 'row',
|
|
2241
2721
|
justifyContent: 'space-between',
|
|
2242
2722
|
alignItems: 'center',
|
|
2243
2723
|
marginBottom: 10,
|
|
2724
|
+
gap: 8,
|
|
2244
2725
|
},
|
|
2245
2726
|
sectionTitle: {
|
|
2246
2727
|
fontFamily: AppFonts.interBold,
|
|
@@ -3081,7 +3562,8 @@ const bundleStyles = StyleSheet.create({
|
|
|
3081
3562
|
alignItems: 'center',
|
|
3082
3563
|
backgroundColor: AppColors.white,
|
|
3083
3564
|
paddingHorizontal: 16,
|
|
3084
|
-
|
|
3565
|
+
paddingTop: 10,
|
|
3566
|
+
paddingBottom: Platform.OS === 'ios' ? 24 : 12,
|
|
3085
3567
|
borderTopWidth: 1,
|
|
3086
3568
|
borderTopColor: AppColors.dividerColor,
|
|
3087
3569
|
shadowColor: AppColors.primaryBlack,
|