react-native-inapp-inspector 2.5.12 → 2.5.13

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 (186) hide show
  1. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  2. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  3. package/android/.gradle/8.9/executionHistory/executionHistory.lock +0 -0
  4. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  5. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  6. package/android/.gradle/8.9/gc.properties +0 -0
  7. package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
  8. package/android/.gradle/9.2.0/fileChanges/last-build.bin +0 -0
  9. package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
  10. package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
  11. package/android/.gradle/9.2.0/gc.properties +0 -0
  12. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  13. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  14. package/android/.gradle/vcs-1/gc.properties +0 -0
  15. package/android/.settings/org.eclipse.buildship.core.prefs +13 -0
  16. package/android/src/main/AndroidManifest.xml +11 -0
  17. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +379 -19
  18. package/android/src/main/res/xml/inappinspector_file_paths.xml +7 -0
  19. package/dist/commonjs/components/Inspector/AnalyticsFilterModal.js +47 -49
  20. package/dist/commonjs/components/Inspector/BoxModelVisualizer.d.ts +8 -0
  21. package/dist/commonjs/components/Inspector/BoxModelVisualizer.js +76 -0
  22. package/dist/commonjs/components/Inspector/ConsoleExportModal.js +51 -51
  23. package/dist/commonjs/components/Inspector/CrashTab.js +17 -17
  24. package/dist/commonjs/components/Inspector/DebuggingTab.js +24 -24
  25. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +2 -2
  26. package/dist/commonjs/components/Inspector/FabLauncher.js +2 -2
  27. package/dist/commonjs/components/Inspector/FloatingCaptureWidget.js +2 -2
  28. package/dist/commonjs/components/Inspector/InspectorHeader.js +10 -10
  29. package/dist/commonjs/components/Inspector/MediaGalleryTab.js +10 -10
  30. package/dist/commonjs/components/Inspector/MediaPreviewModal.d.ts +1 -0
  31. package/dist/commonjs/components/Inspector/MediaPreviewModal.js +222 -222
  32. package/dist/commonjs/components/Inspector/NetworkExportModal.d.ts +10 -0
  33. package/dist/commonjs/components/Inspector/NetworkExportModal.js +333 -0
  34. package/dist/commonjs/components/Inspector/NetworkTab.js +48 -41
  35. package/dist/commonjs/components/Inspector/NpmStarPrompt.js +11 -12
  36. package/dist/commonjs/components/Inspector/ReduxDetail.js +17 -19
  37. package/dist/commonjs/components/Inspector/ReduxTab.js +5 -5
  38. package/dist/commonjs/components/Inspector/SettingsPanel.js +3 -6
  39. package/dist/commonjs/components/Inspector/SocketCard.js +2 -2
  40. package/dist/commonjs/components/Inspector/SupportPage.js +5 -5
  41. package/dist/commonjs/components/Inspector/UiA11yAuditPanel.d.ts +7 -0
  42. package/dist/commonjs/components/Inspector/UiA11yAuditPanel.js +97 -0
  43. package/dist/commonjs/components/Inspector/UiInspectorDetail.d.ts +2 -0
  44. package/dist/commonjs/components/Inspector/UiInspectorDetail.js +485 -0
  45. package/dist/commonjs/components/Inspector/UiInspectorOverlay.d.ts +2 -0
  46. package/dist/commonjs/components/Inspector/UiInspectorOverlay.js +199 -0
  47. package/dist/commonjs/components/Inspector/UiInspectorTab.d.ts +2 -0
  48. package/dist/commonjs/components/Inspector/UiInspectorTab.js +117 -0
  49. package/dist/commonjs/components/Inspector/UiLiveStyleTweaker.d.ts +10 -0
  50. package/dist/commonjs/components/Inspector/UiLiveStyleTweaker.js +148 -0
  51. package/dist/commonjs/components/Inspector/index.d.ts +28 -0
  52. package/dist/commonjs/components/Inspector/index.js +1 -0
  53. package/dist/commonjs/components/LogCard.js +9 -7
  54. package/dist/commonjs/constants/index.js +1 -1
  55. package/dist/commonjs/constants/telemetryConfig.d.ts +3 -3
  56. package/dist/commonjs/constants/telemetryConfig.js +1 -1
  57. package/dist/commonjs/constants/version.d.ts +1 -1
  58. package/dist/commonjs/constants/version.js +1 -1
  59. package/dist/commonjs/customHooks/crashHandler.d.ts +1 -1
  60. package/dist/commonjs/customHooks/crashHandler.js +6 -6
  61. package/dist/commonjs/customHooks/uiInspectorManager.d.ts +22 -0
  62. package/dist/commonjs/customHooks/uiInspectorManager.js +1 -0
  63. package/dist/commonjs/helpers/index.js +1 -3
  64. package/dist/commonjs/helpers/searchQueryParser.d.ts +1 -0
  65. package/dist/commonjs/helpers/searchQueryParser.js +7 -5
  66. package/dist/commonjs/helpers/shareFormatter.d.ts +16 -0
  67. package/dist/commonjs/helpers/shareFormatter.js +16 -9
  68. package/dist/commonjs/helpers/uiInspectorEngine.d.ts +62 -0
  69. package/dist/commonjs/helpers/uiInspectorEngine.js +19 -0
  70. package/dist/commonjs/i18n/locales/ar.json +1 -1
  71. package/dist/commonjs/i18n/locales/bn.json +1 -1
  72. package/dist/commonjs/i18n/locales/de.json +1 -1
  73. package/dist/commonjs/i18n/locales/en.json +1 -1
  74. package/dist/commonjs/i18n/locales/es.json +1 -1
  75. package/dist/commonjs/i18n/locales/fr.json +1 -1
  76. package/dist/commonjs/i18n/locales/gu.json +1 -1
  77. package/dist/commonjs/i18n/locales/hi.json +1 -1
  78. package/dist/commonjs/i18n/locales/id.json +1 -1
  79. package/dist/commonjs/i18n/locales/it.json +1 -1
  80. package/dist/commonjs/i18n/locales/ja.json +1 -1
  81. package/dist/commonjs/i18n/locales/kn.json +1 -1
  82. package/dist/commonjs/i18n/locales/ko.json +1 -1
  83. package/dist/commonjs/i18n/locales/ml.json +1 -1
  84. package/dist/commonjs/i18n/locales/mr.json +1 -1
  85. package/dist/commonjs/i18n/locales/nl.json +1 -1
  86. package/dist/commonjs/i18n/locales/pa.json +1 -1
  87. package/dist/commonjs/i18n/locales/pl.json +1 -1
  88. package/dist/commonjs/i18n/locales/pt.json +1 -1
  89. package/dist/commonjs/i18n/locales/ru.json +1 -1
  90. package/dist/commonjs/i18n/locales/ta.json +1 -1
  91. package/dist/commonjs/i18n/locales/te.json +1 -1
  92. package/dist/commonjs/i18n/locales/tr.json +1 -1
  93. package/dist/commonjs/i18n/locales/vi.json +1 -1
  94. package/dist/commonjs/i18n/locales/zh.json +1 -1
  95. package/dist/commonjs/index.d.ts +3 -1
  96. package/dist/commonjs/index.js +3 -3
  97. package/dist/commonjs/native/NativeInspector.d.ts +2 -0
  98. package/dist/commonjs/native/NativeInspector.js +1 -1
  99. package/dist/commonjs/native/NativeNetworkInspector.d.ts +2 -0
  100. package/dist/commonjs/types/editor.d.ts +31 -0
  101. package/dist/esm/components/Inspector/AnalyticsFilterModal.js +73 -75
  102. package/dist/esm/components/Inspector/BoxModelVisualizer.d.ts +8 -0
  103. package/dist/esm/components/Inspector/BoxModelVisualizer.js +76 -0
  104. package/dist/esm/components/Inspector/ConsoleExportModal.js +67 -67
  105. package/dist/esm/components/Inspector/CrashTab.js +58 -58
  106. package/dist/esm/components/Inspector/DebuggingTab.js +89 -89
  107. package/dist/esm/components/Inspector/DeviceInfoTab.js +2 -2
  108. package/dist/esm/components/Inspector/FabLauncher.js +21 -21
  109. package/dist/esm/components/Inspector/FloatingCaptureWidget.js +23 -23
  110. package/dist/esm/components/Inspector/InspectorHeader.js +26 -26
  111. package/dist/esm/components/Inspector/MediaGalleryTab.js +151 -151
  112. package/dist/esm/components/Inspector/MediaPreviewModal.d.ts +1 -0
  113. package/dist/esm/components/Inspector/MediaPreviewModal.js +468 -468
  114. package/dist/esm/components/Inspector/NetworkExportModal.d.ts +10 -0
  115. package/dist/esm/components/Inspector/NetworkExportModal.js +333 -0
  116. package/dist/esm/components/Inspector/NetworkTab.js +118 -111
  117. package/dist/esm/components/Inspector/NpmStarPrompt.js +32 -33
  118. package/dist/esm/components/Inspector/ReduxDetail.js +54 -56
  119. package/dist/esm/components/Inspector/ReduxTab.js +9 -9
  120. package/dist/esm/components/Inspector/SettingsPanel.js +3 -6
  121. package/dist/esm/components/Inspector/SocketCard.js +13 -13
  122. package/dist/esm/components/Inspector/SupportPage.js +5 -5
  123. package/dist/esm/components/Inspector/UiA11yAuditPanel.d.ts +7 -0
  124. package/dist/esm/components/Inspector/UiA11yAuditPanel.js +97 -0
  125. package/dist/esm/components/Inspector/UiInspectorDetail.d.ts +2 -0
  126. package/dist/esm/components/Inspector/UiInspectorDetail.js +422 -0
  127. package/dist/esm/components/Inspector/UiInspectorOverlay.d.ts +2 -0
  128. package/dist/esm/components/Inspector/UiInspectorOverlay.js +138 -0
  129. package/dist/esm/components/Inspector/UiInspectorTab.d.ts +2 -0
  130. package/dist/esm/components/Inspector/UiInspectorTab.js +117 -0
  131. package/dist/esm/components/Inspector/UiLiveStyleTweaker.d.ts +10 -0
  132. package/dist/esm/components/Inspector/UiLiveStyleTweaker.js +148 -0
  133. package/dist/esm/components/Inspector/index.d.ts +28 -0
  134. package/dist/esm/components/Inspector/index.js +1 -0
  135. package/dist/esm/components/LogCard.js +57 -55
  136. package/dist/esm/constants/index.js +1 -1
  137. package/dist/esm/constants/telemetryConfig.d.ts +3 -3
  138. package/dist/esm/constants/telemetryConfig.js +1 -1
  139. package/dist/esm/constants/version.d.ts +1 -1
  140. package/dist/esm/constants/version.js +1 -1
  141. package/dist/esm/customHooks/crashHandler.d.ts +1 -1
  142. package/dist/esm/customHooks/crashHandler.js +6 -6
  143. package/dist/esm/customHooks/uiInspectorManager.d.ts +22 -0
  144. package/dist/esm/customHooks/uiInspectorManager.js +1 -0
  145. package/dist/esm/helpers/index.js +4 -6
  146. package/dist/esm/helpers/searchQueryParser.d.ts +1 -0
  147. package/dist/esm/helpers/searchQueryParser.js +7 -5
  148. package/dist/esm/helpers/shareFormatter.d.ts +16 -0
  149. package/dist/esm/helpers/shareFormatter.js +20 -13
  150. package/dist/esm/helpers/uiInspectorEngine.d.ts +48 -0
  151. package/dist/esm/helpers/uiInspectorEngine.js +19 -0
  152. package/dist/esm/i18n/locales/ar.json +1 -1
  153. package/dist/esm/i18n/locales/bn.json +1 -1
  154. package/dist/esm/i18n/locales/de.json +1 -1
  155. package/dist/esm/i18n/locales/en.json +1 -1
  156. package/dist/esm/i18n/locales/es.json +1 -1
  157. package/dist/esm/i18n/locales/fr.json +1 -1
  158. package/dist/esm/i18n/locales/gu.json +1 -1
  159. package/dist/esm/i18n/locales/hi.json +1 -1
  160. package/dist/esm/i18n/locales/id.json +1 -1
  161. package/dist/esm/i18n/locales/it.json +1 -1
  162. package/dist/esm/i18n/locales/ja.json +1 -1
  163. package/dist/esm/i18n/locales/kn.json +1 -1
  164. package/dist/esm/i18n/locales/ko.json +1 -1
  165. package/dist/esm/i18n/locales/ml.json +1 -1
  166. package/dist/esm/i18n/locales/mr.json +1 -1
  167. package/dist/esm/i18n/locales/nl.json +1 -1
  168. package/dist/esm/i18n/locales/pa.json +1 -1
  169. package/dist/esm/i18n/locales/pl.json +1 -1
  170. package/dist/esm/i18n/locales/pt.json +1 -1
  171. package/dist/esm/i18n/locales/ru.json +1 -1
  172. package/dist/esm/i18n/locales/ta.json +1 -1
  173. package/dist/esm/i18n/locales/te.json +1 -1
  174. package/dist/esm/i18n/locales/tr.json +1 -1
  175. package/dist/esm/i18n/locales/vi.json +1 -1
  176. package/dist/esm/i18n/locales/zh.json +1 -1
  177. package/dist/esm/index.d.ts +3 -1
  178. package/dist/esm/index.js +7 -7
  179. package/dist/esm/native/NativeInspector.d.ts +2 -0
  180. package/dist/esm/native/NativeInspector.js +1 -1
  181. package/dist/esm/native/NativeNetworkInspector.d.ts +2 -0
  182. package/dist/esm/types/editor.d.ts +31 -0
  183. package/ios/NetworkInspectorModule.mm +314 -16
  184. package/package.json +1 -1
  185. package/src/native/NativeInspector.ts +37 -0
  186. package/src/native/NativeNetworkInspector.ts +2 -0
