react-native-inapp-inspector 2.3.18 → 2.3.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +57 -0
  2. package/dist/commonjs/analytics.js +1 -24
  3. package/dist/commonjs/bundle.js +1 -16
  4. package/dist/commonjs/capture.d.ts +2 -0
  5. package/dist/commonjs/capture.js +1 -32
  6. package/dist/commonjs/components/AnalyticsDetail.js +92 -623
  7. package/dist/commonjs/components/AnalyticsEventCard.js +54 -350
  8. package/dist/commonjs/components/AnalyticsGraph.js +70 -370
  9. package/dist/commonjs/components/AnimatedEntrance.js +1 -11
  10. package/dist/commonjs/components/AppHeaderLogo.js +7 -134
  11. package/dist/commonjs/components/BrandCircleIcon.js +73 -118
  12. package/dist/commonjs/components/BrandSquareIcon.js +63 -108
  13. package/dist/commonjs/components/CodeSnippet.js +48 -623
  14. package/dist/commonjs/components/ConsoleLogCard.js +63 -537
  15. package/dist/commonjs/components/CopyButton.js +3 -89
  16. package/dist/commonjs/components/DiffViewer.js +19 -83
  17. package/dist/commonjs/components/DomainHeader.js +27 -127
  18. package/dist/commonjs/components/EmptyState.d.ts +1 -0
  19. package/dist/commonjs/components/EmptyState.js +10 -87
  20. package/dist/commonjs/components/EndOfListFooter.js +7 -81
  21. package/dist/commonjs/components/ErrorBoundary.js +72 -566
  22. package/dist/commonjs/components/HeadersSection.js +31 -110
  23. package/dist/commonjs/components/HighlightText.js +17 -58
  24. package/dist/commonjs/components/Inspector/AboutModal.d.ts +6 -0
  25. package/dist/commonjs/components/Inspector/AboutModal.js +351 -0
  26. package/dist/commonjs/components/Inspector/AnalyticsFilterModal.js +98 -797
  27. package/dist/commonjs/components/Inspector/AnalyticsTab.js +284 -930
  28. package/dist/commonjs/components/Inspector/BundleTab.js +551 -2918
  29. package/dist/commonjs/components/Inspector/ConsoleTab.js +79 -492
  30. package/dist/commonjs/components/Inspector/CrashDetail.js +123 -672
  31. package/dist/commonjs/components/Inspector/CrashFilterModal.js +66 -498
  32. package/dist/commonjs/components/Inspector/CrashTab.js +98 -670
  33. package/dist/commonjs/components/Inspector/DebuggingTab.js +64 -871
  34. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +143 -907
  35. package/dist/commonjs/components/Inspector/FabLauncher.js +85 -54
  36. package/dist/commonjs/components/Inspector/FeatureUnderDevNotice.js +6 -99
  37. package/dist/commonjs/components/Inspector/FeedbackModal.d.ts +9 -0
  38. package/dist/commonjs/components/Inspector/FeedbackModal.js +167 -521
  39. package/dist/commonjs/components/Inspector/InspectorContext.js +1 -21
  40. package/dist/commonjs/components/Inspector/InspectorHeader.js +219 -1093
  41. package/dist/commonjs/components/Inspector/LogDetail.js +168 -994
  42. package/dist/commonjs/components/Inspector/MainScreen.js +60 -332
  43. package/dist/commonjs/components/Inspector/MediaGalleryTab.js +136 -278
  44. package/dist/commonjs/components/Inspector/MediaPreviewModal.js +134 -361
  45. package/dist/commonjs/components/Inspector/NavigationTracker.js +1 -12
  46. package/dist/commonjs/components/Inspector/NetworkDetail.js +96 -432
  47. package/dist/commonjs/components/Inspector/NetworkFilterModal.js +60 -576
  48. package/dist/commonjs/components/Inspector/NetworkTab.js +84 -514
  49. package/dist/commonjs/components/Inspector/NpmStarPrompt.js +17 -433
  50. package/dist/commonjs/components/Inspector/NpmUpdateToast.js +25 -298
  51. package/dist/commonjs/components/Inspector/PerformanceTab.js +182 -1397
  52. package/dist/commonjs/components/Inspector/ReduxDetail.js +188 -1089
  53. package/dist/commonjs/components/Inspector/ReduxTab.js +85 -701
  54. package/dist/commonjs/components/Inspector/SettingsPanel.js +431 -3431
  55. package/dist/commonjs/components/Inspector/SkeletonPlaceholder.js +11 -180
  56. package/dist/commonjs/components/Inspector/StorageTab.js +93 -826
  57. package/dist/commonjs/components/Inspector/TabBar.js +47 -183
  58. package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +34 -408
  59. package/dist/commonjs/components/JsonViewer.js +168 -380
  60. package/dist/commonjs/components/LogCard.js +57 -567
  61. package/dist/commonjs/components/LogSyntaxHighlighter.js +11 -130
  62. package/dist/commonjs/components/MetaAccordion.js +69 -238
  63. package/dist/commonjs/components/MiniBarChart.js +3 -56
  64. package/dist/commonjs/components/MiniLineChart.js +3 -58
  65. package/dist/commonjs/components/NetworkIcons.d.ts +7 -0
  66. package/dist/commonjs/components/NetworkIcons.js +479 -997
  67. package/dist/commonjs/components/QRCodeView.js +5 -79
  68. package/dist/commonjs/components/SectionHeader.js +15 -37
  69. package/dist/commonjs/components/SegmentedTabs.js +7 -61
  70. package/dist/commonjs/components/SkeletonPlaceholder.js +11 -180
  71. package/dist/commonjs/components/Slider.js +15 -243
  72. package/dist/commonjs/components/SourcePageCard.js +30 -89
  73. package/dist/commonjs/components/Toast.js +5 -147
  74. package/dist/commonjs/components/TouchableScale.js +3 -24
  75. package/dist/commonjs/components/TreeNode.js +55 -130
  76. package/dist/commonjs/console.js +1 -16
  77. package/dist/commonjs/constants/index.js +1 -32
  78. package/dist/commonjs/constants/telemetryConfig.js +1 -6
  79. package/dist/commonjs/constants/version.d.ts +1 -1
  80. package/dist/commonjs/constants/version.js +1 -4
  81. package/dist/commonjs/crash.js +1 -23
  82. package/dist/commonjs/customHooks/analyticsLogger.js +1 -250
  83. package/dist/commonjs/customHooks/bundleAnalyzer.js +1 -957
  84. package/dist/commonjs/customHooks/consoleLogger.js +6 -445
  85. package/dist/commonjs/customHooks/crashHandler.js +7 -656
  86. package/dist/commonjs/customHooks/logFilters.js +1 -23
  87. package/dist/commonjs/customHooks/networkLogger.js +2 -536
  88. package/dist/commonjs/customHooks/performanceTracker.js +63 -750
  89. package/dist/commonjs/customHooks/reduxLogger.js +2 -313
  90. package/dist/commonjs/customHooks/storageInspector.js +1 -435
  91. package/dist/commonjs/customHooks/useAccordion.js +1 -18
  92. package/dist/commonjs/decorators/index.js +1 -100
  93. package/dist/commonjs/helpers/gaAnalyticsRegistry.js +1 -148
  94. package/dist/commonjs/helpers/index.js +8 -921
  95. package/dist/commonjs/helpers/memoryManager.js +1 -99
  96. package/dist/commonjs/helpers/qrGenerator.js +1 -367
  97. package/dist/commonjs/helpers/remoteConfig.js +1 -165
  98. package/dist/commonjs/helpers/searchQueryParser.js +1 -62
  99. package/dist/commonjs/helpers/settingsStore.js +1 -144
  100. package/dist/commonjs/helpers/telemetry.js +1 -501
  101. package/dist/commonjs/helpers/toast.js +1 -20
  102. package/dist/commonjs/i18n/index.js +1 -90
  103. package/dist/commonjs/i18n/locales/en.json +1 -1122
  104. package/dist/commonjs/index.js +5 -2153
  105. package/dist/commonjs/metro.js +6 -468
  106. package/dist/commonjs/native/NativeInspector.d.ts +3 -0
  107. package/dist/commonjs/native/NativeInspector.js +1 -402
  108. package/dist/commonjs/native/NativeNetworkInspector.d.ts +1 -0
  109. package/dist/commonjs/native/NativeNetworkInspector.js +1 -4
  110. package/dist/commonjs/network.js +1 -13
  111. package/dist/commonjs/performance.js +1 -29
  112. package/dist/commonjs/redux.js +1 -20
  113. package/dist/commonjs/storage.js +1 -14
  114. package/dist/commonjs/styles/AppColors.js +1 -423
  115. package/dist/commonjs/styles/AppFonts.js +1 -17
  116. package/dist/commonjs/styles/common.js +1 -190
  117. package/dist/commonjs/styles/index.d.ts +6 -0
  118. package/dist/commonjs/styles/index.js +1 -1589
  119. package/dist/commonjs/types/enums.d.ts +2 -1
  120. package/dist/commonjs/types/enums.js +1 -150
  121. package/dist/commonjs/types/index.js +1 -18
  122. package/dist/commonjs/types/interfaces.d.ts +7 -0
  123. package/dist/commonjs/types/interfaces.js +1 -2
  124. package/dist/esm/analytics.js +1 -2
  125. package/dist/esm/bundle.js +1 -2
  126. package/dist/esm/capture.d.ts +2 -0
  127. package/dist/esm/capture.js +1 -29
  128. package/dist/esm/components/AnalyticsDetail.js +171 -664
  129. package/dist/esm/components/AnalyticsEventCard.js +77 -335
  130. package/dist/esm/components/AnalyticsGraph.js +95 -357
  131. package/dist/esm/components/AnimatedEntrance.js +1 -6
  132. package/dist/esm/components/AppHeaderLogo.js +7 -94
  133. package/dist/esm/components/BrandCircleIcon.js +114 -119
  134. package/dist/esm/components/BrandSquareIcon.js +73 -78
  135. package/dist/esm/components/CodeSnippet.js +58 -595
  136. package/dist/esm/components/ConsoleLogCard.js +91 -526
  137. package/dist/esm/components/CopyButton.js +3 -51
  138. package/dist/esm/components/DiffViewer.js +22 -48
  139. package/dist/esm/components/DomainHeader.js +43 -138
  140. package/dist/esm/components/EmptyState.d.ts +1 -0
  141. package/dist/esm/components/EmptyState.js +17 -56
  142. package/dist/esm/components/EndOfListFooter.js +15 -83
  143. package/dist/esm/components/ErrorBoundary.js +125 -582
  144. package/dist/esm/components/HeadersSection.js +52 -93
  145. package/dist/esm/components/HighlightText.js +17 -53
  146. package/dist/esm/components/Inspector/AboutModal.d.ts +6 -0
  147. package/dist/esm/components/Inspector/AboutModal.js +351 -0
  148. package/dist/esm/components/Inspector/AnalyticsFilterModal.js +225 -886
  149. package/dist/esm/components/Inspector/AnalyticsTab.js +296 -904
  150. package/dist/esm/components/Inspector/BundleTab.js +1175 -3502
  151. package/dist/esm/components/Inspector/ConsoleTab.js +113 -488
  152. package/dist/esm/components/Inspector/CrashDetail.js +236 -747
  153. package/dist/esm/components/Inspector/CrashFilterModal.js +149 -541
  154. package/dist/esm/components/Inspector/CrashTab.js +177 -711
  155. package/dist/esm/components/Inspector/DebuggingTab.js +156 -923
  156. package/dist/esm/components/Inspector/DeviceInfoTab.js +199 -924
  157. package/dist/esm/components/Inspector/FabLauncher.js +85 -49
  158. package/dist/esm/components/Inspector/FeatureUnderDevNotice.js +14 -70
  159. package/dist/esm/components/Inspector/FeedbackModal.d.ts +9 -0
  160. package/dist/esm/components/Inspector/FeedbackModal.js +182 -499
  161. package/dist/esm/components/Inspector/InspectorContext.js +1 -12
  162. package/dist/esm/components/Inspector/InspectorHeader.js +309 -1145
  163. package/dist/esm/components/Inspector/LogDetail.js +235 -1023
  164. package/dist/esm/components/Inspector/MainScreen.js +86 -320
  165. package/dist/esm/components/Inspector/MediaGalleryTab.js +157 -259
  166. package/dist/esm/components/Inspector/MediaPreviewModal.js +153 -340
  167. package/dist/esm/components/Inspector/NavigationTracker.js +1 -10
  168. package/dist/esm/components/Inspector/NetworkDetail.js +141 -472
  169. package/dist/esm/components/Inspector/NetworkFilterModal.js +122 -597
  170. package/dist/esm/components/Inspector/NetworkTab.js +125 -517
  171. package/dist/esm/components/Inspector/NpmStarPrompt.js +58 -434
  172. package/dist/esm/components/Inspector/NpmUpdateToast.js +45 -281
  173. package/dist/esm/components/Inspector/PerformanceTab.js +393 -1570
  174. package/dist/esm/components/Inspector/ReduxDetail.js +307 -1170
  175. package/dist/esm/components/Inspector/ReduxTab.js +144 -722
  176. package/dist/esm/components/Inspector/SettingsPanel.js +647 -3609
  177. package/dist/esm/components/Inspector/SkeletonPlaceholder.js +30 -163
  178. package/dist/esm/components/Inspector/StorageTab.js +172 -866
  179. package/dist/esm/components/Inspector/TabBar.js +52 -183
  180. package/dist/esm/components/Inspector/UpdateAvailableModal.js +79 -416
  181. package/dist/esm/components/JsonViewer.js +179 -353
  182. package/dist/esm/components/LogCard.js +93 -565
  183. package/dist/esm/components/LogSyntaxHighlighter.js +11 -123
  184. package/dist/esm/components/MetaAccordion.js +136 -267
  185. package/dist/esm/components/MiniBarChart.js +3 -18
  186. package/dist/esm/components/MiniLineChart.js +3 -20
  187. package/dist/esm/components/NetworkIcons.d.ts +7 -0
  188. package/dist/esm/components/NetworkIcons.js +481 -817
  189. package/dist/esm/components/QRCodeView.js +8 -45
  190. package/dist/esm/components/SectionHeader.js +22 -39
  191. package/dist/esm/components/SegmentedTabs.js +8 -57
  192. package/dist/esm/components/SkeletonPlaceholder.js +30 -163
  193. package/dist/esm/components/Slider.js +24 -213
  194. package/dist/esm/components/SourcePageCard.js +65 -86
  195. package/dist/esm/components/Toast.js +10 -117
  196. package/dist/esm/components/TouchableScale.js +3 -19
  197. package/dist/esm/components/TreeNode.js +58 -95
  198. package/dist/esm/console.js +1 -2
  199. package/dist/esm/constants/index.js +1 -28
  200. package/dist/esm/constants/telemetryConfig.js +1 -3
  201. package/dist/esm/constants/version.d.ts +1 -1
  202. package/dist/esm/constants/version.js +1 -1
  203. package/dist/esm/crash.js +1 -2
  204. package/dist/esm/customHooks/analyticsLogger.js +1 -230
  205. package/dist/esm/customHooks/bundleAnalyzer.js +1 -944
  206. package/dist/esm/customHooks/consoleLogger.js +6 -432
  207. package/dist/esm/customHooks/crashHandler.js +7 -630
  208. package/dist/esm/customHooks/logFilters.js +1 -20
  209. package/dist/esm/customHooks/networkLogger.js +2 -519
  210. package/dist/esm/customHooks/performanceTracker.js +63 -723
  211. package/dist/esm/customHooks/reduxLogger.js +2 -293
  212. package/dist/esm/customHooks/storageInspector.js +1 -418
  213. package/dist/esm/customHooks/useAccordion.js +1 -16
  214. package/dist/esm/decorators/index.js +1 -95
  215. package/dist/esm/helpers/gaAnalyticsRegistry.js +1 -143
  216. package/dist/esm/helpers/index.js +8 -861
  217. package/dist/esm/helpers/memoryManager.js +1 -91
  218. package/dist/esm/helpers/qrGenerator.js +1 -364
  219. package/dist/esm/helpers/remoteConfig.js +1 -160
  220. package/dist/esm/helpers/searchQueryParser.js +1 -59
  221. package/dist/esm/helpers/settingsStore.js +1 -134
  222. package/dist/esm/helpers/telemetry.js +1 -489
  223. package/dist/esm/helpers/toast.js +1 -15
  224. package/dist/esm/i18n/index.js +1 -78
  225. package/dist/esm/i18n/locales/en.json +1 -1122
  226. package/dist/esm/index.js +7 -1967
  227. package/dist/esm/metro.js +6 -459
  228. package/dist/esm/native/NativeInspector.d.ts +3 -0
  229. package/dist/esm/native/NativeInspector.js +1 -370
  230. package/dist/esm/native/NativeNetworkInspector.d.ts +1 -0
  231. package/dist/esm/native/NativeNetworkInspector.js +1 -2
  232. package/dist/esm/network.js +1 -1
  233. package/dist/esm/performance.js +1 -2
  234. package/dist/esm/redux.js +1 -1
  235. package/dist/esm/storage.js +1 -1
  236. package/dist/esm/styles/AppColors.js +1 -417
  237. package/dist/esm/styles/AppFonts.js +1 -13
  238. package/dist/esm/styles/common.js +1 -186
  239. package/dist/esm/styles/index.d.ts +6 -0
  240. package/dist/esm/styles/index.js +1 -1551
  241. package/dist/esm/types/enums.d.ts +2 -1
  242. package/dist/esm/types/enums.js +1 -147
  243. package/dist/esm/types/index.js +1 -2
  244. package/dist/esm/types/interfaces.d.ts +7 -0
  245. package/dist/esm/types/interfaces.js +1 -1
  246. package/ios/NetworkInspectorModule.mm +253 -136
  247. package/package.json +5 -3
  248. package/react-native-inapp-inspector.podspec +1 -1
  249. package/src/native/NativeInspector.ts +17 -0
  250. package/src/native/NativeNetworkInspector.ts +1 -0
  251. package/src/analytics.ts +0 -35
  252. package/src/bundle.ts +0 -25
  253. package/src/capture.ts +0 -101
  254. package/src/components/AnalyticsDetail.tsx +0 -870
  255. package/src/components/AnalyticsEventCard.tsx +0 -444
  256. package/src/components/AnalyticsGraph.tsx +0 -583
  257. package/src/components/AnimatedEntrance.tsx +0 -20
  258. package/src/components/AppHeaderLogo.tsx +0 -143
  259. package/src/components/BrandCircleIcon.tsx +0 -144
  260. package/src/components/BrandSquareIcon.tsx +0 -184
  261. package/src/components/CodeSnippet.tsx +0 -725
  262. package/src/components/ConsoleLogCard.tsx +0 -679
  263. package/src/components/CopyButton.tsx +0 -87
  264. package/src/components/DiffViewer.tsx +0 -82
  265. package/src/components/DomainHeader.tsx +0 -224
  266. package/src/components/EmptyState.tsx +0 -95
  267. package/src/components/EndOfListFooter.tsx +0 -100
  268. package/src/components/ErrorBoundary.tsx +0 -688
  269. package/src/components/HeadersSection.tsx +0 -172
  270. package/src/components/HighlightText.tsx +0 -100
  271. package/src/components/Inspector/AnalyticsFilterModal.tsx +0 -1250
  272. package/src/components/Inspector/AnalyticsTab.tsx +0 -1362
  273. package/src/components/Inspector/BundleTab.tsx +0 -4768
  274. package/src/components/Inspector/ConsoleTab.tsx +0 -726
  275. package/src/components/Inspector/CrashDetail.tsx +0 -997
  276. package/src/components/Inspector/CrashFilterModal.tsx +0 -721
  277. package/src/components/Inspector/CrashTab.tsx +0 -933
  278. package/src/components/Inspector/DebuggingTab.tsx +0 -1103
  279. package/src/components/Inspector/DeviceInfoTab.tsx +0 -1397
  280. package/src/components/Inspector/FabLauncher.tsx +0 -80
  281. package/src/components/Inspector/FeatureUnderDevNotice.tsx +0 -94
  282. package/src/components/Inspector/FeedbackModal.tsx +0 -626
  283. package/src/components/Inspector/InspectorContext.tsx +0 -28
  284. package/src/components/Inspector/InspectorHeader.tsx +0 -1545
  285. package/src/components/Inspector/LogDetail.tsx +0 -1431
  286. package/src/components/Inspector/MainScreen.tsx +0 -459
  287. package/src/components/Inspector/MediaGalleryTab.tsx +0 -355
  288. package/src/components/Inspector/MediaPreviewModal.tsx +0 -435
  289. package/src/components/Inspector/NavigationTracker.tsx +0 -13
  290. package/src/components/Inspector/NetworkDetail.tsx +0 -795
  291. package/src/components/Inspector/NetworkFilterModal.tsx +0 -730
  292. package/src/components/Inspector/NetworkTab.tsx +0 -820
  293. package/src/components/Inspector/NpmStarPrompt.tsx +0 -532
  294. package/src/components/Inspector/NpmUpdateToast.tsx +0 -387
  295. package/src/components/Inspector/PerformanceTab.tsx +0 -1967
  296. package/src/components/Inspector/ReduxDetail.tsx +0 -1651
  297. package/src/components/Inspector/ReduxTab.tsx +0 -987
  298. package/src/components/Inspector/SettingsPanel.tsx +0 -4580
  299. package/src/components/Inspector/SkeletonPlaceholder.tsx +0 -206
  300. package/src/components/Inspector/StorageTab.tsx +0 -1159
  301. package/src/components/Inspector/TabBar.tsx +0 -263
  302. package/src/components/Inspector/UpdateAvailableModal.tsx +0 -555
  303. package/src/components/JsonViewer.tsx +0 -547
  304. package/src/components/LogCard.tsx +0 -694
  305. package/src/components/LogSyntaxHighlighter.tsx +0 -178
  306. package/src/components/MetaAccordion.tsx +0 -355
  307. package/src/components/MiniBarChart.tsx +0 -42
  308. package/src/components/MiniLineChart.tsx +0 -33
  309. package/src/components/NetworkIcons.tsx +0 -2599
  310. package/src/components/QRCodeView.tsx +0 -75
  311. package/src/components/SectionHeader.tsx +0 -101
  312. package/src/components/SegmentedTabs.tsx +0 -83
  313. package/src/components/SkeletonPlaceholder.tsx +0 -206
  314. package/src/components/Slider.tsx +0 -300
  315. package/src/components/SourcePageCard.tsx +0 -150
  316. package/src/components/Toast.tsx +0 -131
  317. package/src/components/TouchableScale.tsx +0 -61
  318. package/src/components/TreeNode.tsx +0 -171
  319. package/src/console.ts +0 -24
  320. package/src/constants/index.ts +0 -41
  321. package/src/constants/telemetryConfig.ts +0 -4
  322. package/src/constants/version.ts +0 -3
  323. package/src/crash.ts +0 -32
  324. package/src/customHooks/analyticsLogger.ts +0 -336
  325. package/src/customHooks/bundleAnalyzer.ts +0 -1256
  326. package/src/customHooks/consoleLogger.ts +0 -530
  327. package/src/customHooks/crashHandler.ts +0 -944
  328. package/src/customHooks/logFilters.ts +0 -32
  329. package/src/customHooks/networkLogger.ts +0 -624
  330. package/src/customHooks/performanceTracker.ts +0 -1014
  331. package/src/customHooks/reduxLogger.ts +0 -406
  332. package/src/customHooks/storageInspector.ts +0 -513
  333. package/src/customHooks/useAccordion.tsx +0 -27
  334. package/src/decorators/index.ts +0 -184
  335. package/src/helpers/gaAnalyticsRegistry.ts +0 -204
  336. package/src/helpers/index.ts +0 -1092
  337. package/src/helpers/memoryManager.ts +0 -138
  338. package/src/helpers/qrGenerator.ts +0 -430
  339. package/src/helpers/remoteConfig.ts +0 -212
  340. package/src/helpers/searchQueryParser.ts +0 -84
  341. package/src/helpers/settingsStore.ts +0 -171
  342. package/src/helpers/telemetry.ts +0 -568
  343. package/src/helpers/toast.ts +0 -17
  344. package/src/i18n/index.ts +0 -104
  345. package/src/i18n/locales/en.json +0 -1125
  346. package/src/index.tsx +0 -2635
  347. package/src/metro.ts +0 -598
  348. package/src/network.ts +0 -22
  349. package/src/performance.ts +0 -38
  350. package/src/redux.ts +0 -23
  351. package/src/storage.ts +0 -18
  352. package/src/styles/AppColors.ts +0 -455
  353. package/src/styles/AppFonts.ts +0 -26
  354. package/src/styles/common.ts +0 -209
  355. package/src/styles/index.ts +0 -1606
  356. package/src/types/enums.ts +0 -208
  357. package/src/types/index.ts +0 -34
  358. package/src/types/interfaces.ts +0 -530
