react-native-inapp-inspector 2.3.15 → 2.3.17

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 (381) hide show
  1. package/README.md +1 -0
  2. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +438 -7
  3. package/bin/cli.js +0 -0
  4. package/dist/commonjs/capture.d.ts +26 -0
  5. package/dist/commonjs/capture.js +32 -0
  6. package/dist/commonjs/components/AnalyticsEventCard.js +11 -11
  7. package/dist/commonjs/components/AnimatedEntrance.js +6 -70
  8. package/dist/commonjs/components/DomainHeader.js +3 -48
  9. package/dist/commonjs/components/EmptyState.js +2 -2
  10. package/dist/commonjs/components/HeadersSection.js +14 -34
  11. package/dist/commonjs/components/Inspector/AnalyticsTab.js +1 -24
  12. package/dist/commonjs/components/Inspector/ConsoleTab.js +1 -23
  13. package/dist/commonjs/components/Inspector/CrashTab.js +4 -25
  14. package/dist/commonjs/components/Inspector/DebuggingTab.js +2 -2
  15. package/dist/commonjs/components/Inspector/FeedbackModal.d.ts +7 -0
  16. package/dist/commonjs/components/Inspector/FeedbackModal.js +552 -0
  17. package/dist/commonjs/components/Inspector/InspectorHeader.js +675 -285
  18. package/dist/commonjs/components/Inspector/MainScreen.js +66 -69
  19. package/dist/commonjs/components/Inspector/MediaGalleryTab.d.ts +2 -0
  20. package/dist/commonjs/components/Inspector/MediaGalleryTab.js +307 -0
  21. package/dist/commonjs/components/Inspector/MediaPreviewModal.d.ts +11 -0
  22. package/dist/commonjs/components/Inspector/MediaPreviewModal.js +393 -0
  23. package/dist/commonjs/components/Inspector/NetworkTab.js +196 -206
  24. package/dist/commonjs/components/Inspector/NpmStarPrompt.d.ts +3 -0
  25. package/dist/commonjs/components/Inspector/NpmStarPrompt.js +494 -0
  26. package/dist/commonjs/components/Inspector/NpmUpdateToast.js +4 -9
  27. package/dist/commonjs/components/Inspector/PerformanceTab.js +8 -1
  28. package/dist/commonjs/components/Inspector/ReduxTab.js +4 -24
  29. package/dist/commonjs/components/Inspector/SettingsPanel.js +1280 -173
  30. package/dist/commonjs/components/Inspector/SkeletonPlaceholder.js +2 -2
  31. package/dist/commonjs/components/Inspector/StorageTab.js +3 -26
  32. package/dist/commonjs/components/Inspector/TabBar.js +55 -25
  33. package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +5 -10
  34. package/dist/commonjs/components/JsonViewer.js +43 -20
  35. package/dist/commonjs/components/LogCard.js +5 -5
  36. package/dist/commonjs/components/MetaAccordion.js +78 -80
  37. package/dist/commonjs/components/NetworkIcons.d.ts +13 -0
  38. package/dist/commonjs/components/NetworkIcons.js +83 -2
  39. package/dist/commonjs/components/SectionHeader.js +3 -48
  40. package/dist/commonjs/components/SkeletonPlaceholder.js +2 -2
  41. package/dist/commonjs/components/SourcePageCard.js +43 -45
  42. package/dist/commonjs/components/Toast.js +4 -4
  43. package/dist/commonjs/components/TouchableScale.js +9 -65
  44. package/dist/commonjs/components/TreeNode.js +2 -14
  45. package/dist/commonjs/constants/telemetryConfig.d.ts +3 -3
  46. package/dist/commonjs/constants/telemetryConfig.js +3 -3
  47. package/dist/commonjs/constants/version.d.ts +1 -1
  48. package/dist/commonjs/constants/version.js +1 -1
  49. package/dist/commonjs/customHooks/useAccordion.d.ts +3 -8
  50. package/dist/commonjs/customHooks/useAccordion.js +6 -36
  51. package/dist/commonjs/helpers/index.d.ts +3 -1
  52. package/dist/commonjs/helpers/index.js +11 -1
  53. package/dist/commonjs/helpers/remoteConfig.d.ts +4 -0
  54. package/dist/commonjs/helpers/remoteConfig.js +165 -0
  55. package/dist/commonjs/helpers/searchQueryParser.js +2 -0
  56. package/dist/commonjs/helpers/telemetry.d.ts +5 -0
  57. package/dist/commonjs/helpers/telemetry.js +339 -8
  58. package/dist/commonjs/i18n/locales/en.json +66 -2
  59. package/dist/commonjs/index.d.ts +2 -0
  60. package/dist/commonjs/index.js +70 -23
  61. package/dist/commonjs/native/NativeInspector.d.ts +60 -0
  62. package/dist/commonjs/native/NativeInspector.js +109 -2
  63. package/dist/commonjs/native/NativeNetworkInspector.d.ts +8 -0
  64. package/dist/commonjs/styles/AppColors.d.ts +36 -0
  65. package/dist/commonjs/styles/AppColors.js +36 -0
  66. package/dist/commonjs/styles/AppFonts.d.ts +2 -0
  67. package/dist/commonjs/styles/AppFonts.js +1 -0
  68. package/dist/commonjs/styles/index.d.ts +25 -1
  69. package/dist/commonjs/styles/index.js +22 -1
  70. package/dist/commonjs/types/enums.d.ts +2 -0
  71. package/dist/commonjs/types/enums.js +2 -0
  72. package/dist/commonjs/types/index.d.ts +2 -2
  73. package/dist/commonjs/types/interfaces.d.ts +12 -0
  74. package/dist/esm/capture.d.ts +26 -0
  75. package/dist/esm/capture.js +29 -0
  76. package/dist/esm/components/AnalyticsEventCard.js +11 -11
  77. package/dist/esm/components/AnimatedEntrance.js +4 -38
  78. package/dist/esm/components/DomainHeader.js +4 -16
  79. package/dist/esm/components/EmptyState.js +2 -2
  80. package/dist/esm/components/HeadersSection.js +16 -36
  81. package/dist/esm/components/Inspector/AnalyticsTab.js +3 -26
  82. package/dist/esm/components/Inspector/ConsoleTab.js +3 -25
  83. package/dist/esm/components/Inspector/CrashTab.js +6 -27
  84. package/dist/esm/components/Inspector/DebuggingTab.js +3 -3
  85. package/dist/esm/components/Inspector/FeedbackModal.d.ts +7 -0
  86. package/dist/esm/components/Inspector/FeedbackModal.js +515 -0
  87. package/dist/esm/components/Inspector/InspectorHeader.js +678 -288
  88. package/dist/esm/components/Inspector/MainScreen.js +67 -70
  89. package/dist/esm/components/Inspector/MediaGalleryTab.d.ts +2 -0
  90. package/dist/esm/components/Inspector/MediaGalleryTab.js +267 -0
  91. package/dist/esm/components/Inspector/MediaPreviewModal.d.ts +11 -0
  92. package/dist/esm/components/Inspector/MediaPreviewModal.js +353 -0
  93. package/dist/esm/components/Inspector/NetworkTab.js +199 -209
  94. package/dist/esm/components/Inspector/NpmStarPrompt.d.ts +3 -0
  95. package/dist/esm/components/Inspector/NpmStarPrompt.js +454 -0
  96. package/dist/esm/components/Inspector/NpmUpdateToast.js +5 -10
  97. package/dist/esm/components/Inspector/PerformanceTab.js +8 -1
  98. package/dist/esm/components/Inspector/ReduxTab.js +6 -26
  99. package/dist/esm/components/Inspector/SettingsPanel.js +1283 -176
  100. package/dist/esm/components/Inspector/SkeletonPlaceholder.js +2 -2
  101. package/dist/esm/components/Inspector/StorageTab.js +3 -26
  102. package/dist/esm/components/Inspector/TabBar.js +56 -26
  103. package/dist/esm/components/Inspector/UpdateAvailableModal.js +6 -11
  104. package/dist/esm/components/JsonViewer.js +43 -20
  105. package/dist/esm/components/LogCard.js +5 -5
  106. package/dist/esm/components/MetaAccordion.js +79 -81
  107. package/dist/esm/components/NetworkIcons.d.ts +13 -0
  108. package/dist/esm/components/NetworkIcons.js +68 -0
  109. package/dist/esm/components/SectionHeader.js +4 -16
  110. package/dist/esm/components/SkeletonPlaceholder.js +2 -2
  111. package/dist/esm/components/SourcePageCard.js +44 -46
  112. package/dist/esm/components/Toast.js +4 -4
  113. package/dist/esm/components/TouchableScale.js +7 -33
  114. package/dist/esm/components/TreeNode.js +4 -16
  115. package/dist/esm/constants/telemetryConfig.d.ts +3 -3
  116. package/dist/esm/constants/telemetryConfig.js +3 -3
  117. package/dist/esm/constants/version.d.ts +1 -1
  118. package/dist/esm/constants/version.js +1 -1
  119. package/dist/esm/customHooks/useAccordion.d.ts +3 -8
  120. package/dist/esm/customHooks/useAccordion.js +7 -37
  121. package/dist/esm/helpers/index.d.ts +3 -1
  122. package/dist/esm/helpers/index.js +9 -0
  123. package/dist/esm/helpers/remoteConfig.d.ts +4 -0
  124. package/dist/esm/helpers/remoteConfig.js +160 -0
  125. package/dist/esm/helpers/searchQueryParser.js +2 -0
  126. package/dist/esm/helpers/telemetry.d.ts +5 -0
  127. package/dist/esm/helpers/telemetry.js +332 -9
  128. package/dist/esm/i18n/locales/en.json +66 -2
  129. package/dist/esm/index.d.ts +2 -0
  130. package/dist/esm/index.js +66 -23
  131. package/dist/esm/native/NativeInspector.d.ts +60 -0
  132. package/dist/esm/native/NativeInspector.js +100 -1
  133. package/dist/esm/native/NativeNetworkInspector.d.ts +8 -0
  134. package/dist/esm/styles/AppColors.d.ts +36 -0
  135. package/dist/esm/styles/AppColors.js +36 -0
  136. package/dist/esm/styles/AppFonts.d.ts +2 -0
  137. package/dist/esm/styles/AppFonts.js +1 -0
  138. package/dist/esm/styles/index.d.ts +25 -1
  139. package/dist/esm/styles/index.js +22 -1
  140. package/dist/esm/types/enums.d.ts +2 -0
  141. package/dist/esm/types/enums.js +2 -0
  142. package/dist/esm/types/index.d.ts +2 -2
  143. package/dist/esm/types/interfaces.d.ts +12 -0
  144. package/ios/NetworkInspectorModule.h +1 -0
  145. package/ios/NetworkInspectorModule.mm +736 -7
  146. package/package.json +10 -2
  147. package/react-native-inapp-inspector.podspec +1 -0
  148. package/src/capture.ts +101 -0
  149. package/src/components/AnalyticsEventCard.tsx +15 -13
  150. package/src/components/AnimatedEntrance.tsx +3 -47
  151. package/src/components/DomainHeader.tsx +4 -17
  152. package/src/components/EmptyState.tsx +2 -2
  153. package/src/components/HeadersSection.tsx +31 -56
  154. package/src/components/Inspector/AnalyticsTab.tsx +2 -25
  155. package/src/components/Inspector/ConsoleTab.tsx +2 -24
  156. package/src/components/Inspector/CrashTab.tsx +4 -25
  157. package/src/components/Inspector/DebuggingTab.tsx +2 -2
  158. package/src/components/Inspector/FeedbackModal.tsx +626 -0
  159. package/src/components/Inspector/InspectorHeader.tsx +1230 -728
  160. package/src/components/Inspector/MainScreen.tsx +97 -82
  161. package/src/components/Inspector/MediaGalleryTab.tsx +355 -0
  162. package/src/components/Inspector/MediaPreviewModal.tsx +435 -0
  163. package/src/components/Inspector/NetworkTab.tsx +83 -93
  164. package/src/components/Inspector/NpmStarPrompt.tsx +532 -0
  165. package/src/components/Inspector/NpmUpdateToast.tsx +4 -9
  166. package/src/components/Inspector/PerformanceTab.tsx +8 -1
  167. package/src/components/Inspector/ReduxTab.tsx +5 -25
  168. package/src/components/Inspector/SettingsPanel.tsx +1493 -225
  169. package/src/components/Inspector/SkeletonPlaceholder.tsx +2 -2
  170. package/src/components/Inspector/StorageTab.tsx +3 -26
  171. package/src/components/Inspector/TabBar.tsx +63 -32
  172. package/src/components/Inspector/UpdateAvailableModal.tsx +6 -10
  173. package/src/components/JsonViewer.tsx +101 -60
  174. package/src/components/LogCard.tsx +10 -8
  175. package/src/components/MetaAccordion.tsx +6 -6
  176. package/src/components/NetworkIcons.tsx +242 -0
  177. package/src/components/SectionHeader.tsx +4 -16
  178. package/src/components/SkeletonPlaceholder.tsx +2 -2
  179. package/src/components/SourcePageCard.tsx +57 -55
  180. package/src/components/Toast.tsx +4 -4
  181. package/src/components/TouchableScale.tsx +8 -38
  182. package/src/components/TreeNode.tsx +5 -20
  183. package/src/constants/telemetryConfig.ts +3 -5
  184. package/src/constants/version.ts +1 -1
  185. package/src/customHooks/useAccordion.tsx +10 -43
  186. package/src/helpers/index.ts +11 -1
  187. package/src/helpers/remoteConfig.ts +212 -0
  188. package/src/helpers/searchQueryParser.ts +3 -0
  189. package/src/helpers/telemetry.ts +381 -10
  190. package/src/i18n/locales/en.json +69 -2
  191. package/src/index.tsx +93 -23
  192. package/src/native/NativeInspector.ts +186 -1
  193. package/src/native/NativeNetworkInspector.ts +9 -0
  194. package/src/styles/AppColors.ts +38 -0
  195. package/src/styles/AppFonts.ts +2 -0
  196. package/src/styles/index.ts +23 -2
  197. package/src/types/enums.ts +4 -0
  198. package/src/types/index.ts +2 -2
  199. package/src/types/interfaces.ts +12 -0
  200. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  201. package/android/.gradle/8.9/checksums/md5-checksums.bin +0 -0
  202. package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
  203. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  204. package/android/.gradle/8.9/executionHistory/executionHistory.lock +0 -0
  205. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  206. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  207. package/android/.gradle/8.9/gc.properties +0 -0
  208. package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
  209. package/android/.gradle/9.2.0/fileChanges/last-build.bin +0 -0
  210. package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
  211. package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
  212. package/android/.gradle/9.2.0/gc.properties +0 -0
  213. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  214. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  215. package/android/.gradle/vcs-1/gc.properties +0 -0
  216. package/android/build/.transforms/6683d6eeaa3e1dfa689c3385111a0386/results.bin +0 -1
  217. package/android/build/.transforms/6683d6eeaa3e1dfa689c3385111a0386/transformed/classes/classes_dex/classes.dex +0 -0
  218. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/results.bin +0 -1
  219. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/BuildConfig.dex +0 -0
  220. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/InAppInspectorFloatingView$iconView$1.dex +0 -0
  221. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/InAppInspectorFloatingView.dex +0 -0
  222. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NativeNetworkInspectorSpec.dex +0 -0
  223. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NetworkInspectorModule$Companion.dex +0 -0
  224. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NetworkInspectorModule$frameCallback$1.dex +0 -0
  225. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NetworkInspectorModule$shakeListener$1.dex +0 -0
  226. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NetworkInspectorModule.dex +0 -0
  227. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NetworkInspectorPackage.dex +0 -0
  228. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
  229. package/android/build/generated/source/buildConfig/debug/com/inappinspector/BuildConfig.java +0 -10
  230. package/android/build/generated/source/codegen/java/com/inappinspector/NativeNetworkInspectorSpec.java +0 -104
  231. package/android/build/generated/source/codegen/jni/CMakeLists.txt +0 -28
  232. package/android/build/generated/source/codegen/jni/RNInAppInspectorSpec-generated.cpp +0 -128
  233. package/android/build/generated/source/codegen/jni/RNInAppInspectorSpec.h +0 -31
  234. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/ComponentDescriptors.cpp +0 -22
  235. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/ComponentDescriptors.h +0 -24
  236. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/EventEmitters.cpp +0 -16
  237. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/EventEmitters.h +0 -17
  238. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/Props.cpp +0 -19
  239. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/Props.h +0 -18
  240. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/RNInAppInspectorSpecJSI.h +0 -177
  241. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/ShadowNodes.cpp +0 -17
  242. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/ShadowNodes.h +0 -23
  243. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/States.cpp +0 -16
  244. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/States.h +0 -20
  245. package/android/build/generated/source/codegen/schema.json +0 -1
  246. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -7
  247. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
  248. package/android/build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar +0 -0
  249. package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
  250. package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
  251. package/android/build/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt +0 -0
  252. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  253. package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  254. package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
  255. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -1
  256. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
  257. package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
  258. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
  259. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
  260. package/android/build/intermediates/incremental/packageDebugAssets/merger.xml +0 -2
  261. package/android/build/intermediates/java_res/debug/processDebugJavaRes/out/META-INF/react-native-inapp-inspector_debug.kotlin_module +0 -0
  262. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/inappinspector/BuildConfig.class +0 -0
  263. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/inappinspector/NativeNetworkInspectorSpec.class +0 -0
  264. package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -2
  265. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -7
  266. package/android/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-react-native-inapp-inspector.jar +0 -0
  267. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -7
  268. package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
  269. package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
  270. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/META-INF/react-native-inapp-inspector_debug.kotlin_module +0 -0
  271. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/BuildConfig.class +0 -0
  272. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/InAppInspectorFloatingView$iconView$1.class +0 -0
  273. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/InAppInspectorFloatingView.class +0 -0
  274. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NativeNetworkInspectorSpec.class +0 -0
  275. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NetworkInspectorModule$Companion.class +0 -0
  276. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NetworkInspectorModule$frameCallback$1.class +0 -0
  277. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NetworkInspectorModule$shakeListener$1.class +0 -0
  278. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NetworkInspectorModule.class +0 -0
  279. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NetworkInspectorPackage.class +0 -0
  280. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  281. package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -1
  282. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  283. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
  284. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
  285. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
  286. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  287. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
  288. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
  289. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  290. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  291. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  292. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  293. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  294. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  295. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
  296. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  297. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  298. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  299. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  300. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  301. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  302. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
  303. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
  304. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream +0 -0
  305. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len +0 -0
  306. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len +0 -0
  307. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
  308. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i +0 -0
  309. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len +0 -0
  310. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  311. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  312. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  313. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  314. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  315. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  316. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
  317. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  318. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  319. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  320. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  321. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  322. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  323. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
  324. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  325. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
  326. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
  327. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
  328. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  329. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
  330. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
  331. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
  332. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
  333. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
  334. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
  335. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  336. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
  337. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
  338. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
  339. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
  340. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
  341. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
  342. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
  343. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
  344. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
  345. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +0 -2
  346. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  347. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
  348. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
  349. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
  350. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
  351. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
  352. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
  353. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  354. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
  355. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
  356. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
  357. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  358. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
  359. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
  360. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  361. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  362. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  363. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  364. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  365. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  366. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
  367. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  368. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  369. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  370. package/android/build/outputs/aar/react-native-inapp-inspector-debug.aar +0 -0
  371. package/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -17
  372. package/android/build/reports/problems/problems-report.html +0 -659
  373. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  374. package/android/build/tmp/kotlin-classes/debug/META-INF/react-native-inapp-inspector_debug.kotlin_module +0 -0
  375. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/InAppInspectorFloatingView$iconView$1.class +0 -0
  376. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/InAppInspectorFloatingView.class +0 -0
  377. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/NetworkInspectorModule$Companion.class +0 -0
  378. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/NetworkInspectorModule$frameCallback$1.class +0 -0
  379. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/NetworkInspectorModule$shakeListener$1.class +0 -0
  380. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/NetworkInspectorModule.class +0 -0
  381. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/NetworkInspectorPackage.class +0 -0
