react-native-inapp-inspector 2.3.16 → 2.3.18

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 (346) hide show
  1. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +438 -7
  2. package/bin/cli.js +0 -0
  3. package/dist/commonjs/capture.d.ts +26 -0
  4. package/dist/commonjs/capture.js +32 -0
  5. package/dist/commonjs/components/AnalyticsEventCard.js +11 -11
  6. package/dist/commonjs/components/AnimatedEntrance.js +6 -70
  7. package/dist/commonjs/components/DomainHeader.js +3 -48
  8. package/dist/commonjs/components/EmptyState.js +2 -2
  9. package/dist/commonjs/components/HeadersSection.js +14 -34
  10. package/dist/commonjs/components/Inspector/AnalyticsTab.js +1 -2
  11. package/dist/commonjs/components/Inspector/ConsoleTab.js +1 -1
  12. package/dist/commonjs/components/Inspector/CrashTab.js +4 -2
  13. package/dist/commonjs/components/Inspector/DebuggingTab.js +2 -2
  14. package/dist/commonjs/components/Inspector/InspectorHeader.js +651 -313
  15. package/dist/commonjs/components/Inspector/MainScreen.js +25 -70
  16. package/dist/commonjs/components/Inspector/MediaGalleryTab.d.ts +2 -0
  17. package/dist/commonjs/components/Inspector/MediaGalleryTab.js +307 -0
  18. package/dist/commonjs/components/Inspector/MediaPreviewModal.d.ts +11 -0
  19. package/dist/commonjs/components/Inspector/MediaPreviewModal.js +393 -0
  20. package/dist/commonjs/components/Inspector/NetworkTab.js +183 -182
  21. package/dist/commonjs/components/Inspector/NpmUpdateToast.js +4 -9
  22. package/dist/commonjs/components/Inspector/ReduxTab.js +4 -2
  23. package/dist/commonjs/components/Inspector/SettingsPanel.js +245 -0
  24. package/dist/commonjs/components/Inspector/SkeletonPlaceholder.js +2 -2
  25. package/dist/commonjs/components/Inspector/StorageTab.js +3 -3
  26. package/dist/commonjs/components/Inspector/TabBar.js +5 -10
  27. package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +5 -10
  28. package/dist/commonjs/components/JsonViewer.js +43 -20
  29. package/dist/commonjs/components/LogCard.js +5 -5
  30. package/dist/commonjs/components/MetaAccordion.js +78 -80
  31. package/dist/commonjs/components/NetworkIcons.d.ts +8 -0
  32. package/dist/commonjs/components/NetworkIcons.js +51 -1
  33. package/dist/commonjs/components/SectionHeader.js +3 -48
  34. package/dist/commonjs/components/SkeletonPlaceholder.js +2 -2
  35. package/dist/commonjs/components/SourcePageCard.js +43 -45
  36. package/dist/commonjs/components/Toast.js +4 -4
  37. package/dist/commonjs/components/TouchableScale.js +9 -65
  38. package/dist/commonjs/components/TreeNode.js +2 -14
  39. package/dist/commonjs/constants/telemetryConfig.d.ts +3 -3
  40. package/dist/commonjs/constants/telemetryConfig.js +3 -3
  41. package/dist/commonjs/constants/version.d.ts +1 -1
  42. package/dist/commonjs/constants/version.js +1 -1
  43. package/dist/commonjs/customHooks/useAccordion.d.ts +3 -8
  44. package/dist/commonjs/customHooks/useAccordion.js +6 -36
  45. package/dist/commonjs/helpers/index.d.ts +2 -1
  46. package/dist/commonjs/helpers/index.js +10 -1
  47. package/dist/commonjs/i18n/locales/en.json +66 -2
  48. package/dist/commonjs/index.d.ts +1 -0
  49. package/dist/commonjs/index.js +39 -22
  50. package/dist/commonjs/native/NativeInspector.d.ts +60 -0
  51. package/dist/commonjs/native/NativeInspector.js +109 -2
  52. package/dist/commonjs/native/NativeNetworkInspector.d.ts +8 -0
  53. package/dist/commonjs/styles/AppColors.d.ts +36 -0
  54. package/dist/commonjs/styles/AppColors.js +36 -0
  55. package/dist/commonjs/styles/index.d.ts +3 -1
  56. package/dist/commonjs/styles/index.js +3 -1
  57. package/dist/commonjs/types/enums.d.ts +1 -0
  58. package/dist/commonjs/types/enums.js +1 -0
  59. package/dist/commonjs/types/index.d.ts +2 -2
  60. package/dist/esm/capture.d.ts +26 -0
  61. package/dist/esm/capture.js +29 -0
  62. package/dist/esm/components/AnalyticsEventCard.js +11 -11
  63. package/dist/esm/components/AnimatedEntrance.js +4 -38
  64. package/dist/esm/components/DomainHeader.js +4 -16
  65. package/dist/esm/components/EmptyState.js +2 -2
  66. package/dist/esm/components/HeadersSection.js +16 -36
  67. package/dist/esm/components/Inspector/AnalyticsTab.js +2 -3
  68. package/dist/esm/components/Inspector/ConsoleTab.js +2 -2
  69. package/dist/esm/components/Inspector/CrashTab.js +5 -3
  70. package/dist/esm/components/Inspector/DebuggingTab.js +3 -3
  71. package/dist/esm/components/Inspector/InspectorHeader.js +654 -316
  72. package/dist/esm/components/Inspector/MainScreen.js +25 -70
  73. package/dist/esm/components/Inspector/MediaGalleryTab.d.ts +2 -0
  74. package/dist/esm/components/Inspector/MediaGalleryTab.js +267 -0
  75. package/dist/esm/components/Inspector/MediaPreviewModal.d.ts +11 -0
  76. package/dist/esm/components/Inspector/MediaPreviewModal.js +353 -0
  77. package/dist/esm/components/Inspector/NetworkTab.js +185 -184
  78. package/dist/esm/components/Inspector/NpmUpdateToast.js +5 -10
  79. package/dist/esm/components/Inspector/ReduxTab.js +5 -3
  80. package/dist/esm/components/Inspector/SettingsPanel.js +246 -1
  81. package/dist/esm/components/Inspector/SkeletonPlaceholder.js +2 -2
  82. package/dist/esm/components/Inspector/StorageTab.js +3 -3
  83. package/dist/esm/components/Inspector/TabBar.js +6 -11
  84. package/dist/esm/components/Inspector/UpdateAvailableModal.js +6 -11
  85. package/dist/esm/components/JsonViewer.js +43 -20
  86. package/dist/esm/components/LogCard.js +5 -5
  87. package/dist/esm/components/MetaAccordion.js +79 -81
  88. package/dist/esm/components/NetworkIcons.d.ts +8 -0
  89. package/dist/esm/components/NetworkIcons.js +42 -0
  90. package/dist/esm/components/SectionHeader.js +4 -16
  91. package/dist/esm/components/SkeletonPlaceholder.js +2 -2
  92. package/dist/esm/components/SourcePageCard.js +44 -46
  93. package/dist/esm/components/Toast.js +4 -4
  94. package/dist/esm/components/TouchableScale.js +7 -33
  95. package/dist/esm/components/TreeNode.js +4 -16
  96. package/dist/esm/constants/telemetryConfig.d.ts +3 -3
  97. package/dist/esm/constants/telemetryConfig.js +3 -3
  98. package/dist/esm/constants/version.d.ts +1 -1
  99. package/dist/esm/constants/version.js +1 -1
  100. package/dist/esm/customHooks/useAccordion.d.ts +3 -8
  101. package/dist/esm/customHooks/useAccordion.js +7 -37
  102. package/dist/esm/helpers/index.d.ts +2 -1
  103. package/dist/esm/helpers/index.js +8 -0
  104. package/dist/esm/i18n/locales/en.json +66 -2
  105. package/dist/esm/index.d.ts +1 -0
  106. package/dist/esm/index.js +36 -21
  107. package/dist/esm/native/NativeInspector.d.ts +60 -0
  108. package/dist/esm/native/NativeInspector.js +100 -1
  109. package/dist/esm/native/NativeNetworkInspector.d.ts +8 -0
  110. package/dist/esm/styles/AppColors.d.ts +36 -0
  111. package/dist/esm/styles/AppColors.js +36 -0
  112. package/dist/esm/styles/index.d.ts +3 -1
  113. package/dist/esm/styles/index.js +3 -1
  114. package/dist/esm/types/enums.d.ts +1 -0
  115. package/dist/esm/types/enums.js +1 -0
  116. package/dist/esm/types/index.d.ts +2 -2
  117. package/ios/NetworkInspectorModule.h +1 -0
  118. package/ios/NetworkInspectorModule.mm +736 -7
  119. package/package.json +10 -2
  120. package/react-native-inapp-inspector.podspec +1 -0
  121. package/src/capture.ts +101 -0
  122. package/src/components/AnalyticsEventCard.tsx +15 -13
  123. package/src/components/AnimatedEntrance.tsx +3 -47
  124. package/src/components/DomainHeader.tsx +4 -17
  125. package/src/components/EmptyState.tsx +2 -2
  126. package/src/components/HeadersSection.tsx +31 -56
  127. package/src/components/Inspector/AnalyticsTab.tsx +2 -2
  128. package/src/components/Inspector/ConsoleTab.tsx +2 -1
  129. package/src/components/Inspector/CrashTab.tsx +4 -2
  130. package/src/components/Inspector/DebuggingTab.tsx +2 -2
  131. package/src/components/Inspector/InspectorHeader.tsx +1215 -789
  132. package/src/components/Inspector/MainScreen.tsx +44 -85
  133. package/src/components/Inspector/MediaGalleryTab.tsx +355 -0
  134. package/src/components/Inspector/MediaPreviewModal.tsx +435 -0
  135. package/src/components/Inspector/NetworkTab.tsx +14 -15
  136. package/src/components/Inspector/NpmUpdateToast.tsx +4 -9
  137. package/src/components/Inspector/ReduxTab.tsx +5 -2
  138. package/src/components/Inspector/SettingsPanel.tsx +303 -0
  139. package/src/components/Inspector/SkeletonPlaceholder.tsx +2 -2
  140. package/src/components/Inspector/StorageTab.tsx +3 -3
  141. package/src/components/Inspector/TabBar.tsx +6 -12
  142. package/src/components/Inspector/UpdateAvailableModal.tsx +6 -10
  143. package/src/components/JsonViewer.tsx +101 -60
  144. package/src/components/LogCard.tsx +10 -8
  145. package/src/components/MetaAccordion.tsx +6 -6
  146. package/src/components/NetworkIcons.tsx +150 -0
  147. package/src/components/SectionHeader.tsx +4 -16
  148. package/src/components/SkeletonPlaceholder.tsx +2 -2
  149. package/src/components/SourcePageCard.tsx +57 -55
  150. package/src/components/Toast.tsx +4 -4
  151. package/src/components/TouchableScale.tsx +8 -38
  152. package/src/components/TreeNode.tsx +5 -20
  153. package/src/constants/telemetryConfig.ts +3 -5
  154. package/src/constants/version.ts +1 -1
  155. package/src/customHooks/useAccordion.tsx +10 -43
  156. package/src/helpers/index.ts +10 -1
  157. package/src/i18n/locales/en.json +69 -2
  158. package/src/index.tsx +51 -23
  159. package/src/native/NativeInspector.ts +186 -1
  160. package/src/native/NativeNetworkInspector.ts +9 -0
  161. package/src/styles/AppColors.ts +38 -0
  162. package/src/styles/index.ts +3 -1
  163. package/src/types/enums.ts +3 -0
  164. package/src/types/index.ts +2 -2
  165. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  166. package/android/.gradle/8.9/checksums/md5-checksums.bin +0 -0
  167. package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
  168. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  169. package/android/.gradle/8.9/executionHistory/executionHistory.lock +0 -0
  170. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  171. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  172. package/android/.gradle/8.9/gc.properties +0 -0
  173. package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
  174. package/android/.gradle/9.2.0/fileChanges/last-build.bin +0 -0
  175. package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
  176. package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
  177. package/android/.gradle/9.2.0/gc.properties +0 -0
  178. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  179. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  180. package/android/.gradle/vcs-1/gc.properties +0 -0
  181. package/android/build/.transforms/6683d6eeaa3e1dfa689c3385111a0386/results.bin +0 -1
  182. package/android/build/.transforms/6683d6eeaa3e1dfa689c3385111a0386/transformed/classes/classes_dex/classes.dex +0 -0
  183. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/results.bin +0 -1
  184. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/BuildConfig.dex +0 -0
  185. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/InAppInspectorFloatingView$iconView$1.dex +0 -0
  186. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/InAppInspectorFloatingView.dex +0 -0
  187. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NativeNetworkInspectorSpec.dex +0 -0
  188. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NetworkInspectorModule$Companion.dex +0 -0
  189. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NetworkInspectorModule$frameCallback$1.dex +0 -0
  190. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NetworkInspectorModule$shakeListener$1.dex +0 -0
  191. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NetworkInspectorModule.dex +0 -0
  192. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/inappinspector/NetworkInspectorPackage.dex +0 -0
  193. package/android/build/.transforms/9d2a3e5e0f0ea07cafb0c0bf290630ee/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
  194. package/android/build/generated/source/buildConfig/debug/com/inappinspector/BuildConfig.java +0 -10
  195. package/android/build/generated/source/codegen/java/com/inappinspector/NativeNetworkInspectorSpec.java +0 -104
  196. package/android/build/generated/source/codegen/jni/CMakeLists.txt +0 -28
  197. package/android/build/generated/source/codegen/jni/RNInAppInspectorSpec-generated.cpp +0 -128
  198. package/android/build/generated/source/codegen/jni/RNInAppInspectorSpec.h +0 -31
  199. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/ComponentDescriptors.cpp +0 -22
  200. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/ComponentDescriptors.h +0 -24
  201. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/EventEmitters.cpp +0 -16
  202. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/EventEmitters.h +0 -17
  203. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/Props.cpp +0 -19
  204. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/Props.h +0 -18
  205. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/RNInAppInspectorSpecJSI.h +0 -177
  206. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/ShadowNodes.cpp +0 -17
  207. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/ShadowNodes.h +0 -23
  208. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/States.cpp +0 -16
  209. package/android/build/generated/source/codegen/jni/react/renderer/components/RNInAppInspectorSpec/States.h +0 -20
  210. package/android/build/generated/source/codegen/schema.json +0 -1
  211. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -7
  212. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
  213. package/android/build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar +0 -0
  214. package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
  215. package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
  216. package/android/build/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt +0 -0
  217. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  218. package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  219. package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
  220. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -1
  221. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
  222. package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
  223. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
  224. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
  225. package/android/build/intermediates/incremental/packageDebugAssets/merger.xml +0 -2
  226. package/android/build/intermediates/java_res/debug/processDebugJavaRes/out/META-INF/react-native-inapp-inspector_debug.kotlin_module +0 -0
  227. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/inappinspector/BuildConfig.class +0 -0
  228. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/inappinspector/NativeNetworkInspectorSpec.class +0 -0
  229. package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -2
  230. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -7
  231. package/android/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-react-native-inapp-inspector.jar +0 -0
  232. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -7
  233. package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
  234. package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
  235. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/META-INF/react-native-inapp-inspector_debug.kotlin_module +0 -0
  236. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/BuildConfig.class +0 -0
  237. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/InAppInspectorFloatingView$iconView$1.class +0 -0
  238. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/InAppInspectorFloatingView.class +0 -0
  239. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NativeNetworkInspectorSpec.class +0 -0
  240. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NetworkInspectorModule$Companion.class +0 -0
  241. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NetworkInspectorModule$frameCallback$1.class +0 -0
  242. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NetworkInspectorModule$shakeListener$1.class +0 -0
  243. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NetworkInspectorModule.class +0 -0
  244. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/inappinspector/NetworkInspectorPackage.class +0 -0
  245. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  246. package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -1
  247. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  248. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
  249. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
  250. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
  251. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  252. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
  253. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
  254. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  255. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  256. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  257. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  258. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  259. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  260. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
  261. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  262. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  263. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  264. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  265. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  266. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  267. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
  268. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
  269. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream +0 -0
  270. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len +0 -0
  271. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len +0 -0
  272. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
  273. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i +0 -0
  274. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len +0 -0
  275. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  276. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  277. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  278. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  279. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  280. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  281. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
  282. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  283. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  284. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  285. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  286. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  287. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  288. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
  289. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  290. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
  291. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
  292. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
  293. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  294. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
  295. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
  296. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
  297. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
  298. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
  299. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
  300. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  301. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
  302. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
  303. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
  304. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
  305. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
  306. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
  307. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
  308. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
  309. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
  310. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +0 -2
  311. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  312. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
  313. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
  314. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
  315. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
  316. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
  317. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
  318. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  319. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
  320. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
  321. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
  322. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  323. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
  324. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
  325. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  326. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  327. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  328. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  329. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  330. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  331. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
  332. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  333. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  334. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  335. package/android/build/outputs/aar/react-native-inapp-inspector-debug.aar +0 -0
  336. package/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -17
  337. package/android/build/reports/problems/problems-report.html +0 -659
  338. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  339. package/android/build/tmp/kotlin-classes/debug/META-INF/react-native-inapp-inspector_debug.kotlin_module +0 -0
  340. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/InAppInspectorFloatingView$iconView$1.class +0 -0
  341. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/InAppInspectorFloatingView.class +0 -0
  342. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/NetworkInspectorModule$Companion.class +0 -0
  343. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/NetworkInspectorModule$frameCallback$1.class +0 -0
  344. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/NetworkInspectorModule$shakeListener$1.class +0 -0
  345. package/android/build/tmp/kotlin-classes/debug/com/inappinspector/NetworkInspectorModule.class +0 -0
  346. 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,