File without changes
File without changes
@@ -0,0 +1,2 @@
1
+ #Sat Sep 19 10:45:39 IST 2026
2
+ gradle.version=8.9
File without changes
@@ -0,0 +1,13 @@
1
+ arguments=--init-script /var/folders/77/7l8qyhy91k1cyjht91zz_vs00000gp/T/db3b08fc4a9ef609cb16b96b200fa13e563f396e9bb1ed0905fdab7bc3bc513b.gradle --init-script /var/folders/77/7l8qyhy91k1cyjht91zz_vs00000gp/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle --init-script /var/folders/77/7l8qyhy91k1cyjht91zz_vs00000gp/T/861a75667e10803d304a058d833cb7404195ca44013d0d61d3b653eb084379b8.gradle --init-script /var/folders/77/7l8qyhy91k1cyjht91zz_vs00000gp/T/68eb1b6516fe21c6fbba58e63c99c3207ccfc918360613709367eecde56fa77f.gradle --init-script /var/folders/77/7l8qyhy91k1cyjht91zz_vs00000gp/T/da64152279c70a8b4f3de4ca9ea66fd3b3405b7aca4e1f20f2d08e5593aa1ce1.gradle
2
+ auto.sync=false
3
+ build.scans.enabled=false
4
+ connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(8.9))
5
+ connection.project.dir=
6
+ eclipse.preferences.version=1
7
+ gradle.user.home=
8
+ java.home=/Users/vengateswaran/Library/Java/JavaVirtualMachines/ms-17.0.14/Contents/Home
9
+ jvm.arguments=
10
+ offline.mode=false
11
+ override.workspace.settings=true
12
+ show.console.view=true
13
+ show.executions.view=true
@@ -1,3 +1,14 @@
1
1
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
2
  package="com.inappinspector">