@@ -28,8 +28,14 @@ import {
28
28
  getSize,
29
29
  getAppVersionAndBuild,
30
30
  } from '../../helpers';
31
- import {getNativeDeviceMetrics} from '../../native/NativeInspector';
31
+ import {
32
+ getNativeDeviceMetrics,
33
+ triggerNativeHaptic,
34
+ } from '../../native/NativeInspector';
35
+ import {ScreenCapture, CapturedMediaItem} from '../../capture';
36
+ import {showToast} from '../../helpers/toast';
32
37
  import {UpdateAvailableModal} from './UpdateAvailableModal';
38
+ import {MediaPreviewModal} from './MediaPreviewModal';
33
39
  import {
34
40
  WhiteBackNavigation,
35
41
  TrashIcon,
@@ -42,9 +48,14 @@ import {
42
48
  NpmIcon,
43
49
  ResetIcon,
44
50
  BoltIcon,
51
+ InfoCircleIcon,
52
+ CameraIcon,
53
+ VideoCameraIcon,
45
54
  } from '../NetworkIcons';
55
+ import {useTranslation} from '../../i18n';
46
56
 
47
57
  const InspectorHeader = React.memo(() => {
58
+ const {t} = useTranslation();
48
59
  const {
49
60
  modalHeightPercent,
50
61
  appIcon,
@@ -70,6 +81,9 @@ const InspectorHeader = React.memo(() => {
70
81
  runClearAllWithAnimation,
71
82
  settingsPage,
72
83
  setSettingsPage,
84
+ setSettingsActiveSubTab,
85
+ isFeedbackOpen,
86
+ setIsFeedbackOpen,
73
87
  resetToDefaults,
74
88
  closeModal,
75
89
  detailTitle,
@@ -90,18 +104,130 @@ const InspectorHeader = React.memo(() => {
90
104
  return getAppVersionAndBuild().formatted;
91
105
  });
92
106
 
107
+ const [isRecording, setIsRecording] = React.useState<boolean>(false);
108
+ const [recordingSeconds, setRecordingSeconds] = React.useState<number>(0);
109
+ const recordingTimerRef = React.useRef<any>(null);
110
+
93
111
  React.useEffect(() => {
94
- getNativeDeviceMetrics()
95
- .then(metrics => {
96
- if (metrics?.appVersion) {
97
- const v = metrics.appVersion;
98
- const b = metrics.appBuild || '1';
99
- setAppVersionString(`${v} (${b})`);
100
- }
112
+ ScreenCapture.isRecording()
113
+ .then(active => {
114
+ setIsRecording(active);
101
115
  })
102
116
  .catch(() => {});
103
117
  }, []);
104
118
 
119
+ React.useEffect(() => {
120
+ if (isRecording) {
121
+ setRecordingSeconds(0);
122
+ recordingTimerRef.current = setInterval(() => {
123
+ setRecordingSeconds(s => s + 1);
124
+ }, 1000);
125
+ } else {
126
+ if (recordingTimerRef.current) {
127
+ clearInterval(recordingTimerRef.current);
128
+ recordingTimerRef.current = null;
129
+ }
130
+ setRecordingSeconds(0);
131
+ }
132
+ return () => {
133
+ if (recordingTimerRef.current) {
134
+ clearInterval(recordingTimerRef.current);
135
+ }
136
+ };
137
+ }, [isRecording]);
138
+
139
+ const [previewMediaItem, setPreviewMediaItem] =
140
+ React.useState<CapturedMediaItem | null>(null);
141
+
142
+ const handleTakeScreenshot = React.useCallback(async () => {
143
+ try {
144
+ triggerNativeHaptic('light');
145
+ const result = await ScreenCapture.takeScreenshot({
146
+ format: 'png',
147
+ quality: 0.9,
148
+ hideInspector: true,
149
+ });
150
+ if (result) {
151
+ triggerNativeHaptic('success');
152
+ const newItem: CapturedMediaItem = {
153
+ id: `screenshot_${result.timestamp}.png`,
154
+ type: 'image',
155
+ format: result.format,
156
+ uri: result.uri,
157
+ filename:
158
+ result.uri.split('/').pop() || `screenshot_${result.timestamp}.png`,
159
+ sizeBytes: result.sizeBytes,
160
+ timestamp: result.timestamp,
161
+ width: result.width,
162
+ height: result.height,
163
+ };
164
+ setPreviewMediaItem(newItem);
165
+ showToast(t('header.screenshotCaptured'));
166
+ } else {
167
+ showToast(t('header.screenshotFailed'));
168
+ }
169
+ } catch {
170
+ showToast(t('header.screenshotError'));
171
+ }
172
+ }, [t]);
173
+
174
+ const handleToggleVideoRecording = React.useCallback(async () => {
175
+ try {
176
+ if (isRecording) {
177
+ triggerNativeHaptic('medium');
178
+ const result = await ScreenCapture.stopRecording();
179
+ setIsRecording(false);
180
+ if (result) {
181
+ triggerNativeHaptic('success');
182
+ const newItem: CapturedMediaItem = {
183
+ id: `video_${result.timestamp}.${result.format}`,
184
+ type: result.format === 'gif' ? 'gif' : 'video',
185
+ format: result.format,
186
+ uri: result.uri,
187
+ filename:
188
+ result.uri.split('/').pop() ||
189
+ `video_${result.timestamp}.${result.format}`,
190
+ sizeBytes: result.sizeBytes,
191
+ timestamp: result.timestamp,
192
+ durationMs: result.durationMs,
193
+ width: result.width,
194
+ height: result.height,
195
+ hasAudio: result.hasAudio,
196
+ };
197
+ setPreviewMediaItem(newItem);
198
+ showToast(
199
+ t('header.recordingSaved', {
200
+ duration: (result.durationMs / 1000).toFixed(1),
201
+ }),
202
+ );
203
+ }
204
+ } else {
205
+ triggerNativeHaptic('medium');
206
+ const started = await ScreenCapture.startRecording({
207
+ fps: 24,
208
+ audioSource: 'none',
209
+ });
210
+ if (started) {
211
+ setIsRecording(true);
212
+ showToast(t('header.recordingStarted'));
213
+ } else {
214
+ showToast(t('header.recordingStartFailed'));
215
+ }
216
+ }
217
+ } catch {
218
+ showToast(t('header.recordingError'));
219
+ setIsRecording(false);
220
+ }
221
+ }, [isRecording, t]);
222
+
223
+ const formatTimer = (totalSeconds: number) => {
224
+ const mins = Math.floor(totalSeconds / 60);
225
+ const secs = totalSeconds % 60;
226
+ return `${mins.toString().padStart(2, '0')}:${secs
227
+ .toString()
228
+ .padStart(2, '0')}`;
229
+ };
230
+
105
231
  const envConfig = useMemo(() => {
106
232
  const rawEnv = (environment || (__DEV__ ? 'DEV' : 'PROD')).trim();
107
233
  const clean = rawEnv.toUpperCase();
@@ -147,7 +273,7 @@ const InspectorHeader = React.memo(() => {
147
273
  (activeTab === 'crash' && selectedCrash != null);
148
274
 
149
275
  const isSettingsView = settingsPage !== null;
150
- const isAnySelected = isDetailView || isSettingsView;
276
+ const isAnySelected = isDetailView || isSettingsView || isFeedbackOpen;
151
277
 
152
278
  const settingsModuleTitle = useMemo(() => {
153
279
  switch (settingsPage) {
@@ -178,92 +304,114 @@ const InspectorHeader = React.memo(() => {
178
304
 
179
305
  return (
180
306
  <>
181
- <LinearGradient
182
- colors={['#4F46E5', '#7C3AED']}
183
- start={{x: 0, y: 0}}
184
- end={{x: 1, y: 1}}
185
- style={styles.headerGradient}>
186
- <View style={{paddingTop: headerTopPadding, width: '100%'}}>
187
- <View
188
- style={[
189
- styles.header,
190
- {
191
- paddingHorizontal: isNarrow ? 8 : 12,
192
- paddingVertical: isNarrow ? 6 : 8,
193
- minHeight: isNarrow ? 48 : 52,
194
- },
195
- ]}>
307
+ <View
308
+ style={[
309
+ styles.headerGradient,
310
+ {
311
+ minHeight: (isNarrow ? 48 : 52) + headerTopPadding,
312
+ },
313
+ ]}>
314
+ {/* LinearGradient as absolute background layer to avoid Fabric view recycling crash.
315
+ BVLinearGradient as a direct parent of conditionally-mounted children triggers
316
+ RCTComponentViewRegistry 'Attempt to recycle a mounted view' assertion. */}
317
+ <LinearGradient
318
+ colors={[AppColors.indigo600, AppColors.violet600]}
319
+ start={{x: 0, y: 0}}
320
+ end={{x: 1, y: 1}}
321
+ style={{
322
+ position: 'absolute',
323
+ top: 0,
324
+ left: 0,
325
+ right: 0,
326
+ bottom: 0,
327
+ borderTopLeftRadius: 20,
328
+ borderTopRightRadius: 20,
329
+ }}
330
+ pointerEvents="none"
331
+ />
332
+ <View style={{paddingTop: headerTopPadding, width: '100%'}}>
196
333
  <View
197
334
  style={[
198
- styles.headerLeft,
335
+ styles.header,
199
336
  {
337
+ paddingHorizontal: isNarrow ? 8 : 12,
338
+ paddingVertical: isNarrow ? 6 : 8,
339
+ minHeight: isNarrow ? 48 : 52,
340
+ },
341
+ ]}>
342
+ <View
343
+ style={{
200
344
  flexDirection: 'row',
201
345
  alignItems: 'center',
202
346
  gap: isNarrow ? 6 : 8,
203
- flex: !isDetailView ? 1 : 0,
204
- minWidth: 0,
205
- },
206
- ]}>
207
- <TouchableScale
208
- onPress={() => {
209
- if (isSettingsView) {
210
- if (settingsPage === 'main') {
211
- setSettingsPage(null);
212
- } else {
213
- setSettingsPage('main');
214
- }
215
- return;
216
- }
217
- requestAnimationFrame(() => {
218
- setSelected(null);
219
- setSelectedEvent(null);
220
- setSelectedLog(null);
221
- setSelectedReduxSlice(null);
222
- setSelectedReduxAction(null);
223
- setSelectedCrash(null);
224
- });
225
- }}
226
- hitSlop={15}
227
- style={[
228
- {
229
- width: isNarrow ? 32 : 36,
230
- height: isNarrow ? 32 : 36,
231
- borderRadius: isNarrow ? 16 : 18,
232
- alignItems: 'center',
233
- justifyContent: 'center',
234
- backgroundColor: `${AppColors.white}2E`,
235
- borderWidth: 1,
236
- borderColor: `${AppColors.white}4D`,
237
- },
238
- !isAnySelected && {display: 'none'},
239
- ]}>
240
- <View
241
- style={{
242
- position: 'absolute',
243
- width: isNarrow ? 40 : 44,
244
- height: isNarrow ? 40 : 44,
245
- borderRadius: 22,
246
- backgroundColor: `${AppColors.white}1A`,
247
- }}
248
- />
249
- <WhiteBackNavigation />
250
- </TouchableScale>
251
-
252
- {isSettingsView ? (
253
- <View style={{gap: 2, flex: 1, minWidth: 0}}>
254
- <View
255
- style={{flexDirection: 'row', alignItems: 'center', gap: 6}}>
256
- <Text
347
+ flexShrink: 0,
348
+ flex: isAnySelected ? undefined : 1,
349
+ minWidth: isAnySelected ? (isNarrow ? 32 : 36) : 0,
350
+ }}>
351
+ {isAnySelected && (
352
+ <TouchableScale
353
+ onPress={() => {
354
+ if (isFeedbackOpen) {
355
+ setIsFeedbackOpen(false);
356
+ return;
357
+ }
358
+ if (isSettingsView) {
359
+ if (settingsPage === 'main') {
360
+ setSettingsPage(null);
361
+ } else {
362
+ setSettingsPage('main');
363
+ }
364
+ return;
365
+ }
366
+ setSelected(null);
367
+ setSelectedEvent(null);
368
+ setSelectedLog(null);
369
+ setSelectedReduxSlice(null);
370
+ setSelectedReduxAction(null);
371
+ setSelectedCrash(null);
372
+ }}
373
+ hitSlop={15}
374
+ style={{
375
+ width: isNarrow ? 32 : 36,
376
+ height: isNarrow ? 32 : 36,
377
+ borderRadius: isNarrow ? 16 : 18,
378
+ alignItems: 'center',
379
+ justifyContent: 'center',
380
+ backgroundColor: `${AppColors.white}2E`,
381
+ borderWidth: 1,
382
+ borderColor: `${AppColors.white}4D`,
383
+ }}>
384
+ <View
257
385
  style={{
258
- fontFamily: AppFonts.interBold,
259
- fontSize: isNarrow ? 14 : 16,
260
- color: AppColors.white,
261
- letterSpacing: -0.2,
386
+ position: 'absolute',
387
+ width: isNarrow ? 40 : 44,
388
+ height: isNarrow ? 40 : 44,
389
+ borderRadius: 22,
390
+ backgroundColor: `${AppColors.white}1A`,
262
391
  }}
263
- numberOfLines={1}>
264
- {settingsModuleTitle}
265
- </Text>
266
- {settingsPage === 'main' && (
392
+ />
393
+ <WhiteBackNavigation />
394
+ </TouchableScale>
395
+ )}
396
+
397
+ {isFeedbackOpen ? (
398
+ <View style={{gap: 2, flex: 1, minWidth: 0}}>
399
+ <View
400
+ style={{
401
+ flexDirection: 'row',
402
+ alignItems: 'center',
403
+ gap: 6,
404
+ }}>
405
+ <Text
406
+ style={{
407
+ fontFamily: AppFonts.interBold,
408
+ fontSize: isNarrow ? 14 : 16,
409
+ color: AppColors.white,
410
+ letterSpacing: -0.2,
411
+ }}
412
+ numberOfLines={1}>
413
+ Support & Feedback
414
+ </Text>
267
415
  <View
268
416
  style={{
269
417
  backgroundColor: `${AppColors.white}26`,
@@ -282,297 +430,316 @@ const InspectorHeader = React.memo(() => {
282
430
  v{LIB_VERSION}
283
431
  </Text>
284
432
  </View>
285
- )}
433
+ </View>
434
+ <Text
435
+ style={{
436
+ fontFamily: AppFonts.interRegular,
437
+ fontSize: isNarrow ? 9.5 : 10.5,
438
+ color: `${AppColors.white}CC`,
439
+ }}
440
+ numberOfLines={1}>
441
+ Direct line to maintainers & developers
442
+ </Text>
286
443
  </View>
287
- <Text
288
- style={{
289
- fontFamily: AppFonts.interRegular,
290
- fontSize: isNarrow ? 9.5 : 10.5,
291
- color: `${AppColors.white}CC`,
292
- }}
293
- numberOfLines={1}>
294
- {settingsPage === 'main'
295
- ? 'Manage modules and preferences'
296
- : 'Configure module parameters'}
297
- </Text>
298
- </View>
299
- ) : !isAnySelected ? (
300
- <View
301
- style={{
302
- flexDirection: 'row',
303
- alignItems: 'center',
304
- gap: isNarrow ? 6 : 8,
305
- flex: 1,
306
- minWidth: 0,
307
- marginRight: 4,
308
- }}>
309
- <AppHeaderLogo size={logoSize} customIcon={appIcon} />
444
+ ) : isSettingsView ? (
310
445
  <View style={{gap: 2, flex: 1, minWidth: 0}}>
311
446
  <View
312
447
  style={{
313
448
  flexDirection: 'row',
314
449
  alignItems: 'center',
315
- gap: isNarrow ? 4 : 6,
316
- minWidth: 0,
450
+ gap: 6,
317
451
  }}>
318
452
  <Text
319
- style={[
320
- styles.headerTitle,
321
- {
322
- fontSize: isNarrow ? 13.5 : isCompact ? 14.5 : 15.5,
323
- flexShrink: 1,
324
- paddingBottom: 0,
325
- },
326
- ]}
327
- numberOfLines={1}
328
- ellipsizeMode="tail">
329
- {getAppName()}
453
+ style={{
454
+ fontFamily: AppFonts.interBold,
455
+ fontSize: isNarrow ? 14 : 16,
456
+ color: AppColors.white,
457
+ letterSpacing: -0.2,
458
+ }}
459
+ numberOfLines={1}>
460
+ {settingsModuleTitle}
330
461
  </Text>
331
- <View
332
- style={[
333
- styles.envBadge,
334
- {
335
- backgroundColor: envConfig.bg,
336
- borderColor: envConfig.border,
337
- flexShrink: 0,
338
- paddingHorizontal: isNarrow ? 4.5 : 6,
339
- paddingVertical: 1.5,
340
- marginBottom: 0,
341
- },
342
- ]}>
343
- <Text
344
- style={[
345
- styles.envBadgeText,
346
- {
347
- color: envConfig.text,
348
- fontSize: isNarrow ? 8.5 : 9.5,
349
- },
350
- ]}>
351
- {envConfig.label}
352
- </Text>
353
- </View>
354
- {updateAvailable && (
355
- <Pressable
356
- hitSlop={10}
357
- onPress={() => setShowUpdateModal(true)}
462
+ {settingsPage === 'main' && (
463
+ <View
358
464
  style={{
359
- flexDirection: 'row',
360
- alignItems: 'center',
361
- backgroundColor: '#F59E0B',
362
- borderRadius: 5,
363
- paddingHorizontal: isNarrow ? 4 : 5.5,
465
+ backgroundColor: `${AppColors.white}26`,
466
+ paddingHorizontal: isNarrow ? 4 : 6,
364
467
  paddingVertical: 1.5,
365
- gap: 3,
366
- shadowColor: '#F59E0B',
367
- shadowOffset: {width: 0, height: 1.5},
368
- shadowOpacity: 0.35,
369
- shadowRadius: 3,
370
- elevation: 3,
371
- flexShrink: 0,
468
+ borderRadius: 10,
469
+ borderWidth: 1,
470
+ borderColor: `${AppColors.white}20`,
372
471
  }}>
373
- <Animated.View
472
+ <Text
374
473
  style={{
375
- width: 5,
376
- height: 5,
377
- borderRadius: 2.5,
378
- backgroundColor: '#FFFFFF',
379
- opacity: activePulseAnim,
380
- transform: [{scale: unreadPulseAnim}],
381
- }}
382
- />
383
- {!isNarrow && (
384
- <Text
385
- style={{
386
- fontFamily: AppFonts.interBold,
387
- fontSize: 8.5,
388
- color: '#FFFFFF',
389
- letterSpacing: 0.3,
390
- }}>
391
- UPDATE
392
- </Text>
393
- )}
394
- <BoltIcon size={isNarrow ? 8 : 9} color="#FFFFFF" />
395
- </Pressable>
474
+ fontFamily: AppFonts.interBold,
475
+ fontSize: isNarrow ? 8 : 9,
476
+ color: AppColors.white,
477
+ }}>
478
+ v{LIB_VERSION}
479
+ </Text>
480
+ </View>
396
481
  )}
397
482
  </View>
398
-
399
- {/* OS & NPM Version Representation */}
400
- <View
483
+ <Text
401
484
  style={{
402
- flexDirection: 'row',
403
- alignItems: 'center',
404
- gap: isNarrow ? 4 : 5,
405
- minWidth: 0,
406
- }}>
485
+ fontFamily: AppFonts.interRegular,
486
+ fontSize: isNarrow ? 9.5 : 10.5,
487
+ color: `${AppColors.white}CC`,
488
+ }}
489
+ numberOfLines={1}>
490
+ {settingsPage === 'main'
491
+ ? 'Manage modules and preferences'
492
+ : 'Configure module parameters'}
493
+ </Text>
494
+ </View>
495
+ ) : !isAnySelected ? (
496
+ <View
497
+ style={{
498
+ flexDirection: 'row',
499
+ alignItems: 'center',
500
+ gap: isNarrow ? 6 : 8,
501
+ flex: 1,
502
+ minWidth: 0,
503
+ marginRight: 4,
504
+ }}>
505
+ <AppHeaderLogo size={logoSize} customIcon={appIcon} />
506
+ <View style={{gap: 2, flex: 1, minWidth: 0}}>
407
507
  <View
408
508
  style={{
409
509
  flexDirection: 'row',
410
510
  alignItems: 'center',
411
- backgroundColor: `${AppColors.white}1F`,
412
- borderRadius: 5,
413
- paddingHorizontal: isNarrow ? 4.5 : 6,
414
- paddingVertical: 2,
415
- gap: 3.5,
416
- borderWidth: 1,
417
- borderColor: `${AppColors.white}2E`,
418
- flexShrink: 1,
511
+ gap: isNarrow ? 4 : 6,
419
512
  minWidth: 0,
420
513
  }}>
421
- {Platform.OS === 'ios' ? (
422
- <AppleIcon color={`${AppColors.white}E6`} size={isNarrow ? 9 : 10} />
423
- ) : (
424
- <AndroidIcon color={`${AppColors.white}E6`} size={isNarrow ? 9 : 10} />
425
- )}
426
514
  <Text
427
- style={{
428
- fontFamily: AppFonts.interMedium,
429
- fontSize: isNarrow ? 8.5 : 9.5,
430
- color: `${AppColors.white}EB`,
431
- letterSpacing: 0.1,
432
- }}
515
+ style={[
516
+ styles.headerTitle,
517
+ {
518
+ fontSize: isNarrow ? 13.5 : isCompact ? 14.5 : 15.5,
519
+ flexShrink: 1,
520
+ paddingBottom: 0,
521
+ },
522
+ ]}
433
523
  numberOfLines={1}
434
524
  ellipsizeMode="tail">
435
- {appVersionString}
525
+ {getAppName()}
436
526
  </Text>
527
+ <View
528
+ style={[
529
+ styles.envBadge,
530
+ {
531
+ backgroundColor: envConfig.bg,
532
+ borderColor: envConfig.border,
533
+ flexShrink: 0,
534
+ paddingHorizontal: isNarrow ? 4.5 : 6,
535
+ paddingVertical: 1.5,
536
+ marginBottom: 0,
537
+ },
538
+ ]}>
539
+ <Text
540
+ style={[
541
+ styles.envBadgeText,
542
+ {
543
+ color: envConfig.text,
544
+ fontSize: isNarrow ? 8.5 : 9.5,
545
+ },
546
+ ]}>
547
+ {envConfig.label}
548
+ </Text>
549
+ </View>
550
+ {updateAvailable && (
551
+ <Pressable
552
+ hitSlop={10}
553
+ onPress={() => setShowUpdateModal(true)}
554
+ style={{
555
+ flexDirection: 'row',
556
+ alignItems: 'center',
557
+ backgroundColor: AppColors.warningAmber,
558
+ borderRadius: 5,
559
+ paddingHorizontal: isNarrow ? 4 : 5.5,
560
+ paddingVertical: 1.5,
561
+ gap: 3,
562
+ shadowColor: AppColors.warningAmber,
563
+ shadowOffset: {width: 0, height: 1.5},
564
+ shadowOpacity: 0.35,
565
+ shadowRadius: 3,
566
+ elevation: 3,
567
+ flexShrink: 0,
568
+ }}>
569
+ <Animated.View
570
+ style={{
571
+ width: 5,
572
+ height: 5,
573
+ borderRadius: 2.5,
574
+ backgroundColor: AppColors.white,
575
+ opacity: activePulseAnim,
576
+ transform: [{scale: unreadPulseAnim}],
577
+ }}
578
+ />
579
+ {!isNarrow && (
580
+ <Text
581
+ style={{
582
+ fontFamily: AppFonts.interBold,
583
+ fontSize: 8.5,
584
+ color: AppColors.white,
585
+ letterSpacing: 0.3,
586
+ }}>
587
+ UPDATE
588
+ </Text>
589
+ )}
590
+ <BoltIcon
591
+ size={isNarrow ? 8 : 9}
592
+ color={AppColors.white}
593
+ />
594
+ </Pressable>
595
+ )}
437
596
  </View>
438
597
 
439
- <Pressable
440
- onPress={() => {
441
- if (updateAvailable) {
442
- setShowUpdateModal(true);
443
- } else {
444
- Linking.openURL(
445
- 'https://www.npmjs.com/package/react-native-inapp-inspector',
446
- ).catch(() => {});
447
- }
448
- }}
598
+ {/* OS & NPM Version Representation */}
599
+ <View
449
600
  style={{
450
601
  flexDirection: 'row',
451
602
  alignItems: 'center',
452
- backgroundColor: `${AppColors.white}1F`,
453
- borderRadius: 5,
454
- paddingHorizontal: isNarrow ? 4.5 : 6,
455
- paddingVertical: 2,
456
- gap: 3.5,
457
- borderWidth: 1,
458
- borderColor: `${AppColors.white}2E`,
459
- flexShrink: 0,
603
+ gap: isNarrow ? 4 : 5,
604
+ minWidth: 0,
460
605
  }}>
461
- <NpmIcon size={isNarrow ? 9 : 10} color="#FF6B6B" />
462
- <Text
606
+ <View
463
607
  style={{
464
- fontFamily: AppFonts.interMedium,
465
- fontSize: isNarrow ? 8.5 : 9.5,
466
- color: `${AppColors.white}EB`,
467
- letterSpacing: 0.1,
608
+ flexDirection: 'row',
609
+ alignItems: 'center',
610
+ backgroundColor: `${AppColors.white}1F`,
611
+ borderRadius: 5,
612
+ paddingHorizontal: isNarrow ? 4.5 : 6,
613
+ paddingVertical: 2,
614
+ gap: 3.5,
615
+ borderWidth: 1,
616
+ borderColor: `${AppColors.white}2E`,
617
+ flexShrink: 1,
618
+ minWidth: 0,
619
+ }}>
620
+ {Platform.OS === 'ios' ? (
621
+ <AppleIcon
622
+ color={`${AppColors.white}E6`}
623
+ size={isNarrow ? 9 : 10}
624
+ />
625
+ ) : (
626
+ <AndroidIcon
627
+ color={`${AppColors.white}E6`}
628
+ size={isNarrow ? 9 : 10}
629
+ />
630
+ )}
631
+ <Text
632
+ style={{
633
+ fontFamily: AppFonts.interMedium,
634
+ fontSize: isNarrow ? 8.5 : 9.5,
635
+ color: `${AppColors.white}EB`,
636
+ letterSpacing: 0.1,
637
+ }}
638
+ numberOfLines={1}
639
+ ellipsizeMode="tail">
640
+ {appVersionString}
641
+ </Text>
642
+ </View>
643
+
644
+ <Pressable
645
+ onPress={() => {
646
+ if (updateAvailable) {
647
+ setShowUpdateModal(true);
648
+ } else {
649
+ Linking.openURL(
650
+ 'https://www.npmjs.com/package/react-native-inapp-inspector',
651
+ ).catch(() => {});
652
+ }
468
653
  }}
469
- numberOfLines={1}>
470
- v{LIB_VERSION}
471
- </Text>
472
- {updateAvailable && (
654
+ style={{
655
+ flexDirection: 'row',
656
+ alignItems: 'center',
657
+ backgroundColor: `${AppColors.white}1F`,
658
+ borderRadius: 5,
659
+ paddingHorizontal: isNarrow ? 4.5 : 6,
660
+ paddingVertical: 2,
661
+ gap: 3.5,
662
+ borderWidth: 1,
663
+ borderColor: `${AppColors.white}2E`,
664
+ flexShrink: 0,
665
+ }}>
666
+ <NpmIcon
667
+ size={isNarrow ? 9 : 10}
668
+ color={AppColors.npmRedLight}
669
+ />
473
670
  <Text
474
671
  style={{
475
- fontFamily: AppFonts.interBold,
476
- fontSize: 8.5,
477
- color: '#F59E0B',
478
- }}>
479
- ●
672
+ fontFamily: AppFonts.interMedium,
673
+ fontSize: isNarrow ? 8.5 : 9.5,
674
+ color: `${AppColors.white}EB`,
675
+ letterSpacing: 0.1,
676
+ }}
677
+ numberOfLines={1}>
678
+ v{LIB_VERSION}
480
679
  </Text>
481
- )}
482
- </Pressable>
680
+ {updateAvailable && (
681
+ <Text
682
+ style={{
683
+ fontFamily: AppFonts.interBold,
684
+ fontSize: 8.5,
685
+ color: AppColors.warningAmber,
686
+ }}>
687
+ ●
688
+ </Text>
689
+ )}
690
+ </Pressable>
691
+ </View>
483
692
  </View>
484
693
  </View>
485
- </View>
486
- ) : null}
487
- </View>
694
+ ) : null}
695
+ </View>
488
696
 
489
- {isDetailView && (
490
- <View style={[styles.headerCenter, {paddingHorizontal: isNarrow ? 2 : 6}]}>
491
- {activeTab === 'apis' && selected != null ? (
492
- <View style={styles.headerDetailCenter}>
493
- <View style={styles.headerDetailRow}>
494
- <View
495
- style={[
496
- styles.headerMethodBadge,
497
- {
498
- backgroundColor:
499
- METHOD_COLORS[selected.method as Method] ??
500
- AppColors.grayText,
501
- paddingHorizontal: isNarrow ? 5 : 6,
502
- paddingVertical: isNarrow ? 2 : 3,
503
- },
504
- ]}>
505
- <Text style={[styles.headerMethodText, {fontSize: isNarrow ? 9 : 10}]}>
506
- {selected.method}
507
- </Text>
508
- </View>
509
- <Text
510
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
511
- numberOfLines={1}
512
- ellipsizeMode="middle">
513
- {detailTitle}
514
- </Text>
515
- </View>
516
- <ScrollView
517
- horizontal
518
- showsHorizontalScrollIndicator={false}
519
- contentContainerStyle={{
520
- flexDirection: 'row',
521
- alignItems: 'center',
522
- gap: isNarrow ? 4 : 6,
523
- marginTop: 3,
524
- paddingVertical: 1,
525
- }}>
526
- <View
527
- style={{
528
- flexDirection: 'row',
529
- alignItems: 'center',
530
- gap: 4,
531
- paddingHorizontal: isNarrow ? 6 : 8,
532
- paddingVertical: 2.5,
533
- borderRadius: 20,
534
- backgroundColor: `${getStatusColor(selected.status)}26`,
535
- borderWidth: 1,
536
- borderColor: `${getStatusColor(selected.status)}55`,
537
- }}>
697
+ {isDetailView && (
698
+ <View
699
+ style={[
700
+ styles.headerCenter,
701
+ {paddingHorizontal: isNarrow ? 2 : 6},
702
+ ]}>
703
+ {activeTab === 'apis' && selected != null ? (
704
+ <View style={styles.headerDetailCenter}>
705
+ <View style={styles.headerDetailRow}>
538
706
  <View
539
707
  style={[
540
- styles.headerStatusDot,
708
+ styles.headerMethodBadge,
541
709
  {
542
- backgroundColor: getStatusColor(selected.status),
543
- width: isNarrow ? 6 : 7,
544
- height: isNarrow ? 6 : 7,
710
+ backgroundColor:
711
+ METHOD_COLORS[selected.method as Method] ??
712
+ AppColors.grayText,
713
+ paddingHorizontal: isNarrow ? 5 : 6,
714
+ paddingVertical: isNarrow ? 2 : 3,
545
715
  },
546
- ]}
547
- />
716
+ ]}>
717
+ <Text
718
+ style={[
719
+ styles.headerMethodText,
720
+ {fontSize: isNarrow ? 9 : 10},
721
+ ]}>
722
+ {selected.method}
723
+ </Text>
724
+ </View>
548
725
  <Text
549
726
  style={[
550
- styles.headerSubTitle,
551
- {fontFamily: AppFonts.interBold, fontSize: isNarrow ? 10 : 11},
552
- ]}>
553
- {selected.status === 0
554
- ? 'Failed'
555
- : selected.status ?? 'Pending'}
727
+ styles.headerDetailTitle,
728
+ {fontSize: isNarrow ? 13.5 : 15},
729
+ ]}
730
+ numberOfLines={1}
731
+ ellipsizeMode="middle">
732
+ {detailTitle}
556
733
  </Text>
557
734
  </View>
558
735
  <View
559
736
  style={{
560
737
  flexDirection: 'row',
561
738
  alignItems: 'center',
562
- gap: 4,
563
- paddingHorizontal: isNarrow ? 6 : 8,
564
- paddingVertical: 2.5,
565
- borderRadius: 20,
566
- backgroundColor: `${AppColors.white}29`,
739
+ gap: isNarrow ? 4 : 6,
740
+ marginTop: 3,
741
+ paddingVertical: 1,
567
742
  }}>
568
- <ClockIcon color={AppColors.white} size={isNarrow ? 10 : 11} />
569
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
570
- {selected.duration != null
571
- ? `${selected.duration}ms`
572
- : '—'}
573
- </Text>
574
- </View>
575
- {selected.response != null && (
576
743
  <View
577
744
  style={{
578
745
  flexDirection: 'row',
@@ -581,390 +748,563 @@ const InspectorHeader = React.memo(() => {
581
748
  paddingHorizontal: isNarrow ? 6 : 8,
582
749
  paddingVertical: 2.5,
583
750
  borderRadius: 20,
584
- backgroundColor: `${AppColors.white}29`,
751
+ backgroundColor: `${getStatusColor(
752
+ selected.status,
753
+ )}26`,
754
+ borderWidth: 1,
755
+ borderColor: `${getStatusColor(selected.status)}55`,
585
756
  }}>
586
- <SizeIcon color={AppColors.white} size={isNarrow ? 10 : 11} />
587
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
588
- {getSize(selected.response)}
757
+ <View
758
+ style={[
759
+ styles.headerStatusDot,
760
+ {
761
+ backgroundColor: getStatusColor(selected.status),
762
+ width: isNarrow ? 6 : 7,
763
+ height: isNarrow ? 6 : 7,
764
+ },
765
+ ]}
766
+ />
767
+ <Text
768
+ style={[
769
+ styles.headerSubTitle,
770
+ {
771
+ fontFamily: AppFonts.interBold,
772
+ fontSize: isNarrow ? 10 : 11,
773
+ },
774
+ ]}>
775
+ {selected.status === 0
776
+ ? 'Failed'
777
+ : selected.status ?? 'Pending'}
589
778
  </Text>
590
779
  </View>
591
- )}
592
- </ScrollView>
593
- </View>
594
- ) : activeTab === 'analytics' && selectedEvent != null ? (
595
- <View style={styles.headerDetailCenter}>
596
- <View style={styles.headerDetailRow}>
597
- <View
598
- style={[
599
- styles.headerMethodBadge,
600
- {
601
- backgroundColor:
602
- selectedEvent.source === 'firebase'
603
- ? `${AppColors.firebaseOrange}4D`
604
- : `${AppColors.purple}4D`,
605
- paddingHorizontal: isNarrow ? 5 : 6,
606
- paddingVertical: isNarrow ? 2 : 3,
607
- },
608
- ]}>
609
- <Text style={[styles.headerMethodText, {fontSize: isNarrow ? 9 : 10}]}>
610
- {selectedEvent.source === 'firebase' ? 'FB' : 'MAN'}
611
- </Text>
612
- </View>
613
- <Text
614
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
615
- numberOfLines={1}
616
- ellipsizeMode="middle">
617
- {selectedEvent.name}
618
- </Text>
780
+ <View
781
+ style={{
782
+ flexDirection: 'row',
783
+ alignItems: 'center',
784
+ gap: 4,
785
+ paddingHorizontal: isNarrow ? 6 : 8,
786
+ paddingVertical: 2.5,
787
+ borderRadius: 20,
788
+ backgroundColor: `${AppColors.white}29`,
789
+ }}>
790
+ <ClockIcon
791
+ color={AppColors.white}
792
+ size={isNarrow ? 10 : 11}
793
+ />
794
+ <Text
795
+ style={[
796
+ styles.headerSubTitle,
797
+ {fontSize: isNarrow ? 10 : 11},
798
+ ]}>
799
+ {selected.duration != null
800
+ ? `${selected.duration}ms`
801
+ : '—'}
802
+ </Text>
803
+ </View>
804
+ {selected.response != null && (
805
+ <View
806
+ style={{
807
+ flexDirection: 'row',
808
+ alignItems: 'center',
809
+ gap: 4,
810
+ paddingHorizontal: isNarrow ? 6 : 8,
811
+ paddingVertical: 2.5,
812
+ borderRadius: 20,
813
+ backgroundColor: `${AppColors.white}29`,
814
+ }}>
815
+ <SizeIcon
816
+ color={AppColors.white}
817
+ size={isNarrow ? 10 : 11}
818
+ />
819
+ <Text
820
+ style={[
821
+ styles.headerSubTitle,
822
+ {fontSize: isNarrow ? 10 : 11},
823
+ ]}>
824
+ {getSize(selected.response)}
825
+ </Text>
826
+ </View>
827
+ )}
828
+ </View>
619
829
  </View>
620
- <ScrollView
621
- horizontal
622
- showsHorizontalScrollIndicator={false}
623
- contentContainerStyle={{
624
- flexDirection: 'row',
625
- alignItems: 'center',
626
- gap: isNarrow ? 4 : 6,
627
- marginTop: 3,
628
- paddingVertical: 1,
629
- }}>
630
- <View
631
- style={[
632
- styles.headerStatusDot,
633
- {
634
- backgroundColor:
635
- selectedEvent.source === 'firebase'
636
- ? AppColors.firebaseOrange
637
- : AppColors.purple,
638
- width: isNarrow ? 6 : 7,
639
- height: isNarrow ? 6 : 7,
640
- },
641
- ]}
642
- />
643
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
644
- {Object.keys(selectedEvent.params).length} param
645
- {Object.keys(selectedEvent.params).length !== 1
646
- ? 's'
647
- : ''}
648
- {' · '}
649
- {selectedEvent.source}
650
- </Text>
651
- </ScrollView>
652
- </View>
653
- ) : activeTab === 'logs' && selectedLog != null ? (
654
- <View style={styles.headerDetailCenter}>
655
- <View style={styles.headerDetailRow}>
656
- <View
657
- style={[
658
- styles.headerMethodBadge,
659
- {
660
- backgroundColor:
661
- selectedLog.type === 'error'
662
- ? `${AppColors.errorColor}4D`
663
- : selectedLog.type === 'warn'
664
- ? `${AppColors.lightOrange}4D`
665
- : `${AppColors.purple}4D`,
666
- paddingHorizontal: isNarrow ? 5 : 6,
667
- paddingVertical: isNarrow ? 2 : 3,
668
- },
669
- ]}>
670
- <Text style={[styles.headerMethodText, {fontSize: isNarrow ? 9 : 10}]}>
671
- {selectedLog.type.toUpperCase()}
830
+ ) : activeTab === 'analytics' && selectedEvent != null ? (
831
+ <View style={styles.headerDetailCenter}>
832
+ <View style={styles.headerDetailRow}>
833
+ <View
834
+ style={[
835
+ styles.headerMethodBadge,
836
+ {
837
+ backgroundColor:
838
+ selectedEvent.source === 'firebase'
839
+ ? `${AppColors.firebaseOrange}4D`
840
+ : `${AppColors.purple}4D`,
841
+ paddingHorizontal: isNarrow ? 5 : 6,
842
+ paddingVertical: isNarrow ? 2 : 3,
843
+ },
844
+ ]}>
845
+ <Text
846
+ style={[
847
+ styles.headerMethodText,
848
+ {fontSize: isNarrow ? 9 : 10},
849
+ ]}>
850
+ {selectedEvent.source === 'firebase' ? 'FB' : 'MAN'}
851
+ </Text>
852
+ </View>
853
+ <Text
854
+ style={[
855
+ styles.headerDetailTitle,
856
+ {fontSize: isNarrow ? 13.5 : 15},
857
+ ]}
858
+ numberOfLines={1}
859
+ ellipsizeMode="middle">
860
+ {selectedEvent.name}
672
861
  </Text>
673
862
  </View>
674
- <Text
675
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
676
- numberOfLines={1}
677
- ellipsizeMode="middle">
678
- console.
679
- {selectedLog.sourceMethod || selectedLog.type || 'log'}
680
- </Text>
681
- </View>
682
- <ScrollView
683
- horizontal
684
- showsHorizontalScrollIndicator={false}
685
- contentContainerStyle={{
686
- flexDirection: 'row',
687
- alignItems: 'center',
688
- gap: isNarrow ? 4 : 6,
689
- marginTop: 3,
690
- paddingVertical: 1,
691
- }}>
692
863
  <View
693
864
  style={{
694
865
  flexDirection: 'row',
695
866
  alignItems: 'center',
696
- gap: 4,
697
- paddingHorizontal: isNarrow ? 6 : 8,
698
- paddingVertical: 2.5,
699
- borderRadius: 20,
700
- backgroundColor: `${AppColors.white}29`,
867
+ gap: isNarrow ? 4 : 6,
868
+ marginTop: 3,
869
+ paddingVertical: 1,
701
870
  }}>
702
- <ClockIcon color={AppColors.white} size={isNarrow ? 10 : 11} />
703
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
704
- {formatTime(selectedLog.timestamp)}
871
+ <View
872
+ style={[
873
+ styles.headerStatusDot,
874
+ {
875
+ backgroundColor:
876
+ selectedEvent.source === 'firebase'
877
+ ? AppColors.firebaseOrange
878
+ : AppColors.purple,
879
+ width: isNarrow ? 6 : 7,
880
+ height: isNarrow ? 6 : 7,
881
+ },
882
+ ]}
883
+ />
884
+ <Text
885
+ style={[
886
+ styles.headerSubTitle,
887
+ {fontSize: isNarrow ? 10 : 11},
888
+ ]}>
889
+ {Object.keys(selectedEvent.params).length} param
890
+ {Object.keys(selectedEvent.params).length !== 1
891
+ ? 's'
892
+ : ''}
893
+ {' · '}
894
+ {selectedEvent.source}
705
895
  </Text>
706
896
  </View>
707
- </ScrollView>
708
- </View>
709
- ) : activeTab === 'redux' && selectedReduxSlice != null ? (
710
- (() => {
711
- const sliceData = reduxState?.[selectedReduxSlice];
712
- const keyCount =
713
- sliceData && typeof sliceData === 'object'
714
- ? Object.keys(sliceData).length
715
- : typeof sliceData !== 'undefined'
716
- ? 1
717
- : 0;
718
- const sliceSize = getSize(sliceData);
719
- const lastAction = reduxLastActionMap[selectedReduxSlice];
720
-
721
- return (
722
- <View style={styles.headerDetailCenter}>
723
- <View style={styles.headerDetailRow}>
724
- <View
897
+ </View>
898
+ ) : activeTab === 'logs' && selectedLog != null ? (
899
+ <View style={styles.headerDetailCenter}>
900
+ <View style={styles.headerDetailRow}>
901
+ <View
902
+ style={[
903
+ styles.headerMethodBadge,
904
+ {
905
+ backgroundColor:
906
+ selectedLog.type === 'error'
907
+ ? `${AppColors.errorColor}4D`
908
+ : selectedLog.type === 'warn'
909
+ ? `${AppColors.lightOrange}4D`
910
+ : `${AppColors.purple}4D`,
911
+ paddingHorizontal: isNarrow ? 5 : 6,
912
+ paddingVertical: isNarrow ? 2 : 3,
913
+ },
914
+ ]}>
915
+ <Text
725
916
  style={[
726
- styles.headerMethodBadge,
727
- {
728
- backgroundColor: `${AppColors.purple}4D`,
729
- paddingHorizontal: isNarrow ? 5 : 6,
730
- paddingVertical: isNarrow ? 2 : 3,
731
- },
917
+ styles.headerMethodText,
918
+ {fontSize: isNarrow ? 9 : 10},
732
919
  ]}>
733
- <Text style={[styles.headerMethodText, {fontSize: isNarrow ? 9 : 10}]}>SLICE</Text>
734
- </View>
735
- <Text
736
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
737
- numberOfLines={1}
738
- ellipsizeMode="middle">
739
- {selectedReduxSlice}
920
+ {selectedLog.type.toUpperCase()}
740
921
  </Text>
741
922
  </View>
742
- <ScrollView
743
- horizontal
744
- showsHorizontalScrollIndicator={false}
745
- contentContainerStyle={{
923
+ <Text
924
+ style={[
925
+ styles.headerDetailTitle,
926
+ {fontSize: isNarrow ? 13.5 : 15},
927
+ ]}
928
+ numberOfLines={1}
929
+ ellipsizeMode="middle">
930
+ console.
931
+ {selectedLog.sourceMethod || selectedLog.type || 'log'}
932
+ </Text>
933
+ </View>
934
+ <View
935
+ style={{
936
+ flexDirection: 'row',
937
+ alignItems: 'center',
938
+ gap: isNarrow ? 4 : 6,
939
+ marginTop: 3,
940
+ paddingVertical: 1,
941
+ }}>
942
+ <View
943
+ style={{
746
944
  flexDirection: 'row',
747
945
  alignItems: 'center',
748
- gap: isNarrow ? 4 : 6,
749
- marginTop: 3,
750
- paddingVertical: 1,
946
+ gap: 4,
947
+ paddingHorizontal: isNarrow ? 6 : 8,
948
+ paddingVertical: 2.5,
949
+ borderRadius: 20,
950
+ backgroundColor: `${AppColors.white}29`,
751
951
  }}>
752
- <View
753
- style={[
754
- styles.headerStatusDot,
755
- {
756
- backgroundColor: AppColors.liveGreen,
757
- width: isNarrow ? 6 : 7,
758
- height: isNarrow ? 6 : 7,
759
- },
760
- ]}
952
+ <ClockIcon
953
+ color={AppColors.white}
954
+ size={isNarrow ? 10 : 11}
761
955
  />
762
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>Live</Text>
763
- <Text style={[styles.headerSubTitle, {opacity: 0.6, fontSize: isNarrow ? 10 : 11}]}>
764
- •
765
- </Text>
766
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
767
- {keyCount} keys
768
- </Text>
769
- <Text style={[styles.headerSubTitle, {opacity: 0.6, fontSize: isNarrow ? 10 : 11}]}>
770
- •
956
+ <Text
957
+ style={[
958
+ styles.headerSubTitle,
959
+ {fontSize: isNarrow ? 10 : 11},
960
+ ]}>
961
+ {formatTime(selectedLog.timestamp)}
771
962
  </Text>
772
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>{sliceSize}</Text>
773
- {lastAction?.timestamp && (
774
- <>
963
+ </View>
964
+ </View>
965
+ </View>
966
+ ) : activeTab === 'redux' && selectedReduxSlice != null ? (
967
+ (() => {
968
+ const sliceData = reduxState?.[selectedReduxSlice];
969
+ const keyCount =
970
+ sliceData && typeof sliceData === 'object'
971
+ ? Object.keys(sliceData).length
972
+ : typeof sliceData !== 'undefined'
973
+ ? 1
974
+ : 0;
975
+ const sliceSize = getSize(sliceData);
976
+ const lastAction = reduxLastActionMap[selectedReduxSlice];
977
+
978
+ return (
979
+ <View style={styles.headerDetailCenter}>
980
+ <View style={styles.headerDetailRow}>
981
+ <View
982
+ style={[
983
+ styles.headerMethodBadge,
984
+ {
985
+ backgroundColor: `${AppColors.purple}4D`,
986
+ paddingHorizontal: isNarrow ? 5 : 6,
987
+ paddingVertical: isNarrow ? 2 : 3,
988
+ },
989
+ ]}>
775
990
  <Text
776
- style={[styles.headerSubTitle, {opacity: 0.6, fontSize: isNarrow ? 10 : 11}]}>
777
- •
991
+ style={[
992
+ styles.headerMethodText,
993
+ {fontSize: isNarrow ? 9 : 10},
994
+ ]}>
995
+ SLICE
778
996
  </Text>
779
- <View
780
- style={{
781
- flexDirection: 'row',
782
- alignItems: 'center',
783
- gap: 3,
784
- }}>
785
- <ClockIcon color={AppColors.white} size={isNarrow ? 9 : 10} />
786
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
787
- {lastAction.timestamp}
997
+ </View>
998
+ <Text
999
+ style={[
1000
+ styles.headerDetailTitle,
1001
+ {fontSize: isNarrow ? 13.5 : 15},
1002
+ ]}
1003
+ numberOfLines={1}
1004
+ ellipsizeMode="middle">
1005
+ {selectedReduxSlice}
1006
+ </Text>
1007
+ </View>
1008
+ <View
1009
+ style={{
1010
+ flexDirection: 'row',
1011
+ alignItems: 'center',
1012
+ gap: isNarrow ? 4 : 6,
1013
+ marginTop: 3,
1014
+ paddingVertical: 1,
1015
+ }}>
1016
+ <View
1017
+ style={[
1018
+ styles.headerStatusDot,
1019
+ {
1020
+ backgroundColor: AppColors.liveGreen,
1021
+ width: isNarrow ? 6 : 7,
1022
+ height: isNarrow ? 6 : 7,
1023
+ },
1024
+ ]}
1025
+ />
1026
+ <Text
1027
+ style={[
1028
+ styles.headerSubTitle,
1029
+ {fontSize: isNarrow ? 10 : 11},
1030
+ ]}>
1031
+ Live
1032
+ </Text>
1033
+ <Text
1034
+ style={[
1035
+ styles.headerSubTitle,
1036
+ {opacity: 0.6, fontSize: isNarrow ? 10 : 11},
1037
+ ]}>
1038
+ •
1039
+ </Text>
1040
+ <Text
1041
+ style={[
1042
+ styles.headerSubTitle,
1043
+ {fontSize: isNarrow ? 10 : 11},
1044
+ ]}>
1045
+ {keyCount} keys
1046
+ </Text>
1047
+ <Text
1048
+ style={[
1049
+ styles.headerSubTitle,
1050
+ {opacity: 0.6, fontSize: isNarrow ? 10 : 11},
1051
+ ]}>
1052
+ •
1053
+ </Text>
1054
+ <Text
1055
+ style={[
1056
+ styles.headerSubTitle,
1057
+ {fontSize: isNarrow ? 10 : 11},
1058
+ ]}>
1059
+ {sliceSize}
1060
+ </Text>
1061
+ {lastAction?.timestamp && (
1062
+ <>
1063
+ <Text
1064
+ style={[
1065
+ styles.headerSubTitle,
1066
+ {opacity: 0.6, fontSize: isNarrow ? 10 : 11},
1067
+ ]}>
1068
+ •
788
1069
  </Text>
789
- </View>
790
- </>
791
- )}
792
- </ScrollView>
1070
+ <View
1071
+ style={{
1072
+ flexDirection: 'row',
1073
+ alignItems: 'center',
1074
+ gap: 3,
1075
+ }}>
1076
+ <ClockIcon
1077
+ color={AppColors.white}
1078
+ size={isNarrow ? 9 : 10}
1079
+ />
1080
+ <Text
1081
+ style={[
1082
+ styles.headerSubTitle,
1083
+ {fontSize: isNarrow ? 10 : 11},
1084
+ ]}>
1085
+ {lastAction.timestamp}
1086
+ </Text>
1087
+ </View>
1088
+ </>
1089
+ )}
1090
+ </View>
1091
+ </View>
1092
+ );
1093
+ })()
1094
+ ) : activeTab === 'redux' && selectedReduxAction != null ? (
1095
+ <View style={styles.headerDetailCenter}>
1096
+ <View style={styles.headerDetailRow}>
1097
+ <View
1098
+ style={[
1099
+ styles.headerMethodBadge,
1100
+ {
1101
+ backgroundColor: `${AppColors.brandPurple}4D`,
1102
+ paddingHorizontal: isNarrow ? 5 : 6,
1103
+ paddingVertical: isNarrow ? 2 : 3,
1104
+ },
1105
+ ]}>
1106
+ <Text
1107
+ style={[
1108
+ styles.headerMethodText,
1109
+ {fontSize: isNarrow ? 9 : 10},
1110
+ ]}>
1111
+ ACTION
1112
+ </Text>
1113
+ </View>
1114
+ <Text
1115
+ style={[
1116
+ styles.headerDetailTitle,
1117
+ {fontSize: isNarrow ? 13.5 : 15},
1118
+ ]}
1119
+ numberOfLines={1}
1120
+ ellipsizeMode="middle">
1121
+ {selectedReduxAction.type}
1122
+ </Text>
793
1123
  </View>
794
- );
795
- })()
796
- ) : activeTab === 'redux' && selectedReduxAction != null ? (
797
- <View style={styles.headerDetailCenter}>
798
- <View style={styles.headerDetailRow}>
799
1124
  <View
800
- style={[
801
- styles.headerMethodBadge,
802
- {
803
- backgroundColor: `${AppColors.brandPurple}4D`,
804
- paddingHorizontal: isNarrow ? 5 : 6,
805
- paddingVertical: isNarrow ? 2 : 3,
806
- },
807
- ]}>
808
- <Text style={[styles.headerMethodText, {fontSize: isNarrow ? 9 : 10}]}>ACTION</Text>
1125
+ style={{
1126
+ flexDirection: 'row',
1127
+ alignItems: 'center',
1128
+ gap: isNarrow ? 4 : 6,
1129
+ marginTop: 3,
1130
+ paddingVertical: 1,
1131
+ }}>
1132
+ <View
1133
+ style={[
1134
+ styles.headerStatusDot,
1135
+ {
1136
+ backgroundColor: AppColors.purple,
1137
+ width: isNarrow ? 6 : 7,
1138
+ height: isNarrow ? 6 : 7,
1139
+ },
1140
+ ]}
1141
+ />
1142
+ <Text
1143
+ style={[
1144
+ styles.headerSubTitle,
1145
+ {fontSize: isNarrow ? 10 : 11},
1146
+ ]}>
1147
+ {selectedReduxAction.timestamp || 'Dispatched'}
1148
+ </Text>
809
1149
  </View>
810
- <Text
811
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
812
- numberOfLines={1}
813
- ellipsizeMode="middle">
814
- {selectedReduxAction.type}
815
- </Text>
816
1150
  </View>
817
- <ScrollView
818
- horizontal
819
- showsHorizontalScrollIndicator={false}
820
- contentContainerStyle={{
821
- flexDirection: 'row',
822
- alignItems: 'center',
823
- gap: isNarrow ? 4 : 6,
824
- marginTop: 3,
825
- paddingVertical: 1,
826
- }}>
827
- <View
828
- style={[
829
- styles.headerStatusDot,
830
- {
831
- backgroundColor: AppColors.purple,
832
- width: isNarrow ? 6 : 7,
833
- height: isNarrow ? 6 : 7,
834
- },
835
- ]}
836
- />
837
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
838
- {selectedReduxAction.timestamp || 'Dispatched'}
839
- </Text>
840
- </ScrollView>
841
- </View>
842
- ) : activeTab === 'crash' && selectedCrash != null ? (
843
- <View style={styles.headerDetailCenter}>
844
- <View style={styles.headerDetailRow}>
1151
+ ) : activeTab === 'crash' && selectedCrash != null ? (
1152
+ <View style={styles.headerDetailCenter}>
1153
+ <View style={styles.headerDetailRow}>
1154
+ <View
1155
+ style={[
1156
+ styles.headerMethodBadge,
1157
+ {
1158
+ backgroundColor: selectedCrash.isFatal
1159
+ ? AppColors.red600
1160
+ : AppColors.amber600,
1161
+ paddingHorizontal: isNarrow ? 5 : 6,
1162
+ paddingVertical: isNarrow ? 2 : 3,
1163
+ },
1164
+ ]}>
1165
+ <Text
1166
+ style={[
1167
+ styles.headerMethodText,
1168
+ {fontSize: isNarrow ? 9 : 10},
1169
+ ]}>
1170
+ {selectedCrash.isFatal
1171
+ ? 'FATAL'
1172
+ : selectedCrash.type.toUpperCase()}
1173
+ </Text>
1174
+ </View>
1175
+ <Text
1176
+ style={[
1177
+ styles.headerDetailTitle,
1178
+ {fontSize: isNarrow ? 13.5 : 15},
1179
+ ]}
1180
+ numberOfLines={1}
1181
+ ellipsizeMode="middle">
1182
+ {selectedCrash.name || selectedCrash.message}
1183
+ </Text>
1184
+ </View>
845
1185
  <View
846
- style={[
847
- styles.headerMethodBadge,
848
- {
849
- backgroundColor: selectedCrash.isFatal
850
- ? AppColors.red600
851
- : AppColors.amber600,
852
- paddingHorizontal: isNarrow ? 5 : 6,
853
- paddingVertical: isNarrow ? 2 : 3,
854
- },
855
- ]}>
856
- <Text style={[styles.headerMethodText, {fontSize: isNarrow ? 9 : 10}]}>
857
- {selectedCrash.isFatal
858
- ? 'FATAL'
859
- : selectedCrash.type.toUpperCase()}
1186
+ style={{
1187
+ flexDirection: 'row',
1188
+ alignItems: 'center',
1189
+ gap: isNarrow ? 4 : 6,
1190
+ marginTop: 3,
1191
+ paddingVertical: 1,
1192
+ }}>
1193
+ <View
1194
+ style={[
1195
+ styles.headerStatusDot,
1196
+ {
1197
+ backgroundColor: selectedCrash.isFatal
1198
+ ? AppColors.red600
1199
+ : AppColors.amber500,
1200
+ width: isNarrow ? 6 : 7,
1201
+ height: isNarrow ? 6 : 7,
1202
+ },
1203
+ ]}
1204
+ />
1205
+ <Text
1206
+ style={[
1207
+ styles.headerSubTitle,
1208
+ {fontSize: isNarrow ? 10 : 11},
1209
+ ]}>
1210
+ {selectedCrash.timeStr ||
1211
+ new Date(
1212
+ selectedCrash.timestamp,
1213
+ ).toLocaleTimeString()}
860
1214
  </Text>
1215
+ {selectedCrash.deviceInfo?.platform && (
1216
+ <>
1217
+ <Text
1218
+ style={[
1219
+ styles.headerSubTitle,
1220
+ {opacity: 0.6, fontSize: isNarrow ? 10 : 11},
1221
+ ]}>
1222
+ •
1223
+ </Text>
1224
+ <Text
1225
+ style={[
1226
+ styles.headerSubTitle,
1227
+ {fontSize: isNarrow ? 10 : 11},
1228
+ ]}>
1229
+ {selectedCrash.deviceInfo.platform.toUpperCase()}
1230
+ </Text>
1231
+ </>
1232
+ )}
861
1233
  </View>
862
- <Text
863
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
864
- numberOfLines={1}
865
- ellipsizeMode="middle">
866
- {selectedCrash.name || selectedCrash.message}
867
- </Text>
868
1234
  </View>
869
- <ScrollView
870
- horizontal
871
- showsHorizontalScrollIndicator={false}
872
- contentContainerStyle={{
873
- flexDirection: 'row',
874
- alignItems: 'center',
875
- gap: isNarrow ? 4 : 6,
876
- marginTop: 3,
877
- paddingVertical: 1,
878
- }}>
879
- <View
880
- style={[
881
- styles.headerStatusDot,
1235
+ ) : null}
1236
+ </View>
1237
+ )}
1238
+
1239
+ <View
1240
+ style={[
1241
+ styles.headerRight,
1242
+ {
1243
+ flexDirection: 'row',
1244
+ alignItems: 'center',
1245
+ justifyContent: 'flex-end',
1246
+ flexShrink: 0,
1247
+ gap: isNarrow ? 5 : 7,
1248
+ },
1249
+ ]}>
1250
+ {isSettingsView && (
1251
+ <TouchableScale
1252
+ onPress={() => {
1253
+ Alert.alert(
1254
+ 'Reset All Settings',
1255
+ 'This restores all module visibility and UI preferences to defaults. Continue?',
1256
+ [
1257
+ {text: 'Cancel', style: 'cancel'},
882
1258
  {
883
- backgroundColor: selectedCrash.isFatal
884
- ? AppColors.red600
885
- : AppColors.amber500,
886
- width: isNarrow ? 6 : 7,
887
- height: isNarrow ? 6 : 7,
1259
+ text: 'Reset',
1260
+ style: 'destructive',
1261
+ onPress: resetToDefaults,
888
1262
  },
889
- ]}
890
- />
891
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
892
- {selectedCrash.timeStr ||
893
- new Date(selectedCrash.timestamp).toLocaleTimeString()}
894
- </Text>
895
- {selectedCrash.deviceInfo?.platform && (
896
- <>
897
- <Text style={[styles.headerSubTitle, {opacity: 0.6, fontSize: isNarrow ? 10 : 11}]}>
898
- •
899
- </Text>
900
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
901
- {selectedCrash.deviceInfo.platform.toUpperCase()}
902
- </Text>
903
- </>
904
- )}
905
- </ScrollView>
906
- </View>
907
- ) : null}
908
- </View>
909
- )}
1263
+ ],
1264
+ );
1265
+ }}
1266
+ hitSlop={15}
1267
+ style={[
1268
+ styles.closeButtonSquare,
1269
+ {
1270
+ width: buttonSize,
1271
+ height: buttonSize,
1272
+ borderRadius: isNarrow ? 6 : 7,
1273
+ },
1274
+ ]}>
1275
+ <ResetIcon
1276
+ color={AppColors.white}
1277
+ size={isNarrow ? 12 : 14}
1278
+ />
1279
+ </TouchableScale>
1280
+ )}
910
1281
 
911
- <View
912
- style={[
913
- styles.headerRight,
914
- {
915
- flexDirection: 'row',
916
- alignItems: 'center',
917
- justifyContent: 'flex-end',
918
- flexShrink: 0,
919
- gap: isNarrow ? 5 : 7,
920
- },
921
- ]}>
922
- {isSettingsView && (
923
- <TouchableScale
924
- onPress={() => {
925
- Alert.alert(
926
- 'Reset All Settings',
927
- 'This restores all module visibility and UI preferences to defaults. Continue?',
928
- [
929
- {text: 'Cancel', style: 'cancel'},
930
- {
931
- text: 'Reset',
932
- style: 'destructive',
933
- onPress: resetToDefaults,
934
- },
935
- ],
936
- );
937
- }}
938
- hitSlop={15}
939
- style={[
940
- styles.closeButtonSquare,
941
- {
942
- width: buttonSize,
943
- height: buttonSize,
944
- borderRadius: isNarrow ? 6 : 7,
945
- },
946
- ]}>
947
- <ResetIcon color={AppColors.white} size={isNarrow ? 12 : 14} />
948
- </TouchableScale>
949
- )}
1282
+ {!isAnySelected && (
1283
+ <TouchableScale
1284
+ accessible={true}
1285
+ accessibilityRole="button"
1286
+ accessibilityLabel="Settings"
1287
+ onPress={() => setSettingsPage('main')}
1288
+ hitSlop={15}
1289
+ style={[
1290
+ styles.closeButtonSquare,
1291
+ {
1292
+ width: buttonSize,
1293
+ height: buttonSize,
1294
+ borderRadius: isNarrow ? 6 : 7,
1295
+ },
1296
+ ]}>
1297
+ <SettingsIcon
1298
+ color={AppColors.white}
1299
+ size={isNarrow ? 12 : 14}
1300
+ />
1301
+ </TouchableScale>
1302
+ )}
950
1303
 
951
- {!isAnySelected && (
952
- <TouchableScale
953
- onPress={() => {
954
- Alert.alert(
955
- 'Clear Everything',
956
- 'This clears all tabs — APIs, Logs, Analytics, Redux timeline and Crash history. Continue?',
957
- [
958
- {text: 'Cancel', style: 'cancel'},
959
- {
960
- text: 'Clear All',
961
- onPress: runClearAllWithAnimation,
962
- style: 'destructive',
963
- },
964
- ],
965
- );
966
- }}
967
- hitSlop={15}
1304
+ <TouchableOpacity
1305
+ onPress={closeModal}
1306
+ hitSlop={{top: 12, bottom: 12, left: 12, right: 12}}
1307
+ activeOpacity={0.6}
968
1308
  style={[
969
1309
  styles.closeButtonSquare,
970
1310
  {
@@ -973,69 +1313,231 @@ const InspectorHeader = React.memo(() => {
973
1313
  borderRadius: isNarrow ? 6 : 7,
974
1314
  },
975
1315
  ]}>
976
- <Animated.View
1316
+ <CloseWhite size={isNarrow ? 12 : 14} />
1317
+ </TouchableOpacity>
1318
+ </View>
1319
+ </View>
1320
+
1321
+ {/* Secondary Action Header (Sub-Toolbar) */}
1322
+ {!isAnySelected && (
1323
+ <View
1324
+ style={{
1325
+ flexDirection: 'row',
1326
+ alignItems: 'center',
1327
+ justifyContent: 'space-between',
1328
+ paddingHorizontal: isNarrow ? 8 : 12,
1329
+ paddingBottom: isNarrow ? 6 : 8,
1330
+ paddingTop: 0,
1331
+ gap: 6,
1332
+ }}>
1333
+ <View
1334
+ style={{flexDirection: 'row', alignItems: 'center', gap: 6}}>
1335
+ {/* Photo Capture Button */}
1336
+ <TouchableScale
1337
+ onPress={handleTakeScreenshot}
977
1338
  style={{
978
- transform: [
979
- {
980
- rotate: clearAnim.interpolate({
981
- inputRange: [0, 1],
982
- outputRange: ['0deg', '-25deg'],
983
- }),
984
- },
985
- {
986
- scale: clearAnim.interpolate({
987
- inputRange: [0, 0.5, 1],
988
- outputRange: [1, 1.25, 1],
989
- }),
990
- },
991
- ],
1339
+ flexDirection: 'row',
1340
+ alignItems: 'center',
1341
+ gap: 4.5,
1342
+ backgroundColor: `${AppColors.white}24`,
1343
+ paddingHorizontal: isNarrow ? 8 : 10,
1344
+ paddingVertical: isNarrow ? 4 : 5,
1345
+ borderRadius: 6,
1346
+ borderWidth: 1,
1347
+ borderColor: `${AppColors.white}33`,
992
1348
  }}>
993
- <TrashIcon color={AppColors.white} size={isNarrow ? 12 : 14} />
994
- </Animated.View>
995
- </TouchableScale>
996
- )}
1349
+ <CameraIcon
1350
+ size={isNarrow ? 12 : 13}
1351
+ color={AppColors.white}
1352
+ />
1353
+ <Text
1354
+ style={{
1355
+ fontFamily: AppFonts.interSemiBold,
1356
+ fontSize: isNarrow ? 10 : 11,
1357
+ color: AppColors.white,
1358
+ }}>
1359
+ {t('header.photo')}
1360
+ </Text>
1361
+ </TouchableScale>
997
1362
 
998
- {!isAnySelected && (
999
- <TouchableScale
1000
- onPress={() => setSettingsPage('main')}
1001
- hitSlop={15}
1002
- style={[
1003
- styles.closeButtonSquare,
1004
- {
1005
- width: buttonSize,
1006
- height: buttonSize,
1007
- borderRadius: isNarrow ? 6 : 7,
1008
- },
1009
- ]}>
1010
- <SettingsIcon color={AppColors.white} size={isNarrow ? 12 : 14} />
1011
- </TouchableScale>
1012
- )}
1363
+ {/* Video / GIF Record Button */}
1364
+ <TouchableScale
1365
+ onPress={handleToggleVideoRecording}
1366
+ style={{
1367
+ flexDirection: 'row',
1368
+ alignItems: 'center',
1369
+ gap: 4.5,
1370
+ backgroundColor: isRecording
1371
+ ? `${AppColors.red500}33`
1372
+ : `${AppColors.white}24`,
1373
+ paddingHorizontal: isNarrow ? 8 : 10,
1374
+ paddingVertical: isNarrow ? 4 : 5,
1375
+ borderRadius: 6,
1376
+ borderWidth: 1,
1377
+ borderColor: isRecording
1378
+ ? AppColors.red500
1379
+ : `${AppColors.white}33`,
1380
+ }}>
1381
+ {isRecording ? (
1382
+ <Animated.View
1383
+ style={{
1384
+ width: 6,
1385
+ height: 6,
1386
+ borderRadius: 3,
1387
+ backgroundColor: AppColors.red500,
1388
+ }}
1389
+ />
1390
+ ) : (
1391
+ <VideoCameraIcon
1392
+ size={isNarrow ? 12 : 13}
1393
+ color={AppColors.white}
1394
+ />
1395
+ )}
1396
+ <Text
1397
+ style={{
1398
+ fontFamily: AppFonts.interSemiBold,
1399
+ fontSize: isNarrow ? 10 : 11,
1400
+ color: isRecording ? AppColors.red300 : AppColors.white,
1401
+ }}>
1402
+ {isRecording
1403
+ ? `${t('header.rec')} ${formatTimer(recordingSeconds)}`
1404
+ : t('header.record')}
1405
+ </Text>
1406
+ </TouchableScale>
1407
+ </View>
1013
1408
 
1014
- <TouchableOpacity
1015
- onPress={closeModal}
1016
- hitSlop={{top: 12, bottom: 12, left: 12, right: 12}}
1017
- activeOpacity={0.6}
1018
- style={[
1019
- styles.closeButtonSquare,
1020
- {
1021
- width: buttonSize,
1022
- height: buttonSize,
1023
- borderRadius: isNarrow ? 6 : 7,
1024
- },
1025
- ]}>
1026
- <CloseWhite size={isNarrow ? 12 : 14} />
1027
- </TouchableOpacity>
1028
- </View>
1409
+ <View
1410
+ style={{flexDirection: 'row', alignItems: 'center', gap: 6}}>
1411
+ {/* Clear All Action */}
1412
+ <TouchableScale
1413
+ onPress={() => {
1414
+ Alert.alert(
1415
+ t('header.clearEverythingTitle'),
1416
+ t('header.clearEverythingMessage'),
1417
+ [
1418
+ {text: t('common.cancel'), style: 'cancel'},
1419
+ {
1420
+ text: t('common.clearAll'),
1421
+ onPress: runClearAllWithAnimation,
1422
+ style: 'destructive',
1423
+ },
1424
+ ],
1425
+ );
1426
+ }}
1427
+ style={{
1428
+ flexDirection: 'row',
1429
+ alignItems: 'center',
1430
+ gap: 4,
1431
+ backgroundColor: `${AppColors.white}1A`,
1432
+ paddingHorizontal: isNarrow ? 7 : 9,
1433
+ paddingVertical: isNarrow ? 4 : 5,
1434
+ borderRadius: 6,
1435
+ borderWidth: 1,
1436
+ borderColor: `${AppColors.white}26`,
1437
+ }}>
1438
+ <Animated.View
1439
+ style={{
1440
+ transform: [
1441
+ {
1442
+ rotate: clearAnim.interpolate({
1443
+ inputRange: [0, 1],
1444
+ outputRange: ['0deg', '-25deg'],
1445
+ }),
1446
+ },
1447
+ {
1448
+ scale: clearAnim.interpolate({
1449
+ inputRange: [0, 0.5, 1],
1450
+ outputRange: [1, 1.25, 1],
1451
+ }),
1452
+ },
1453
+ ],
1454
+ }}>
1455
+ <TrashIcon
1456
+ color={AppColors.white}
1457
+ size={isNarrow ? 11 : 12}
1458
+ />
1459
+ </Animated.View>
1460
+ <Text
1461
+ style={{
1462
+ fontFamily: AppFonts.interMedium,
1463
+ fontSize: isNarrow ? 10 : 11,
1464
+ color: `${AppColors.white}E6`,
1465
+ }}>
1466
+ {t('header.clear')}
1467
+ </Text>
1468
+ </TouchableScale>
1469
+
1470
+ {/* About Action */}
1471
+ <TouchableScale
1472
+ onPress={() => {
1473
+ setSettingsActiveSubTab('about');
1474
+ setSettingsPage('main');
1475
+ }}
1476
+ style={{
1477
+ flexDirection: 'row',
1478
+ alignItems: 'center',
1479
+ gap: 4,
1480
+ backgroundColor: `${AppColors.white}1A`,
1481
+ paddingHorizontal: isNarrow ? 7 : 9,
1482
+ paddingVertical: isNarrow ? 4 : 5,
1483
+ borderRadius: 6,
1484
+ borderWidth: 1,
1485
+ borderColor: `${AppColors.white}26`,
1486
+ }}>
1487
+ <InfoCircleIcon
1488
+ color={AppColors.white}
1489
+ size={isNarrow ? 11 : 12}
1490
+ />
1491
+ <Text
1492
+ style={{
1493
+ fontFamily: AppFonts.interMedium,
1494
+ fontSize: isNarrow ? 10 : 11,
1495
+ color: `${AppColors.white}E6`,
1496
+ }}>
1497
+ {t('header.about')}
1498
+ </Text>
1499
+ </TouchableScale>
1500
+ </View>
1501
+ </View>
1502
+ )}
1029
1503
  </View>
1030
1504
  </View>
1031
- </LinearGradient>
1032
1505
 
1033
- {/* Dedicated Update Available Details Modal */}
1034
- <UpdateAvailableModal
1035
- visible={showUpdateModal}
1036
- latestVersion={latestNpmVersion}
1037
- onClose={() => setShowUpdateModal(false)}
1038
- />
1506
+ {/* Dedicated Update Available Details Modal */}
1507
+ <UpdateAvailableModal
1508
+ visible={showUpdateModal}
1509
+ latestVersion={latestNpmVersion}
1510
+ onClose={() => setShowUpdateModal(false)}
1511
+ />
1512
+
1513
+ {/* Instant Media Preview Modal for Screenshots and Video Recordings */}
1514
+ <MediaPreviewModal
1515
+ item={previewMediaItem}
1516
+ visible={!!previewMediaItem}
1517
+ onClose={() => setPreviewMediaItem(null)}
1518
+ onDelete={async item => {
1519
+ await ScreenCapture.deleteMedia(item.uri);
1520
+ setPreviewMediaItem(null);
1521
+ }}
1522
+ onConvertToGif={async item => {
1523
+ const gif = await ScreenCapture.convertToGif(item.uri, {
1524
+ fps: 12,
1525
+ width: 480,
1526
+ });
1527
+ if (gif) {
1528
+ setPreviewMediaItem({
1529
+ id: `anim_${gif.timestamp}.gif`,
1530
+ type: 'gif',
1531
+ format: 'gif',
1532
+ uri: gif.uri,
1533
+ filename: gif.uri.split('/').pop() || `anim_${gif.timestamp}.gif`,
1534
+ sizeBytes: gif.sizeBytes,
1535
+ timestamp: gif.timestamp,
1536
+ durationMs: gif.durationMs,
1537
+ });
1538
+ }
1539
+ }}
1540
+ />
1039
1541
  </>
1040
1542
  );
1041
1543
  });