@@ -43,9 +49,13 @@ import {
43
49
  ResetIcon,
44
50
  BoltIcon,
45
51
  InfoCircleIcon,
52
+ CameraIcon,
53
+ VideoCameraIcon,
46
54
  } from '../NetworkIcons';
55
+ import {useTranslation} from '../../i18n';
47
56
 
48
57
  const InspectorHeader = React.memo(() => {
58
+ const {t} = useTranslation();
49
59
  const {
50
60
  modalHeightPercent,
51
61
  appIcon,
@@ -94,18 +104,130 @@ const InspectorHeader = React.memo(() => {
94
104
  return getAppVersionAndBuild().formatted;
95
105
  });
96
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
+
97
111
  React.useEffect(() => {
98
- getNativeDeviceMetrics()
99
- .then(metrics => {
100
- if (metrics?.appVersion) {
101
- const v = metrics.appVersion;
102
- const b = metrics.appBuild || '1';
103
- setAppVersionString(`${v} (${b})`);
104
- }
112
+ ScreenCapture.isRecording()
113
+ .then(active => {
114
+ setIsRecording(active);
105
115
  })
106
116
  .catch(() => {});
107
117
  }, []);
108
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
+
109
231
  const envConfig = useMemo(() => {
110
232
  const rawEnv = (environment || (__DEV__ ? 'DEV' : 'PROD')).trim();
111
233
  const clean = rawEnv.toUpperCase();
@@ -182,139 +304,114 @@ const InspectorHeader = React.memo(() => {
182
304
 
183
305
  return (
184
306
  <>
185
- <LinearGradient
186
- colors={['#4F46E5', '#7C3AED']}
187
- start={{x: 0, y: 0}}
188
- end={{x: 1, y: 1}}
189
- style={styles.headerGradient}>
190
- <View style={{paddingTop: headerTopPadding, width: '100%'}}>
191
- <View
192
- style={[
193
- styles.header,
194
- {
195
- paddingHorizontal: isNarrow ? 8 : 12,
196
- paddingVertical: isNarrow ? 6 : 8,
197
- minHeight: isNarrow ? 48 : 52,
198
- },
199
- ]}>
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%'}}>
200
333
  <View
201
334
  style={[
202
- styles.headerLeft,
335
+ styles.header,
203
336
  {
337
+ paddingHorizontal: isNarrow ? 8 : 12,
338
+ paddingVertical: isNarrow ? 6 : 8,
339
+ minHeight: isNarrow ? 48 : 52,
340
+ },
341
+ ]}>
342
+ <View
343
+ style={{
204
344
  flexDirection: 'row',
205
345
  alignItems: 'center',
206
346
  gap: isNarrow ? 6 : 8,
207
- flex: !isDetailView ? 1 : 0,
208
- minWidth: 0,
209
- },
210
- ]}>
211
- <TouchableScale
212
- onPress={() => {
213
- if (isFeedbackOpen) {
214
- setIsFeedbackOpen(false);
215
- return;
216
- }
217
- if (isSettingsView) {
218
- if (settingsPage === 'main') {
219
- setSettingsPage(null);
220
- } else {
221
- setSettingsPage('main');
222
- }
223
- return;
224
- }
225
- requestAnimationFrame(() => {
226
- setSelected(null);
227
- setSelectedEvent(null);
228
- setSelectedLog(null);
229
- setSelectedReduxSlice(null);
230
- setSelectedReduxAction(null);
231
- setSelectedCrash(null);
232
- });
233
- }}
234
- hitSlop={15}
235
- style={[
236
- {
237
- width: isNarrow ? 32 : 36,
238
- height: isNarrow ? 32 : 36,
239
- borderRadius: isNarrow ? 16 : 18,
240
- alignItems: 'center',
241
- justifyContent: 'center',
242
- backgroundColor: `${AppColors.white}2E`,
243
- borderWidth: 1,
244
- borderColor: `${AppColors.white}4D`,
245
- },
246
- !isAnySelected && {display: 'none'},
247
- ]}>
248
- <View
249
- style={{
250
- position: 'absolute',
251
- width: isNarrow ? 40 : 44,
252
- height: isNarrow ? 40 : 44,
253
- borderRadius: 22,
254
- backgroundColor: `${AppColors.white}1A`,
255
- }}
256
- />
257
- <WhiteBackNavigation />
258
- </TouchableScale>
259
-
260
- {isFeedbackOpen ? (
261
- <View style={{gap: 2, flex: 1, minWidth: 0}}>
262
- <View
263
- style={{flexDirection: 'row', alignItems: 'center', gap: 6}}>
264
- <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
265
385
  style={{
266
- fontFamily: AppFonts.interBold,
267
- fontSize: isNarrow ? 14 : 16,
268
- color: AppColors.white,
269
- letterSpacing: -0.2,
386
+ position: 'absolute',
387
+ width: isNarrow ? 40 : 44,
388
+ height: isNarrow ? 40 : 44,
389
+ borderRadius: 22,
390
+ backgroundColor: `${AppColors.white}1A`,
270
391
  }}
271
- numberOfLines={1}>
272
- Support & Feedback
273
- </Text>
392
+ />
393
+ <WhiteBackNavigation />
394
+ </TouchableScale>
395
+ )}
396
+
397
+ {isFeedbackOpen ? (
398
+ <View style={{gap: 2, flex: 1, minWidth: 0}}>
274
399
  <View
275
400
  style={{
276
- backgroundColor: `${AppColors.white}26`,
277
- paddingHorizontal: isNarrow ? 4 : 6,
278
- paddingVertical: 1.5,
279
- borderRadius: 10,
280
- borderWidth: 1,
281
- borderColor: `${AppColors.white}20`,
401
+ flexDirection: 'row',
402
+ alignItems: 'center',
403
+ gap: 6,
282
404
  }}>
283
405
  <Text
284
406
  style={{
285
407
  fontFamily: AppFonts.interBold,
286
- fontSize: isNarrow ? 8 : 9,
408
+ fontSize: isNarrow ? 14 : 16,
287
409
  color: AppColors.white,
288
- }}>
289
- v{LIB_VERSION}
410
+ letterSpacing: -0.2,
411
+ }}
412
+ numberOfLines={1}>
413
+ Support & Feedback
290
414
  </Text>
291
- </View>
292
- </View>
293
- <Text
294
- style={{
295
- fontFamily: AppFonts.interRegular,
296
- fontSize: isNarrow ? 9.5 : 10.5,
297
- color: `${AppColors.white}CC`,
298
- }}
299
- numberOfLines={1}>
300
- Direct line to maintainers & developers
301
- </Text>
302
- </View>
303
- ) : isSettingsView ? (
304
- <View style={{gap: 2, flex: 1, minWidth: 0}}>
305
- <View
306
- style={{flexDirection: 'row', alignItems: 'center', gap: 6}}>
307
- <Text
308
- style={{
309
- fontFamily: AppFonts.interBold,
310
- fontSize: isNarrow ? 14 : 16,
311
- color: AppColors.white,
312
- letterSpacing: -0.2,
313
- }}
314
- numberOfLines={1}>
315
- {settingsModuleTitle}
316
- </Text>
317
- {settingsPage === 'main' && (
318
415
  <View
319
416
  style={{
320
417
  backgroundColor: `${AppColors.white}26`,
@@ -333,297 +430,316 @@ const InspectorHeader = React.memo(() => {
333
430
  v{LIB_VERSION}
334
431
  </Text>
335
432
  </View>
336
- )}
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>
337
443
  </View>
338
- <Text
339
- style={{
340
- fontFamily: AppFonts.interRegular,
341
- fontSize: isNarrow ? 9.5 : 10.5,
342
- color: `${AppColors.white}CC`,
343
- }}
344
- numberOfLines={1}>
345
- {settingsPage === 'main'
346
- ? 'Manage modules and preferences'
347
- : 'Configure module parameters'}
348
- </Text>
349
- </View>
350
- ) : !isAnySelected ? (
351
- <View
352
- style={{
353
- flexDirection: 'row',
354
- alignItems: 'center',
355
- gap: isNarrow ? 6 : 8,
356
- flex: 1,
357
- minWidth: 0,
358
- marginRight: 4,
359
- }}>
360
- <AppHeaderLogo size={logoSize} customIcon={appIcon} />
444
+ ) : isSettingsView ? (
361
445
  <View style={{gap: 2, flex: 1, minWidth: 0}}>
362
446
  <View
363
447
  style={{
364
448
  flexDirection: 'row',
365
449
  alignItems: 'center',
366
- gap: isNarrow ? 4 : 6,
367
- minWidth: 0,
450
+ gap: 6,
368
451
  }}>
369
452
  <Text
370
- style={[
371
- styles.headerTitle,
372
- {
373
- fontSize: isNarrow ? 13.5 : isCompact ? 14.5 : 15.5,
374
- flexShrink: 1,
375
- paddingBottom: 0,
376
- },
377
- ]}
378
- numberOfLines={1}
379
- ellipsizeMode="tail">
380
- {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}
381
461
  </Text>
382
- <View
383
- style={[
384
- styles.envBadge,
385
- {
386
- backgroundColor: envConfig.bg,
387
- borderColor: envConfig.border,
388
- flexShrink: 0,
389
- paddingHorizontal: isNarrow ? 4.5 : 6,
390
- paddingVertical: 1.5,
391
- marginBottom: 0,
392
- },
393
- ]}>
394
- <Text
395
- style={[
396
- styles.envBadgeText,
397
- {
398
- color: envConfig.text,
399
- fontSize: isNarrow ? 8.5 : 9.5,
400
- },
401
- ]}>
402
- {envConfig.label}
403
- </Text>
404
- </View>
405
- {updateAvailable && (
406
- <Pressable
407
- hitSlop={10}
408
- onPress={() => setShowUpdateModal(true)}
462
+ {settingsPage === 'main' && (
463
+ <View
409
464
  style={{
410
- flexDirection: 'row',
411
- alignItems: 'center',
412
- backgroundColor: '#F59E0B',
413
- borderRadius: 5,
414
- paddingHorizontal: isNarrow ? 4 : 5.5,
465
+ backgroundColor: `${AppColors.white}26`,
466
+ paddingHorizontal: isNarrow ? 4 : 6,
415
467
  paddingVertical: 1.5,
416
- gap: 3,
417
- shadowColor: '#F59E0B',
418
- shadowOffset: {width: 0, height: 1.5},
419
- shadowOpacity: 0.35,
420
- shadowRadius: 3,
421
- elevation: 3,
422
- flexShrink: 0,
468
+ borderRadius: 10,
469
+ borderWidth: 1,
470
+ borderColor: `${AppColors.white}20`,
423
471
  }}>
424
- <Animated.View
472
+ <Text
425
473
  style={{
426
- width: 5,
427
- height: 5,
428
- borderRadius: 2.5,
429
- backgroundColor: '#FFFFFF',
430
- opacity: activePulseAnim,
431
- transform: [{scale: unreadPulseAnim}],
432
- }}
433
- />
434
- {!isNarrow && (
435
- <Text
436
- style={{
437
- fontFamily: AppFonts.interBold,
438
- fontSize: 8.5,
439
- color: '#FFFFFF',
440
- letterSpacing: 0.3,
441
- }}>
442
- UPDATE
443
- </Text>
444
- )}
445
- <BoltIcon size={isNarrow ? 8 : 9} color="#FFFFFF" />
446
- </Pressable>
474
+ fontFamily: AppFonts.interBold,
475
+ fontSize: isNarrow ? 8 : 9,
476
+ color: AppColors.white,
477
+ }}>
478
+ v{LIB_VERSION}
479
+ </Text>
480
+ </View>
447
481
  )}
448
482
  </View>
449
-
450
- {/* OS & NPM Version Representation */}
451
- <View
483
+ <Text
452
484
  style={{
453
- flexDirection: 'row',
454
- alignItems: 'center',
455
- gap: isNarrow ? 4 : 5,
456
- minWidth: 0,
457
- }}>
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}}>
458
507
  <View
459
508
  style={{
460
509
  flexDirection: 'row',
461
510
  alignItems: 'center',
462
- backgroundColor: `${AppColors.white}1F`,
463
- borderRadius: 5,
464
- paddingHorizontal: isNarrow ? 4.5 : 6,
465
- paddingVertical: 2,
466
- gap: 3.5,
467
- borderWidth: 1,
468
- borderColor: `${AppColors.white}2E`,
469
- flexShrink: 1,
511
+ gap: isNarrow ? 4 : 6,
470
512
  minWidth: 0,
471
513
  }}>
472
- {Platform.OS === 'ios' ? (
473
- <AppleIcon color={`${AppColors.white}E6`} size={isNarrow ? 9 : 10} />
474
- ) : (
475
- <AndroidIcon color={`${AppColors.white}E6`} size={isNarrow ? 9 : 10} />
476
- )}
477
514
  <Text
478
- style={{
479
- fontFamily: AppFonts.interMedium,
480
- fontSize: isNarrow ? 8.5 : 9.5,
481
- color: `${AppColors.white}EB`,
482
- letterSpacing: 0.1,
483
- }}
515
+ style={[
516
+ styles.headerTitle,
517
+ {
518
+ fontSize: isNarrow ? 13.5 : isCompact ? 14.5 : 15.5,
519
+ flexShrink: 1,
520
+ paddingBottom: 0,
521
+ },
522
+ ]}
484
523
  numberOfLines={1}
485
524
  ellipsizeMode="tail">
486
- {appVersionString}
525
+ {getAppName()}
487
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
+ )}
488
596
  </View>
489
597
 
490
- <Pressable
491
- onPress={() => {
492
- if (updateAvailable) {
493
- setShowUpdateModal(true);
494
- } else {
495
- Linking.openURL(
496
- 'https://www.npmjs.com/package/react-native-inapp-inspector',
497
- ).catch(() => {});
498
- }
499
- }}
598
+ {/* OS & NPM Version Representation */}
599
+ <View
500
600
  style={{
501
601
  flexDirection: 'row',
502
602
  alignItems: 'center',
503
- backgroundColor: `${AppColors.white}1F`,
504
- borderRadius: 5,
505
- paddingHorizontal: isNarrow ? 4.5 : 6,
506
- paddingVertical: 2,
507
- gap: 3.5,
508
- borderWidth: 1,
509
- borderColor: `${AppColors.white}2E`,
510
- flexShrink: 0,
603
+ gap: isNarrow ? 4 : 5,
604
+ minWidth: 0,
511
605
  }}>
512
- <NpmIcon size={isNarrow ? 9 : 10} color="#FF6B6B" />
513
- <Text
606
+ <View
514
607
  style={{
515
- fontFamily: AppFonts.interMedium,
516
- fontSize: isNarrow ? 8.5 : 9.5,
517
- color: `${AppColors.white}EB`,
518
- 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
+ }
519
653
  }}
520
- numberOfLines={1}>
521
- v{LIB_VERSION}
522
- </Text>
523
- {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
+ />
524
670
  <Text
525
671
  style={{
526
- fontFamily: AppFonts.interBold,
527
- fontSize: 8.5,
528
- color: '#F59E0B',
529
- }}>
530
- ●
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}
531
679
  </Text>
532
- )}
533
- </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>
534
692
  </View>
535
693
  </View>
536
- </View>
537
- ) : null}
538
- </View>
694
+ ) : null}
695
+ </View>
539
696
 
540
- {isDetailView && (
541
- <View style={[styles.headerCenter, {paddingHorizontal: isNarrow ? 2 : 6}]}>
542
- {activeTab === 'apis' && selected != null ? (
543
- <View style={styles.headerDetailCenter}>
544
- <View style={styles.headerDetailRow}>
545
- <View
546
- style={[
547
- styles.headerMethodBadge,
548
- {
549
- backgroundColor:
550
- METHOD_COLORS[selected.method as Method] ??
551
- AppColors.grayText,
552
- paddingHorizontal: isNarrow ? 5 : 6,
553
- paddingVertical: isNarrow ? 2 : 3,
554
- },
555
- ]}>
556
- <Text style={[styles.headerMethodText, {fontSize: isNarrow ? 9 : 10}]}>
557
- {selected.method}
558
- </Text>
559
- </View>
560
- <Text
561
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
562
- numberOfLines={1}
563
- ellipsizeMode="middle">
564
- {detailTitle}
565
- </Text>
566
- </View>
567
- <ScrollView
568
- horizontal
569
- showsHorizontalScrollIndicator={false}
570
- contentContainerStyle={{
571
- flexDirection: 'row',
572
- alignItems: 'center',
573
- gap: isNarrow ? 4 : 6,
574
- marginTop: 3,
575
- paddingVertical: 1,
576
- }}>
577
- <View
578
- style={{
579
- flexDirection: 'row',
580
- alignItems: 'center',
581
- gap: 4,
582
- paddingHorizontal: isNarrow ? 6 : 8,
583
- paddingVertical: 2.5,
584
- borderRadius: 20,
585
- backgroundColor: `${getStatusColor(selected.status)}26`,
586
- borderWidth: 1,
587
- borderColor: `${getStatusColor(selected.status)}55`,
588
- }}>
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}>
589
706
  <View
590
707
  style={[
591
- styles.headerStatusDot,
708
+ styles.headerMethodBadge,
592
709
  {
593
- backgroundColor: getStatusColor(selected.status),
594
- width: isNarrow ? 6 : 7,
595
- 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,
596
715
  },
597
- ]}
598
- />
716
+ ]}>
717
+ <Text
718
+ style={[
719
+ styles.headerMethodText,
720
+ {fontSize: isNarrow ? 9 : 10},
721
+ ]}>
722
+ {selected.method}
723
+ </Text>
724
+ </View>
599
725
  <Text
600
726
  style={[
601
- styles.headerSubTitle,
602
- {fontFamily: AppFonts.interBold, fontSize: isNarrow ? 10 : 11},
603
- ]}>
604
- {selected.status === 0
605
- ? 'Failed'
606
- : selected.status ?? 'Pending'}
727
+ styles.headerDetailTitle,
728
+ {fontSize: isNarrow ? 13.5 : 15},
729
+ ]}
730
+ numberOfLines={1}
731
+ ellipsizeMode="middle">
732
+ {detailTitle}
607
733
  </Text>
608
734
  </View>
609
735
  <View
610
736
  style={{
611
737
  flexDirection: 'row',
612
738
  alignItems: 'center',
613
- gap: 4,
614
- paddingHorizontal: isNarrow ? 6 : 8,
615
- paddingVertical: 2.5,
616
- borderRadius: 20,
617
- backgroundColor: `${AppColors.white}29`,
739
+ gap: isNarrow ? 4 : 6,
740
+ marginTop: 3,
741
+ paddingVertical: 1,
618
742
  }}>
619
- <ClockIcon color={AppColors.white} size={isNarrow ? 10 : 11} />
620
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
621
- {selected.duration != null
622
- ? `${selected.duration}ms`
623
- : '—'}
624
- </Text>
625
- </View>
626
- {selected.response != null && (
627
743
  <View
628
744
  style={{
629
745
  flexDirection: 'row',
@@ -632,390 +748,563 @@ const InspectorHeader = React.memo(() => {
632
748
  paddingHorizontal: isNarrow ? 6 : 8,
633
749
  paddingVertical: 2.5,
634
750
  borderRadius: 20,
635
- backgroundColor: `${AppColors.white}29`,
751
+ backgroundColor: `${getStatusColor(
752
+ selected.status,
753
+ )}26`,
754
+ borderWidth: 1,
755
+ borderColor: `${getStatusColor(selected.status)}55`,
636
756
  }}>
637
- <SizeIcon color={AppColors.white} size={isNarrow ? 10 : 11} />
638
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
639
- {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'}
640
778
  </Text>
641
779
  </View>
642
- )}
643
- </ScrollView>
644
- </View>
645
- ) : activeTab === 'analytics' && selectedEvent != null ? (
646
- <View style={styles.headerDetailCenter}>
647
- <View style={styles.headerDetailRow}>
648
- <View
649
- style={[
650
- styles.headerMethodBadge,
651
- {
652
- backgroundColor:
653
- selectedEvent.source === 'firebase'
654
- ? `${AppColors.firebaseOrange}4D`
655
- : `${AppColors.purple}4D`,
656
- paddingHorizontal: isNarrow ? 5 : 6,
657
- paddingVertical: isNarrow ? 2 : 3,
658
- },
659
- ]}>
660
- <Text style={[styles.headerMethodText, {fontSize: isNarrow ? 9 : 10}]}>
661
- {selectedEvent.source === 'firebase' ? 'FB' : 'MAN'}
662
- </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
+ )}
663
828
  </View>
664
- <Text
665
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
666
- numberOfLines={1}
667
- ellipsizeMode="middle">
668
- {selectedEvent.name}
669
- </Text>
670
829
  </View>
671
- <ScrollView
672
- horizontal
673
- showsHorizontalScrollIndicator={false}
674
- contentContainerStyle={{
675
- flexDirection: 'row',
676
- alignItems: 'center',
677
- gap: isNarrow ? 4 : 6,
678
- marginTop: 3,
679
- paddingVertical: 1,
680
- }}>
681
- <View
682
- style={[
683
- styles.headerStatusDot,
684
- {
685
- backgroundColor:
686
- selectedEvent.source === 'firebase'
687
- ? AppColors.firebaseOrange
688
- : AppColors.purple,
689
- width: isNarrow ? 6 : 7,
690
- height: isNarrow ? 6 : 7,
691
- },
692
- ]}
693
- />
694
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
695
- {Object.keys(selectedEvent.params).length} param
696
- {Object.keys(selectedEvent.params).length !== 1
697
- ? 's'
698
- : ''}
699
- {' · '}
700
- {selectedEvent.source}
701
- </Text>
702
- </ScrollView>
703
- </View>
704
- ) : activeTab === 'logs' && selectedLog != null ? (
705
- <View style={styles.headerDetailCenter}>
706
- <View style={styles.headerDetailRow}>
707
- <View
708
- style={[
709
- styles.headerMethodBadge,
710
- {
711
- backgroundColor:
712
- selectedLog.type === 'error'
713
- ? `${AppColors.errorColor}4D`
714
- : selectedLog.type === 'warn'
715
- ? `${AppColors.lightOrange}4D`
716
- : `${AppColors.purple}4D`,
717
- paddingHorizontal: isNarrow ? 5 : 6,
718
- paddingVertical: isNarrow ? 2 : 3,
719
- },
720
- ]}>
721
- <Text style={[styles.headerMethodText, {fontSize: isNarrow ? 9 : 10}]}>
722
- {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}
723
861
  </Text>
724
862
  </View>
725
- <Text
726
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
727
- numberOfLines={1}
728
- ellipsizeMode="middle">
729
- console.
730
- {selectedLog.sourceMethod || selectedLog.type || 'log'}
731
- </Text>
732
- </View>
733
- <ScrollView
734
- horizontal
735
- showsHorizontalScrollIndicator={false}
736
- contentContainerStyle={{
737
- flexDirection: 'row',
738
- alignItems: 'center',
739
- gap: isNarrow ? 4 : 6,
740
- marginTop: 3,
741
- paddingVertical: 1,
742
- }}>
743
863
  <View
744
864
  style={{
745
865
  flexDirection: 'row',
746
866
  alignItems: 'center',
747
- gap: 4,
748
- paddingHorizontal: isNarrow ? 6 : 8,
749
- paddingVertical: 2.5,
750
- borderRadius: 20,
751
- backgroundColor: `${AppColors.white}29`,
867
+ gap: isNarrow ? 4 : 6,
868
+ marginTop: 3,
869
+ paddingVertical: 1,
752
870
  }}>
753
- <ClockIcon color={AppColors.white} size={isNarrow ? 10 : 11} />
754
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
755
- {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}
756
895
  </Text>
757
896
  </View>
758
- </ScrollView>
759
- </View>
760
- ) : activeTab === 'redux' && selectedReduxSlice != null ? (
761
- (() => {
762
- const sliceData = reduxState?.[selectedReduxSlice];
763
- const keyCount =
764
- sliceData && typeof sliceData === 'object'
765
- ? Object.keys(sliceData).length
766
- : typeof sliceData !== 'undefined'
767
- ? 1
768
- : 0;
769
- const sliceSize = getSize(sliceData);
770
- const lastAction = reduxLastActionMap[selectedReduxSlice];
771
-
772
- return (
773
- <View style={styles.headerDetailCenter}>
774
- <View style={styles.headerDetailRow}>
775
- <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
776
916
  style={[
777
- styles.headerMethodBadge,
778
- {
779
- backgroundColor: `${AppColors.purple}4D`,
780
- paddingHorizontal: isNarrow ? 5 : 6,
781
- paddingVertical: isNarrow ? 2 : 3,
782
- },
917
+ styles.headerMethodText,
918
+ {fontSize: isNarrow ? 9 : 10},
783
919
  ]}>
784
- <Text style={[styles.headerMethodText, {fontSize: isNarrow ? 9 : 10}]}>SLICE</Text>
785
- </View>
786
- <Text
787
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
788
- numberOfLines={1}
789
- ellipsizeMode="middle">
790
- {selectedReduxSlice}
920
+ {selectedLog.type.toUpperCase()}
791
921
  </Text>
792
922
  </View>
793
- <ScrollView
794
- horizontal
795
- showsHorizontalScrollIndicator={false}
796
- 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={{
797
944
  flexDirection: 'row',
798
945
  alignItems: 'center',
799
- gap: isNarrow ? 4 : 6,
800
- marginTop: 3,
801
- paddingVertical: 1,
946
+ gap: 4,
947
+ paddingHorizontal: isNarrow ? 6 : 8,
948
+ paddingVertical: 2.5,
949
+ borderRadius: 20,
950
+ backgroundColor: `${AppColors.white}29`,
802
951
  }}>
803
- <View
804
- style={[
805
- styles.headerStatusDot,
806
- {
807
- backgroundColor: AppColors.liveGreen,
808
- width: isNarrow ? 6 : 7,
809
- height: isNarrow ? 6 : 7,
810
- },
811
- ]}
952
+ <ClockIcon
953
+ color={AppColors.white}
954
+ size={isNarrow ? 10 : 11}
812
955
  />
813
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>Live</Text>
814
- <Text style={[styles.headerSubTitle, {opacity: 0.6, fontSize: isNarrow ? 10 : 11}]}>
815
- •
816
- </Text>
817
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
818
- {keyCount} keys
819
- </Text>
820
- <Text style={[styles.headerSubTitle, {opacity: 0.6, fontSize: isNarrow ? 10 : 11}]}>
821
- •
956
+ <Text
957
+ style={[
958
+ styles.headerSubTitle,
959
+ {fontSize: isNarrow ? 10 : 11},
960
+ ]}>
961
+ {formatTime(selectedLog.timestamp)}
822
962
  </Text>
823
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>{sliceSize}</Text>
824
- {lastAction?.timestamp && (
825
- <>
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
+ ]}>
826
990
  <Text
827
- style={[styles.headerSubTitle, {opacity: 0.6, fontSize: isNarrow ? 10 : 11}]}>
828
- •
991
+ style={[
992
+ styles.headerMethodText,
993
+ {fontSize: isNarrow ? 9 : 10},
994
+ ]}>
995
+ SLICE
829
996
  </Text>
830
- <View
831
- style={{
832
- flexDirection: 'row',
833
- alignItems: 'center',
834
- gap: 3,
835
- }}>
836
- <ClockIcon color={AppColors.white} size={isNarrow ? 9 : 10} />
837
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
838
- {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
+ •
839
1069
  </Text>
840
- </View>
841
- </>
842
- )}
843
- </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>
844
1123
  </View>
845
- );
846
- })()
847
- ) : activeTab === 'redux' && selectedReduxAction != null ? (
848
- <View style={styles.headerDetailCenter}>
849
- <View style={styles.headerDetailRow}>
850
1124
  <View
851
- style={[
852
- styles.headerMethodBadge,
853
- {
854
- backgroundColor: `${AppColors.brandPurple}4D`,
855
- paddingHorizontal: isNarrow ? 5 : 6,
856
- paddingVertical: isNarrow ? 2 : 3,
857
- },
858
- ]}>
859
- <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>
860
1149
  </View>
861
- <Text
862
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
863
- numberOfLines={1}
864
- ellipsizeMode="middle">
865
- {selectedReduxAction.type}
866
- </Text>
867
1150
  </View>
868
- <ScrollView
869
- horizontal
870
- showsHorizontalScrollIndicator={false}
871
- contentContainerStyle={{
872
- flexDirection: 'row',
873
- alignItems: 'center',
874
- gap: isNarrow ? 4 : 6,
875
- marginTop: 3,
876
- paddingVertical: 1,
877
- }}>
878
- <View
879
- style={[
880
- styles.headerStatusDot,
881
- {
882
- backgroundColor: AppColors.purple,
883
- width: isNarrow ? 6 : 7,
884
- height: isNarrow ? 6 : 7,
885
- },
886
- ]}
887
- />
888
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
889
- {selectedReduxAction.timestamp || 'Dispatched'}
890
- </Text>
891
- </ScrollView>
892
- </View>
893
- ) : activeTab === 'crash' && selectedCrash != null ? (
894
- <View style={styles.headerDetailCenter}>
895
- <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>
896
1185
  <View
897
- style={[
898
- styles.headerMethodBadge,
899
- {
900
- backgroundColor: selectedCrash.isFatal
901
- ? AppColors.red600
902
- : AppColors.amber600,
903
- paddingHorizontal: isNarrow ? 5 : 6,
904
- paddingVertical: isNarrow ? 2 : 3,
905
- },
906
- ]}>
907
- <Text style={[styles.headerMethodText, {fontSize: isNarrow ? 9 : 10}]}>
908
- {selectedCrash.isFatal
909
- ? 'FATAL'
910
- : 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()}
911
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
+ )}
912
1233
  </View>