3
+ <application>
4
+ <provider
5
+ android:name="androidx.core.content.FileProvider"
6
+ android:authorities="${applicationId}.inappinspector.provider"
7
+ android:exported="false"
8
+ android:grantUriPermissions="true">
9
+ <meta-data
10
+ android:name="android.support.FILE_PROVIDER_PATHS"
11
+ android:resource="@xml/inappinspector_file_paths" />
12
+ </provider>
13
+ </application>
3
14
  </manifest>
@@ -1407,6 +1407,24 @@ class NetworkInspectorModule(private val reactContext: ReactApplicationContext)
1407
1407
  // 100% Native Media Editor: Photo Editing (Bitmap + ColorMatrix + Canvas)
1408
1408
  // ─────────────────────────────────────────────────────────────────────────
1409
1409
 
1410
+ private fun parseInspectorHexColor(hex: String?, defaultColor: Int = android.graphics.Color.RED): Int {
1411
+ if (hex.isNullOrBlank()) return defaultColor
1412
+ val clean = hex.trim()
1413
+ return try {
1414
+ if (clean.startsWith("#") && clean.length == 9) {
1415
+ val r = clean.substring(1, 3)
1416
+ val g = clean.substring(3, 5)
1417
+ val b = clean.substring(5, 7)
1418
+ val a = clean.substring(7, 9)
1419
+ android.graphics.Color.parseColor("#$a$r$g$b")
1420
+ } else {
1421
+ android.graphics.Color.parseColor(clean)
1422
+ }
1423
+ } catch (_: Exception) {
1424
+ defaultColor
1425
+ }
1426
+ }
1427
+
1410
1428
  @ReactMethod