@@ -1,4580 +0,0 @@
1
- import React, {useMemo, useState, useEffect, useRef} from 'react';
2
- import {
3
- Alert,
4
- Animated,
5
- DevSettings,
6
- Dimensions,
7
- Linking,
8
- PixelRatio,
9
- Platform,
10
- ScrollView,
11
- StatusBar,
12
- StyleSheet,
13
- Text,
14
- TextInput,
15
- View,
16
- } from 'react-native';
17
- import Svg, {Path} from 'react-native-svg';
18
- import {animateNextLayout, useInspector} from './InspectorContext';
19
- import TouchableScale from '../TouchableScale';
20
- import Slider from '../Slider';
21
- import {toggleGlobalTheme} from '../../styles';
22
- import {AppColors} from '../../styles/AppColors';
23
- import {AppFonts} from '../../styles/AppFonts';
24
- import {
25
- isPersistentStorageAvailable,
26
- calculateRamBasedLimits,
27
- } from '../../helpers/settingsStore';
28
- import {clearNetworkLogs} from '../../customHooks/networkLogger';
29
- import {clearConsoleLogs} from '../../customHooks/consoleLogger';
30
- import {clearAnalyticsEvents} from '../../customHooks/analyticsLogger';
31
- import {clearCrashRecords} from '../../customHooks/crashHandler';
32
- import {clearCachedBundleAnalysis} from '../../customHooks/bundleAnalyzer';
33
- import {clearPerformanceEvents} from '../../customHooks/performanceTracker';
34
- import {isReduxConnected} from '../../customHooks/reduxLogger';
35
- import {isAnalyticsConnected} from '../../customHooks/analyticsLogger';
36
- import {useTranslation} from '../../i18n';
37
- import {ActiveTab} from '../../types';
38
- import {
39
- SignalIcon,
40
- TerminalIcon,
41
- AnalyticsIcon,
42
- SettingsIcon,
43
- SunIcon,
44
- MoonIcon,
45
- ScreenIcon,
46
- MotionIcon,
47
- LayersIcon,
48
- EyeIcon,
49
- CheckIcon,
50
- TrashIcon,
51
- PackageIcon,
52
- ReduxIcon,
53
- PerformanceIcon,
54
- CrashIcon,
55
- ShieldAlertIcon,
56
- ForwardChevronIcon,
57
- ChevronDownIcon,
58
- NpmIcon,
59
- BoltIcon,
60
- BrainIcon,
61
- SmartphoneIcon,
62
- DatabaseIcon,
63
- QrCodeIcon,
64
- GitHubIcon,
65
- InfoCircleIcon,
66
- CopyIcon,
67
- FilmIcon,
68
- CameraIcon,
69
- VideoCameraIcon,
70
- MicrophoneIcon,
71
- GifIcon,
72
- ImageIcon,
73
- } from '../NetworkIcons';
74
- import {ScreenCapture} from '../../capture';
75
-
76
- import {LIB_VERSION} from '../../constants';
77
- import {
78
- copyToClipboard,
79
- isLocalDebugEnvironment,
80
- getAppName,
81
- getBundleIdentifier,
82
- getAppVersionAndBuild,
83
- } from '../../helpers';
84
- import {showToast} from '../../helpers/toast';
85
- import {pruneAllLogs} from '../../helpers/memoryManager';
86
-
87
- const SettingsPanel = () => {
88
- const {t} = useTranslation();
89
- const {
90
- settingsPage,
91
- setSettingsPage,
92
- settingsActiveSubTab,
93
- setSettingsActiveSubTab,
94
- tabVisibility,
95
- toggleTabVisibility,
96
- defaultTab,
97
- setDefaultTab,
98
- isDark,
99
- setIsDark,
100
- modalHeightPercent,
101
- setModalHeightPercent,
102
- modalAnimationType,
103
- setModalAnimationType,
104
- showDuplicateLogs,
105
- setShowDuplicateLogs,
106
- showUpdateToast,
107
- setShowUpdateToast,
108
- showConsoleLevels,
109
- setShowConsoleLevels,
110
- resetToDefaults,
111
- closeModal,
112
- storage,
113
- logs,
114
- consoleLogs,
115
- analyticsEvents,
116
- reduxState,
117
- maxNetworkLogs,
118
- setMaxNetworkLogs,
119
- maxConsoleLogs,
120
- setMaxConsoleLogs,
121
- maxAnalyticsEventsLimit,
122
- setMaxAnalyticsEventsLimit,
123
- isAutoRamLimitEnabled,
124
- setIsAutoRamLimitEnabled,
125
- deviceFreeRamMb,
126
- reduxAutoRefresh,
127
- setReduxAutoRefreshState,
128
- reduxExpandDepth,
129
- setReduxExpandDepth,
130
- switchActiveTab,
131
- setSelected,
132
- setSelectedEvent,
133
- setReduxState,
134
- crashRecords,
135
- maxCrashLogs,
136
- setMaxCrashLogs,
137
- updateAvailable,
138
- latestNpmVersion,
139
- } = useInspector();
140
-
141
- const [stagedHeight, setStagedHeight] = useState(modalHeightPercent);
142
-
143
- useEffect(() => {
144
- setStagedHeight(modalHeightPercent);
145
- }, [modalHeightPercent]);
146
-
147
- const autoRamProfile = calculateRamBasedLimits(deviceFreeRamMb);
148
-
149
- const isPersistent = isPersistentStorageAvailable();
150
-
151
- // Safe Area & Status Bar Padding for All Device Form Factors
152
- const statusBarHeight =
153
- Platform.OS === 'android' ? StatusBar.currentHeight || 24 : 44;
154
- const headerTopPadding = modalHeightPercent >= 95 ? statusBarHeight : 0;
155
-
156
- const allModules = useMemo(
157
- () =>
158
- (
159
- [
160
- {
161
- id: 1,
162
- key: 'apis',
163
- label: 'APIs (Network)',
164
- category: 'core',
165
- icon: 'apis',
166
- desc: 'HTTP/HTTPS requests, GraphQL, Axios & WebSocket inspector',
167
- },
168
- {
169
- id: 2,
170
- key: 'logs',
171
- label: 'Console Logs',
172
- category: 'core',
173
- icon: 'logs',
174
- desc: 'Terminal console logs, warnings, errors & stack traces',
175
- },
176
- {
177
- id: 3,
178
- key: 'analytics',
179
- label: 'Analytics Logger',
180
- category: 'telemetry',
181
- icon: 'analytics',
182
- desc: 'Firebase & custom analytics events, user properties & params',
183
- },
184
- {
185
- id: 4,
186
- key: 'redux',
187
- label: 'Redux Inspector',
188
- category: 'telemetry',
189
- icon: 'redux',
190
- desc: 'Store state diffing, action history & reducer timeline',
191
- },
192
- {
193
- id: 5,
194
- key: 'storage',
195
- label: 'Storage Inspector',
196
- category: 'telemetry',
197
- icon: 'storage',
198
- desc: 'AsyncStorage & MMKV key-value store viewer with full CRUD support',
199
- },
200
- {
201
- id: 6,
202
- key: 'device',
203
- label: 'Device Info',
204
- category: 'diagnostic',
205
- icon: 'device',
206
- desc: 'Hardware specs, IP address, screen metrics, UDID & runtime stats',
207
- },
208
- {
209
- id: 7,
210
- key: 'crash',
211
- label: 'Crash Protection',
212
- category: 'diagnostic',
213
- icon: 'crash',
214
- desc: 'Runtime exception guard, breadcrumbs & memory snapshot',
215
- },
216
- {
217
- id: 8,
218
- key: 'bundle',
219
- label: 'Bundle Analyzer',
220
- category: 'diagnostic',
221
- icon: 'bundle',
222
- desc: 'Metro packager dependencies, source maps & asset breakdown',
223
- },
224
- {
225
- id: 9,
226
- key: 'performance',
227
- label: 'Performance & Tracker',
228
- category: 'diagnostic',
229
- icon: 'performance',
230
- desc: '60 FPS monitor, Hermes memory telemetry & re-render profiler',
231
- },
232
- {
233
- id: 10,
234
- key: 'debugging',
235
- label: 'Multi-Device Debugging',
236
- category: 'diagnostic',
237
- icon: 'debugging',
238
- desc: 'QR Code bridge for direct Debug APK download & Metro live-reload sync',
239
- },
240
- ] as const
241
- ).filter(m =>
242
- m.key === 'debugging'
243
- ? Platform.OS === 'android' && isLocalDebugEnvironment()
244
- : true,
245
- ),
246
- [],
247
- );
248
-
249
- // Staged selection state for checkboxes before clicking "Save Changes"
250
- const [stagedTabVisibility, setStagedTabVisibility] = useState<
251
- Record<ActiveTab, boolean>
252
- >(() => ({
253
- apis: true,
254
- logs: Boolean(tabVisibility?.logs),
255
- analytics: Boolean(tabVisibility?.analytics),
256
- redux: Boolean(tabVisibility?.redux),
257
- storage: Boolean(tabVisibility?.storage),
258
- device: Boolean(tabVisibility?.device),
259
- crash: Boolean(tabVisibility?.crash),
260
- bundle: Boolean(tabVisibility?.bundle),
261
- performance: Boolean(tabVisibility?.performance),
262
- debugging: Boolean(tabVisibility?.debugging),
263
- }));
264
-
265
- // Synchronize staged state with tabVisibility when tabVisibility updates
266
- useEffect(() => {
267
- setStagedTabVisibility({
268
- apis: true,
269
- logs: Boolean(tabVisibility?.logs),
270
- analytics: Boolean(tabVisibility?.analytics),
271
- redux: Boolean(tabVisibility?.redux),
272
- storage: Boolean(tabVisibility?.storage),
273
- device: Boolean(tabVisibility?.device),
274
- crash: Boolean(tabVisibility?.crash),
275
- bundle: Boolean(tabVisibility?.bundle),
276
- performance: Boolean(tabVisibility?.performance),
277
- debugging: Boolean(tabVisibility?.debugging),
278
- });
279
- }, [tabVisibility]);
280
-
281
-
282
- const hasUnsavedChanges = useMemo(() => {
283
- return allModules.some(
284
- m =>
285
- Boolean(stagedTabVisibility[m.key as ActiveTab]) !==
286
- Boolean(tabVisibility?.[m.key as ActiveTab]),
287
- );
288
- }, [stagedTabVisibility, tabVisibility, allModules]);
289
-
290
- const stagedActiveCount = allModules.filter(
291
- m => m.key === 'apis' || Boolean(stagedTabVisibility[m.key as ActiveTab]),
292
- ).length;
293
-
294
- const handleSaveChanges = () => {
295
- if (!hasUnsavedChanges) return;
296
-
297
- Alert.alert(
298
- 'Apply Changes & Reload',
299
- 'Are you sure you want to save module changes? The inspector will close and reload the app to apply the new configuration.',
300
- [
301
- {
302
- text: 'Cancel',
303
- style: 'cancel',
304
- onPress: () => {
305
- // Discard: Revert staged visibility back to saved tabVisibility
306
- setStagedTabVisibility({
307
- apis: true,
308
- logs: Boolean(tabVisibility?.logs),
309
- analytics: Boolean(tabVisibility?.analytics),
310
- redux: Boolean(tabVisibility?.redux),
311
- storage: Boolean(tabVisibility?.storage),
312
- device: Boolean(tabVisibility?.device),
313
- crash: Boolean(tabVisibility?.crash),
314
- bundle: Boolean(tabVisibility?.bundle),
315
- performance: Boolean(tabVisibility?.performance),
316
- debugging: Boolean(tabVisibility?.debugging),
317
- });
318
-
319
- },
320
- },
321
- {
322
- text: 'Save & Reload',
323
- style: 'default',
324
- onPress: () => {
325
- animateNextLayout();
326
- allModules.forEach(m => {
327
- if (m.key !== 'apis') {
328
- const isStagedOn = Boolean(stagedTabVisibility[m.key as ActiveTab]);
329
- const isCurrentOn = Boolean(tabVisibility?.[m.key as ActiveTab]);
330
- if (isStagedOn !== isCurrentOn) {
331
- toggleTabVisibility(m.key as ActiveTab);
332
- }
333
- }
334
- });
335
- closeModal();
336
- setTimeout(() => {
337
- if (__DEV__ && DevSettings && DevSettings.reload) {
338
- DevSettings.reload();
339
- }
340
- }, 350);
341
- },
342
- },
343
- ],
344
- );
345
- };
346
-
347
- const [isDefaultTabDropdownOpen, setIsDefaultTabDropdownOpen] =
348
- useState(false);
349
-
350
- const goBackToMain = () => {
351
- animateNextLayout();
352
- setSettingsPage('main');
353
- };
354
-
355
- // Helper: settings row with icon + label + optional description
356
- const renderSettingRow = (opts: {
357
- icon: React.ReactNode;
358
- label: string;
359
- description?: string;
360
- right?: React.ReactNode;
361
- picker?: {
362
- options: readonly any[];
363
- selectedValue: any;
364
- onSelect: (val: any) => void;
365
- formatLabel?: (val: any) => string;
366
- };
367
- numericInput?: {
368
- value: number;
369
- onChange: (val: number) => void;
370
- min?: number;
371
- max?: number;
372
- placeholder?: string;
373
- keyboardType?: 'numeric' | 'number-pad' | 'decimal-pad';
374
- };
375
- onPress?: () => void;
376
- isLast?: boolean;
377
- }) => {
378
- return (
379
- <View
380
- style={{
381
- paddingVertical: 12,
382
- borderBottomWidth: opts.isLast ? 0 : 1,
383
- borderBottomColor: AppColors.dividerColor,
384
- }}>
385
- <TouchableScale
386
- disabled={!opts.onPress}
387
- onPress={opts.onPress}
388
- style={{
389
- flexDirection: 'row',
390
- alignItems: 'center',
391
- gap: 12,
392
- }}>
393
- <View
394
- style={{
395
- width: 36,
396
- height: 36,
397
- borderRadius: 10,
398
- backgroundColor: AppColors.purpleShade50,
399
- borderWidth: 1,
400
- borderColor: `${AppColors.purple}2E`,
401
- alignItems: 'center',
402
- justifyContent: 'center',
403
- }}>
404
- {opts.icon}
405
- </View>
406
- <View style={{flex: 1}}>
407
- <Text
408
- style={{
409
- fontFamily: AppFonts.interBold,
410
- fontSize: 14,
411
- lineHeight: 18,
412
- color: AppColors.primaryBlack,
413
- }}>
414
- {opts.label}
415
- </Text>
416
- {opts.description ? (
417
- <Text
418
- style={{
419
- fontFamily: AppFonts.interRegular,
420
- fontSize: 11,
421
- lineHeight: 15,
422
- color: AppColors.grayText,
423
- marginTop: 1,
424
- }}>
425
- {opts.description}
426
- </Text>
427
- ) : null}
428
- </View>
429
- {opts.right || null}
430
- </TouchableScale>
431
- {opts.numericInput && (
432
- <View style={{marginTop: 10, gap: 6}}>
433
- <View
434
- style={{
435
- flexDirection: 'row',
436
- alignItems: 'center',
437
- backgroundColor: AppColors.grayBackground,
438
- borderRadius: 8,
439
- borderWidth: 1,
440
- borderColor: AppColors.dividerColor,
441
- paddingHorizontal: 12,
442
- paddingVertical: 4,
443
- }}>
444
- <TextInput
445
- style={{
446
- flex: 1,
447
- fontFamily: AppFonts.interMedium,
448
- fontSize: 14,
449
- lineHeight: 18,
450
- color: AppColors.primaryBlack,
451
- paddingVertical: 6,
452
- }}
453
- value={String(opts.numericInput.value || '')}
454
- onChangeText={text => {
455
- const num = parseInt(text.replace(/[^0-9]/g, ''), 10);
456
- if (!isNaN(num)) {
457
- const clamped = Math.max(
458
- opts.numericInput?.min ?? 1,
459
- Math.min(opts.numericInput?.max ?? 10000, num),
460
- );
461
- opts.numericInput?.onChange(clamped);
462
- }
463
- }}
464
- keyboardType={opts.numericInput.keyboardType ?? 'number-pad'}
465
- placeholder={opts.numericInput.placeholder}
466
- placeholderTextColor={AppColors.grayTextWeak}
467
- maxLength={6}
468
- selectTextOnFocus
469
- />
470
- <Text
471
- style={{
472
- fontFamily: AppFonts.interBold,
473
- fontSize: 11,
474
- color: AppColors.purple,
475
- marginLeft: 6,
476
- }}>
477
- MAX
478
- </Text>
479
- </View>
480
- {opts.numericInput.min !== undefined ||
481
- opts.numericInput.max !== undefined ? (
482
- <Text
483
- style={{
484
- fontFamily: AppFonts.interRegular,
485
- fontSize: 10,
486
- lineHeight: 13,
487
- color: AppColors.grayTextWeak,
488
- }}>
489
- Range: {opts.numericInput.min ?? 1} -{' '}
490
- {opts.numericInput.max ?? '∞'}
491
- </Text>
492
- ) : null}
493
- </View>
494
- )}
495
- {opts.picker && (
496
- <View
497
- style={{
498
- flexDirection: 'row',
499
- backgroundColor: AppColors.grayBackground,
500
- borderRadius: 8,
501
- padding: 2.5,
502
- marginTop: 10,
503
- borderWidth: 1,
504
- borderColor: AppColors.dividerColor,
505
- }}>
506
- {opts.picker.options.map(opt => {
507
- const isActive = opts.picker!.selectedValue === opt;
508
- return (
509
- <TouchableScale
510
- key={String(opt)}
511
- onPress={() => opts.picker!.onSelect(opt)}
512
- style={{
513
- flex: 1,
514
- paddingVertical: 6,
515
- alignItems: 'center',
516
- borderRadius: 6,
517
- backgroundColor: isActive
518
- ? AppColors.purple
519
- : 'transparent',
520
- }}>
521
- <Text
522
- style={{
523
- fontFamily: AppFonts.interBold,
524
- fontSize: 11,
525
- lineHeight: 14,
526
- color: isActive ? AppColors.white : AppColors.grayText,
527
- }}>
528
- {opts.picker!.formatLabel
529
- ? opts.picker!.formatLabel(opt)
530
- : opt}
531
- </Text>
532
- </TouchableScale>
533
- );
534
- })}
535
- </View>
536
- )}
537
- </View>
538
- );
539
- };
540
-
541
- const renderMainSettingsContent = () => (
542
- <View
543
- style={{
544
- flex: 1,
545
- backgroundColor: AppColors.grayBackground,
546
- }}>
547
- <ScrollView
548
- style={{flex: 1}}
549
- contentContainerStyle={{padding: 16, paddingBottom: 100, gap: 14}}
550
- showsVerticalScrollIndicator={false}>
551
- {/* Segmented Top Navigation Sub-Tabs */}
552
- {/* ─── Modern Scrollable Settings Sub-Tabs Bar ─── */}
553
- <View
554
- style={{
555
- backgroundColor: AppColors.primaryLight,
556
- borderRadius: 13,
557
- paddingVertical: 4,
558
- paddingHorizontal: 4,
559
- borderWidth: 1,
560
- borderColor: AppColors.grayBorderSecondary,
561
- shadowColor: AppColors.black,
562
- shadowOpacity: 0.04,
563
- shadowRadius: 4,
564
- shadowOffset: {width: 0, height: 2},
565
- }}>
566
- <ScrollView
567
- horizontal
568
- showsHorizontalScrollIndicator={false}
569
- contentContainerStyle={{
570
- flexDirection: 'row',
571
- alignItems: 'center',
572
- gap: 6,
573
- paddingHorizontal: 2,
574
- }}>
575
- {[
576
- {
577
- key: 'module' as const,
578
- label: t('settings.modulesAndTools', 'Modules & Tools'),
579
- Icon: LayersIcon,
580
- badge: `${allModules.filter(m => stagedTabVisibility?.[m.key as ActiveTab] || m.key === 'apis').length}/${allModules.length}`,
581
- },
582
- {
583
- key: 'ui' as const,
584
- label: t('settings.uiPreferences', 'UI Preferences'),
585
- Icon: ScreenIcon,
586
- },
587
- {
588
- key: 'limits' as const,
589
- label: t('settings.ramLimits', 'RAM & Limits'),
590
- Icon: BrainIcon,
591
- },
592
- {
593
- key: 'capture' as const,
594
- label: t('settings.screenVideoCapture', 'Screen & Video Capture'),
595
- Icon: CameraIcon,
596
- },
597
- {
598
- key: 'about' as const,
599
- label: t('settings.aboutAndSpecs', 'About & Specs'),
600
- Icon: InfoCircleIcon,
601
- },
602
- ].map(tab => {
603
- const isActive = settingsActiveSubTab === tab.key;
604
- const IconComp = tab.Icon;
605
- return (
606
- <TouchableScale
607
- key={tab.key}
608
- accessible={true}
609
- accessibilityRole="tab"
610
- accessibilityLabel={tab.label}
611
- accessibilityState={{selected: isActive}}
612
- onPress={() => {
613
- animateNextLayout();
614
- setSettingsActiveSubTab(tab.key);
615
- }}
616
- style={{
617
- paddingVertical: 8,
618
- paddingHorizontal: 14,
619
- flexDirection: 'row',
620
- alignItems: 'center',
621
- justifyContent: 'center',
622
- gap: 6,
623
- borderRadius: 9,
624
- backgroundColor: isActive
625
- ? AppColors.purple
626
- : 'transparent',
627
- }}>
628
- <IconComp
629
- color={isActive ? AppColors.white : AppColors.grayText}
630
- size={13}
631
- />
632
- <Text
633
- style={{
634
- fontFamily: AppFonts.interBold,
635
- fontSize: 12.5,
636
- lineHeight: 16,
637
- color: isActive
638
- ? AppColors.white
639
- : AppColors.grayText,
640
- }}>
641
- {tab.label}
642
- </Text>
643
- {tab.badge && (
644
- <View
645
- style={{
646
- backgroundColor: isActive
647
- ? 'rgba(255,255,255,0.25)'
648
- : `${AppColors.purple}18`,
649
- paddingHorizontal: 5.5,
650
- paddingVertical: 1,
651
- borderRadius: 10,
652
- }}>
653
- <Text
654
- style={{
655
- fontFamily: AppFonts.interBold,
656
- fontSize: 9.5,
657
- color: isActive
658
- ? AppColors.white
659
- : AppColors.purple,
660
- }}>
661
- {tab.badge}
662
- </Text>
663
- </View>
664
- )}
665
- </TouchableScale>
666
- );
667
- })}
668
- </ScrollView>
669
- </View>
670
-
671
- {settingsActiveSubTab === 'module' && (
672
- <View style={{gap: 12}}>
673
- {/* Individual Module Cards with Left Checkboxes */}
674
- <View style={{gap: 10}}>
675
- {allModules.map(moduleItem => {
676
- const isReduxAvail = isReduxConnected();
677
- const isAnalyticsAvail = isAnalyticsConnected();
678
- const isUnavailable =
679
- (moduleItem.key === 'redux' && !isReduxAvail) ||
680
- (moduleItem.key === 'analytics' && !isAnalyticsAvail);
681
- const isLocked = moduleItem.key === 'apis' || isUnavailable;
682
- const isChecked =
683
- moduleItem.key === 'apis' ||
684
- (Boolean(
685
- stagedTabVisibility?.[moduleItem.key as ActiveTab],
686
- ) &&
687
- !isUnavailable);
688
-
689
- const liveStats =
690
- moduleItem.key === 'apis'
691
- ? `${logs.length} requests • Limit: ${maxNetworkLogs}`
692
- : moduleItem.key === 'logs'
693
- ? `${consoleLogs.length} logs • Limit: ${maxConsoleLogs}`
694
- : moduleItem.key === 'performance'
695
- ? '60 FPS Target • Memory Telemetry'
696
- : moduleItem.key === 'bundle'
697
- ? 'Metro Packager • Dependency Map'
698
- : moduleItem.key === 'crash'
699
- ? `${
700
- crashRecords?.length || 0
701
- } crashes recorded • Crash Guard`
702
- : moduleItem.key === 'analytics'
703
- ? `${analyticsEvents.length} events logged`
704
- : moduleItem.key === 'redux'
705
- ? `${
706
- Object.keys(reduxState || {}).length
707
- } slices • Depth: ${reduxExpandDepth}`
708
- : '';
709
-
710
- return (
711
- <View
712
- key={moduleItem.key}
713
- style={{
714
- backgroundColor: AppColors.primaryLight,
715
- borderRadius: 14,
716
- borderWidth: 1.5,
717
- borderColor: isChecked
718
- ? `${AppColors.purple}38`
719
- : AppColors.grayBorderSecondary,
720
- padding: 14,
721
- gap: 10,
722
- shadowColor: AppColors.black,
723
- shadowOpacity: isChecked ? 0.04 : 0.02,
724
- shadowRadius: 5,
725
- shadowOffset: {width: 0, height: 2},
726
- }}>
727
- {/* Top Row: [Checkbox] -> [Icon Tile] -> [Title & Subtitle] */}
728
- <View
729
- style={{
730
- flexDirection: 'row',
731
- alignItems: 'flex-start',
732
- gap: 10,
733
- }}>
734
- {/* 1. Checkbox on the Left */}
735
- <TouchableScale
736
- accessible={true}
737
- accessibilityRole="checkbox"
738
- accessibilityLabel={`Select ${moduleItem.label}`}
739
- accessibilityState={{
740
- checked: isChecked,
741
- disabled: isLocked,
742
- }}
743
- disabled={isLocked}
744
- onPress={() => {
745
- if (isLocked) return;
746
- setStagedTabVisibility(prev => ({
747
- ...prev,
748
- [moduleItem.key]:
749
- !prev[moduleItem.key as ActiveTab],
750
- }));
751
- }}
752
- hitSlop={8}
753
- style={{
754
- width: 22,
755
- height: 22,
756
- borderRadius: 6,
757
- borderWidth: isChecked ? 0 : 1.8,
758
- borderColor: isLocked
759
- ? AppColors.dividerColor
760
- : AppColors.grayBorderSecondary,
761
- backgroundColor:
762
- moduleItem.key === 'apis'
763
- ? `${AppColors.blue500}22`
764
- : isChecked
765
- ? AppColors.purple
766
- : AppColors.grayBackground,
767
- alignItems: 'center',
768
- justifyContent: 'center',
769
- marginTop: 7,
770
- shadowColor: isChecked
771
- ? AppColors.purple
772
- : 'transparent',
773
- shadowOpacity: isChecked ? 0.25 : 0,
774
- shadowRadius: 2,
775
- elevation: isChecked ? 2 : 0,
776
- }}>
777
- {moduleItem.key === 'apis' ? (
778
- <CheckIcon size={12} color={AppColors.blue500} />
779
- ) : isChecked ? (
780
- <CheckIcon size={12} color={AppColors.white} />
781
- ) : isLocked ? (
782
- <Svg
783
- width={10}
784
- height={10}
785
- viewBox="0 0 24 24"
786
- fill="none">
787
- <Path
788
- d="M7 10V7a5 5 0 0 1 10 0v3"
789
- stroke={AppColors.grayText}
790
- strokeWidth="2.2"
791
- strokeLinecap="round"
792
- />
793
- <Path
794
- d="M5 10h14v9a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1z"
795
- fill={AppColors.grayText}
796
- />
797
- </Svg>
798
- ) : null}
799
- </TouchableScale>
800
-
801
- {/* 2. Middle Tap Zone: Icon + Title & Desc */}
802
- <TouchableScale
803
- accessible={true}
804
- accessibilityRole="button"
805
- accessibilityLabel={`${moduleItem.label} settings`}
806
- disabled={isUnavailable}
807
- onPress={() => {
808
- animateNextLayout();
809
- setSettingsPage(moduleItem.key);
810
- }}
811
- style={{
812
- flex: 1,
813
- flexDirection: 'row',
814
- alignItems: 'flex-start',
815
- gap: 10,
816
- }}>
817
- {/* Icon Tile */}
818
- <View
819
- style={{
820
- width: 36,
821
- height: 36,
822
- borderRadius: 10,
823
- backgroundColor: isLocked
824
- ? `${AppColors.grayBorderSecondary}4D`
825
- : isChecked
826
- ? `${AppColors.purple}14`
827
- : AppColors.grayBackground,
828
- borderWidth: 1,
829
- borderColor: isLocked
830
- ? AppColors.dividerColor
831
- : isChecked
832
- ? `${AppColors.purple}33`
833
- : AppColors.grayBorderSecondary,
834
- alignItems: 'center',
835
- justifyContent: 'center',
836
- marginTop: 1,
837
- }}>
838
- {moduleItem.icon === 'apis' && (
839
- <SignalIcon
840
- color={
841
- isChecked
842
- ? AppColors.purple
843
- : AppColors.grayTextWeak
844
- }
845
- size={16}
846
- />
847
- )}
848
- {moduleItem.icon === 'logs' && (
849
- <TerminalIcon
850
- color={
851
- isChecked
852
- ? AppColors.purple
853
- : AppColors.grayTextWeak
854
- }
855
- size={16}
856
- />
857
- )}
858
- {moduleItem.icon === 'performance' && (
859
- <PerformanceIcon
860
- color={
861
- isChecked
862
- ? AppColors.purple
863
- : AppColors.grayTextWeak
864
- }
865
- size={16}
866
- />
867
- )}
868
- {moduleItem.icon === 'bundle' && (
869
- <PackageIcon
870
- color={
871
- isChecked
872
- ? AppColors.purple
873
- : AppColors.grayTextWeak
874
- }
875
- size={16}
876
- />
877
- )}
878
- {moduleItem.icon === 'crash' && (
879
- <CrashIcon
880
- color={
881
- isChecked
882
- ? AppColors.purple
883
- : AppColors.grayTextWeak
884
- }
885
- size={16}
886
- />
887
- )}
888
- {moduleItem.icon === 'analytics' && (
889
- <AnalyticsIcon
890
- color={
891
- isChecked
892
- ? AppColors.purple
893
- : AppColors.grayTextWeak
894
- }
895
- size={16}
896
- />
897
- )}
898
- {moduleItem.icon === 'redux' && (
899
- <ReduxIcon
900
- color={
901
- isChecked
902
- ? AppColors.purple
903
- : AppColors.grayTextWeak
904
- }
905
- size={16}
906
- />
907
- )}
908
- {moduleItem.icon === 'device' && (
909
- <SmartphoneIcon
910
- color={
911
- isChecked
912
- ? AppColors.purple
913
- : AppColors.grayTextWeak
914
- }
915
- size={16}
916
- />
917
- )}
918
- {moduleItem.icon === 'storage' && (
919
- <DatabaseIcon
920
- color={
921
- isChecked
922
- ? AppColors.purple
923
- : AppColors.grayTextWeak
924
- }
925
- size={16}
926
- />
927
- )}
928
- {moduleItem.icon === 'debugging' && (
929
- <QrCodeIcon
930
- color={
931
- isChecked
932
- ? AppColors.purple
933
- : AppColors.grayTextWeak
934
- }
935
- size={16}
936
- />
937
- )}
938
- </View>
939
-
940
- {/* Titles & Status Pill */}
941
- <View style={{flex: 1, gap: 2}}>
942
- <View
943
- style={{
944
- flexDirection: 'row',
945
- alignItems: 'center',
946
- gap: 6,
947
- flexWrap: 'wrap',
948
- }}>
949
- <View
950
- style={{
951
- minWidth: 22,
952
- height: 22,
953
- paddingHorizontal: 5,
954
- borderRadius: 11,
955
- backgroundColor: isChecked
956
- ? `${AppColors.purple}1C`
957
- : `${AppColors.grayBorderSecondary}80`,
958
- borderWidth: 1,
959
- borderColor: isChecked
960
- ? `${AppColors.purple}44`
961
- : AppColors.grayBorderSecondary,
962
- alignItems: 'center',
963
- justifyContent: 'center',
964
- }}>
965
- <Text
966
- style={{
967
- fontFamily: AppFonts.interBold,
968
- fontSize: 10,
969
- lineHeight: 13,
970
- color: isChecked
971
- ? AppColors.purple
972
- : AppColors.grayText,
973
- }}>
974
- #{moduleItem.id}
975
- </Text>
976
- </View>
977
- <Text
978
- style={{
979
- fontFamily: AppFonts.interBold,
980
- fontSize: 14,
981
- lineHeight: 18,
982
- color: isLocked
983
- ? AppColors.grayText
984
- : AppColors.primaryBlack,
985
- }}>
986
- {moduleItem.label}
987
- </Text>
988
-
989
- {/* Default Startup Tab Badge */}
990
- {moduleItem.key === defaultTab &&
991
- !isUnavailable && (
992
- <View
993
- style={{
994
- flexDirection: 'row',
995
- alignItems: 'center',
996
- backgroundColor: `${AppColors.purple}14`,
997
- borderRadius: 12,
998
- paddingHorizontal: 5,
999
- paddingVertical: 1.5,
1000
- borderWidth: 1,
1001
- borderColor: `${AppColors.purple}2E`,
1002
- gap: 3,
1003
- }}>
1004
- <View
1005
- style={{
1006
- width: 4,
1007
- height: 4,
1008
- borderRadius: 2,
1009
- backgroundColor: AppColors.purple,
1010
- }}
1011
- />
1012
- <Text
1013
- style={{
1014
- fontFamily: AppFonts.interBold,
1015
- fontSize: 8,
1016
- lineHeight: 11,
1017
- color: AppColors.purple,
1018
- letterSpacing: 0.4,
1019
- }}>
1020
- {t('settings.defaultBadge')}
1021
- </Text>
1022
- </View>
1023
- )}
1024
-
1025
- {/* Status Pill */}
1026
- {moduleItem.key === 'apis' ? (
1027
- <View
1028
- style={{
1029
- backgroundColor: `${AppColors.blue500}14`,
1030
- borderRadius: 4,
1031
- paddingHorizontal: 5,
1032
- paddingVertical: 1.5,
1033
- borderWidth: 1,
1034
- borderColor: `${AppColors.blue500}33`,
1035
- }}>
1036
- <Text
1037
- style={{
1038
- fontFamily: AppFonts.interBold,
1039
- fontSize: 8,
1040
- lineHeight: 11,
1041
- color: AppColors.blue500,
1042
- letterSpacing: 0.3,
1043
- }}>
1044
- {t('settings.coreBadge')}
1045
- </Text>
1046
- </View>
1047
- ) : isUnavailable ? (
1048
- <View
1049
- style={{
1050
- backgroundColor: `${AppColors.amber500}18`,
1051
- borderRadius: 4,
1052
- paddingHorizontal: 5,
1053
- paddingVertical: 1.5,
1054
- borderWidth: 1,
1055
- borderColor: `${AppColors.amber500}35`,
1056
- }}>
1057
- <Text
1058
- style={{
1059
- fontFamily: AppFonts.interBold,
1060
- fontSize: 8,
1061
- lineHeight: 11,
1062
- color: AppColors.amber700,
1063
- letterSpacing: 0.3,
1064
- }}>
1065
- {moduleItem.key === 'redux'
1066
- ? t('settings.notConnectedBadge')
1067
- : t('settings.notDetectedBadge')}
1068
- </Text>
1069
- </View>
1070
- ) : isChecked ? (
1071
- <View
1072
- style={{
1073
- backgroundColor: `${AppColors.liveGreen}18`,
1074
- borderRadius: 4,
1075
- paddingHorizontal: 5,
1076
- paddingVertical: 1.5,
1077
- borderWidth: 1,
1078
- borderColor: `${AppColors.liveGreen}38`,
1079
- }}>
1080
- <Text
1081
- style={{
1082
- fontFamily: AppFonts.interBold,
1083
- fontSize: 8,
1084
- lineHeight: 11,
1085
- color: AppColors.green700,
1086
- letterSpacing: 0.3,
1087
- }}>
1088
- {t('settings.activeBadge')}
1089
- </Text>
1090
- </View>
1091
- ) : (
1092
- <View
1093
- style={{
1094
- backgroundColor: `${AppColors.grayTextWeak}18`,
1095
- borderRadius: 4,
1096
- paddingHorizontal: 5,
1097
- paddingVertical: 1.5,
1098
- borderWidth: 1,
1099
- borderColor: `${AppColors.grayTextWeak}2E`,
1100
- }}>
1101
- <Text
1102
- style={{
1103
- fontFamily: AppFonts.interBold,
1104
- fontSize: 8,
1105
- lineHeight: 11,
1106
- color: AppColors.grayTextWeak,
1107
- letterSpacing: 0.3,
1108
- }}>
1109
- {t('settings.dormantBadge')}
1110
- </Text>
1111
- </View>
1112
- )}
1113
- </View>
1114
-
1115
- <Text
1116
- style={{
1117
- fontFamily: AppFonts.interRegular,
1118
- fontSize: 11,
1119
- color: AppColors.grayText,
1120
- lineHeight: 15,
1121
- marginTop: 1,
1122
- }}>
1123
- {moduleItem.desc}
1124
- </Text>
1125
- </View>
1126
- </TouchableScale>
1127
- </View>
1128
-
1129
- {/* Card Footer: Live Stats + Configure Button */}
1130
- {!isUnavailable && (
1131
- <View
1132
- style={{
1133
- flexDirection: 'row',
1134
- alignItems: 'center',
1135
- justifyContent: 'space-between',
1136
- paddingTop: 8,
1137
- borderTopWidth: 1,
1138
- borderTopColor: AppColors.dividerColor,
1139
- }}>
1140
- {/* Live Info Pill */}
1141
- <View
1142
- style={{
1143
- flexDirection: 'row',
1144
- alignItems: 'center',
1145
- gap: 6,
1146
- flex: 1,
1147
- }}>
1148
- <View
1149
- style={{
1150
- width: 6,
1151
- height: 6,
1152
- borderRadius: 3,
1153
- backgroundColor: isChecked
1154
- ? AppColors.liveGreen
1155
- : AppColors.grayTextWeak,
1156
- }}
1157
- />
1158
- <Text
1159
- style={{
1160
- fontFamily: AppFonts.interMedium,
1161
- fontSize: 11,
1162
- color: AppColors.grayText,
1163
- lineHeight: 14,
1164
- }}>
1165
- {liveStats}
1166
- </Text>
1167
- </View>
1168
-
1169
- {/* Sleek Configure Button */}
1170
- <TouchableScale
1171
- accessible={true}
1172
- accessibilityRole="button"
1173
- accessibilityLabel={`Configure ${moduleItem.label} settings`}
1174
- onPress={() => {
1175
- animateNextLayout();
1176
- setSettingsPage(moduleItem.key);
1177
- }}
1178
- style={{
1179
- flexDirection: 'row',
1180
- alignItems: 'center',
1181
- gap: 5,
1182
- backgroundColor: `${AppColors.purple}12`,
1183
- paddingHorizontal: 10,
1184
- paddingVertical: 5,
1185
- borderRadius: 8,
1186
- borderWidth: 1,
1187
- borderColor: `${AppColors.purple}26`,
1188
- }}>
1189
- <SettingsIcon color={AppColors.purple} size={11} />
1190
- <Text
1191
- style={{
1192
- fontFamily: AppFonts.interBold,
1193
- fontSize: 11,
1194
- lineHeight: 14,
1195
- color: AppColors.purple,
1196
- }}>
1197
- {t('settings.configure')}
1198
- </Text>
1199
- <ForwardChevronIcon
1200
- color={AppColors.purple}
1201
- size={9}
1202
- />
1203
- </TouchableScale>
1204
- </View>
1205
- )}
1206
- </View>
1207
- );
1208
- })}
1209
- </View>
1210
- </View>
1211
- )}
1212
-
1213
- {settingsActiveSubTab === 'ui' && (
1214
- <View style={{gap: 14}}>
1215
- {/* Section 1: Appearance */}
1216
- <View
1217
- style={{
1218
- backgroundColor: AppColors.primaryLight,
1219
- borderRadius: 14,
1220
- borderWidth: 1,
1221
- borderColor: AppColors.grayBorderSecondary,
1222
- overflow: 'hidden',
1223
- padding: 14,
1224
- gap: 12,
1225
- }}>
1226
- <Text
1227
- style={{
1228
- fontFamily: AppFonts.interBold,
1229
- fontSize: 11,
1230
- lineHeight: 14,
1231
- color: AppColors.grayTextWeak,
1232
- letterSpacing: 0.8,
1233
- }}>
1234
- {t('settings.appearanceTheme')}
1235
- </Text>
1236
-
1237
- <View
1238
- style={{
1239
- flexDirection: 'row',
1240
- alignItems: 'center',
1241
- justifyContent: 'space-between',
1242
- }}>
1243
- <View
1244
- style={{
1245
- flexDirection: 'row',
1246
- alignItems: 'center',
1247
- gap: 10,
1248
- flex: 1,
1249
- }}>
1250
- <View
1251
- style={{
1252
- width: 32,
1253
- height: 32,
1254
- borderRadius: 8,
1255
- backgroundColor: AppColors.purpleShade50,
1256
- alignItems: 'center',
1257
- justifyContent: 'center',
1258
- }}>
1259
- {isDark ? (
1260
- <SunIcon color={AppColors.purple} size={15} />
1261
- ) : (
1262
- <MoonIcon color={AppColors.purple} size={15} />
1263
- )}
1264
- </View>
1265
- <View style={{flex: 1}}>
1266
- <Text
1267
- style={{
1268
- fontFamily: AppFonts.interBold,
1269
- fontSize: 13.5,
1270
- lineHeight: 18,
1271
- color: AppColors.primaryBlack,
1272
- }}>
1273
- {t('settings.general.darkMode')}
1274
- </Text>
1275
- <Text
1276
- style={{
1277
- fontFamily: AppFonts.interRegular,
1278
- fontSize: 11,
1279
- lineHeight: 15,
1280
- color: AppColors.grayText,
1281
- marginTop: 1,
1282
- }}>
1283
- {t('settings.general.darkModeDescription')}
1284
- </Text>
1285
- </View>
1286
- </View>
1287
-
1288
- <TouchableScale
1289
- accessible={true}
1290
- accessibilityRole="switch"
1291
- accessibilityLabel="Toggle Dark Theme"
1292
- accessibilityState={{checked: isDark}}
1293
- onPress={() => {
1294
- const newTheme = !isDark;
1295
- setIsDark(newTheme);
1296
- toggleGlobalTheme(newTheme);
1297
- }}
1298
- style={{
1299
- width: 42,
1300
- height: 24,
1301
- borderRadius: 12,
1302
- backgroundColor: isDark
1303
- ? AppColors.purple
1304
- : AppColors.grayBorderSecondary,
1305
- padding: 2,
1306
- justifyContent: 'center',
1307
- alignItems: isDark ? 'flex-end' : 'flex-start',
1308
- }}>
1309
- <View
1310
- style={{
1311
- width: 20,
1312
- height: 20,
1313
- borderRadius: 10,
1314
- backgroundColor: AppColors.white,
1315
- shadowColor: AppColors.black,
1316
- shadowOpacity: 0.18,
1317
- shadowRadius: 2,
1318
- shadowOffset: {width: 0, height: 1},
1319
- }}
1320
- />
1321
- </TouchableScale>
1322
- </View>
1323
- </View>
1324
-
1325
- {/* Section 2: Window & Layout */}
1326
- <View
1327
- style={{
1328
- backgroundColor: AppColors.primaryLight,
1329
- borderRadius: 14,
1330
- borderWidth: 1,
1331
- borderColor: AppColors.grayBorderSecondary,
1332
- overflow: 'hidden',
1333
- padding: 14,
1334
- gap: 14,
1335
- }}>
1336
- <Text
1337
- style={{
1338
- fontFamily: AppFonts.interBold,
1339
- fontSize: 11,
1340
- lineHeight: 14,
1341
- color: AppColors.grayTextWeak,
1342
- letterSpacing: 0.8,
1343
- }}>
1344
- {t('settings.windowLayout')}
1345
- </Text>
1346
-
1347
- {/* Modal Height */}
1348
- <View style={{gap: 8}}>
1349
- <View
1350
- style={{
1351
- flexDirection: 'row',
1352
- alignItems: 'center',
1353
- justifyContent: 'space-between',
1354
- gap: 10,
1355
- }}>
1356
- <View
1357
- style={{
1358
- flexDirection: 'row',
1359
- alignItems: 'center',
1360
- gap: 10,
1361
- flex: 1,
1362
- }}>
1363
- <View
1364
- style={{
1365
- width: 32,
1366
- height: 32,
1367
- borderRadius: 8,
1368
- backgroundColor: AppColors.purpleShade50,
1369
- alignItems: 'center',
1370
- justifyContent: 'center',
1371
- }}>
1372
- <ScreenIcon color={AppColors.purple} size={15} />
1373
- </View>
1374
- <View style={{flex: 1}}>
1375
- <Text
1376
- style={{
1377
- fontFamily: AppFonts.interBold,
1378
- fontSize: 13.5,
1379
- lineHeight: 18,
1380
- color: AppColors.primaryBlack,
1381
- }}>
1382
- {t('settings.general.modalHeight')}
1383
- </Text>
1384
- <Text
1385
- style={{
1386
- fontFamily: AppFonts.interRegular,
1387
- fontSize: 11,
1388
- lineHeight: 15,
1389
- color: AppColors.grayText,
1390
- marginTop: 1,
1391
- }}>
1392
- {t('settings.general.modalHeightDescription')}
1393
- </Text>
1394
- </View>
1395
- </View>
1396
-
1397
- {stagedHeight !== modalHeightPercent && (
1398
- <TouchableScale
1399
- onPress={() => {
1400
- setModalHeightPercent(stagedHeight);
1401
- }}
1402
- style={{
1403
- flexDirection: 'row',
1404
- alignItems: 'center',
1405
- gap: 5,
1406
- backgroundColor: AppColors.purple,
1407
- paddingHorizontal: 10,
1408
- paddingVertical: 5,
1409
- borderRadius: 7,
1410
- shadowColor: AppColors.purple,
1411
- shadowOffset: {width: 0, height: 1},
1412
- shadowOpacity: 0.28,
1413
- shadowRadius: 2,
1414
- elevation: 2,
1415
- }}>
1416
- <CheckIcon size={11} color={AppColors.white} />
1417
- <Text
1418
- style={{
1419
- fontFamily: AppFonts.interBold,
1420
- fontSize: 11,
1421
- color: AppColors.white,
1422
- }}>
1423
- Save ({stagedHeight}%)
1424
- </Text>
1425
- </TouchableScale>
1426
- )}
1427
- </View>
1428
-
1429
- <View style={{marginTop: 6}}>
1430
- <Slider
1431
- value={stagedHeight}
1432
- onValueChange={setStagedHeight}
1433
- min={50}
1434
- max={90}
1435
- step={5}
1436
- quickPresets={[50, 60, 70, 80, 90]}
1437
- formatLabel={val => `${Math.round(val)}%`}
1438
- />
1439
- </View>
1440
- </View>
1441
-
1442
- <View
1443
- style={{height: 1, backgroundColor: AppColors.dividerColor}}
1444
- />
1445
-
1446
- {/* Modal Animation */}
1447
- <View style={{gap: 8}}>
1448
- <View
1449
- style={{
1450
- flexDirection: 'row',
1451
- alignItems: 'center',
1452
- gap: 10,
1453
- }}>
1454
- <View
1455
- style={{
1456
- width: 32,
1457
- height: 32,
1458
- borderRadius: 8,
1459
- backgroundColor: AppColors.purpleShade50,
1460
- alignItems: 'center',
1461
- justifyContent: 'center',
1462
- }}>
1463
- <MotionIcon color={AppColors.purple} size={15} />
1464
- </View>
1465
- <View style={{flex: 1}}>
1466
- <Text
1467
- style={{
1468
- fontFamily: AppFonts.interBold,
1469
- fontSize: 13.5,
1470
- lineHeight: 18,
1471
- color: AppColors.primaryBlack,
1472
- }}>
1473
- {t('settings.general.modalAnimation')}
1474
- </Text>
1475
- <Text
1476
- style={{
1477
- fontFamily: AppFonts.interRegular,
1478
- fontSize: 11,
1479
- lineHeight: 15,
1480
- color: AppColors.grayText,
1481
- marginTop: 1,
1482
- }}>
1483
- {t('settings.general.modalAnimationDescription')}
1484
- </Text>
1485
- </View>
1486
- </View>
1487
-
1488
- <View
1489
- style={{
1490
- flexDirection: 'row',
1491
- backgroundColor: AppColors.grayBackground,
1492
- borderRadius: 10,
1493
- padding: 3,
1494
- borderWidth: 1,
1495
- borderColor: AppColors.dividerColor,
1496
- }}>
1497
- {[
1498
- {key: 'slide' as const, label: 'Slide Up'},
1499
- {key: 'fade' as const, label: 'Fade'},
1500
- {key: 'none' as const, label: 'None'},
1501
- ].map(opt => {
1502
- const isActive = modalAnimationType === opt.key;
1503
- return (
1504
- <TouchableScale
1505
- key={opt.key}
1506
- accessible={true}
1507
- accessibilityRole="button"
1508
- accessibilityLabel={`Set transition animation to ${opt.label}`}
1509
- accessibilityState={{selected: isActive}}
1510
- onPress={() => setModalAnimationType(opt.key)}
1511
- style={{
1512
- flex: 1,
1513
- paddingVertical: 7,
1514
- alignItems: 'center',
1515
- borderRadius: 8,
1516
- backgroundColor: isActive
1517
- ? AppColors.purple
1518
- : 'transparent',
1519
- }}>
1520
- <Text
1521
- style={{
1522
- fontFamily: AppFonts.interBold,
1523
- fontSize: 11.5,
1524
- lineHeight: 15,
1525
- color: isActive
1526
- ? AppColors.white
1527
- : AppColors.grayText,
1528
- }}>
1529
- {opt.label}
1530
- </Text>
1531
- </TouchableScale>
1532
- );
1533
- })}
1534
- </View>
1535
- </View>
1536
- </View>
1537
-
1538
- {/* Section 3: Default Startup Tab */}
1539
- <View
1540
- style={{
1541
- backgroundColor: AppColors.primaryLight,
1542
- borderRadius: 14,
1543
- borderWidth: 1,
1544
- borderColor: AppColors.grayBorderSecondary,
1545
- overflow: 'hidden',
1546
- padding: 14,
1547
- gap: 12,
1548
- }}>
1549
- <Text
1550
- style={{
1551
- fontFamily: AppFonts.interBold,
1552
- fontSize: 11,
1553
- lineHeight: 14,
1554
- color: AppColors.grayTextWeak,
1555
- letterSpacing: 0.8,
1556
- }}>
1557
- {t('settings.startupDefault')}
1558
- </Text>
1559
-
1560
- <View
1561
- style={{
1562
- flexDirection: 'row',
1563
- alignItems: 'center',
1564
- gap: 10,
1565
- }}>
1566
- <View
1567
- style={{
1568
- width: 32,
1569
- height: 32,
1570
- borderRadius: 8,
1571
- backgroundColor: AppColors.purpleShade50,
1572
- alignItems: 'center',
1573
- justifyContent: 'center',
1574
- }}>
1575
- <LayersIcon color={AppColors.purple} size={15} />
1576
- </View>
1577
- <View style={{flex: 1}}>
1578
- <Text
1579
- style={{
1580
- fontFamily: AppFonts.interBold,
1581
- fontSize: 13.5,
1582
- lineHeight: 18,
1583
- color: AppColors.primaryBlack,
1584
- }}>
1585
- {t('settings.general.defaultOpeningTab')}
1586
- </Text>
1587
- <Text
1588
- style={{
1589
- fontFamily: AppFonts.interRegular,
1590
- fontSize: 11,
1591
- lineHeight: 15,
1592
- color: AppColors.grayText,
1593
- marginTop: 1,
1594
- }}>
1595
- {t('settings.general.defaultOpeningTabDesc')}
1596
- </Text>
1597
- </View>
1598
- </View>
1599
-
1600
- {/* Sleek Interactive Dropdown Picker */}
1601
- <View style={{marginTop: 6, gap: 6}}>
1602
- <TouchableScale
1603
- accessible={true}
1604
- accessibilityRole="button"
1605
- accessibilityLabel={`Default opening tab: ${
1606
- allModules.find(m => m.key === defaultTab)?.label || 'APIs'
1607
- }`}
1608
- onPress={() => setIsDefaultTabDropdownOpen(prev => !prev)}
1609
- style={{
1610
- flexDirection: 'row',
1611
- alignItems: 'center',
1612
- justifyContent: 'space-between',
1613
- backgroundColor: AppColors.grayBackground,
1614
- borderRadius: 10,
1615
- borderWidth: 1.5,
1616
- borderColor: isDefaultTabDropdownOpen
1617
- ? AppColors.purple
1618
- : AppColors.grayBorderSecondary,
1619
- paddingHorizontal: 14,
1620
- paddingVertical: 11,
1621
- }}>
1622
- <View
1623
- style={{
1624
- flexDirection: 'row',
1625
- alignItems: 'center',
1626
- gap: 10,
1627
- flex: 1,
1628
- }}>
1629
- <View
1630
- style={{
1631
- width: 8,
1632
- height: 8,
1633
- borderRadius: 4,
1634
- backgroundColor: AppColors.purple,
1635
- }}
1636
- />
1637
- <Text
1638
- style={{
1639
- fontFamily: AppFonts.interBold,
1640
- fontSize: 13.5,
1641
- lineHeight: 18,
1642
- color: AppColors.primaryBlack,
1643
- }}>
1644
- {allModules.find(m => m.key === defaultTab)
1645
- ? `#${allModules.find(m => m.key === defaultTab)?.id} ${allModules.find(m => m.key === defaultTab)?.label}`
1646
- : '#1 APIs (Network)'}
1647
- </Text>
1648
- <View
1649
- style={{
1650
- backgroundColor: `${AppColors.purple}14`,
1651
- paddingHorizontal: 6,
1652
- paddingVertical: 1.5,
1653
- borderRadius: 6,
1654
- }}>
1655
- <Text
1656
- style={{
1657
- fontFamily: AppFonts.interBold,
1658
- fontSize: 8.5,
1659
- color: AppColors.purple,
1660
- }}>
1661
- DEFAULT
1662
- </Text>
1663
- </View>
1664
- </View>
1665
-
1666
- <View
1667
- style={{
1668
- transform: [
1669
- {rotate: isDefaultTabDropdownOpen ? '180deg' : '0deg'},
1670
- ],
1671
- }}>
1672
- <ChevronDownIcon color={AppColors.grayText} size={15} />
1673
- </View>
1674
- </TouchableScale>
1675
-
1676
- {/* Dropdown Options List */}
1677
- {isDefaultTabDropdownOpen && (
1678
- <View
1679
- style={{
1680
- backgroundColor: AppColors.primaryLight,
1681
- borderRadius: 10,
1682
- borderWidth: 1,
1683
- borderColor: AppColors.grayBorderSecondary,
1684
- overflow: 'hidden',
1685
- shadowColor: AppColors.black,
1686
- shadowOpacity: 0.08,
1687
- shadowRadius: 6,
1688
- shadowOffset: {width: 0, height: 3},
1689
- elevation: 4,
1690
- }}>
1691
- {allModules
1692
- .filter(
1693
- tab =>
1694
- tab.key === 'apis' ||
1695
- stagedTabVisibility?.[tab.key as ActiveTab] ||
1696
- tabVisibility?.[tab.key as ActiveTab],
1697
- )
1698
- .map((tab, idx, arr) => {
1699
- const isActive = defaultTab === tab.key;
1700
- const isLast = idx === arr.length - 1;
1701
- return (
1702
- <TouchableScale
1703
- key={tab.key}
1704
- accessible={true}
1705
- accessibilityRole="button"
1706
- accessibilityLabel={`Select ${tab.label} as default tab`}
1707
- onPress={() => {
1708
- setDefaultTab(tab.key);
1709
- setIsDefaultTabDropdownOpen(false);
1710
- }}
1711
- style={{
1712
- flexDirection: 'row',
1713
- alignItems: 'center',
1714
- justifyContent: 'space-between',
1715
- paddingHorizontal: 14,
1716
- paddingVertical: 11,
1717
- backgroundColor: isActive
1718
- ? `${AppColors.purple}0F`
1719
- : 'transparent',
1720
- borderBottomWidth: isLast ? 0 : 1,
1721
- borderBottomColor: AppColors.dividerColor,
1722
- }}>
1723
- <View
1724
- style={{
1725
- flexDirection: 'row',
1726
- alignItems: 'center',
1727
- gap: 10,
1728
- }}>
1729
- <View
1730
- style={{
1731
- width: 6,
1732
- height: 6,
1733
- borderRadius: 3,
1734
- backgroundColor: isActive
1735
- ? AppColors.purple
1736
- : AppColors.grayTextWeak,
1737
- }}
1738
- />
1739
- <Text
1740
- style={{
1741
- fontFamily: isActive
1742
- ? AppFonts.interBold
1743
- : AppFonts.interMedium,
1744
- fontSize: 13,
1745
- color: isActive
1746
- ? AppColors.purple
1747
- : AppColors.primaryBlack,
1748
- }}>
1749
- #{tab.id} {tab.label}
1750
- </Text>
1751
- </View>
1752
- {isActive && (
1753
- <CheckIcon size={14} color={AppColors.purple} />
1754
- )}
1755
- </TouchableScale>
1756
- );
1757
- })}
1758
- </View>
1759
- )}
1760
- </View>
1761
- </View>
1762
-
1763
- {/* Section 4: Notifications & Toasts */}
1764
- <View
1765
- style={{
1766
- backgroundColor: AppColors.primaryLight,
1767
- borderRadius: 14,
1768
- borderWidth: 1,
1769
- borderColor: AppColors.grayBorderSecondary,
1770
- overflow: 'hidden',
1771
- padding: 14,
1772
- gap: 12,
1773
- }}>
1774
- <Text
1775
- style={{
1776
- fontFamily: AppFonts.interBold,
1777
- fontSize: 11,
1778
- lineHeight: 14,
1779
- color: AppColors.grayTextWeak,
1780
- letterSpacing: 0.8,
1781
- }}>
1782
- NOTIFICATIONS & TOASTS
1783
- </Text>
1784
-
1785
- <View
1786
- style={{
1787
- flexDirection: 'row',
1788
- alignItems: 'center',
1789
- justifyContent: 'space-between',
1790
- }}>
1791
- <View
1792
- style={{
1793
- flexDirection: 'row',
1794
- alignItems: 'center',
1795
- gap: 10,
1796
- flex: 1,
1797
- marginRight: 10,
1798
- }}>
1799
- <View
1800
- style={{
1801
- width: 32,
1802
- height: 32,
1803
- borderRadius: 8,
1804
- backgroundColor: AppColors.purpleShade50,
1805
- alignItems: 'center',
1806
- justifyContent: 'center',
1807
- }}>
1808
- <PackageIcon color={AppColors.purple} size={15} />
1809
- </View>
1810
- <View style={{flex: 1}}>
1811
- <Text
1812
- style={{
1813
- fontFamily: AppFonts.interBold,
1814
- fontSize: 13.5,
1815
- lineHeight: 18,
1816
- color: AppColors.primaryBlack,
1817
- }}>
1818
- NPM Update Toast
1819
- </Text>
1820
- <Text
1821
- style={{
1822
- fontFamily: AppFonts.interRegular,
1823
- fontSize: 11,
1824
- lineHeight: 15,
1825
- color: AppColors.grayText,
1826
- marginTop: 1,
1827
- }}>
1828
- Show a floating toast banner with countdown progress when
1829
- a newer release is published on npm.
1830
- </Text>
1831
- </View>
1832
- </View>
1833
-
1834
- <TouchableScale
1835
- accessible={true}
1836
- accessibilityRole="switch"
1837
- accessibilityLabel="Toggle NPM Update Toast"
1838
- accessibilityState={{checked: showUpdateToast}}
1839
- onPress={() => setShowUpdateToast(prev => !prev)}
1840
- style={{
1841
- width: 42,
1842
- height: 24,
1843
- borderRadius: 12,
1844
- backgroundColor: showUpdateToast
1845
- ? AppColors.purple
1846
- : AppColors.grayBorderSecondary,
1847
- padding: 2,
1848
- justifyContent: 'center',
1849
- alignItems: showUpdateToast ? 'flex-end' : 'flex-start',
1850
- }}>
1851
- <View
1852
- style={{
1853
- width: 20,
1854
- height: 20,
1855
- borderRadius: 10,
1856
- backgroundColor: AppColors.white,
1857
- shadowColor: AppColors.black,
1858
- shadowOpacity: 0.18,
1859
- shadowRadius: 2,
1860
- shadowOffset: {width: 0, height: 1},
1861
- }}
1862
- />
1863
- </TouchableScale>
1864
- </View>
1865
- </View>
1866
- </View>
1867
- )}
1868
-
1869
- {settingsActiveSubTab === 'limits' && (
1870
- <View style={{gap: 14}}>
1871
- {/* Section 1: Device RAM & Auto Profile */}
1872
- <View
1873
- style={{
1874
- backgroundColor: AppColors.primaryLight,
1875
- borderRadius: 14,
1876
- borderWidth: 1,
1877
- borderColor: AppColors.grayBorderSecondary,
1878
- overflow: 'hidden',
1879
- padding: 14,
1880
- gap: 12,
1881
- }}>
1882
- <Text
1883
- style={{
1884
- fontFamily: AppFonts.interBold,
1885
- fontSize: 11,
1886
- lineHeight: 14,
1887
- color: AppColors.grayTextWeak,
1888
- letterSpacing: 0.8,
1889
- }}>
1890
- DEVICE MEMORY & AUTO PROFILES
1891
- </Text>
1892
-
1893
- {/* Auto RAM Limit Toggle */}
1894
- <View
1895
- style={{
1896
- flexDirection: 'row',
1897
- alignItems: 'center',
1898
- justifyContent: 'space-between',
1899
- }}>
1900
- <View
1901
- style={{
1902
- flexDirection: 'row',
1903
- alignItems: 'center',
1904
- gap: 10,
1905
- flex: 1,
1906
- }}>
1907
- <View
1908
- style={{
1909
- width: 32,
1910
- height: 32,
1911
- borderRadius: 8,
1912
- backgroundColor: AppColors.purpleShade50,
1913
- alignItems: 'center',
1914
- justifyContent: 'center',
1915
- }}>
1916
- <BrainIcon color={AppColors.purple} size={16} />
1917
- </View>
1918
- <View style={{flex: 1}}>
1919
- <Text
1920
- style={{
1921
- fontFamily: AppFonts.interBold,
1922
- fontSize: 13.5,
1923
- lineHeight: 18,
1924
- color: AppColors.primaryBlack,
1925
- }}>
1926
- Auto-Calculate Limits from RAM
1927
- </Text>
1928
- <Text
1929
- style={{
1930
- fontFamily: AppFonts.interRegular,
1931
- fontSize: 11,
1932
- lineHeight: 15,
1933
- color: AppColors.grayText,
1934
- marginTop: 1,
1935
- }}>
1936
- Dynamically sets log limits according to available device memory
1937
- </Text>
1938
- </View>
1939
- </View>
1940
-
1941
- <TouchableScale
1942
- accessible={true}
1943
- accessibilityRole="switch"
1944
- accessibilityLabel="Toggle auto RAM limit calculation"
1945
- accessibilityState={{checked: isAutoRamLimitEnabled}}
1946
- onPress={() => setIsAutoRamLimitEnabled(prev => !prev)}
1947
- style={{
1948
- width: 42,
1949
- height: 24,
1950
- borderRadius: 12,
1951
- backgroundColor: isAutoRamLimitEnabled
1952
- ? AppColors.purple
1953
- : AppColors.grayBorderSecondary,
1954
- padding: 2,
1955
- justifyContent: 'center',
1956
- alignItems: isAutoRamLimitEnabled
1957
- ? 'flex-end'
1958
- : 'flex-start',
1959
- }}>
1960
- <View
1961
- style={{
1962
- width: 20,
1963
- height: 20,
1964
- borderRadius: 10,
1965
- backgroundColor: AppColors.white,
1966
- shadowColor: AppColors.black,
1967
- shadowOpacity: 0.18,
1968
- shadowRadius: 2,
1969
- shadowOffset: {width: 0, height: 1},
1970
- }}
1971
- />
1972
- </TouchableScale>
1973
- </View>
1974
-
1975
- <View
1976
- style={{height: 1, backgroundColor: AppColors.dividerColor}}
1977
- />
1978
-
1979
- {/* Device Free RAM Display */}
1980
- <View
1981
- style={{flexDirection: 'row', alignItems: 'center', gap: 10}}>
1982
- <View
1983
- style={{
1984
- width: 32,
1985
- height: 32,
1986
- borderRadius: 8,
1987
- backgroundColor: isAutoRamLimitEnabled
1988
- ? `${AppColors.purple}14`
1989
- : AppColors.grayBackground,
1990
- alignItems: 'center',
1991
- justifyContent: 'center',
1992
- }}>
1993
- <SignalIcon
1994
- color={
1995
- isAutoRamLimitEnabled
1996
- ? AppColors.purple
1997
- : AppColors.grayTextWeak
1998
- }
1999
- size={15}
2000
- />
2001
- </View>
2002
- <View style={{flex: 1}}>
2003
- <Text
2004
- style={{
2005
- fontFamily: AppFonts.interBold,
2006
- fontSize: 13.5,
2007
- lineHeight: 18,
2008
- color: isAutoRamLimitEnabled
2009
- ? AppColors.primaryBlack
2010
- : AppColors.grayText,
2011
- }}>
2012
- Detected Available RAM
2013
- </Text>
2014
- <Text
2015
- style={{
2016
- fontFamily: AppFonts.interRegular,
2017
- fontSize: 11,
2018
- lineHeight: 15,
2019
- color: AppColors.grayText,
2020
- marginTop: 1,
2021
- }}>
2022
- {deviceFreeRamMb} MB available on device
2023
- </Text>
2024
- </View>
2025
- <View
2026
- style={{
2027
- paddingHorizontal: 10,
2028
- paddingVertical: 5,
2029
- borderRadius: 8,
2030
- backgroundColor: isAutoRamLimitEnabled
2031
- ? `${AppColors.purple}12`
2032
- : AppColors.grayBackground,
2033
- borderWidth: 1,
2034
- borderColor: isAutoRamLimitEnabled
2035
- ? `${AppColors.purple}26`
2036
- : AppColors.dividerColor,
2037
- }}>
2038
- <Text
2039
- style={{
2040
- fontFamily: AppFonts.interBold,
2041
- fontSize: 12,
2042
- lineHeight: 15,
2043
- color: isAutoRamLimitEnabled
2044
- ? AppColors.purple
2045
- : AppColors.grayText,
2046
- }}>
2047
- {deviceFreeRamMb} MB
2048
- </Text>
2049
- </View>
2050
- </View>
2051
-
2052
- {/* Profile Overview */}
2053
- <View
2054
- style={{
2055
- marginTop: 4,
2056
- paddingTop: 8,
2057
- borderTopWidth: 1,
2058
- borderTopColor: AppColors.dividerColor,
2059
- gap: 6,
2060
- }}>
2061
- <View
2062
- style={{
2063
- flexDirection: 'row',
2064
- alignItems: 'center',
2065
- justifyContent: 'space-between',
2066
- }}>
2067
- <Text
2068
- style={{
2069
- fontFamily: AppFonts.interBold,
2070
- fontSize: 11.5,
2071
- lineHeight: 15,
2072
- color: AppColors.purple,
2073
- }}>
2074
- Profile: {autoRamProfile.profileName}
2075
- </Text>
2076
- <View
2077
- style={{
2078
- backgroundColor: isAutoRamLimitEnabled
2079
- ? `${AppColors.emerald500}18`
2080
- : `${AppColors.purple}18`,
2081
- paddingHorizontal: 7,
2082
- paddingVertical: 2.5,
2083
- borderRadius: 4,
2084
- }}>
2085
- <Text
2086
- style={{
2087
- fontFamily: AppFonts.interBold,
2088
- fontSize: 9.5,
2089
- color: isAutoRamLimitEnabled
2090
- ? AppColors.emerald500
2091
- : AppColors.purple,
2092
- }}>
2093
- {isAutoRamLimitEnabled ? 'AUTO-TUNED' : 'MANUAL'}
2094
- </Text>
2095
- </View>
2096
- </View>
2097
-
2098
- <View
2099
- style={{flexDirection: 'row', flexWrap: 'wrap', gap: 8, marginTop: 4}}>
2100
- {[
2101
- {
2102
- label: 'APIs',
2103
- value: isAutoRamLimitEnabled
2104
- ? autoRamProfile.maxNetworkLogs
2105
- : maxNetworkLogs,
2106
- color: AppColors.blue500,
2107
- },
2108
- {
2109
- label: 'Logs',
2110
- value: isAutoRamLimitEnabled
2111
- ? autoRamProfile.maxConsoleLogs
2112
- : maxConsoleLogs,
2113
- color: AppColors.sky500,
2114
- },
2115
- {
2116
- label: 'Analytics',
2117
- value: isAutoRamLimitEnabled
2118
- ? autoRamProfile.maxAnalyticsEvents
2119
- : maxAnalyticsEventsLimit,
2120
- color: AppColors.purple,
2121
- },
2122
- {
2123
- label: 'Crash',
2124
- value: isAutoRamLimitEnabled
2125
- ? autoRamProfile.maxCrashRecords
2126
- : maxCrashLogs,
2127
- color: AppColors.errorColor,
2128
- },
2129
- ].map(item => (
2130
- <View
2131
- key={item.label}
2132
- style={{
2133
- flexDirection: 'row',
2134
- alignItems: 'center',
2135
- gap: 4,
2136
- paddingHorizontal: 8,
2137
- paddingVertical: 4,
2138
- borderRadius: 6,
2139
- backgroundColor: `${item.color}14`,
2140
- borderWidth: 1,
2141
- borderColor: `${item.color}33`,
2142
- }}>
2143
- <Text
2144
- style={{
2145
- fontFamily: AppFonts.interBold,
2146
- fontSize: 10.5,
2147
- lineHeight: 14,
2148
- color: item.color,
2149
- }}>
2150
- {item.label}:
2151
- </Text>
2152
- <Text
2153
- style={{
2154
- fontFamily: AppFonts.interBold,
2155
- fontSize: 10.5,
2156
- lineHeight: 14,
2157
- color: item.color,
2158
- }}>
2159
- {item.value} max
2160
- </Text>
2161
- </View>
2162
- ))}
2163
- </View>
2164
- </View>
2165
- </View>
2166
-
2167
- {/* Section 2: Memory-Safe OS Pruning Shield */}
2168
- <View
2169
- style={{
2170
- backgroundColor: AppColors.primaryLight,
2171
- borderRadius: 14,
2172
- borderWidth: 1,
2173
- borderColor: AppColors.grayBorderSecondary,
2174
- overflow: 'hidden',
2175
- padding: 14,
2176
- gap: 12,
2177
- }}>
2178
- <Text
2179
- style={{
2180
- fontFamily: AppFonts.interBold,
2181
- fontSize: 11,
2182
- lineHeight: 14,
2183
- color: AppColors.grayTextWeak,
2184
- letterSpacing: 0.8,
2185
- }}>
2186
- LOW MEMORY PRESSURE PROTECTION
2187
- </Text>
2188
-
2189
- <View
2190
- style={{flexDirection: 'row', alignItems: 'center', gap: 10}}>
2191
- <View
2192
- style={{
2193
- width: 32,
2194
- height: 32,
2195
- borderRadius: 8,
2196
- backgroundColor: `${AppColors.emerald500}14`,
2197
- alignItems: 'center',
2198
- justifyContent: 'center',
2199
- }}>
2200
- <ShieldAlertIcon color={AppColors.emerald500} size={15} />
2201
- </View>
2202
- <View style={{flex: 1}}>
2203
- <Text
2204
- style={{
2205
- fontFamily: AppFonts.interBold,
2206
- fontSize: 13.5,
2207
- lineHeight: 18,
2208
- color: AppColors.primaryBlack,
2209
- }}>
2210
- OS Memory Warning Guard
2211
- </Text>
2212
- <Text
2213
- style={{
2214
- fontFamily: AppFonts.interRegular,
2215
- fontSize: 11,
2216
- lineHeight: 15,
2217
- color: AppColors.grayText,
2218
- marginTop: 1,
2219
- }}>
2220
- Automatically prunes in-memory buffers by 50% when the OS signals low memory
2221
- </Text>
2222
- </View>
2223
- <View
2224
- style={{
2225
- paddingHorizontal: 8,
2226
- paddingVertical: 3,
2227
- borderRadius: 6,
2228
- backgroundColor: `${AppColors.emerald500}18`,
2229
- }}>
2230
- <Text
2231
- style={{
2232
- fontFamily: AppFonts.interBold,
2233
- fontSize: 10,
2234
- color: AppColors.emerald500,
2235
- }}>
2236
- ACTIVE
2237
- </Text>
2238
- </View>
2239
- </View>
2240
-
2241
- <View
2242
- style={{height: 1, backgroundColor: AppColors.dividerColor}}
2243
- />
2244
-
2245
- {/* Instant Prune Button */}
2246
- <View
2247
- style={{
2248
- flexDirection: 'row',
2249
- alignItems: 'center',
2250
- justifyContent: 'space-between',
2251
- gap: 10,
2252
- }}>
2253
- <View style={{flex: 1}}>
2254
- <Text
2255
- style={{
2256
- fontFamily: AppFonts.interBold,
2257
- fontSize: 13,
2258
- color: AppColors.primaryBlack,
2259
- }}>
2260
- Manual Memory Cleanup
2261
- </Text>
2262
- <Text
2263
- style={{
2264
- fontFamily: AppFonts.interRegular,
2265
- fontSize: 11,
2266
- color: AppColors.grayText,
2267
- marginTop: 1,
2268
- }}>
2269
- Prune older entries across all log stores and free RAM
2270
- </Text>
2271
- </View>
2272
- <TouchableScale
2273
- onPress={() => {
2274
- const summary = pruneAllLogs('manual', 0.5);
2275
- showToast(
2276
- `Pruned ${summary.totalPruned} items from memory`,
2277
- );
2278
- }}
2279
- style={{
2280
- backgroundColor: AppColors.purple,
2281
- paddingHorizontal: 12,
2282
- paddingVertical: 8,
2283
- borderRadius: 8,
2284
- flexDirection: 'row',
2285
- alignItems: 'center',
2286
- gap: 5,
2287
- }}>
2288
- <TrashIcon size={13} color={AppColors.white} />
2289
- <Text
2290
- style={{
2291
- fontFamily: AppFonts.interBold,
2292
- fontSize: 11.5,
2293
- color: AppColors.white,
2294
- }}>
2295
- Prune Now
2296
- </Text>
2297
- </TouchableScale>
2298
- </View>
2299
- </View>
2300
- </View>
2301
- )}
2302
- {settingsActiveSubTab === 'capture' && (
2303
- <View style={{gap: 12}}>
2304
- {/* Screenshot Preferences Card */}
2305
- <View
2306
- style={{
2307
- backgroundColor: AppColors.primaryLight,
2308
- padding: 16,
2309
- borderRadius: 14,
2310
- borderWidth: 1,
2311
- borderColor: AppColors.grayBorderSecondary,
2312
- gap: 12,
2313
- }}>
2314
- <View style={{flexDirection: 'row', alignItems: 'center', gap: 10}}>
2315
- <View
2316
- style={{
2317
- width: 36,
2318
- height: 36,
2319
- borderRadius: 10,
2320
- backgroundColor: AppColors.purpleShade50,
2321
- alignItems: 'center',
2322
- justifyContent: 'center',
2323
- }}>
2324
- <CameraIcon color={AppColors.purple} size={16} />
2325
- </View>
2326
- <View style={{flex: 1}}>
2327
- <Text
2328
- style={{
2329
- fontFamily: AppFonts.interBold,
2330
- fontSize: 14,
2331
- lineHeight: 18,
2332
- color: AppColors.primaryBlack,
2333
- }}>
2334
- {t('settings.media.screenshotCardTitle', 'Screenshot Capture Settings')}
2335
- </Text>
2336
- <Text
2337
- style={{
2338
- fontFamily: AppFonts.interRegular,
2339
- fontSize: 11,
2340
- lineHeight: 15,
2341
- color: AppColors.grayText,
2342
- marginTop: 1,
2343
- }}>
2344
- {t('settings.media.screenshotCardDesc', 'Image encoding format, compression quality and overlay auto-hide')}
2345
- </Text>
2346
- </View>
2347
- </View>
2348
-
2349
- {renderSettingRow({
2350
- icon: <ImageIcon color={AppColors.purple} size={16} />,
2351
- label: t('settings.media.imageFormat', 'Image Format'),
2352
- description: t('settings.media.imageFormatDesc', 'Export formats (PNG lossless, JPEG lossy, WebP)'),
2353
- right: (
2354
- <View style={{flexDirection: 'row', gap: 4}}>
2355
- {['PNG', 'JPEG', 'WEBP'].map(fmt => (
2356
- <View
2357
- key={fmt}
2358
- style={{
2359
- paddingHorizontal: 8,
2360
- paddingVertical: 4,
2361
- borderRadius: 6,
2362
- backgroundColor: fmt === 'PNG' ? AppColors.purple : `${AppColors.purple}1A`,
2363
- }}>
2364
- <Text
2365
- style={{
2366
- fontFamily: AppFonts.interBold,
2367
- fontSize: 10,
2368
- color: fmt === 'PNG' ? AppColors.white : AppColors.purple,
2369
- }}>
2370
- {fmt}
2371
- </Text>
2372
- </View>
2373
- ))}
2374
- </View>
2375
- ),
2376
- })}
2377
-
2378
- {renderSettingRow({
2379
- icon: <EyeIcon color={AppColors.purple} size={16} />,
2380
- label: t('settings.media.autoHide', 'Auto-Hide Inspector During Capture'),
2381
- description: t('settings.media.autoHideDesc', 'Temporarily hides the inspector overlay during screen capture'),
2382
- isLast: true,
2383
- right: (
2384
- <View
2385
- style={{
2386
- paddingHorizontal: 8,
2387
- paddingVertical: 4,
2388
- borderRadius: 6,
2389
- backgroundColor: `${AppColors.emerald500}26`,
2390
- }}>
2391
- <Text
2392
- style={{
2393
- fontFamily: AppFonts.interBold,
2394
- fontSize: 10,
2395
- color: AppColors.emerald500,
2396
- }}>
2397
- {t('settings.media.enabled', 'ON')}
2398
- </Text>
2399
- </View>
2400
- ),
2401
- })}
2402
- </View>
2403
-
2404
- {/* Video & GIF Recording Card */}
2405
- <View
2406
- style={{
2407
- backgroundColor: AppColors.primaryLight,
2408
- padding: 16,
2409
- borderRadius: 14,
2410
- borderWidth: 1,
2411
- borderColor: AppColors.grayBorderSecondary,
2412
- gap: 12,
2413
- }}>
2414
- <View style={{flexDirection: 'row', alignItems: 'center', gap: 10}}>
2415
- <View
2416
- style={{
2417
- width: 36,
2418
- height: 36,
2419
- borderRadius: 10,
2420
- backgroundColor: AppColors.purpleShade50,
2421
- alignItems: 'center',
2422
- justifyContent: 'center',
2423
- }}>
2424
- <VideoCameraIcon color={AppColors.purple} size={16} />
2425
- </View>
2426
- <View style={{flex: 1}}>
2427
- <Text
2428
- style={{
2429
- fontFamily: AppFonts.interBold,
2430
- fontSize: 14,
2431
- lineHeight: 18,
2432
- color: AppColors.primaryBlack,
2433
- }}>
2434
- {t('settings.media.videoCardTitle', 'Video Recording & GIF Conversion')}
2435
- </Text>
2436
- <Text
2437
- style={{
2438
- fontFamily: AppFonts.interRegular,
2439
- fontSize: 11,
2440
- lineHeight: 15,
2441
- color: AppColors.grayText,
2442
- marginTop: 1,
2443
- }}>
2444
- {t('settings.media.videoCardDesc', 'ReplayKit hardware encoding, frame capture fallback and GIF generation')}
2445
- </Text>
2446
- </View>
2447
- </View>
2448
-
2449
- {renderSettingRow({
2450
- icon: <MicrophoneIcon color={AppColors.purple} size={16} />,
2451
- label: t('settings.media.audioMode', 'Audio Source'),
2452
- description: t('settings.media.audioModeDesc', 'Record video with muted, app audio, or microphone commentary'),
2453
- right: (
2454
- <View style={{flexDirection: 'row', gap: 4}}>
2455
- {['Muted', 'App', 'Mic'].map((aud, i) => (
2456
- <View
2457
- key={aud}
2458
- style={{
2459
- paddingHorizontal: 7,
2460
- paddingVertical: 4,
2461
- borderRadius: 6,
2462
- backgroundColor: i === 0 ? AppColors.purple : `${AppColors.purple}1A`,
2463
- }}>
2464
- <Text
2465
- style={{
2466
- fontFamily: AppFonts.interBold,
2467
- fontSize: 10,
2468
- color: i === 0 ? AppColors.white : AppColors.purple,
2469
- }}>
2470
- {aud}
2471
- </Text>
2472
- </View>
2473
- ))}
2474
- </View>
2475
- ),
2476
- })}
2477
-
2478
- {renderSettingRow({
2479
- icon: <FilmIcon color={AppColors.purple} size={16} />,
2480
- label: t('settings.media.frameRate', 'Recording Frame Rate (FPS)'),
2481
- description: t('settings.media.frameRateDesc', 'Target video smoothness: 15, 24, 30, or 60 FPS'),
2482
- right: (
2483
- <View style={{flexDirection: 'row', gap: 4}}>
2484
- {['15', '24', '30', '60'].map(fps => (
2485
- <View
2486
- key={fps}
2487
- style={{
2488
- paddingHorizontal: 6,
2489
- paddingVertical: 4,
2490
- borderRadius: 6,
2491
- backgroundColor: fps === '24' ? AppColors.purple : `${AppColors.purple}1A`,
2492
- }}>
2493
- <Text
2494
- style={{
2495
- fontFamily: AppFonts.interBold,
2496
- fontSize: 10,
2497
- color: fps === '24' ? AppColors.white : AppColors.purple,
2498
- }}>
2499
- {fps}fps
2500
- </Text>
2501
- </View>
2502
- ))}
2503
- </View>
2504
- ),
2505
- })}
2506
-
2507
- {renderSettingRow({
2508
- icon: <GifIcon color={AppColors.purple} size={16} />,
2509
- label: t('settings.media.gifAutoOpt', 'Auto GIF Optimization'),
2510
- description: t('settings.media.gifAutoOptDesc', 'Automatic palette reduction and frame skip for lightweight animated GIFs'),
2511
- isLast: true,
2512
- right: (
2513
- <View
2514
- style={{
2515
- paddingHorizontal: 8,
2516
- paddingVertical: 4,
2517
- borderRadius: 6,
2518
- backgroundColor: `${AppColors.emerald500}26`,
2519
- }}>
2520
- <Text
2521
- style={{
2522
- fontFamily: AppFonts.interBold,
2523
- fontSize: 10,
2524
- color: AppColors.emerald500,
2525
- }}>
2526
- ON
2527
- </Text>
2528
- </View>
2529
- ),
2530
- })}
2531
- </View>
2532
-
2533
- {/* Media Storage Cache Management */}
2534
- <View
2535
- style={{
2536
- backgroundColor: AppColors.primaryLight,
2537
- borderRadius: 14,
2538
- borderWidth: 1,
2539
- borderColor: AppColors.grayBorderSecondary,
2540
- padding: 16,
2541
- }}>
2542
- {renderSettingRow({
2543
- icon: <TrashIcon color={AppColors.errorColor} size={16} />,
2544
- label: t('settings.media.purgeAll', 'Purge Captured Media Cache'),
2545
- description: t('settings.media.purgeAllDesc', 'Delete all local screenshots, screen recordings and converted GIFs'),
2546
- isLast: true,
2547
- onPress: () => {
2548
- Alert.alert(
2549
- t('settings.media.purgeConfirmTitle', 'Purge Media Storage?'),
2550
- t('settings.media.purgeConfirmMessage', 'This will permanently delete all captured screenshots and videos from disk.'),
2551
- [
2552
- {text: t('common.cancel', 'Cancel'), style: 'cancel'},
2553
- {
2554
- text: t('settings.media.purgeCacheBtn', 'Purge All'),
2555
- style: 'destructive',
2556
- onPress: async () => {
2557
- await ScreenCapture.clearAllMedia();
2558
- showToast(t('settings.media.purgedSuccess', 'Media cache cleared successfully'));
2559
- },
2560
- },
2561
- ],
2562
- );
2563
- },
2564
- right: (
2565
- <View
2566
- style={{
2567
- paddingHorizontal: 12,
2568
- paddingVertical: 6,
2569
- borderRadius: 8,
2570
- backgroundColor: `${AppColors.errorColor}14`,
2571
- borderWidth: 1,
2572
- borderColor: `${AppColors.errorColor}33`,
2573
- }}>
2574
- <Text
2575
- style={{
2576
- fontFamily: AppFonts.interBold,
2577
- fontSize: 11,
2578
- lineHeight: 14,
2579
- color: AppColors.errorColor,
2580
- }}>
2581
- {t('settings.media.purgeCacheBtn', 'Purge All')}
2582
- </Text>
2583
- </View>
2584
- ),
2585
- })}
2586
- </View>
2587
- </View>
2588
- )}
2589
- {settingsActiveSubTab === 'about' && (
2590
- <View style={{gap: 14}}>
2591
- {/* Header Hero Branding Card */}
2592
- <View
2593
- style={{
2594
- backgroundColor: AppColors.primaryLight,
2595
- borderRadius: 14,
2596
- borderWidth: 1,
2597
- borderColor: AppColors.grayBorderSecondary,
2598
- padding: 16,
2599
- gap: 12,
2600
- }}>
2601
- <View
2602
- style={{
2603
- flexDirection: 'row',
2604
- alignItems: 'center',
2605
- justifyContent: 'space-between',
2606
- }}>
2607
- <View
2608
- style={{
2609
- flexDirection: 'row',
2610
- alignItems: 'center',
2611
- gap: 12,
2612
- flex: 1,
2613
- }}>
2614
- <View
2615
- style={{
2616
- width: 44,
2617
- height: 44,
2618
- borderRadius: 12,
2619
- backgroundColor: `${AppColors.purple}1A`,
2620
- alignItems: 'center',
2621
- justifyContent: 'center',
2622
- borderWidth: 1,
2623
- borderColor: `${AppColors.purple}33`,
2624
- }}>
2625
- <PackageIcon color={AppColors.purple} size={22} />
2626
- </View>
2627
- <View style={{flex: 1}}>
2628
- <View
2629
- style={{
2630
- flexDirection: 'row',
2631
- alignItems: 'center',
2632
- gap: 8,
2633
- flexWrap: 'wrap',
2634
- }}>
2635
- <Text
2636
- style={{
2637
- fontFamily: AppFonts.interBold,
2638
- fontSize: 15,
2639
- lineHeight: 20,
2640
- color: AppColors.primaryBlack,
2641
- }}>
2642
- In-App Inspector
2643
- </Text>
2644
- <View
2645
- style={{
2646
- backgroundColor: `${AppColors.purple}18`,
2647
- paddingHorizontal: 7,
2648
- paddingVertical: 2,
2649
- borderRadius: 6,
2650
- borderWidth: 1,
2651
- borderColor: `${AppColors.purple}33`,
2652
- }}>
2653
- <Text
2654
- style={{
2655
- fontFamily: AppFonts.interBold,
2656
- fontSize: 10,
2657
- color: AppColors.purple,
2658
- }}>
2659
- v{LIB_VERSION}
2660
- </Text>
2661
- </View>
2662
- {updateAvailable ? (
2663
- <View
2664
- style={{
2665
- flexDirection: 'row',
2666
- alignItems: 'center',
2667
- gap: 3,
2668
- backgroundColor: '#F59E0B20',
2669
- paddingHorizontal: 6,
2670
- paddingVertical: 2,
2671
- borderRadius: 6,
2672
- borderWidth: 1,
2673
- borderColor: '#F59E0B60',
2674
- }}>
2675
- <Text
2676
- style={{
2677
- fontFamily: AppFonts.interBold,
2678
- fontSize: 9.5,
2679
- color: '#D97706',
2680
- }}>
2681
- v{latestNpmVersion} Available
2682
- </Text>
2683
- <BoltIcon size={9} color="#D97706" />
2684
- </View>
2685
- ) : (
2686
- <View
2687
- style={{
2688
- backgroundColor: `${AppColors.emerald500}20`,
2689
- paddingHorizontal: 6,
2690
- paddingVertical: 2,
2691
- borderRadius: 6,
2692
- borderWidth: 1,
2693
- borderColor: `${AppColors.emerald500}50`,
2694
- }}>
2695
- <Text
2696
- style={{
2697
- fontFamily: AppFonts.interBold,
2698
- fontSize: 9.5,
2699
- color: AppColors.emerald600,
2700
- }}>
2701
- Up to date
2702
- </Text>
2703
- </View>
2704
- )}
2705
- </View>
2706
- <Text
2707
- style={{
2708
- fontFamily: AppFonts.interRegular,
2709
- fontSize: 11,
2710
- lineHeight: 15,
2711
- color: AppColors.grayText,
2712
- marginTop: 2,
2713
- }}>
2714
- react-native-inapp-inspector
2715
- </Text>
2716
- </View>
2717
- </View>
2718
- </View>
2719
-
2720
- <Text
2721
- style={{
2722
- fontFamily: AppFonts.interRegular,
2723
- fontSize: 11.5,
2724
- lineHeight: 16,
2725
- color: AppColors.grayText,
2726
- }}>
2727
- High-performance in-app debugging, network logging, console inspection, performance profiling, storage viewer & telemetry diagnostics for React Native.
2728
- </Text>
2729
-
2730
- {updateAvailable && (
2731
- <TouchableScale
2732
- onPress={() => {
2733
- copyToClipboard(
2734
- 'npm install react-native-inapp-inspector@latest',
2735
- 'Install Command',
2736
- );
2737
- showToast('Copied npm upgrade command!');
2738
- }}
2739
- style={{
2740
- backgroundColor: AppColors.purple,
2741
- paddingVertical: 8,
2742
- paddingHorizontal: 12,
2743
- borderRadius: 8,
2744
- flexDirection: 'row',
2745
- alignItems: 'center',
2746
- justifyContent: 'center',
2747
- gap: 6,
2748
- }}>
2749
- <BoltIcon size={12} color={AppColors.white} />
2750
- <Text
2751
- style={{
2752
- fontFamily: AppFonts.interBold,
2753
- fontSize: 12,
2754
- color: AppColors.white,
2755
- }}>
2756
- Copy Upgrade Command (v{latestNpmVersion})
2757
- </Text>
2758
- </TouchableScale>
2759
- )}
2760
- </View>
2761
-
2762
- {/* Quick Actions & Developer Community Grid */}
2763
- <View
2764
- style={{
2765
- flexDirection: 'row',
2766
- flexWrap: 'wrap',
2767
- gap: 8,
2768
- }}>
2769
- <TouchableScale
2770
- onPress={() => {
2771
- Linking.openURL(
2772
- 'https://github.com/vengatmacuser/react-native-inapp-inspector',
2773
- ).catch(() => {});
2774
- }}
2775
- style={{
2776
- flex: 1,
2777
- minWidth: '47%',
2778
- backgroundColor: `${AppColors.purple}0F`,
2779
- borderRadius: 12,
2780
- borderWidth: 1,
2781
- borderColor: `${AppColors.purple}30`,
2782
- paddingVertical: 10,
2783
- paddingHorizontal: 12,
2784
- flexDirection: 'row',
2785
- alignItems: 'center',
2786
- gap: 8,
2787
- }}>
2788
- <GitHubIcon color={AppColors.purple} size={18} />
2789
- <View style={{flex: 1}}>
2790
- <Text
2791
- style={{
2792
- fontFamily: AppFonts.interBold,
2793
- fontSize: 11.5,
2794
- color: AppColors.primaryBlack,
2795
- }}>
2796
- ⭐ Star on GitHub
2797
- </Text>
2798
- <Text
2799
- style={{
2800
- fontFamily: AppFonts.interRegular,
2801
- fontSize: 9.5,
2802
- color: AppColors.grayText,
2803
- }}>
2804
- Support open source
2805
- </Text>
2806
- </View>
2807
- </TouchableScale>
2808
-
2809
- <TouchableScale
2810
- onPress={() => {
2811
- Linking.openURL(
2812
- 'https://www.npmjs.com/package/react-native-inapp-inspector',
2813
- ).catch(() => {});
2814
- }}
2815
- style={{
2816
- flex: 1,
2817
- minWidth: '47%',
2818
- backgroundColor: AppColors.primaryLight,
2819
- borderRadius: 12,
2820
- borderWidth: 1,
2821
- borderColor: AppColors.grayBorderSecondary,
2822
- paddingVertical: 10,
2823
- paddingHorizontal: 12,
2824
- flexDirection: 'row',
2825
- alignItems: 'center',
2826
- gap: 8,
2827
- }}>
2828
- <NpmIcon color="#CB3837" size={18} />
2829
- <View style={{flex: 1}}>
2830
- <Text
2831
- style={{
2832
- fontFamily: AppFonts.interBold,
2833
- fontSize: 11.5,
2834
- color: AppColors.primaryBlack,
2835
- }}>
2836
- NPM Registry
2837
- </Text>
2838
- <Text
2839
- style={{
2840
- fontFamily: AppFonts.interRegular,
2841
- fontSize: 9.5,
2842
- color: AppColors.grayText,
2843
- }}>
2844
- Package repository
2845
- </Text>
2846
- </View>
2847
- </TouchableScale>
2848
-
2849
- <TouchableScale
2850
- onPress={() => {
2851
- Linking.openURL(
2852
- 'https://github.com/vengatmacuser/react-native-inapp-inspector#readme',
2853
- ).catch(() => {});
2854
- }}
2855
- style={{
2856
- flex: 1,
2857
- minWidth: '47%',
2858
- backgroundColor: AppColors.primaryLight,
2859
- borderRadius: 12,
2860
- borderWidth: 1,
2861
- borderColor: AppColors.grayBorderSecondary,
2862
- paddingVertical: 10,
2863
- paddingHorizontal: 12,
2864
- flexDirection: 'row',
2865
- alignItems: 'center',
2866
- gap: 8,
2867
- }}>
2868
- <Text style={{fontSize: 16}}>📖</Text>
2869
- <View style={{flex: 1}}>
2870
- <Text
2871
- style={{
2872
- fontFamily: AppFonts.interBold,
2873
- fontSize: 11.5,
2874
- color: AppColors.primaryBlack,
2875
- }}>
2876
- Documentation
2877
- </Text>
2878
- <Text
2879
- style={{
2880
- fontFamily: AppFonts.interRegular,
2881
- fontSize: 9.5,
2882
- color: AppColors.grayText,
2883
- }}>
2884
- Setup & API guide
2885
- </Text>
2886
- </View>
2887
- </TouchableScale>
2888
-
2889
- <TouchableScale
2890
- onPress={() => {
2891
- Linking.openURL(
2892
- 'https://github.com/vengatmacuser/react-native-inapp-inspector/issues',
2893
- ).catch(() => {});
2894
- }}
2895
- style={{
2896
- flex: 1,
2897
- minWidth: '47%',
2898
- backgroundColor: AppColors.primaryLight,
2899
- borderRadius: 12,
2900
- borderWidth: 1,
2901
- borderColor: AppColors.grayBorderSecondary,
2902
- paddingVertical: 10,
2903
- paddingHorizontal: 12,
2904
- flexDirection: 'row',
2905
- alignItems: 'center',
2906
- gap: 8,
2907
- }}>
2908
- <Text style={{fontSize: 16}}>🐞</Text>
2909
- <View style={{flex: 1}}>
2910
- <Text
2911
- style={{
2912
- fontFamily: AppFonts.interBold,
2913
- fontSize: 11.5,
2914
- color: AppColors.primaryBlack,
2915
- }}>
2916
- Report Issue
2917
- </Text>
2918
- <Text
2919
- style={{
2920
- fontFamily: AppFonts.interRegular,
2921
- fontSize: 9.5,
2922
- color: AppColors.grayText,
2923
- }}>
2924
- Bugs & feature requests
2925
- </Text>
2926
- </View>
2927
- </TouchableScale>
2928
-
2929
- <TouchableScale
2930
- onPress={() => {
2931
- Linking.openURL(
2932
- 'https://github.com/vengatmacuser/react-native-inapp-inspector/releases',
2933
- ).catch(() => {});
2934
- }}
2935
- style={{
2936
- flex: 1,
2937
- minWidth: '47%',
2938
- backgroundColor: AppColors.primaryLight,
2939
- borderRadius: 12,
2940
- borderWidth: 1,
2941
- borderColor: AppColors.grayBorderSecondary,
2942
- paddingVertical: 10,
2943
- paddingHorizontal: 12,
2944
- flexDirection: 'row',
2945
- alignItems: 'center',
2946
- gap: 8,
2947
- }}>
2948
- <Text style={{fontSize: 16}}>🏷️</Text>
2949
- <View style={{flex: 1}}>
2950
- <Text
2951
- style={{
2952
- fontFamily: AppFonts.interBold,
2953
- fontSize: 11.5,
2954
- color: AppColors.primaryBlack,
2955
- }}>
2956
- Release Notes
2957
- </Text>
2958
- <Text
2959
- style={{
2960
- fontFamily: AppFonts.interRegular,
2961
- fontSize: 9.5,
2962
- color: AppColors.grayText,
2963
- }}>
2964
- Version changelog
2965
- </Text>
2966
- </View>
2967
- </TouchableScale>
2968
-
2969
- <TouchableScale
2970
- onPress={() => {
2971
- const win = Dimensions.get('window');
2972
- const scr = Dimensions.get('screen');
2973
- const rnVer = (Platform.constants as any)?.reactNativeVersion;
2974
- const specsPayload = {
2975
- package: {
2976
- name: 'react-native-inapp-inspector',
2977
- version: `v${LIB_VERSION}`,
2978
- latestNpmVersion: latestNpmVersion ? `v${latestNpmVersion}` : 'Checking...',
2979
- license: 'MIT',
2980
- repository: 'https://github.com/vengatmacuser/react-native-inapp-inspector',
2981
- },
2982
- hostApp: {
2983
- name: getAppName(),
2984
- bundleId: getBundleIdentifier(),
2985
- versionAndBuild: getAppVersionAndBuild().formatted,
2986
- buildVariant: __DEV__ ? 'Development (Debug)' : 'Production (Release)',
2987
- metroConnected: isLocalDebugEnvironment(),
2988
- },
2989
- runtime: {
2990
- reactNativeVersion: rnVer ? `${rnVer.major}.${rnVer.minor}.${rnVer.patch}` : '0.74+',
2991
- reactVersion: React.version,
2992
- jsEngine: Boolean((global as any)?.HermesInternal) ? 'Hermes' : 'JavaScriptCore (JSC)',
2993
- architecture: Boolean((global as any)?.nativeFabricUIManager) ? 'Fabric (New Architecture)' : 'Paper (Legacy Bridge)',
2994
- turboModules: Boolean((global as any)?.__turboModuleProxy || (global as any)?.TurboModuleRegistry),
2995
- },
2996
- device: {
2997
- platform: Platform.OS,
2998
- osVersion: Platform.Version,
2999
- deviceModel: (Platform.constants as any)?.Model || 'Unknown Device',
3000
- windowDimensions: `${Math.round(win.width)}x${Math.round(win.height)} pt`,
3001
- screenDimensions: `${Math.round(scr.width)}x${Math.round(scr.height)} pt`,
3002
- pixelRatio: PixelRatio.get(),
3003
- fontScale: PixelRatio.getFontScale(),
3004
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'Unknown',
3005
- locale: Intl.DateTimeFormat().resolvedOptions().locale || 'en',
3006
- },
3007
- storageAndCapabilities: {
3008
- storageEngine: isPersistentStorageAvailable() ? 'MMKV (Fast Native Storage)' : 'In-Memory State',
3009
- hasNativeModule: Boolean((global as any)?.NativeInspectorModule || (global as any)?.__IN_APP_INSPECTOR_NATIVE__),
3010
- reduxConnected: isReduxConnected(),
3011
- analyticsConnected: isAnalyticsConnected(),
3012
- },
3013
- };
3014
-
3015
- copyToClipboard(
3016
- JSON.stringify(specsPayload, null, 2),
3017
- 'Diagnostic Specifications',
3018
- );
3019
- showToast('Copied full diagnostic specs to clipboard!');
3020
- }}
3021
- style={{
3022
- flex: 1,
3023
- minWidth: '47%',
3024
- backgroundColor: AppColors.primaryLight,
3025
- borderRadius: 12,
3026
- borderWidth: 1,
3027
- borderColor: AppColors.grayBorderSecondary,
3028
- paddingVertical: 10,
3029
- paddingHorizontal: 12,
3030
- flexDirection: 'row',
3031
- alignItems: 'center',
3032
- gap: 8,
3033
- }}>
3034
- <CopyIcon color={AppColors.purple} size={16} />
3035
- <View style={{flex: 1}}>
3036
- <Text
3037
- style={{
3038
- fontFamily: AppFonts.interBold,
3039
- fontSize: 11.5,
3040
- color: AppColors.primaryBlack,
3041
- }}>
3042
- Copy Specs JSON
3043
- </Text>
3044
- <Text
3045
- style={{
3046
- fontFamily: AppFonts.interRegular,
3047
- fontSize: 9.5,
3048
- color: AppColors.grayText,
3049
- }}>
3050
- Diagnostics payload
3051
- </Text>
3052
- </View>
3053
- </TouchableScale>
3054
- </View>
3055
-
3056
- {/* Section: Package Version & Upgrades */}
3057
- <View
3058
- style={{
3059
- backgroundColor: AppColors.primaryLight,
3060
- borderRadius: 14,
3061
- borderWidth: 1,
3062
- borderColor: AppColors.grayBorderSecondary,
3063
- overflow: 'hidden',
3064
- padding: 14,
3065
- gap: 12,
3066
- }}>
3067
- <Text
3068
- style={{
3069
- fontFamily: AppFonts.interBold,
3070
- fontSize: 11,
3071
- lineHeight: 14,
3072
- color: AppColors.grayTextWeak,
3073
- letterSpacing: 0.8,
3074
- }}>
3075
- PACKAGE VERSION & UPGRADES
3076
- </Text>
3077
-
3078
- <View
3079
- style={{
3080
- flexDirection: 'row',
3081
- alignItems: 'center',
3082
- justifyContent: 'space-between',
3083
- }}>
3084
- <View
3085
- style={{
3086
- flexDirection: 'row',
3087
- alignItems: 'center',
3088
- gap: 10,
3089
- flex: 1,
3090
- marginRight: 8,
3091
- }}>
3092
- <View
3093
- style={{
3094
- width: 34,
3095
- height: 34,
3096
- borderRadius: 9,
3097
- backgroundColor: '#CB383715',
3098
- alignItems: 'center',
3099
- justifyContent: 'center',
3100
- }}>
3101
- <NpmIcon color="#CB3837" size={17} />
3102
- </View>
3103
- <View style={{flex: 1}}>
3104
- <View
3105
- style={{
3106
- flexDirection: 'row',
3107
- alignItems: 'center',
3108
- gap: 6,
3109
- }}>
3110
- <Text
3111
- style={{
3112
- fontFamily: AppFonts.interBold,
3113
- fontSize: 14,
3114
- lineHeight: 18,
3115
- color: AppColors.primaryBlack,
3116
- }}>
3117
- v{LIB_VERSION}
3118
- </Text>
3119
- {updateAvailable ? (
3120
- <View
3121
- style={{
3122
- flexDirection: 'row',
3123
- alignItems: 'center',
3124
- gap: 3,
3125
- backgroundColor: '#F59E0B20',
3126
- paddingHorizontal: 6,
3127
- paddingVertical: 1.5,
3128
- borderRadius: 5,
3129
- borderWidth: 1,
3130
- borderColor: '#F59E0B60',
3131
- }}>
3132
- <Text
3133
- style={{
3134
- fontFamily: AppFonts.interBold,
3135
- fontSize: 9.5,
3136
- color: '#D97706',
3137
- }}>
3138
- v{latestNpmVersion} Available
3139
- </Text>
3140
- <BoltIcon size={9} color="#D97706" />
3141
- </View>
3142
- ) : (
3143
- <View
3144
- style={{
3145
- backgroundColor: `${AppColors.emerald500}20`,
3146
- paddingHorizontal: 6,
3147
- paddingVertical: 1.5,
3148
- borderRadius: 5,
3149
- borderWidth: 1,
3150
- borderColor: `${AppColors.emerald500}50`,
3151
- }}>
3152
- <Text
3153
- style={{
3154
- fontFamily: AppFonts.interBold,
3155
- fontSize: 9.5,
3156
- color: AppColors.emerald600,
3157
- }}>
3158
- Up to date
3159
- </Text>
3160
- </View>
3161
- )}
3162
- </View>
3163
- <Text
3164
- style={{
3165
- fontFamily: AppFonts.interRegular,
3166
- fontSize: 11,
3167
- lineHeight: 15,
3168
- color: AppColors.grayText,
3169
- marginTop: 1,
3170
- }}>
3171
- {updateAvailable
3172
- ? `A newer release (v${latestNpmVersion}) is available on npm registry.`
3173
- : 'You are running the latest version from npm registry.'}
3174
- </Text>
3175
- </View>
3176
- </View>
3177
-
3178
- <TouchableScale
3179
- onPress={() => {
3180
- copyToClipboard(
3181
- 'npm install react-native-inapp-inspector@latest',
3182
- 'Install Command',
3183
- );
3184
- showToast('Copied npm install command!');
3185
- }}
3186
- style={{
3187
- backgroundColor: updateAvailable ? AppColors.purple : `${AppColors.purple}18`,
3188
- paddingVertical: 7,
3189
- paddingHorizontal: 11,
3190
- borderRadius: 8,
3191
- flexDirection: 'row',
3192
- alignItems: 'center',
3193
- gap: 5,
3194
- }}>
3195
- <CopyIcon color={updateAvailable ? AppColors.white : AppColors.purple} size={12} />
3196
- <Text
3197
- style={{
3198
- fontFamily: AppFonts.interBold,
3199
- fontSize: 11,
3200
- color: updateAvailable ? AppColors.white : AppColors.purple,
3201
- }}>
3202
- {updateAvailable ? 'Copy Upgrade' : 'Copy Install'}
3203
- </Text>
3204
- </TouchableScale>
3205
- </View>
3206
- </View>
3207
-
3208
- {/* Section 1: Host Application Specs */}
3209
- <View
3210
- style={{
3211
- backgroundColor: AppColors.primaryLight,
3212
- borderRadius: 14,
3213
- borderWidth: 1,
3214
- borderColor: AppColors.grayBorderSecondary,
3215
- padding: 14,
3216
- gap: 10,
3217
- }}>
3218
- <Text
3219
- style={{
3220
- fontFamily: AppFonts.interBold,
3221
- fontSize: 11,
3222
- lineHeight: 14,
3223
- color: AppColors.grayTextWeak,
3224
- letterSpacing: 0.8,
3225
- }}>
3226
- HOST APPLICATION & BUILD
3227
- </Text>
3228
-
3229
- <View style={{gap: 8}}>
3230
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3231
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3232
- Application Name
3233
- </Text>
3234
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3235
- {getAppName()}
3236
- </Text>
3237
- </View>
3238
-
3239
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3240
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3241
- Bundle ID / Package
3242
- </Text>
3243
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11, color: AppColors.primaryBlack}}>
3244
- {getBundleIdentifier()}
3245
- </Text>
3246
- </View>
3247
-
3248
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3249
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3250
- Version & Build Number
3251
- </Text>
3252
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3253
- {getAppVersionAndBuild().formatted}
3254
- </Text>
3255
- </View>
3256
-
3257
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3258
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3259
- Build Variant
3260
- </Text>
3261
- <View
3262
- style={{
3263
- backgroundColor: __DEV__ ? `${AppColors.amber500}20` : `${AppColors.emerald500}20`,
3264
- paddingHorizontal: 6,
3265
- paddingVertical: 1.5,
3266
- borderRadius: 5,
3267
- borderWidth: 1,
3268
- borderColor: __DEV__ ? `${AppColors.amber500}50` : `${AppColors.emerald500}50`,
3269
- }}>
3270
- <Text
3271
- style={{
3272
- fontFamily: AppFonts.interBold,
3273
- fontSize: 10,
3274
- color: __DEV__ ? AppColors.amber500 : AppColors.emerald600,
3275
- }}>
3276
- {__DEV__ ? 'Development (Debug)' : 'Production (Release)'}
3277
- </Text>
3278
- </View>
3279
- </View>
3280
-
3281
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3282
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3283
- Metro Bundler Connection
3284
- </Text>
3285
- <Text
3286
- style={{
3287
- fontFamily: AppFonts.interBold,
3288
- fontSize: 11.5,
3289
- color: isLocalDebugEnvironment() ? AppColors.emerald600 : AppColors.grayText,
3290
- }}>
3291
- {isLocalDebugEnvironment() ? 'Connected (Hot Reload Active)' : 'Offline / Standalone'}
3292
- </Text>
3293
- </View>
3294
- </View>
3295
- </View>
3296
-
3297
- {/* Section 2: React Native Engine & Runtime Specs */}
3298
- <View
3299
- style={{
3300
- backgroundColor: AppColors.primaryLight,
3301
- borderRadius: 14,
3302
- borderWidth: 1,
3303
- borderColor: AppColors.grayBorderSecondary,
3304
- padding: 14,
3305
- gap: 10,
3306
- }}>
3307
- <Text
3308
- style={{
3309
- fontFamily: AppFonts.interBold,
3310
- fontSize: 11,
3311
- lineHeight: 14,
3312
- color: AppColors.grayTextWeak,
3313
- letterSpacing: 0.8,
3314
- }}>
3315
- FRAMEWORK & RUNTIME ENGINE
3316
- </Text>
3317
-
3318
- <View style={{gap: 8}}>
3319
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3320
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3321
- React Native Version
3322
- </Text>
3323
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3324
- v{((Platform.constants as any)?.reactNativeVersion?.major != null)
3325
- ? `${(Platform.constants as any).reactNativeVersion.major}.${(Platform.constants as any).reactNativeVersion.minor}.${(Platform.constants as any).reactNativeVersion.patch}`
3326
- : '0.74+'}
3327
- </Text>
3328
- </View>
3329
-
3330
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3331
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3332
- React Core Version
3333
- </Text>
3334
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3335
- v{React.version}
3336
- </Text>
3337
- </View>
3338
-
3339
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3340
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3341
- JavaScript Engine
3342
- </Text>
3343
- <View
3344
- style={{
3345
- backgroundColor: `${AppColors.purple}15`,
3346
- paddingHorizontal: 6,
3347
- paddingVertical: 1.5,
3348
- borderRadius: 5,
3349
- borderWidth: 1,
3350
- borderColor: `${AppColors.purple}40`,
3351
- }}>
3352
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 10.5, color: AppColors.purple}}>
3353
- {Boolean((global as any)?.HermesInternal) ? 'Hermes Engine (Active)' : 'JavaScriptCore (JSC)'}
3354
- </Text>
3355
- </View>
3356
- </View>
3357
-
3358
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3359
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3360
- Rendering Architecture
3361
- </Text>
3362
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3363
- {Boolean((global as any)?.nativeFabricUIManager) ? 'Fabric (New Architecture)' : 'Paper (Legacy Bridge)'}
3364
- </Text>
3365
- </View>
3366
-
3367
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3368
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3369
- TurboModules Support
3370
- </Text>
3371
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3372
- {Boolean((global as any)?.__turboModuleProxy || (global as any)?.TurboModuleRegistry)
3373
- ? 'Enabled (C++ JSI)'
3374
- : 'Standard Bridge'}
3375
- </Text>
3376
- </View>
3377
- </View>
3378
- </View>
3379
-
3380
- {/* Section 3: Device & Display Metrics */}
3381
- <View
3382
- style={{
3383
- backgroundColor: AppColors.primaryLight,
3384
- borderRadius: 14,
3385
- borderWidth: 1,
3386
- borderColor: AppColors.grayBorderSecondary,
3387
- padding: 14,
3388
- gap: 10,
3389
- }}>
3390
- <Text
3391
- style={{
3392
- fontFamily: AppFonts.interBold,
3393
- fontSize: 11,
3394
- lineHeight: 14,
3395
- color: AppColors.grayTextWeak,
3396
- letterSpacing: 0.8,
3397
- }}>
3398
- DEVICE & DISPLAY METRICS
3399
- </Text>
3400
-
3401
- <View style={{gap: 8}}>
3402
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3403
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3404
- Operating System
3405
- </Text>
3406
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3407
- {Platform.OS === 'ios' ? 'Apple iOS' : Platform.OS === 'android' ? 'Google Android' : Platform.OS}{' '}
3408
- {Platform.Version}
3409
- </Text>
3410
- </View>
3411
-
3412
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3413
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3414
- Device Hardware Model
3415
- </Text>
3416
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3417
- {(Platform.constants as any)?.Model ||
3418
- (Platform.OS === 'ios' ? 'Apple Device' : 'Android Device')}
3419
- </Text>
3420
- </View>
3421
-
3422
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3423
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3424
- Window Viewport (Points)
3425
- </Text>
3426
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3427
- {Math.round(Dimensions.get('window').width)} × {Math.round(Dimensions.get('window').height)} pt
3428
- </Text>
3429
- </View>
3430
-
3431
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3432
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3433
- Native Physical Resolution
3434
- </Text>
3435
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3436
- {Math.round(Dimensions.get('screen').width * PixelRatio.get())} × {Math.round(Dimensions.get('screen').height * PixelRatio.get())} px
3437
- </Text>
3438
- </View>
3439
-
3440
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3441
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3442
- Pixel Density & Font Scale
3443
- </Text>
3444
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3445
- {PixelRatio.get().toFixed(1)}x ({PixelRatio.get() >= 3 ? '@3x' : PixelRatio.get() >= 2 ? '@2x' : '@1x'}) • Font: {PixelRatio.getFontScale().toFixed(2)}x
3446
- </Text>
3447
- </View>
3448
-
3449
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3450
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3451
- Timezone & Locale
3452
- </Text>
3453
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3454
- {Intl.DateTimeFormat().resolvedOptions().timeZone || 'System'} ({Intl.DateTimeFormat().resolvedOptions().locale || 'en'})
3455
- </Text>
3456
- </View>
3457
- </View>
3458
- </View>
3459
-
3460
- {/* Section 4: Inspector Capabilities & Storage */}
3461
- <View
3462
- style={{
3463
- backgroundColor: AppColors.primaryLight,
3464
- borderRadius: 14,
3465
- borderWidth: 1,
3466
- borderColor: AppColors.grayBorderSecondary,
3467
- padding: 14,
3468
- gap: 10,
3469
- }}>
3470
- <Text
3471
- style={{
3472
- fontFamily: AppFonts.interBold,
3473
- fontSize: 11,
3474
- lineHeight: 14,
3475
- color: AppColors.grayTextWeak,
3476
- letterSpacing: 0.8,
3477
- }}>
3478
- INSPECTOR STORAGE & CAPABILITIES
3479
- </Text>
3480
-
3481
- <View style={{gap: 8}}>
3482
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3483
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3484
- Storage Persistence Engine
3485
- </Text>
3486
- <View
3487
- style={{
3488
- backgroundColor: isPersistentStorageAvailable() ? `${AppColors.emerald500}18` : `${AppColors.amber500}18`,
3489
- paddingHorizontal: 6,
3490
- paddingVertical: 1.5,
3491
- borderRadius: 5,
3492
- borderWidth: 1,
3493
- borderColor: isPersistentStorageAvailable() ? `${AppColors.emerald500}50` : `${AppColors.amber500}50`,
3494
- }}>
3495
- <Text
3496
- style={{
3497
- fontFamily: AppFonts.interBold,
3498
- fontSize: 10.5,
3499
- color: isPersistentStorageAvailable() ? AppColors.emerald600 : AppColors.amber500,
3500
- }}>
3501
- {isPersistentStorageAvailable() ? 'MMKV Fast Native Storage' : 'In-Memory State'}
3502
- </Text>
3503
- </View>
3504
- </View>
3505
-
3506
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3507
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3508
- Native Module Status
3509
- </Text>
3510
- <Text
3511
- style={{
3512
- fontFamily: AppFonts.interBold,
3513
- fontSize: 11.5,
3514
- color: Boolean((global as any)?.NativeInspectorModule) ? AppColors.emerald600 : AppColors.grayText,
3515
- }}>
3516
- {Boolean((global as any)?.NativeInspectorModule) ? 'Linked & Active' : 'JavaScript Only'}
3517
- </Text>
3518
- </View>
3519
-
3520
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3521
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3522
- Network Logger Interceptor
3523
- </Text>
3524
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.emerald600}}>
3525
- Active (XMLHttpRequest & Fetch Hooked)
3526
- </Text>
3527
- </View>
3528
-
3529
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3530
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3531
- Redux & Analytics Watchers
3532
- </Text>
3533
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3534
- Redux: {isReduxConnected() ? 'Connected' : 'Listening'} • Analytics: {isAnalyticsConnected() ? 'Connected' : 'Listening'}
3535
- </Text>
3536
- </View>
3537
-
3538
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3539
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3540
- Crash & Exception Boundary
3541
- </Text>
3542
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.emerald600}}>
3543
- Global JS Exception Handler Active
3544
- </Text>
3545
- </View>
3546
-
3547
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3548
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3549
- Memory Management
3550
- </Text>
3551
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.emerald600}}>
3552
- Dynamic Auto RAM Tiering Active
3553
- </Text>
3554
- </View>
3555
- </View>
3556
- </View>
3557
-
3558
- {/* Section 5: License & Copyright */}
3559
- <View
3560
- style={{
3561
- backgroundColor: AppColors.primaryLight,
3562
- borderRadius: 14,
3563
- borderWidth: 1,
3564
- borderColor: AppColors.grayBorderSecondary,
3565
- padding: 14,
3566
- gap: 8,
3567
- }}>
3568
- <Text
3569
- style={{
3570
- fontFamily: AppFonts.interBold,
3571
- fontSize: 11,
3572
- lineHeight: 14,
3573
- color: AppColors.grayTextWeak,
3574
- letterSpacing: 0.8,
3575
- }}>
3576
- LICENSE & CREDITS
3577
- </Text>
3578
-
3579
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3580
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3581
- License
3582
- </Text>
3583
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.emerald600}}>
3584
- MIT Permissive Open Source
3585
- </Text>
3586
- </View>
3587
-
3588
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3589
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3590
- Created & Maintained By
3591
- </Text>
3592
- <Text style={{fontFamily: AppFonts.interBold, fontSize: 11.5, color: AppColors.primaryBlack}}>
3593
- Vengateswaran
3594
- </Text>
3595
- </View>
3596
-
3597
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
3598
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11.5, color: AppColors.grayText}}>
3599
- Repository
3600
- </Text>
3601
- <Text style={{fontFamily: AppFonts.interRegular, fontSize: 11, color: AppColors.purple}}>
3602
- github.com/vengatmacuser/react-native-inapp-inspector
3603
- </Text>
3604
- </View>
3605
- </View>
3606
- </View>
3607
- )}
3608
- <View style={{height: 48}} />
3609
- </ScrollView>
3610
-
3611
- {/* Bottom Sticky Action Bar for Save Changes */}
3612
- {settingsActiveSubTab === 'module' && (
3613
- <View
3614
- style={{
3615
- paddingHorizontal: 16,
3616
- paddingTop: 12,
3617
- paddingBottom: Platform.OS === 'ios' ? 36 : 24,
3618
- backgroundColor: AppColors.primaryLight,
3619
- borderTopWidth: 1,
3620
- borderTopColor: AppColors.dividerColor,
3621
- flexDirection: 'row',
3622
- alignItems: 'center',
3623
- gap: 12,
3624
- shadowColor: AppColors.black,
3625
- shadowOpacity: 0.08,
3626
- shadowRadius: 8,
3627
- shadowOffset: {width: 0, height: -3},
3628
- elevation: 8,
3629
- }}>
3630
- <View style={{flex: 1}}>
3631
- <Text
3632
- style={{
3633
- fontFamily: AppFonts.interBold,
3634
- fontSize: 13,
3635
- lineHeight: 17,
3636
- color: AppColors.primaryBlack,
3637
- }}>
3638
- {stagedActiveCount} of {allModules.length} Modules Active
3639
- </Text>
3640
- <Text
3641
- style={{
3642
- fontFamily: AppFonts.interRegular,
3643
- fontSize: 11,
3644
- lineHeight: 15,
3645
- color: hasUnsavedChanges
3646
- ? AppColors.purple
3647
- : AppColors.grayText,
3648
- marginTop: 1,
3649
- }}>
3650
- {hasUnsavedChanges
3651
- ? t('settings.unsavedPending')
3652
- : t('settings.allSynchronized')}
3653
- </Text>
3654
- </View>
3655
-
3656
- <TouchableScale
3657
- accessible={true}
3658
- accessibilityRole="button"
3659
- accessibilityLabel="Save Changes"
3660
- onPress={handleSaveChanges}
3661
- style={{
3662
- flexDirection: 'row',
3663
- alignItems: 'center',
3664
- gap: 6,
3665
- backgroundColor: hasUnsavedChanges
3666
- ? AppColors.purple
3667
- : `${AppColors.purple}22`,
3668
- paddingHorizontal: 18,
3669
- paddingVertical: 10,
3670
- borderRadius: 10,
3671
- }}>
3672
- <CheckIcon
3673
- size={14}
3674
- color={hasUnsavedChanges ? AppColors.white : AppColors.purple}
3675
- />
3676
- <Text
3677
- style={{
3678
- fontFamily: AppFonts.interBold,
3679
- fontSize: 13,
3680
- lineHeight: 17,
3681
- color: hasUnsavedChanges ? AppColors.white : AppColors.purple,
3682
- }}>
3683
- {t('settings.saveChanges')}
3684
- </Text>
3685
- </TouchableScale>
3686
- </View>
3687
- )}
3688
- </View>
3689
- );
3690
-
3691
- let content: React.ReactNode = null;
3692
- let title = '';
3693
- let icon: React.ReactNode = null;
3694
- let rightInfo = '';
3695
-
3696
- if (settingsPage === 'apis') {
3697
- title = t('settings.apis.title');
3698
- icon = <SignalIcon color={AppColors.white} size={16} />;
3699
- rightInfo = t('settings.apis.total', {count: logs.length});
3700
- content = (
3701
- <ScrollView
3702
- style={{flex: 1}}
3703
- contentContainerStyle={{padding: 16, paddingBottom: 100, gap: 12}}>
3704
- <View
3705
- style={{
3706
- backgroundColor: AppColors.primaryLight,
3707
- padding: 16,
3708
- borderRadius: 14,
3709
- borderWidth: 1,
3710
- borderColor: AppColors.grayBorderSecondary,
3711
- }}>
3712
- {renderSettingRow({
3713
- icon: <SignalIcon color={AppColors.purple} size={16} />,
3714
- label: t('settings.apis.maxRequestLogs'),
3715
- description: t('settings.apis.maxRequestLogsDescription'),
3716
- numericInput: {
3717
- value: maxNetworkLogs,
3718
- onChange: setMaxNetworkLogs,
3719
- min: 10,
3720
- max: 100,
3721
- placeholder: 'Enter max requests (10-100)',
3722
- },
3723
- isLast: true,
3724
- })}
3725
- </View>
3726
-
3727
- <View
3728
- style={{
3729
- backgroundColor: AppColors.primaryLight,
3730
- borderRadius: 14,
3731
- borderWidth: 1,
3732
- borderColor: AppColors.grayBorderSecondary,
3733
- padding: 16,
3734
- }}>
3735
- {renderSettingRow({
3736
- icon: <TrashIcon color={AppColors.errorColor} size={16} />,
3737
- label: t('settings.apis.clearNetworkLogs'),
3738
- description: t('settings.apis.clearNetworkLogsDescription', {
3739
- count: logs.length,
3740
- }),
3741
- isLast: true,
3742
- onPress: () => {
3743
- clearNetworkLogs();
3744
- setSelected(null);
3745
- Alert.alert(
3746
- t('common.success'),
3747
- t('settings.apis.networkLogsCleared'),
3748
- );
3749
- },
3750
- right: (
3751
- <View
3752
- style={{
3753
- paddingHorizontal: 12,
3754
- paddingVertical: 6,
3755
- borderRadius: 8,
3756
- backgroundColor: `${AppColors.errorColor}14`,
3757
- borderWidth: 1,
3758
- borderColor: `${AppColors.errorColor}33`,
3759
- }}>
3760
- <Text
3761
- style={{
3762
- fontFamily: AppFonts.interBold,
3763
- fontSize: 11,
3764
- lineHeight: 14,
3765
- color: AppColors.errorColor,
3766
- }}>
3767
- {t('common.clear')}
3768
- </Text>
3769
- </View>
3770
- ),
3771
- })}
3772
- </View>
3773
- <View style={{height: 48}} />
3774
- </ScrollView>
3775
- );
3776
- } else if (settingsPage === 'logs') {
3777
- title = t('settings.logs.title');
3778
- icon = <TerminalIcon color={AppColors.white} size={16} />;
3779
- rightInfo = t('settings.logs.total', {count: consoleLogs.length});
3780
- content = (
3781
- <ScrollView
3782
- style={{flex: 1}}
3783
- contentContainerStyle={{padding: 16, paddingBottom: 100, gap: 12}}>
3784
- <View
3785
- style={{
3786
- backgroundColor: AppColors.primaryLight,
3787
- padding: 16,
3788
- borderRadius: 14,
3789
- borderWidth: 1,
3790
- borderColor: AppColors.grayBorderSecondary,
3791
- gap: 4,
3792
- }}>
3793
- {renderSettingRow({
3794
- icon: <TerminalIcon color={AppColors.purple} size={16} />,
3795
- label: t('settings.logs.maxConsoleLogs'),
3796
- description: t('settings.logs.maxConsoleLogsDescription'),
3797
- numericInput: {
3798
- value: maxConsoleLogs,
3799
- onChange: setMaxConsoleLogs,
3800
- min: 10,
3801
- max: 100,
3802
- placeholder: 'Enter max logs (10-100)',
3803
- },
3804
- })}
3805
- <View style={{height: 1, backgroundColor: AppColors.dividerColor}} />
3806
- <Text
3807
- style={{
3808
- fontFamily: AppFonts.interBold,
3809
- fontSize: 13,
3810
- lineHeight: 17,
3811
- color: AppColors.primaryBlack,
3812
- paddingTop: 6,
3813
- }}>
3814
- {t('settings.logs.logLevels')}
3815
- </Text>
3816
- {(['info', 'warn', 'error'] as const).map(level => {
3817
- const isLvlActive = showConsoleLevels?.[level];
3818
- const levelColor =
3819
- level === 'error'
3820
- ? AppColors.errorColor
3821
- : level === 'warn'
3822
- ? AppColors.warningIconGold
3823
- : AppColors.skyBlue;
3824
- const label =
3825
- level === 'info'
3826
- ? t('settings.logs.showInfo')
3827
- : level === 'warn'
3828
- ? t('settings.logs.showWarn')
3829
- : t('settings.logs.showError');
3830
- const desc =
3831
- level === 'info'
3832
- ? t('settings.logs.showInfoDesc')
3833
- : level === 'warn'
3834
- ? t('settings.logs.showWarnDesc')
3835
- : t('settings.logs.showErrorDesc');
3836
-
3837
- return renderSettingRow({
3838
- icon: (
3839
- <View
3840
- style={{
3841
- width: 12,
3842
- height: 12,
3843
- borderRadius: 6,
3844
- backgroundColor: levelColor,
3845
- }}
3846
- />
3847
- ),
3848
- label,
3849
- description: desc,
3850
- isLast: level === 'error',
3851
- onPress: () =>
3852
- setShowConsoleLevels(prev => ({
3853
- ...prev,
3854
- [level]: !prev[level],
3855
- })),
3856
- right: (
3857
- <View
3858
- style={{
3859
- width: 22,
3860
- height: 22,
3861
- borderRadius: 6,
3862
- borderWidth: 2,
3863
- borderColor: isLvlActive
3864
- ? AppColors.purple
3865
- : AppColors.grayTextWeak,
3866
- backgroundColor: isLvlActive
3867
- ? `${AppColors.purple}1A`
3868
- : 'transparent',
3869
- alignItems: 'center',
3870
- justifyContent: 'center',
3871
- }}>
3872
- {isLvlActive && (
3873
- <CheckIcon size={12} color={AppColors.purple} />
3874
- )}
3875
- </View>
3876
- ),
3877
- });
3878
- })}
3879
- </View>
3880
-
3881
- {/* Log Deduplication Card */}
3882
- <View
3883
- style={{
3884
- backgroundColor: AppColors.primaryLight,
3885
- borderRadius: 14,
3886
- borderWidth: 1,
3887
- borderColor: AppColors.grayBorderSecondary,
3888
- overflow: 'hidden',
3889
- padding: 16,
3890
- gap: 14,
3891
- }}>
3892
- <Text
3893
- style={{
3894
- fontFamily: AppFonts.interBold,
3895
- fontSize: 11,
3896
- lineHeight: 14,
3897
- color: AppColors.grayTextWeak,
3898
- letterSpacing: 0.8,
3899
- }}>
3900
- {t('settings.logFiltersDeduplication')}
3901
- </Text>
3902
-
3903
- {/* Show Duplicate Logs */}
3904
- <View
3905
- style={{
3906
- flexDirection: 'row',
3907
- alignItems: 'center',
3908
- justifyContent: 'space-between',
3909
- }}>
3910
- <View
3911
- style={{
3912
- flexDirection: 'row',
3913
- alignItems: 'center',
3914
- gap: 10,
3915
- flex: 1,
3916
- }}>
3917
- <View
3918
- style={{
3919
- width: 32,
3920
- height: 32,
3921
- borderRadius: 8,
3922
- backgroundColor: AppColors.purpleShade50,
3923
- alignItems: 'center',
3924
- justifyContent: 'center',
3925
- }}>
3926
- <EyeIcon color={AppColors.purple} size={15} />
3927
- </View>
3928
- <View style={{flex: 1}}>
3929
- <Text
3930
- style={{
3931
- fontFamily: AppFonts.interBold,
3932
- fontSize: 13.5,
3933
- lineHeight: 18,
3934
- color: AppColors.primaryBlack,
3935
- }}>
3936
- {t('settings.general.duplicateLogs')}
3937
- </Text>
3938
- <Text
3939
- style={{
3940
- fontFamily: AppFonts.interRegular,
3941
- fontSize: 11,
3942
- lineHeight: 15,
3943
- color: AppColors.grayText,
3944
- marginTop: 1,
3945
- }}>
3946
- {t('settings.general.duplicateLogsDescription')}
3947
- </Text>
3948
- </View>
3949
- </View>
3950
-
3951
- <TouchableScale
3952
- accessible={true}
3953
- accessibilityRole="switch"
3954
- accessibilityLabel="Toggle show duplicate logs"
3955
- accessibilityState={{checked: showDuplicateLogs}}
3956
- onPress={() => setShowDuplicateLogs(prev => !prev)}
3957
- style={{
3958
- width: 42,
3959
- height: 24,
3960
- borderRadius: 12,
3961
- backgroundColor: showDuplicateLogs
3962
- ? AppColors.purple
3963
- : AppColors.grayBorderSecondary,
3964
- padding: 2,
3965
- justifyContent: 'center',
3966
- alignItems: showDuplicateLogs ? 'flex-end' : 'flex-start',
3967
- }}>
3968
- <View
3969
- style={{
3970
- width: 20,
3971
- height: 20,
3972
- borderRadius: 10,
3973
- backgroundColor: AppColors.white,
3974
- shadowColor: AppColors.black,
3975
- shadowOpacity: 0.18,
3976
- shadowRadius: 2,
3977
- shadowOffset: {width: 0, height: 1},
3978
- }}
3979
- />
3980
- </TouchableScale>
3981
- </View>
3982
- </View>
3983
-
3984
- <View
3985
- style={{
3986
- backgroundColor: AppColors.primaryLight,
3987
- borderRadius: 14,
3988
- borderWidth: 1,
3989
- borderColor: AppColors.grayBorderSecondary,
3990
- padding: 16,
3991
- }}>
3992
- {renderSettingRow({
3993
- icon: <TrashIcon color={AppColors.errorColor} size={16} />,
3994
- label: t('settings.logs.clearConsoleLogs'),
3995
- description: t('settings.logs.clearConsoleLogsDescription', {
3996
- count: consoleLogs.length,
3997
- }),
3998
- isLast: true,
3999
- onPress: () => {
4000
- clearConsoleLogs();
4001
- Alert.alert(
4002
- t('common.success'),
4003
- t('settings.logs.consoleLogsCleared'),
4004
- );
4005
- },
4006
- right: (
4007
- <View
4008
- style={{
4009
- paddingHorizontal: 12,
4010
- paddingVertical: 6,
4011
- borderRadius: 8,
4012
- backgroundColor: `${AppColors.errorColor}14`,
4013
- borderWidth: 1,
4014
- borderColor: `${AppColors.errorColor}33`,
4015
- }}>
4016
- <Text
4017
- style={{
4018
- fontFamily: AppFonts.interBold,
4019
- fontSize: 11,
4020
- lineHeight: 14,
4021
- color: AppColors.errorColor,
4022
- }}>
4023
- {t('common.clear')}
4024
- </Text>
4025
- </View>
4026
- ),
4027
- })}
4028
- </View>
4029
- <View style={{height: 48}} />
4030
- </ScrollView>
4031
- );
4032
- } else if (settingsPage === 'analytics') {
4033
- title = t('settings.analytics.title');
4034
- icon = <AnalyticsIcon color={AppColors.white} size={16} />;
4035
- rightInfo = t('settings.analytics.total', {count: analyticsEvents.length});
4036
- content = (
4037
- <ScrollView
4038
- style={{flex: 1}}
4039
- contentContainerStyle={{padding: 16, paddingBottom: 100, gap: 12}}>
4040
- <View
4041
- style={{
4042
- backgroundColor: AppColors.primaryLight,
4043
- padding: 16,
4044
- borderRadius: 14,
4045
- borderWidth: 1,
4046
- borderColor: AppColors.grayBorderSecondary,
4047
- }}>
4048
- {renderSettingRow({
4049
- icon: <AnalyticsIcon color={AppColors.purple} size={16} />,
4050
- label: t('settings.analytics.maxAnalyticsEvents'),
4051
- description: t('settings.analytics.maxAnalyticsEventsDescription', {
4052
- count: analyticsEvents.length,
4053
- }),
4054
- numericInput: {
4055
- value: maxAnalyticsEventsLimit,
4056
- onChange: setMaxAnalyticsEventsLimit,
4057
- min: 10,
4058
- max: 75,
4059
- placeholder: 'Enter max events (10-75)',
4060
- },
4061
- isLast: true,
4062
- })}
4063
- </View>
4064
- <View
4065
- style={{
4066
- backgroundColor: AppColors.primaryLight,
4067
- borderRadius: 14,
4068
- borderWidth: 1,
4069
- borderColor: AppColors.grayBorderSecondary,
4070
- padding: 16,
4071
- }}>
4072
- {renderSettingRow({
4073
- icon: <TrashIcon color={AppColors.errorColor} size={16} />,
4074
- label: t('settings.analytics.clearAnalyticsEvents'),
4075
- description: t(
4076
- 'settings.analytics.clearAnalyticsEventsDescription',
4077
- ),
4078
- isLast: true,
4079
- onPress: () => {
4080
- clearAnalyticsEvents();
4081
- setSelectedEvent(null);
4082
- Alert.alert(
4083
- t('common.success'),
4084
- t('settings.analytics.analyticsEventsCleared'),
4085
- );
4086
- },
4087
- right: (
4088
- <View
4089
- style={{
4090
- paddingHorizontal: 12,
4091
- paddingVertical: 6,
4092
- borderRadius: 8,
4093
- backgroundColor: `${AppColors.errorColor}14`,
4094
- borderWidth: 1,
4095
- borderColor: `${AppColors.errorColor}33`,
4096
- }}>
4097
- <Text
4098
- style={{
4099
- fontFamily: AppFonts.interBold,
4100
- fontSize: 11,
4101
- lineHeight: 14,
4102
- color: AppColors.errorColor,
4103
- }}>
4104
- {t('common.clear')}
4105
- </Text>
4106
- </View>
4107
- ),
4108
- })}
4109
- </View>
4110
- <View style={{height: 48}} />
4111
- </ScrollView>
4112
- );
4113
- } else if (settingsPage === 'redux') {
4114
- title = t('settings.redux.title');
4115
- icon = <ReduxIcon color={AppColors.white} size={16} />;
4116
- rightInfo = t('settings.redux.reducers', {
4117
- count: Object.keys(reduxState || {}).length,
4118
- });
4119
- content = (
4120
- <ScrollView
4121
- style={{flex: 1}}
4122
- contentContainerStyle={{padding: 16, paddingBottom: 100, gap: 12}}>
4123
- <View
4124
- style={{
4125
- backgroundColor: AppColors.primaryLight,
4126
- padding: 16,
4127
- borderRadius: 14,
4128
- borderWidth: 1,
4129
- borderColor: AppColors.grayBorderSecondary,
4130
- gap: 4,
4131
- }}>
4132
- {renderSettingRow({
4133
- icon: <ReduxIcon color={AppColors.purple} size={16} />,
4134
- label: t('settings.redux.autoRefresh'),
4135
- description: t('settings.redux.autoRefreshDescription'),
4136
- onPress: () => setReduxAutoRefreshState(prev => !prev),
4137
- right: (
4138
- <View
4139
- style={{
4140
- width: 22,
4141
- height: 22,
4142
- borderRadius: 6,
4143
- borderWidth: 2,
4144
- borderColor: reduxAutoRefresh
4145
- ? AppColors.purple
4146
- : AppColors.grayTextWeak,
4147
- backgroundColor: reduxAutoRefresh
4148
- ? `${AppColors.purple}1A`
4149
- : 'transparent',
4150
- alignItems: 'center',
4151
- justifyContent: 'center',
4152
- }}>
4153
- {reduxAutoRefresh && (
4154
- <CheckIcon size={12} color={AppColors.purple} />
4155
- )}
4156
- </View>
4157
- ),
4158
- })}
4159
- <View style={{height: 1, backgroundColor: AppColors.dividerColor}} />
4160
- {renderSettingRow({
4161
- icon: <LayersIcon color={AppColors.purple} size={16} />,
4162
- label: t('settings.redux.defaultJsonExpandDepth'),
4163
- description: t('settings.redux.defaultJsonExpandDepthDescription'),
4164
- picker: {
4165
- options: [1, 2, 3, 5] as const,
4166
- selectedValue: reduxExpandDepth,
4167
- onSelect: setReduxExpandDepth,
4168
- },
4169
- isLast: true,
4170
- })}
4171
- </View>
4172
-
4173
- <View
4174
- style={{
4175
- backgroundColor: AppColors.primaryLight,
4176
- borderRadius: 14,
4177
- borderWidth: 1,
4178
- borderColor: AppColors.grayBorderSecondary,
4179
- padding: 16,
4180
- }}>
4181
- {renderSettingRow({
4182
- icon: <TrashIcon color={AppColors.errorColor} size={16} />,
4183
- label: t('settings.redux.clearReduxState'),
4184
- description: reduxState
4185
- ? t('settings.redux.clearReduxStateDescription')
4186
- : t('settings.redux.clearReduxStateEmpty'),
4187
- isLast: true,
4188
- onPress: () => {
4189
- setReduxState(null);
4190
- Alert.alert(
4191
- t('common.success'),
4192
- t('settings.redux.reduxStateCleared'),
4193
- );
4194
- },
4195
- right: (
4196
- <View
4197
- style={{
4198
- paddingHorizontal: 12,
4199
- paddingVertical: 6,
4200
- borderRadius: 8,
4201
- backgroundColor: `${AppColors.errorColor}14`,
4202
- borderWidth: 1,
4203
- borderColor: `${AppColors.errorColor}33`,
4204
- }}>
4205
- <Text
4206
- style={{
4207
- fontFamily: AppFonts.interBold,
4208
- fontSize: 11,
4209
- lineHeight: 14,
4210
- color: AppColors.errorColor,
4211
- }}>
4212
- {t('common.clear')}
4213
- </Text>
4214
- </View>
4215
- ),
4216
- })}
4217
- </View>
4218
- <View style={{height: 48}} />
4219
- </ScrollView>
4220
- );
4221
- } else if (settingsPage === 'crash') {
4222
- title = t('settings.crash.title');
4223
- icon = <CrashIcon color={AppColors.white} size={16} />;
4224
- rightInfo = `Total: ${crashRecords?.length || 0}`;
4225
- content = (
4226
- <ScrollView
4227
- style={{flex: 1}}
4228
- contentContainerStyle={{padding: 16, paddingBottom: 100, gap: 12}}>
4229
- <View
4230
- style={{
4231
- backgroundColor: AppColors.primaryLight,
4232
- padding: 16,
4233
- borderRadius: 14,
4234
- borderWidth: 1,
4235
- borderColor: AppColors.grayBorderSecondary,
4236
- gap: 4,
4237
- }}>
4238
- {renderSettingRow({
4239
- icon: <LayersIcon color={AppColors.purple} size={16} />,
4240
- label: t('settings.crash.maxCrashLogs'),
4241
- description: t('settings.crash.maxCrashLogsDesc'),
4242
- numericInput: {
4243
- value: maxCrashLogs,
4244
- onChange: setMaxCrashLogs,
4245
- min: 5,
4246
- max: 50,
4247
- placeholder: 'Enter max crashes (5-50)',
4248
- },
4249
- })}
4250
- <View style={{height: 1, backgroundColor: AppColors.dividerColor}} />
4251
- {renderSettingRow({
4252
- icon: <ShieldAlertIcon color={AppColors.greenColor} size={16} />,
4253
- label: t('settings.crash.globalGuard'),
4254
- description: t('settings.crash.globalGuardDesc'),
4255
- isLast: true,
4256
- right: (
4257
- <View
4258
- style={{
4259
- paddingHorizontal: 8,
4260
- paddingVertical: 4,
4261
- borderRadius: 6,
4262
- backgroundColor: `${AppColors.greenColor}1F`,
4263
- }}>
4264
- <Text
4265
- style={{
4266
- fontFamily: AppFonts.interBold,
4267
- fontSize: 10,
4268
- lineHeight: 13,
4269
- color: AppColors.greenColor,
4270
- }}>
4271
- {t('settings.protectedBadge')}
4272
- </Text>
4273
- </View>
4274
- ),
4275
- })}
4276
- </View>
4277
-
4278
- <View
4279
- style={{
4280
- backgroundColor: AppColors.primaryLight,
4281
- borderRadius: 14,
4282
- borderWidth: 1,
4283
- borderColor: AppColors.grayBorderSecondary,
4284
- padding: 16,
4285
- }}>
4286
- {renderSettingRow({
4287
- icon: <TrashIcon color={AppColors.errorColor} size={16} />,
4288
- label: t('settings.crash.clearHistory'),
4289
- description: t('settings.crash.clearHistoryDesc', {
4290
- count: crashRecords?.length || 0,
4291
- }),
4292
- isLast: true,
4293
- onPress: () => {
4294
- clearCrashRecords();
4295
- Alert.alert(
4296
- t('common.success'),
4297
- t('settings.crash.historyCleared'),
4298
- );
4299
- },
4300
- right: (
4301
- <View
4302
- style={{
4303
- paddingHorizontal: 12,
4304
- paddingVertical: 6,
4305
- borderRadius: 8,
4306
- backgroundColor: `${AppColors.errorColor}14`,
4307
- borderWidth: 1,
4308
- borderColor: `${AppColors.errorColor}33`,
4309
- }}>
4310
- <Text
4311
- style={{
4312
- fontFamily: AppFonts.interBold,
4313
- fontSize: 11,
4314
- lineHeight: 14,
4315
- color: AppColors.errorColor,
4316
- }}>
4317
- {t('common.clear')}
4318
- </Text>
4319
- </View>
4320
- ),
4321
- })}
4322
- </View>
4323
- <View style={{height: 48}} />
4324
- </ScrollView>
4325
- );
4326
- } else if (settingsPage === 'bundle') {
4327
- title = t('settings.bundle.title');
4328
- icon = <PackageIcon color={AppColors.white} size={16} />;
4329
- rightInfo = 'Metro';
4330
- content = (
4331
- <ScrollView
4332
- style={{flex: 1}}
4333
- contentContainerStyle={{padding: 16, paddingBottom: 100, gap: 12}}>
4334
- <View
4335
- style={{
4336
- backgroundColor: AppColors.primaryLight,
4337
- padding: 16,
4338
- borderRadius: 14,
4339
- borderWidth: 1,
4340
- borderColor: AppColors.grayBorderSecondary,
4341
- gap: 8,
4342
- }}>
4343
- <View style={{flexDirection: 'row', alignItems: 'center', gap: 10}}>
4344
- <View
4345
- style={{
4346
- width: 36,
4347
- height: 36,
4348
- borderRadius: 10,
4349
- backgroundColor: AppColors.purpleShade50,
4350
- alignItems: 'center',
4351
- justifyContent: 'center',
4352
- }}>
4353
- <PackageIcon color={AppColors.purple} size={16} />
4354
- </View>
4355
- <View style={{flex: 1}}>
4356
- <Text
4357
- style={{
4358
- fontFamily: AppFonts.interBold,
4359
- fontSize: 14,
4360
- lineHeight: 18,
4361
- color: AppColors.primaryBlack,
4362
- }}>
4363
- {t('settings.bundle.sourceBundler')}
4364
- </Text>
4365
- <Text
4366
- style={{
4367
- fontFamily: AppFonts.interRegular,
4368
- fontSize: 11,
4369
- lineHeight: 15,
4370
- color: AppColors.grayText,
4371
- marginTop: 1,
4372
- }}>
4373
- {t('settings.bundle.sourceBundlerDesc')}
4374
- </Text>
4375
- </View>
4376
- </View>
4377
- </View>
4378
-
4379
- <View
4380
- style={{
4381
- backgroundColor: AppColors.primaryLight,
4382
- borderRadius: 14,
4383
- borderWidth: 1,
4384
- borderColor: AppColors.grayBorderSecondary,
4385
- padding: 16,
4386
- }}>
4387
- {renderSettingRow({
4388
- icon: <TrashIcon color={AppColors.errorColor} size={16} />,
4389
- label: t('settings.bundle.clearCache'),
4390
- description: t('settings.bundle.clearCacheDesc'),
4391
- isLast: true,
4392
- onPress: () => {
4393
- clearCachedBundleAnalysis();
4394
- Alert.alert(
4395
- t('common.success'),
4396
- t('settings.bundle.cacheCleared'),
4397
- );
4398
- },
4399
- right: (
4400
- <View
4401
- style={{
4402
- paddingHorizontal: 12,
4403
- paddingVertical: 6,
4404
- borderRadius: 8,
4405
- backgroundColor: `${AppColors.errorColor}14`,
4406
- borderWidth: 1,
4407
- borderColor: `${AppColors.errorColor}33`,
4408
- }}>
4409
- <Text
4410
- style={{
4411
- fontFamily: AppFonts.interBold,
4412
- fontSize: 11,
4413
- lineHeight: 14,
4414
- color: AppColors.errorColor,
4415
- }}>
4416
- {t('common.clear')}
4417
- </Text>
4418
- </View>
4419
- ),
4420
- })}
4421
- </View>
4422
- <View style={{height: 48}} />
4423
- </ScrollView>
4424
- );
4425
- } else if (settingsPage === 'performance') {
4426
- title = t('settings.performance.title');
4427
- icon = <PerformanceIcon color={AppColors.white} size={16} />;
4428
- rightInfo = '60 FPS Target';
4429
- content = (
4430
- <ScrollView
4431
- style={{flex: 1}}
4432
- contentContainerStyle={{padding: 16, paddingBottom: 100, gap: 12}}>
4433
- <View
4434
- style={{
4435
- backgroundColor: AppColors.primaryLight,
4436
- padding: 16,
4437
- borderRadius: 14,
4438
- borderWidth: 1,
4439
- borderColor: AppColors.grayBorderSecondary,
4440
- gap: 8,
4441
- }}>
4442
- <View style={{flexDirection: 'row', alignItems: 'center', gap: 10}}>
4443
- <View
4444
- style={{
4445
- width: 36,
4446
- height: 36,
4447
- borderRadius: 10,
4448
- backgroundColor: AppColors.purpleShade50,
4449
- alignItems: 'center',
4450
- justifyContent: 'center',
4451
- }}>
4452
- <PerformanceIcon color={AppColors.purple} size={16} />
4453
- </View>
4454
- <View style={{flex: 1}}>
4455
- <Text
4456
- style={{
4457
- fontFamily: AppFonts.interBold,
4458
- fontSize: 14,
4459
- lineHeight: 18,
4460
- color: AppColors.primaryBlack,
4461
- }}>
4462
- {t('settings.performance.frameMeasurement')}
4463
- </Text>
4464
- <Text
4465
- style={{
4466
- fontFamily: AppFonts.interRegular,
4467
- fontSize: 11,
4468
- lineHeight: 15,
4469
- color: AppColors.grayText,
4470
- marginTop: 1,
4471
- }}>
4472
- {t('settings.performance.frameMeasurementDesc')}
4473
- </Text>
4474
- </View>
4475
- </View>
4476
- </View>
4477
-
4478
- <View
4479
- style={{
4480
- backgroundColor: AppColors.primaryLight,
4481
- borderRadius: 14,
4482
- borderWidth: 1,
4483
- borderColor: AppColors.grayBorderSecondary,
4484
- padding: 16,
4485
- }}>
4486
- {renderSettingRow({
4487
- icon: <TrashIcon color={AppColors.errorColor} size={16} />,
4488
- label: t('settings.performance.clearEvents'),
4489
- description: t('settings.performance.clearEventsDesc'),
4490
- isLast: true,
4491
- onPress: () => {
4492
- clearPerformanceEvents();
4493
- Alert.alert(
4494
- t('common.success'),
4495
- t('settings.performance.eventsCleared'),
4496
- );
4497
- },
4498
- right: (
4499
- <View
4500
- style={{
4501
- paddingHorizontal: 12,
4502
- paddingVertical: 6,
4503
- borderRadius: 8,
4504
- backgroundColor: `${AppColors.errorColor}14`,
4505
- borderWidth: 1,
4506
- borderColor: `${AppColors.errorColor}33`,
4507
- }}>
4508
- <Text
4509
- style={{
4510
- fontFamily: AppFonts.interBold,
4511
- fontSize: 11,
4512
- lineHeight: 14,
4513
- color: AppColors.errorColor,
4514
- }}>
4515
- {t('common.clear')}
4516
- </Text>
4517
- </View>
4518
- ),
4519
- })}
4520
- </View>
4521
- <View style={{height: 48}} />
4522
- </ScrollView>
4523
- );
4524
- }
4525
-
4526
-
4527
- const subPageAnim = useRef(new Animated.Value(0)).current;
4528
- useEffect(() => {
4529
- if (settingsPage !== 'main') {
4530
- subPageAnim.setValue(0);
4531
- Animated.spring(subPageAnim, {
4532
- toValue: 1,
4533
- friction: 8,
4534
- tension: 65,
4535
- useNativeDriver: true,
4536
- }).start();
4537
- }
4538
- }, [settingsPage]);
4539
-
4540
- return (
4541
- <View
4542
- style={{
4543
- flex: 1,
4544
- backgroundColor: AppColors.grayBackground,
4545
- }}>
4546
- {/* ─── Persistent Main Settings (Retains 100% scroll position) ─── */}
4547
- <View
4548
- style={[
4549
- StyleSheet.absoluteFill,
4550
- settingsPage !== 'main' && {pointerEvents: 'none'},
4551
- ]}>
4552
- {renderMainSettingsContent()}
4553
- </View>
4554
-
4555
- {/* ─── Sub-module Settings Overlay (Smooth Animated Slide) ─── */}
4556
- {settingsPage !== 'main' && (
4557
- <Animated.View
4558
- style={[
4559
- StyleSheet.absoluteFill,
4560
- {
4561
- backgroundColor: AppColors.grayBackground,
4562
- opacity: subPageAnim,
4563
- transform: [
4564
- {
4565
- translateX: subPageAnim.interpolate({
4566
- inputRange: [0, 1],
4567
- outputRange: [30, 0],
4568
- }),
4569
- },
4570
- ],
4571
- },
4572
- ]}>
4573
- {content}
4574
- </Animated.View>
4575
- )}
4576
- </View>
4577
- );
4578
- };
4579
-
4580
- export default SettingsPanel;