913
- <Text
914
- style={[styles.headerDetailTitle, {fontSize: isNarrow ? 13.5 : 15}]}
915
- numberOfLines={1}
916
- ellipsizeMode="middle">
917
- {selectedCrash.name || selectedCrash.message}
918
- </Text>
919
1234
  </View>
920
- <ScrollView
921
- horizontal
922
- showsHorizontalScrollIndicator={false}
923
- contentContainerStyle={{
924
- flexDirection: 'row',
925
- alignItems: 'center',
926
- gap: isNarrow ? 4 : 6,
927
- marginTop: 3,
928
- paddingVertical: 1,
929
- }}>
930
- <View
931
- style={[
932
- 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'},
933
1258
  {
934
- backgroundColor: selectedCrash.isFatal
935
- ? AppColors.red600
936
- : AppColors.amber500,
937
- width: isNarrow ? 6 : 7,
938
- height: isNarrow ? 6 : 7,
1259
+ text: 'Reset',
1260
+ style: 'destructive',
1261
+ onPress: resetToDefaults,
939
1262
  },
940
- ]}
941
- />
942
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
943
- {selectedCrash.timeStr ||
944
- new Date(selectedCrash.timestamp).toLocaleTimeString()}
945
- </Text>
946
- {selectedCrash.deviceInfo?.platform && (
947
- <>
948
- <Text style={[styles.headerSubTitle, {opacity: 0.6, fontSize: isNarrow ? 10 : 11}]}>
949
- •
950
- </Text>
951
- <Text style={[styles.headerSubTitle, {fontSize: isNarrow ? 10 : 11}]}>
952
- {selectedCrash.deviceInfo.platform.toUpperCase()}
953
- </Text>
954
- </>
955
- )}
956
- </ScrollView>
957
- </View>
958
- ) : null}
959
- </View>
960
- )}
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
+ )}
961
1281
 