1411
1429
  fun editPhoto(options: ReadableMap, promise: Promise) {
1412
1430
  captureExecutor.execute {
@@ -1599,54 +1617,302 @@ class NetworkInspectorModule(private val reactContext: ReactApplicationContext)
1599
1617
  finalBitmap = croppedBitmap
1600
1618
  }
1601
1619
 
1602
- // 5. Apply Redactions & Annotations Overlay if provided
1620
+ // 5. Apply Redactions, Freehand Drawings, Draggable Texts & Annotations Overlay if provided
1603
1621
  val mutableBitmap = if (finalBitmap.isMutable) finalBitmap else finalBitmap.copy(Bitmap.Config.ARGB_8888, true)
1604
1622
  val canvas = android.graphics.Canvas(mutableBitmap)
1605
- val overlayPaint = android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG)
1623
+ val canvasW = mutableBitmap.width.toFloat()
1624
+ val canvasH = mutableBitmap.height.toFloat()
1625
+ val baseScale = Math.max(1.0f, canvasW / 380.0f)
1606
1626
 
1627
+ // A. Redactions (Blackout or Blur/Pixelate Box)
1607
1628
  if (options.hasKey("redactions")) {
1608
1629
  val redactions = options.getArray("redactions")
1609
1630
  if (redactions != null) {
1610
- overlayPaint.color = android.graphics.Color.BLACK
1611
- overlayPaint.style = android.graphics.Paint.Style.FILL
1631
+ val redactPaint = android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG).apply {
1632
+ style = android.graphics.Paint.Style.FILL
1633
+ }
1612
1634
  for (i in 0 until redactions.size()) {
1613
1635
  val box = redactions.getMap(i) ?: continue
1614
1636
  var x = if (box.hasKey("x")) box.getDouble("x").toFloat() else 0f
1615
1637
  var y = if (box.hasKey("y")) box.getDouble("y").toFloat() else 0f
1616
1638
  var w = if (box.hasKey("width")) box.getDouble("width").toFloat() else 0f
1617
1639
  var h = if (box.hasKey("height")) box.getDouble("height").toFloat() else 0f
1618
- val isNorm = if (box.hasKey("isNormalized")) box.getBoolean("isNormalized") else false
1640
+ val isNorm = if (box.hasKey("isNormalized")) box.getBoolean("isNormalized") else true
1619
1641
  if (isNorm) {
1620
- x *= mutableBitmap.width
1621
- y *= mutableBitmap.height
1622
- w *= mutableBitmap.width
1623
- h *= mutableBitmap.height
1642
+ x *= canvasW
1643
+ y *= canvasH
1644
+ w *= canvasW
1645
+ h *= canvasH
1624
1646
  }
1625
- canvas.drawRect(x, y, x + w, y + h, overlayPaint)
1647
+ val style = if (box.hasKey("style")) box.getString("style") else "blackout"
1648
+ if (style == "blur" || style == "pixelate") {
1649
+ redactPaint.color = android.graphics.Color.argb(235, 30, 30, 30)
1650
+ } else {
1651
+ redactPaint.color = android.graphics.Color.BLACK
1652
+ }
1653
+ canvas.drawRect(x, y, x + w, y + h, redactPaint)
1654
+ }
1655
+ }
1656
+ }
1657
+
1658
+ // B. Freehand Drawings & Vector Shapes (Brush, Highlighter, Arrow, Rect, Circle, Step)
1659
+ if (options.hasKey("drawings")) {
1660
+ val drawings = options.getArray("drawings")
1661
+ if (drawings != null) {
1662
+ val strokePaint = android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG)
1663
+
1664
+ for (i in 0 until drawings.size()) {
1665
+ val stroke = drawings.getMap(i) ?: continue
1666
+ val type = if (stroke.hasKey("type")) stroke.getString("type") ?: "brush" else "brush"
1667
+ val colorHex = if (stroke.hasKey("color")) stroke.getString("color") else "#EF4444"
1668
+ val parsedColor = parseInspectorHexColor(colorHex, android.graphics.Color.RED)
1669
+ val strokeW = (if (stroke.hasKey("strokeWidth")) stroke.getDouble("strokeWidth").toFloat() else 4.0f) * baseScale
1670
+ val isNorm = if (stroke.hasKey("isNormalized")) stroke.getBoolean("isNormalized") else true
1671
+ val points = if (stroke.hasKey("points")) stroke.getArray("points") else null
1672
+
1673
+ when (type) {
1674
+ "brush" -> {
1675
+ if (points != null && points.size() > 1) {
1676
+ strokePaint.style = android.graphics.Paint.Style.STROKE
1677
+ strokePaint.color = parsedColor
1678
+ strokePaint.strokeWidth = strokeW
1679
+ strokePaint.strokeCap = android.graphics.Paint.Cap.ROUND
1680
+ strokePaint.strokeJoin = android.graphics.Paint.Join.ROUND
1681
+ strokePaint.alpha = 255
1682
+
1683
+ val path = android.graphics.Path()
1684
+ for (pIdx in 0 until points.size()) {
1685
+ val pt = points.getMap(pIdx) ?: continue
1686
+ val px = (if (pt.hasKey("x")) pt.getDouble("x").toFloat() else 0f) * (if (isNorm) canvasW else 1f)
1687
+ val py = (if (pt.hasKey("y")) pt.getDouble("y").toFloat() else 0f) * (if (isNorm) canvasH else 1f)
1688
+ if (pIdx == 0) path.moveTo(px, py) else path.lineTo(px, py)
1689
+ }
1690
+ canvas.drawPath(path, strokePaint)
1691
+ }
1692
+ }
1693
+ "highlighter" -> {
1694
+ if (points != null && points.size() > 1) {
1695
+ strokePaint.style = android.graphics.Paint.Style.STROKE
1696
+ strokePaint.color = parsedColor
1697
+ strokePaint.strokeWidth = strokeW * 2.5f
1698
+ strokePaint.strokeCap = android.graphics.Paint.Cap.ROUND
1699
+ strokePaint.strokeJoin = android.graphics.Paint.Join.ROUND
1700
+ strokePaint.alpha = (255 * 0.4f).toInt()
1701
+
1702
+ val path = android.graphics.Path()
1703
+ for (pIdx in 0 until points.size()) {
1704
+ val pt = points.getMap(pIdx) ?: continue
1705
+ val px = (if (pt.hasKey("x")) pt.getDouble("x").toFloat() else 0f) * (if (isNorm) canvasW else 1f)
1706
+ val py = (if (pt.hasKey("y")) pt.getDouble("y").toFloat() else 0f) * (if (isNorm) canvasH else 1f)
1707
+ if (pIdx == 0) path.moveTo(px, py) else path.lineTo(px, py)
1708
+ }
1709
+ canvas.drawPath(path, strokePaint)
1710
+ }
1711
+ }
1712
+ "arrow" -> {
1713
+ if (points != null && points.size() >= 2) {
1714
+ val p0 = points.getMap(0)
1715
+ val p1 = points.getMap(points.size() - 1)
1716
+ if (p0 != null && p1 != null) {
1717
+ val x0 = (if (p0.hasKey("x")) p0.getDouble("x").toFloat() else 0f) * (if (isNorm) canvasW else 1f)
1718
+ val y0 = (if (p0.hasKey("y")) p0.getDouble("y").toFloat() else 0f) * (if (isNorm) canvasH else 1f)
1719
+ val x1 = (if (p1.hasKey("x")) p1.getDouble("x").toFloat() else 0f) * (if (isNorm) canvasW else 1f)
1720
+ val y1 = (if (p1.hasKey("y")) p1.getDouble("y").toFloat() else 0f) * (if (isNorm) canvasH else 1f)
1721
+
1722
+ strokePaint.style = android.graphics.Paint.Style.STROKE
1723
+ strokePaint.color = parsedColor
1724
+ strokePaint.strokeWidth = strokeW
1725
+ strokePaint.strokeCap = android.graphics.Paint.Cap.ROUND
1726
+ strokePaint.alpha = 255
1727
+ canvas.drawLine(x0, y0, x1, y1, strokePaint)
1728
+
1729
+ val dx = x1 - x0
1730
+ val dy = y1 - y0
1731
+ val angle = Math.atan2(dy.toDouble(), dx.toDouble())
1732
+ val headLen = Math.max(14.0 * baseScale, Math.min(32.0 * baseScale, (strokeW * 3.5).toDouble()))
1733
+ val headAngle = Math.PI / 6.0
1734
+ val ax1 = (x1 - headLen * Math.cos(angle - headAngle)).toFloat()
1735
+ val ay1 = (y1 - headLen * Math.sin(angle - headAngle)).toFloat()
1736
+ val ax2 = (x1 - headLen * Math.cos(angle + headAngle)).toFloat()
1737
+ val ay2 = (y1 - headLen * Math.sin(angle + headAngle)).toFloat()
1738
+
1739
+ val arrowPath = android.graphics.Path().apply {
1740
+ moveTo(x1, y1)
1741
+ lineTo(ax1, ay1)
1742
+ lineTo(ax2, ay2)
1743
+ close()
1744
+ }
1745
+ strokePaint.style = android.graphics.Paint.Style.FILL
1746
+ canvas.drawPath(arrowPath, strokePaint)
1747
+ }
1748
+ }
1749
+ }
1750
+ "rect" -> {
1751
+ if (points != null && points.size() >= 2) {
1752
+ val p0 = points.getMap(0) ?: continue
1753
+ val p1 = points.getMap(1) ?: p0
1754
+ val x0 = (if (p0.hasKey("x")) p0.getDouble("x").toFloat() else 0f) * (if (isNorm) canvasW else 1f)
1755
+ val y0 = (if (p0.hasKey("y")) p0.getDouble("y").toFloat() else 0f) * (if (isNorm) canvasH else 1f)
1756
+ val x1 = (if (p1.hasKey("x")) p1.getDouble("x").toFloat() else 0f) * (if (isNorm) canvasW else 1f)
1757
+ val y1 = (if (p1.hasKey("y")) p1.getDouble("y").toFloat() else 0f) * (if (isNorm) canvasH else 1f)
1758
+
1759
+ strokePaint.style = android.graphics.Paint.Style.STROKE
1760
+ strokePaint.color = parsedColor
1761
+ strokePaint.strokeWidth = strokeW
1762
+ strokePaint.alpha = 255
1763
+ canvas.drawRect(Math.min(x0, x1), Math.min(y0, y1), Math.max(x0, x1), Math.max(y0, y1), strokePaint)
1764
+ }
1765
+ }
1766
+ "circle", "spotlight" -> {
1767
+ if (points != null && points.size() >= 2) {
1768
+ val p0 = points.getMap(0) ?: continue
1769
+ val p1 = points.getMap(1) ?: p0
1770
+ val x0 = (if (p0.hasKey("x")) p0.getDouble("x").toFloat() else 0f) * (if (isNorm) canvasW else 1f)
1771
+ val y0 = (if (p0.hasKey("y")) p0.getDouble("y").toFloat() else 0f) * (if (isNorm) canvasH else 1f)
1772
+ val x1 = (if (p1.hasKey("x")) p1.getDouble("x").toFloat() else 0f) * (if (isNorm) canvasW else 1f)
1773
+ val y1 = (if (p1.hasKey("y")) p1.getDouble("y").toFloat() else 0f) * (if (isNorm) canvasH else 1f)
1774
+
1775
+ strokePaint.style = android.graphics.Paint.Style.STROKE
1776
+ strokePaint.color = parsedColor
1777
+ strokePaint.strokeWidth = strokeW
1778
+ strokePaint.alpha = 255
1779
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
1780
+ canvas.drawOval(Math.min(x0, x1), Math.min(y0, y1), Math.max(x0, x1), Math.max(y0, y1), strokePaint)
1781
+ } else {
1782
+ canvas.drawOval(android.graphics.RectF(Math.min(x0, x1), Math.min(y0, y1), Math.max(x0, x1), Math.max(y0, y1)), strokePaint)
1783
+ }
1784
+ }
1785
+ }
1786
+ "step" -> {
1787
+ if (points != null && points.size() > 0) {
1788
+ val p0 = points.getMap(0) ?: continue
1789
+ val cx = (if (p0.hasKey("x")) p0.getDouble("x").toFloat() else 0f) * (if (isNorm) canvasW else 1f)
1790
+ val cy = (if (p0.hasKey("y")) p0.getDouble("y").toFloat() else 0f) * (if (isNorm) canvasH else 1f)
1791
+ val radius = 16f * baseScale
1792
+
1793
+ // Badge circle
1794
+ strokePaint.style = android.graphics.Paint.Style.FILL
1795
+ strokePaint.color = parsedColor
1796
+ strokePaint.alpha = 255
1797
+ canvas.drawCircle(cx, cy, radius, strokePaint)
1798
+
1799
+ // White border
1800
+ strokePaint.style = android.graphics.Paint.Style.STROKE
1801
+ strokePaint.color = android.graphics.Color.WHITE
1802
+ strokePaint.strokeWidth = 2f * baseScale
1803
+ canvas.drawCircle(cx, cy, radius, strokePaint)
1804
+
1805
+ // Step number
1806
+ val stepNum = if (stroke.hasKey("stepNumber")) stroke.getInt("stepNumber") else 1
1807
+ val textPaint = android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG).apply {
1808
+ color = android.graphics.Color.WHITE
1809
+ textSize = 14f * baseScale
1810
+ typeface = android.graphics.Typeface.DEFAULT_BOLD
1811
+ textAlign = android.graphics.Paint.Align.CENTER
1812
+ }
1813
+ val fontMetrics = textPaint.fontMetrics
1814
+ val textY = cy - (fontMetrics.ascent + fontMetrics.descent) / 2f
1815
+ canvas.drawText(stepNum.toString(), cx, textY, textPaint)
1816
+ }
1817
+ }
1818
+ }
1819
+ }
1820
+ }
1821
+ }
1822
+
1823
+ // C. Draggable Text Badges / Notes
1824
+ if (options.hasKey("texts")) {
1825
+ val texts = options.getArray("texts")
1826
+ if (texts != null) {
1827
+ for (i in 0 until texts.size()) {
1828
+ val tItem = texts.getMap(i) ?: continue
1829
+ val textStr = if (tItem.hasKey("text")) tItem.getString("text") ?: "" else ""
1830
+ if (textStr.isEmpty()) continue
1831
+
1832
+ val isNorm = if (tItem.hasKey("isNormalized")) tItem.getBoolean("isNormalized") else true
1833
+ val tx = (if (tItem.hasKey("x")) tItem.getDouble("x").toFloat() else 0f) * (if (isNorm) canvasW else 1f)
1834
+ val ty = (if (tItem.hasKey("y")) tItem.getDouble("y").toFloat() else 0f) * (if (isNorm) canvasH else 1f)
1835
+ val textColor = parseInspectorHexColor(if (tItem.hasKey("color")) tItem.getString("color") else null, android.graphics.Color.WHITE)
1836
+ val bgColor = parseInspectorHexColor(if (tItem.hasKey("bgColor")) tItem.getString("bgColor") else null, parseInspectorHexColor("#EF4444"))
1837
+
1838
+ val textPaint = android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG).apply {
1839
+ color = textColor
1840
+ textSize = 15f * baseScale
1841
+ typeface = android.graphics.Typeface.DEFAULT_BOLD
1842
+ }
1843
+
1844
+ val textWidth = textPaint.measureText(textStr)
1845
+ val fontMetrics = textPaint.fontMetrics
1846
+ val textHeight = fontMetrics.descent - fontMetrics.ascent
1847
+ val padH = 12f * baseScale
1848
+ val padV = 6f * baseScale
1849
+ val pillW = textWidth + padH * 2f
1850
+ val pillH = textHeight + padV * 2f
1851
+
1852
+ val pillRect = android.graphics.RectF(tx, ty, tx + pillW, ty + pillH)
1853
+ val bgPaint = android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG).apply {
1854
+ style = android.graphics.Paint.Style.FILL
1855
+ color = bgColor
1856
+ }
1857
+ canvas.drawRoundRect(pillRect, pillH / 2f, pillH / 2f, bgPaint)
1858
+
1859
+ val borderPaint = android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG).apply {
1860
+ style = android.graphics.Paint.Style.STROKE
1861
+ color = android.graphics.Color.argb(100, 255, 255, 255)
1862
+ strokeWidth = 1.5f * baseScale
1863
+ }
1864
+ canvas.drawRoundRect(pillRect, pillH / 2f, pillH / 2f, borderPaint)
1865
+
1866
+ canvas.drawText(textStr, tx + padH, ty + padV - fontMetrics.ascent, textPaint)
1626
1867
  }