962
- <View
963
- style={[
964
- styles.headerRight,
965
- {
966
- flexDirection: 'row',
967
- alignItems: 'center',
968
- justifyContent: 'flex-end',
969
- flexShrink: 0,
970
- gap: isNarrow ? 5 : 7,
971
- },
972
- ]}>
973
- {isSettingsView && (
974
- <TouchableScale
975
- onPress={() => {
976
- Alert.alert(
977
- 'Reset All Settings',
978
- 'This restores all module visibility and UI preferences to defaults. Continue?',
979
- [
980
- {text: 'Cancel', style: 'cancel'},
981
- {
982
- text: 'Reset',
983
- style: 'destructive',
984
- onPress: resetToDefaults,
985
- },
986
- ],
987
- );
988
- }}
989
- hitSlop={15}
990
- style={[
991
- styles.closeButtonSquare,
992
- {
993
- width: buttonSize,
994
- height: buttonSize,
995
- borderRadius: isNarrow ? 6 : 7,
996
- },
997
- ]}>
998
- <ResetIcon color={AppColors.white} size={isNarrow ? 12 : 14} />
999
- </TouchableScale>
1000
- )}
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
+ )}
1001
1303
 
1002
- {!isAnySelected && (
1003
- <TouchableScale
1004
- onPress={() => {
1005
- Alert.alert(
1006
- 'Clear Everything',
1007
- 'This clears all tabs — APIs, Logs, Analytics, Redux timeline and Crash history. Continue?',
1008
- [
1009
- {text: 'Cancel', style: 'cancel'},
1010
- {
1011
- text: 'Clear All',
1012
- onPress: runClearAllWithAnimation,
1013
- style: 'destructive',
1014
- },
1015
- ],
1016
- );
1017
- }}
1018
- hitSlop={15}
1304
+ <TouchableOpacity
1305
+ onPress={closeModal}
1306
+ hitSlop={{top: 12, bottom: 12, left: 12, right: 12}}
1307
+ activeOpacity={0.6}
1019
1308
  style={[
1020
1309
  styles.closeButtonSquare,
1021
1310
  {
@@ -1024,94 +1313,231 @@ const InspectorHeader = React.memo(() => {
1024
1313
  borderRadius: isNarrow ? 6 : 7,
1025
1314
  },
1026
1315
  ]}>
1027
- <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}
1028
1338
  style={{
1029
- transform: [
1030
- {
1031
- rotate: clearAnim.interpolate({
1032
- inputRange: [0, 1],
1033
- outputRange: ['0deg', '-25deg'],
1034
- }),
1035
- },
1036
- {
1037
- scale: clearAnim.interpolate({
1038
- inputRange: [0, 0.5, 1],
1039
- outputRange: [1, 1.25, 1],
1040
- }),
1041
- },
1042
- ],
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`,
1043
1348
  }}>
1044
- <TrashIcon color={AppColors.white} size={isNarrow ? 12 : 14} />
1045
- </Animated.View>
1046
- </TouchableScale>
1047
- )}
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>
1048
1362
 
1049
- {!isAnySelected && (
1050
- <TouchableScale
1051
- accessible={true}
1052
- accessibilityRole="button"
1053
- accessibilityLabel="Settings"
1054
- onPress={() => setSettingsPage('main')}
1055
- hitSlop={15}
1056
- style={[
1057
- styles.closeButtonSquare,
1058
- {
1059
- width: buttonSize,
1060
- height: buttonSize,
1061
- borderRadius: isNarrow ? 6 : 7,
1062
- },
1063
- ]}>
1064
- <SettingsIcon color={AppColors.white} size={isNarrow ? 12 : 14} />
1065
- </TouchableScale>
1066
- )}
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>
1067
1408
 
1068
- {!isAnySelected && (
1069
- <TouchableScale
1070
- accessible={true}
1071
- accessibilityRole="button"
1072
- accessibilityLabel="About and System Specifications"
1073
- onPress={() => {
1074
- setSettingsActiveSubTab('about');
1075
- setSettingsPage('main');
1076
- }}
1077
- hitSlop={15}
1078
- style={[
1079
- styles.closeButtonSquare,
1080
- {
1081
- width: buttonSize,
1082
- height: buttonSize,
1083
- borderRadius: isNarrow ? 6 : 7,
1084
- },
1085
- ]}>
1086
- <InfoCircleIcon color={AppColors.white} size={isNarrow ? 12 : 14} />
1087
- </TouchableScale>
1088
- )}
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>
1089
1469
 
1090
- <TouchableOpacity
1091
- onPress={closeModal}
1092
- hitSlop={{top: 12, bottom: 12, left: 12, right: 12}}
1093
- activeOpacity={0.6}
1094
- style={[
1095
- styles.closeButtonSquare,
1096
- {
1097
- width: buttonSize,
1098
- height: buttonSize,
1099
- borderRadius: isNarrow ? 6 : 7,
1100
- },
1101
- ]}>
1102
- <CloseWhite size={isNarrow ? 12 : 14} />
1103
- </TouchableOpacity>
1104
- </View>
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
+ )}
1105
1503
  </View>
1106
1504
  </View>
1107
- </LinearGradient>
1108
1505
 
1109
- {/* Dedicated Update Available Details Modal */}
1110
- <UpdateAvailableModal
1111
- visible={showUpdateModal}
1112
- latestVersion={latestNpmVersion}
1113
- onClose={() => setShowUpdateModal(false)}
1114
- />
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
+ />
1115
1541
  </>
1116
1542
  );
1117
1543
  });