1627
1868
  }
1628
1869
  }
1629
1870
 
1630
- if (options.hasKey("annotations")) {
1871
+ // D. Legacy / Standalone Annotations
1872
+ if (options.hasKey("annotations") && !options.hasKey("drawings")) {
1631
1873
  val annotations = options.getArray("annotations")
1632
1874
  if (annotations != null) {
1633
- overlayPaint.color = android.graphics.Color.RED
1634
- overlayPaint.style = android.graphics.Paint.Style.STROKE
1635
- overlayPaint.strokeWidth = 6f
1875
+ val overlayPaint = android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG)
1636
1876
  for (i in 0 until annotations.size()) {
1637
1877
  val ann = annotations.getMap(i) ?: continue
1638
1878
  var x = if (ann.hasKey("x")) ann.getDouble("x").toFloat() else 0f
1639
1879
  var y = if (ann.hasKey("y")) ann.getDouble("y").toFloat() else 0f
1640
1880
  var w = if (ann.hasKey("width")) ann.getDouble("width").toFloat() else 0f
1641
1881
  var h = if (ann.hasKey("height")) ann.getDouble("height").toFloat() else 0f
1642
- val isNorm = if (ann.hasKey("isNormalized")) ann.getBoolean("isNormalized") else false
1882
+ val isNorm = if (ann.hasKey("isNormalized")) ann.getBoolean("isNormalized") else true
1643
1883
  if (isNorm) {
1644
- x *= mutableBitmap.width
1645
- y *= mutableBitmap.height
1646
- w *= mutableBitmap.width
1647
- h *= mutableBitmap.height
1884
+ x *= canvasW
1885
+ y *= canvasH
1886
+ w *= canvasW
1887
+ h *= canvasH
1648
1888
  }
1889
+ val annColorHex = if (ann.hasKey("color")) ann.getString("color") else "#EF4444"
1890
+ val annColor = parseInspectorHexColor(annColorHex, android.graphics.Color.RED)
1891
+ overlayPaint.color = annColor
1892
+ overlayPaint.style = android.graphics.Paint.Style.STROKE
1893
+ overlayPaint.strokeWidth = 4f * baseScale
1649
1894
  canvas.drawRect(x, y, x + w, y + h, overlayPaint)
1895
+
1896
+ val label = if (ann.hasKey("label")) ann.getString("label") else null
1897
+ if (!label.isNullOrEmpty()) {
1898
+ val labelPaint = android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG).apply {
1899
+ color = android.graphics.Color.WHITE
1900
+ textSize = 13f * baseScale
1901
+ typeface = android.graphics.Typeface.DEFAULT_BOLD
1902
+ }
1903
+ val textWidth = labelPaint.measureText(label)
1904
+ val fontMetrics = labelPaint.fontMetrics
1905
+ val textHeight = fontMetrics.descent - fontMetrics.ascent
1906
+ val padH = 6f * baseScale
1907
+ val padV = 3f * baseScale
1908
+ val tagRect = android.graphics.RectF(x, Math.max(0f, y - textHeight - padV * 2f), x + textWidth + padH * 2f, y)
1909
+ val bgPaint = android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG).apply {
1910
+ style = android.graphics.Paint.Style.FILL
1911
+ color = annColor
1912
+ }
1913
+ canvas.drawRect(tagRect, bgPaint)
1914
+ canvas.drawText(label, tagRect.left + padH, tagRect.bottom - padV - fontMetrics.descent, labelPaint)
1915
+ }
1650
1916
  }
1651
1917
  }
1652
1918
  }
@@ -1933,6 +2199,100 @@ class NetworkInspectorModule(private val reactContext: ReactApplicationContext)
1933
2199
 
1934
2200
 
1935
2201
 
2202
+ @ReactMethod
2203
+ fun writeExportFile(filename: String, content: String, promise: Promise) {
2204
+ captureExecutor.execute {
2205
+ try {
2206
+ val dir = getCapturesDirectory()
2207
+ val cleanFilename = File(filename).name
2208
+ val file = File(dir, cleanFilename)
2209
+ file.writeText(content, Charsets.UTF_8)
2210
+ promise.resolve("file://${file.absolutePath}")
2211
+ } catch (e: Exception) {
2212
+ promise.reject("WRITE_ERROR", e.message ?: "Failed to write export file", e)
2213
+ }
2214
+ }
2215
+ }
2216
+
2217
+ @ReactMethod
2218
+ fun shareFile(filePath: String, mimeType: String?, title: String?, promise: Promise) {
2219
+ val activity = reactContext.currentActivity
2220
+ if (activity == null) {
2221
+ promise.reject("NO_ACTIVITY", "Current activity is null")
2222
+ return
2223
+ }
2224
+
2225
+ try {
2226
+ val cleanPath = when {
2227
+ filePath.startsWith("file://") -> Uri.parse(filePath).path ?: filePath.substring(7)
2228
+ else -> filePath
2229
+ }
2230
+ val file = File(cleanPath)
2231
+ if (!file.exists()) {
2232
+ promise.reject("FILE_NOT_FOUND", "File does not exist: $filePath")
2233
+ return
2234
+ }
2235
+
2236
+ val uri: Uri = try {
2237
+ androidx.core.content.FileProvider.getUriForFile(
2238
+ activity,
2239
+ "${activity.packageName}.inappinspector.provider",
2240
+ file
2241
+ )
2242
+ } catch (e: Exception) {
2243
+ try {
2244
+ androidx.core.content.FileProvider.getUriForFile(
2245
+ activity,
2246
+ "${activity.packageName}.provider",
2247
+ file
2248
+ )
2249
+ } catch (e2: Exception) {
2250
+ Uri.fromFile(file)
2251
+ }
2252
+ }
2253
+
2254
+ val resolvedMime = mimeType ?: when {
2255
+ file.name.endsWith(".json") -> "application/json"
2256
+ file.name.endsWith(".txt") || file.name.endsWith(".log") -> "text/plain"
2257
+ file.name.endsWith(".png") -> "image/png"
2258
+ file.name.endsWith(".jpg") || file.name.endsWith(".jpeg") -> "image/jpeg"
2259
+ file.name.endsWith(".mp4") -> "video/mp4"
2260
+ file.name.endsWith(".gif") -> "image/gif"
2261
+ else -> "*/*"
2262
+ }
2263
+
2264
+ val sendIntent = Intent(Intent.ACTION_SEND).apply {
2265
+ type = resolvedMime
2266
+ putExtra(Intent.EXTRA_STREAM, uri)
2267
+ if (!title.isNullOrEmpty()) {
2268
+ putExtra(Intent.EXTRA_SUBJECT, title)
2269
+ }
2270
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
2271
+ }
2272
+
2273
+ val chooser = Intent.createChooser(sendIntent, title ?: "Share File").apply {
2274
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
2275
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
2276
+ }
2277
+
2278
+ val resInfoList = activity.packageManager.queryIntentActivities(chooser, android.content.pm.PackageManager.MATCH_DEFAULT_ONLY)
2279
+ for (resolveInfo in resInfoList) {
2280
+ val packageName = resolveInfo.activityInfo.packageName
2281
+ activity.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
2282
+ }
2283
+
2284
+ activity.startActivity(chooser)
2285
+ promise.resolve(true)
2286
+ } catch (e: Exception) {
2287
+ promise.reject("SHARE_ERROR", e.message ?: "Failed to share file", e)
2288
+ }
2289
+ }
2290
+
2291
+ @ReactMethod
2292
+ fun addListener(eventName: String) {
2293
+ // Required for React Native NativeEventEmitter
2294
+ }
2295
+
1936
2296
  @ReactMethod
1937
2297
  fun removeListeners(count: Double) {
1938
2298
  // Required for React Native NativeEventEmitter
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <paths xmlns:android="http://schemas.android.com/apk/res/android">
3
+ <cache-path name="inspector_cache" path="." />
4
+ <files-path name="inspector_files" path="." />
5
+ <external-cache-path name="inspector_external_cache" path="." />
6
+ <external-files-path name="inspector_external_files" path="." />
7
+ </paths>