react-native-acoustic-connect 19.0.9 → 19.0.28

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 (378) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/ConnectConfig.example.json +1 -1
  3. package/README.md +390 -1
  4. package/android/build.gradle +86 -3
  5. package/android/config.gradle +137 -13
  6. package/android/src/main/assets/ConnectAdvancedConfig.json +1 -1
  7. package/android/src/main/java/com/acousticconnectrn/HybridAcousticConnectRN.kt +407 -34
  8. package/app.plugin.js +2 -2
  9. package/ios/AcousticConnectRNConfig.json +2 -2
  10. package/ios/ConnectRNParsing.swift +229 -0
  11. package/ios/HybridAcousticConnectRN.swift +290 -30
  12. package/lib/commonjs/TLTRN.js +116 -3
  13. package/lib/commonjs/TLTRN.js.map +1 -1
  14. package/lib/commonjs/components/Connect.js +145 -27
  15. package/lib/commonjs/components/Connect.js.map +1 -1
  16. package/lib/commonjs/index.js +3 -0
  17. package/lib/commonjs/index.js.map +1 -1
  18. package/lib/module/TLTRN.js +116 -3
  19. package/lib/module/TLTRN.js.map +1 -1
  20. package/lib/module/components/Connect.js +146 -28
  21. package/lib/module/components/Connect.js.map +1 -1
  22. package/lib/module/index.js +5 -0
  23. package/lib/module/index.js.map +1 -1
  24. package/lib/typescript/src/TLTRN.d.ts +85 -1
  25. package/lib/typescript/src/TLTRN.d.ts.map +1 -1
  26. package/lib/typescript/src/components/Connect.d.ts.map +1 -1
  27. package/lib/typescript/src/index.d.ts +1 -0
  28. package/lib/typescript/src/index.d.ts.map +1 -1
  29. package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts +178 -10
  30. package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts.map +1 -1
  31. package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.cpp +5 -9
  32. package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.hpp +1 -1
  33. package/nitrogen/generated/android/kotlin/com/margelo/nitro/acousticconnectrn/HybridAcousticConnectRNSpec.kt +2 -1
  34. package/nitrogen/generated/ios/AcousticConnectRN-Swift-Cxx-Umbrella.hpp +1 -0
  35. package/nitrogen/generated/ios/c++/HybridAcousticConnectRNSpecSwift.hpp +2 -1
  36. package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec.swift +1 -1
  37. package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec_cxx.swift +2 -25
  38. package/nitrogen/generated/shared/c++/HybridAcousticConnectRNSpec.hpp +2 -1
  39. package/package.json +4 -7
  40. package/plugin/build/withConnectAndroidConfig.d.ts +2 -2
  41. package/plugin/build/withConnectAndroidConfig.js +2 -2
  42. package/plugin/build/withConnectIosSigning.d.ts +1 -1
  43. package/plugin/build/withConnectIosSigning.js +1 -1
  44. package/plugin/src/withConnectAndroidConfig.ts +2 -2
  45. package/plugin/src/withConnectIosSigning.ts +1 -1
  46. package/scripts/gradleParser.js +1 -1
  47. package/src/TLTRN.ts +125 -4
  48. package/src/components/Connect.tsx +150 -27
  49. package/src/index.ts +5 -0
  50. package/src/specs/react-native-acoustic-connect.nitro.ts +180 -10
  51. package/Examples/SampleUI/.bundle/config +0 -2
  52. package/Examples/SampleUI/.detoxrc.js +0 -83
  53. package/Examples/SampleUI/.eslintrc.js +0 -4
  54. package/Examples/SampleUI/.prettierrc.js +0 -7
  55. package/Examples/SampleUI/.watchmanconfig +0 -1
  56. package/Examples/SampleUI/App.js +0 -1
  57. package/Examples/SampleUI/Gemfile +0 -10
  58. package/Examples/SampleUI/Gemfile.lock +0 -121
  59. package/Examples/SampleUI/README.md +0 -79
  60. package/Examples/SampleUI/__tests__/App.test.tsx +0 -17
  61. package/Examples/SampleUI/android/app/build.gradle +0 -129
  62. package/Examples/SampleUI/android/app/debug.keystore +0 -0
  63. package/Examples/SampleUI/android/app/proguard-rules.pro +0 -10
  64. package/Examples/SampleUI/android/app/src/debug/AndroidManifest.xml +0 -9
  65. package/Examples/SampleUI/android/app/src/main/AndroidManifest.xml +0 -31
  66. package/Examples/SampleUI/android/app/src/main/java/com/sampleui/MainActivity.kt +0 -30
  67. package/Examples/SampleUI/android/app/src/main/java/com/sampleui/MainApplication.kt +0 -53
  68. package/Examples/SampleUI/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -37
  69. package/Examples/SampleUI/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  70. package/Examples/SampleUI/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  71. package/Examples/SampleUI/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  72. package/Examples/SampleUI/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  73. package/Examples/SampleUI/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  74. package/Examples/SampleUI/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  75. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  76. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  77. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  78. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  79. package/Examples/SampleUI/android/app/src/main/res/values/strings.xml +0 -3
  80. package/Examples/SampleUI/android/app/src/main/res/values/styles.xml +0 -9
  81. package/Examples/SampleUI/android/build.gradle +0 -21
  82. package/Examples/SampleUI/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  83. package/Examples/SampleUI/android/gradle/wrapper/gradle-wrapper.properties +0 -7
  84. package/Examples/SampleUI/android/gradle.properties +0 -39
  85. package/Examples/SampleUI/android/gradlew +0 -252
  86. package/Examples/SampleUI/android/gradlew.bat +0 -94
  87. package/Examples/SampleUI/android/settings.gradle +0 -21
  88. package/Examples/SampleUI/app.json +0 -51
  89. package/Examples/SampleUI/assets/fonts/Abel-Regular.ttf +0 -0
  90. package/Examples/SampleUI/assets/fonts/NotoSans-Regular.ttf +0 -0
  91. package/Examples/SampleUI/assets/images/android-icon.png +0 -0
  92. package/Examples/SampleUI/assets/images/artist-1.jpg +0 -0
  93. package/Examples/SampleUI/assets/images/artist-2.jpg +0 -0
  94. package/Examples/SampleUI/assets/images/avatar.png +0 -0
  95. package/Examples/SampleUI/assets/images/beach.jpg +0 -0
  96. package/Examples/SampleUI/assets/images/bridge.jpg +0 -0
  97. package/Examples/SampleUI/assets/images/chameleon.jpg +0 -0
  98. package/Examples/SampleUI/assets/images/city.jpg +0 -0
  99. package/Examples/SampleUI/assets/images/email-icon.png +0 -0
  100. package/Examples/SampleUI/assets/images/favorite.png +0 -0
  101. package/Examples/SampleUI/assets/images/forest.jpg +0 -0
  102. package/Examples/SampleUI/assets/images/paper-icon.png +0 -0
  103. package/Examples/SampleUI/assets/images/players-2.jpg +0 -0
  104. package/Examples/SampleUI/assets/images/players.jpg +0 -0
  105. package/Examples/SampleUI/assets/images/restaurant-1.jpg +0 -0
  106. package/Examples/SampleUI/assets/images/restaurant-2.jpg +0 -0
  107. package/Examples/SampleUI/assets/images/song-1.jpg +0 -0
  108. package/Examples/SampleUI/assets/images/song-2.jpg +0 -0
  109. package/Examples/SampleUI/assets/images/splash.png +0 -0
  110. package/Examples/SampleUI/assets/images/strawberries.jpg +0 -0
  111. package/Examples/SampleUI/assets/images/wrecked-ship.jpg +0 -0
  112. package/Examples/SampleUI/assets/styles/fonts.css +0 -47
  113. package/Examples/SampleUI/babel.config.js +0 -22
  114. package/Examples/SampleUI/index.js +0 -9
  115. package/Examples/SampleUI/ios/.xcode.env +0 -11
  116. package/Examples/SampleUI/ios/Podfile +0 -71
  117. package/Examples/SampleUI/ios/Podfile.lock +0 -2276
  118. package/Examples/SampleUI/ios/SampleUI/AppDelegate.h +0 -7
  119. package/Examples/SampleUI/ios/SampleUI/AppDelegate.mm +0 -31
  120. package/Examples/SampleUI/ios/SampleUI/Images.xcassets/AppIcon.appiconset/Contents.json +0 -53
  121. package/Examples/SampleUI/ios/SampleUI/Images.xcassets/Contents.json +0 -6
  122. package/Examples/SampleUI/ios/SampleUI/Info.plist +0 -52
  123. package/Examples/SampleUI/ios/SampleUI/LaunchScreen.storyboard +0 -47
  124. package/Examples/SampleUI/ios/SampleUI/PrivacyInfo.xcprivacy +0 -48
  125. package/Examples/SampleUI/ios/SampleUI/main.m +0 -10
  126. package/Examples/SampleUI/ios/SampleUI.xcodeproj/project.pbxproj +0 -785
  127. package/Examples/SampleUI/ios/SampleUI.xcodeproj/xcshareddata/xcschemes/SampleUI.xcscheme +0 -105
  128. package/Examples/SampleUI/ios/SampleUI.xcworkspace/contents.xcworkspacedata +0 -10
  129. package/Examples/SampleUI/ios/SampleUITests/Info.plist +0 -24
  130. package/Examples/SampleUI/ios/SampleUITests/SampleUITests.m +0 -66
  131. package/Examples/SampleUI/jest.config.js +0 -3
  132. package/Examples/SampleUI/metro.config.js +0 -54
  133. package/Examples/SampleUI/package.json +0 -65
  134. package/Examples/SampleUI/scripts/integration-test-android.sh +0 -292
  135. package/Examples/SampleUI/src/DrawerItems.tsx +0 -322
  136. package/Examples/SampleUI/src/ExampleList.tsx +0 -175
  137. package/Examples/SampleUI/src/Examples/ActivityIndicatorExample.tsx +0 -73
  138. package/Examples/SampleUI/src/Examples/AnimatedFABExample/AnimatedFABExample.tsx +0 -220
  139. package/Examples/SampleUI/src/Examples/AnimatedFABExample/CustomFAB.tsx +0 -70
  140. package/Examples/SampleUI/src/Examples/AnimatedFABExample/CustomFABControls.tsx +0 -146
  141. package/Examples/SampleUI/src/Examples/AnimatedFABExample/index.ts +0 -1
  142. package/Examples/SampleUI/src/Examples/AppbarExample.tsx +0 -263
  143. package/Examples/SampleUI/src/Examples/AvatarExample.tsx +0 -76
  144. package/Examples/SampleUI/src/Examples/BadgeExample.tsx +0 -97
  145. package/Examples/SampleUI/src/Examples/BannerExample.tsx +0 -152
  146. package/Examples/SampleUI/src/Examples/BottomNavigationBarExample.tsx +0 -94
  147. package/Examples/SampleUI/src/Examples/BottomNavigationExample.tsx +0 -205
  148. package/Examples/SampleUI/src/Examples/ButtonExample.tsx +0 -405
  149. package/Examples/SampleUI/src/Examples/CardExample.tsx +0 -245
  150. package/Examples/SampleUI/src/Examples/CheckboxExample.tsx +0 -87
  151. package/Examples/SampleUI/src/Examples/CheckboxItemExample.tsx +0 -72
  152. package/Examples/SampleUI/src/Examples/ChipExample.tsx +0 -432
  153. package/Examples/SampleUI/src/Examples/DataTableExample.tsx +0 -128
  154. package/Examples/SampleUI/src/Examples/DialogExample.tsx +0 -217
  155. package/Examples/SampleUI/src/Examples/Dialogs/DialogTextComponent.tsx +0 -31
  156. package/Examples/SampleUI/src/Examples/Dialogs/DialogTrackingTest.tsx +0 -307
  157. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithCustomColors.tsx +0 -57
  158. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithDismissableBackButton.tsx +0 -38
  159. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithIcon.tsx +0 -42
  160. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithLoadingIndicator.tsx +0 -48
  161. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithLongText.tsx +0 -81
  162. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithRadioBtns.tsx +0 -111
  163. package/Examples/SampleUI/src/Examples/Dialogs/UndismissableDialog.tsx +0 -30
  164. package/Examples/SampleUI/src/Examples/Dialogs/index.tsx +0 -44
  165. package/Examples/SampleUI/src/Examples/DividerExample.tsx +0 -30
  166. package/Examples/SampleUI/src/Examples/FABExample.tsx +0 -226
  167. package/Examples/SampleUI/src/Examples/IconButtonExample.tsx +0 -230
  168. package/Examples/SampleUI/src/Examples/IconExample.tsx +0 -50
  169. package/Examples/SampleUI/src/Examples/ListAccordionExample.tsx +0 -65
  170. package/Examples/SampleUI/src/Examples/ListAccordionGroupExample.tsx +0 -80
  171. package/Examples/SampleUI/src/Examples/ListItemExample.tsx +0 -310
  172. package/Examples/SampleUI/src/Examples/ListSectionExample.tsx +0 -159
  173. package/Examples/SampleUI/src/Examples/MaterialBottomTabNavigatorExample.tsx +0 -87
  174. package/Examples/SampleUI/src/Examples/MenuExample.tsx +0 -211
  175. package/Examples/SampleUI/src/Examples/ProgressBarExample.tsx +0 -142
  176. package/Examples/SampleUI/src/Examples/RadioButtonExample.tsx +0 -104
  177. package/Examples/SampleUI/src/Examples/RadioButtonGroupExample.tsx +0 -67
  178. package/Examples/SampleUI/src/Examples/RadioButtonItemExample.tsx +0 -77
  179. package/Examples/SampleUI/src/Examples/SearchbarExample.tsx +0 -249
  180. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonCustomColorCheck.tsx +0 -93
  181. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonDefault.tsx +0 -49
  182. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonDisabled.tsx +0 -47
  183. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonMultiselect.tsx +0 -50
  184. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonMultiselectIcons.tsx +0 -49
  185. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonMultiselectRealCase.tsx +0 -114
  186. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonOnlyIcons.tsx +0 -40
  187. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonOnlyIconsWithCheck.tsx +0 -43
  188. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonRealCase.tsx +0 -97
  189. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonWithDensity.tsx +0 -47
  190. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonWithSelectedCheck.tsx +0 -52
  191. package/Examples/SampleUI/src/Examples/SegmentedButtons/index.ts +0 -9
  192. package/Examples/SampleUI/src/Examples/SegmentedButtonsExample.tsx +0 -57
  193. package/Examples/SampleUI/src/Examples/SnackbarExample.tsx +0 -141
  194. package/Examples/SampleUI/src/Examples/SurfaceExample.tsx +0 -130
  195. package/Examples/SampleUI/src/Examples/SwitchExample.tsx +0 -105
  196. package/Examples/SampleUI/src/Examples/TeamDetails.tsx +0 -291
  197. package/Examples/SampleUI/src/Examples/TeamsList.tsx +0 -57
  198. package/Examples/SampleUI/src/Examples/TextExample.tsx +0 -132
  199. package/Examples/SampleUI/src/Examples/TextInputExample.tsx +0 -914
  200. package/Examples/SampleUI/src/Examples/ThemeExample.tsx +0 -41
  201. package/Examples/SampleUI/src/Examples/ThemingWithReactNavigation.tsx +0 -75
  202. package/Examples/SampleUI/src/Examples/ToggleButtonExample.tsx +0 -128
  203. package/Examples/SampleUI/src/Examples/TooltipExample.tsx +0 -191
  204. package/Examples/SampleUI/src/Examples/TouchableRippleExample.tsx +0 -37
  205. package/Examples/SampleUI/src/RootNavigator.tsx +0 -95
  206. package/Examples/SampleUI/src/ScreenWrapper.tsx +0 -67
  207. package/Examples/SampleUI/src/components/ActivityIndicator.tsx +0 -254
  208. package/Examples/SampleUI/src/components/Appbar/Appbar.tsx +0 -364
  209. package/Examples/SampleUI/src/components/Appbar/AppbarAction.tsx +0 -132
  210. package/Examples/SampleUI/src/components/Appbar/AppbarBackAction.tsx +0 -77
  211. package/Examples/SampleUI/src/components/Appbar/AppbarBackIcon.tsx +0 -52
  212. package/Examples/SampleUI/src/components/Appbar/AppbarContent.tsx +0 -249
  213. package/Examples/SampleUI/src/components/Appbar/AppbarHeader.tsx +0 -174
  214. package/Examples/SampleUI/src/components/Appbar/index.ts +0 -22
  215. package/Examples/SampleUI/src/components/Appbar/utils.ts +0 -188
  216. package/Examples/SampleUI/src/components/Avatar/Avatar.tsx +0 -8
  217. package/Examples/SampleUI/src/components/Avatar/AvatarIcon.tsx +0 -87
  218. package/Examples/SampleUI/src/components/Avatar/AvatarImage.tsx +0 -128
  219. package/Examples/SampleUI/src/components/Avatar/AvatarText.tsx +0 -127
  220. package/Examples/SampleUI/src/components/Badge.tsx +0 -138
  221. package/Examples/SampleUI/src/components/Banner.tsx +0 -302
  222. package/Examples/SampleUI/src/components/BottomNavigation/BottomNavigation.tsx +0 -643
  223. package/Examples/SampleUI/src/components/BottomNavigation/BottomNavigationBar.tsx +0 -1039
  224. package/Examples/SampleUI/src/components/BottomNavigation/BottomNavigationRouteScreen.tsx +0 -31
  225. package/Examples/SampleUI/src/components/BottomNavigation/utils.ts +0 -70
  226. package/Examples/SampleUI/src/components/Button/Button.tsx +0 -503
  227. package/Examples/SampleUI/src/components/Button/utils.tsx +0 -272
  228. package/Examples/SampleUI/src/components/Card/Card.tsx +0 -373
  229. package/Examples/SampleUI/src/components/Card/CardActions.tsx +0 -74
  230. package/Examples/SampleUI/src/components/Card/CardContent.tsx +0 -99
  231. package/Examples/SampleUI/src/components/Card/CardCover.tsx +0 -96
  232. package/Examples/SampleUI/src/components/Card/CardTitle.tsx +0 -236
  233. package/Examples/SampleUI/src/components/Card/utils.tsx +0 -110
  234. package/Examples/SampleUI/src/components/Checkbox/Checkbox.tsx +0 -78
  235. package/Examples/SampleUI/src/components/Checkbox/CheckboxAndroid.tsx +0 -180
  236. package/Examples/SampleUI/src/components/Checkbox/CheckboxIOS.tsx +0 -104
  237. package/Examples/SampleUI/src/components/Checkbox/CheckboxItem.tsx +0 -236
  238. package/Examples/SampleUI/src/components/Checkbox/index.ts +0 -19
  239. package/Examples/SampleUI/src/components/Checkbox/utils.ts +0 -183
  240. package/Examples/SampleUI/src/components/Chip/Chip.tsx +0 -513
  241. package/Examples/SampleUI/src/components/Chip/helpers.tsx +0 -322
  242. package/Examples/SampleUI/src/components/CrossFadeIcon.tsx +0 -140
  243. package/Examples/SampleUI/src/components/DataTable/DataTable.tsx +0 -138
  244. package/Examples/SampleUI/src/components/DataTable/DataTableCell.tsx +0 -132
  245. package/Examples/SampleUI/src/components/DataTable/DataTableHeader.tsx +0 -82
  246. package/Examples/SampleUI/src/components/DataTable/DataTablePagination.tsx +0 -407
  247. package/Examples/SampleUI/src/components/DataTable/DataTableRow.tsx +0 -107
  248. package/Examples/SampleUI/src/components/DataTable/DataTableTitle.tsx +0 -208
  249. package/Examples/SampleUI/src/components/Dialog/Dialog.tsx +0 -191
  250. package/Examples/SampleUI/src/components/Dialog/DialogActions.tsx +0 -94
  251. package/Examples/SampleUI/src/components/Dialog/DialogContent.tsx +0 -54
  252. package/Examples/SampleUI/src/components/Dialog/DialogIcon.tsx +0 -100
  253. package/Examples/SampleUI/src/components/Dialog/DialogScrollArea.tsx +0 -88
  254. package/Examples/SampleUI/src/components/Dialog/DialogTitle.tsx +0 -94
  255. package/Examples/SampleUI/src/components/Divider.tsx +0 -102
  256. package/Examples/SampleUI/src/components/Drawer/Drawer.tsx +0 -8
  257. package/Examples/SampleUI/src/components/Drawer/DrawerCollapsedItem.tsx +0 -282
  258. package/Examples/SampleUI/src/components/Drawer/DrawerItem.tsx +0 -209
  259. package/Examples/SampleUI/src/components/Drawer/DrawerSection.tsx +0 -138
  260. package/Examples/SampleUI/src/components/FAB/AnimatedFAB.tsx +0 -619
  261. package/Examples/SampleUI/src/components/FAB/FAB.tsx +0 -371
  262. package/Examples/SampleUI/src/components/FAB/FABGroup.tsx +0 -532
  263. package/Examples/SampleUI/src/components/FAB/index.ts +0 -13
  264. package/Examples/SampleUI/src/components/FAB/utils.ts +0 -474
  265. package/Examples/SampleUI/src/components/HelperText/HelperText.tsx +0 -168
  266. package/Examples/SampleUI/src/components/HelperText/utils.ts +0 -30
  267. package/Examples/SampleUI/src/components/Icon.tsx +0 -170
  268. package/Examples/SampleUI/src/components/IconButton/IconButton.tsx +0 -234
  269. package/Examples/SampleUI/src/components/IconButton/utils.ts +0 -190
  270. package/Examples/SampleUI/src/components/List/List.tsx +0 -20
  271. package/Examples/SampleUI/src/components/List/ListAccordion.tsx +0 -391
  272. package/Examples/SampleUI/src/components/List/ListAccordionGroup.tsx +0 -88
  273. package/Examples/SampleUI/src/components/List/ListIcon.tsx +0 -79
  274. package/Examples/SampleUI/src/components/List/ListImage.tsx +0 -89
  275. package/Examples/SampleUI/src/components/List/ListItem.tsx +0 -313
  276. package/Examples/SampleUI/src/components/List/ListSection.tsx +0 -87
  277. package/Examples/SampleUI/src/components/List/ListSubheader.tsx +0 -79
  278. package/Examples/SampleUI/src/components/List/utils.ts +0 -113
  279. package/Examples/SampleUI/src/components/MaterialCommunityIcon.tsx +0 -121
  280. package/Examples/SampleUI/src/components/Menu/Menu.tsx +0 -711
  281. package/Examples/SampleUI/src/components/Menu/MenuItem.tsx +0 -257
  282. package/Examples/SampleUI/src/components/Menu/utils.ts +0 -110
  283. package/Examples/SampleUI/src/components/Modal.tsx +0 -245
  284. package/Examples/SampleUI/src/components/Portal/Portal.tsx +0 -69
  285. package/Examples/SampleUI/src/components/Portal/PortalConsumer.tsx +0 -44
  286. package/Examples/SampleUI/src/components/Portal/PortalHost.tsx +0 -143
  287. package/Examples/SampleUI/src/components/Portal/PortalManager.tsx +0 -54
  288. package/Examples/SampleUI/src/components/ProgressBar.tsx +0 -292
  289. package/Examples/SampleUI/src/components/RadioButton/RadioButton.tsx +0 -86
  290. package/Examples/SampleUI/src/components/RadioButton/RadioButtonAndroid.tsx +0 -202
  291. package/Examples/SampleUI/src/components/RadioButton/RadioButtonGroup.tsx +0 -67
  292. package/Examples/SampleUI/src/components/RadioButton/RadioButtonIOS.tsx +0 -130
  293. package/Examples/SampleUI/src/components/RadioButton/RadioButtonItem.tsx +0 -268
  294. package/Examples/SampleUI/src/components/RadioButton/index.ts +0 -22
  295. package/Examples/SampleUI/src/components/RadioButton/utils.ts +0 -37
  296. package/Examples/SampleUI/src/components/Searchbar.tsx +0 -459
  297. package/Examples/SampleUI/src/components/SegmentedButtons/SegmentedButtonItem.tsx +0 -271
  298. package/Examples/SampleUI/src/components/SegmentedButtons/SegmentedButtons.tsx +0 -197
  299. package/Examples/SampleUI/src/components/SegmentedButtons/utils.ts +0 -179
  300. package/Examples/SampleUI/src/components/Snackbar.tsx +0 -430
  301. package/Examples/SampleUI/src/components/Surface.tsx +0 -376
  302. package/Examples/SampleUI/src/components/Switch/Switch.tsx +0 -108
  303. package/Examples/SampleUI/src/components/Switch/utils.ts +0 -113
  304. package/Examples/SampleUI/src/components/TextInput/Addons/Outline.tsx +0 -64
  305. package/Examples/SampleUI/src/components/TextInput/Addons/Underline.tsx +0 -78
  306. package/Examples/SampleUI/src/components/TextInput/Adornment/TextInputAdornment.tsx +0 -208
  307. package/Examples/SampleUI/src/components/TextInput/Adornment/TextInputAffix.tsx +0 -212
  308. package/Examples/SampleUI/src/components/TextInput/Adornment/TextInputIcon.tsx +0 -195
  309. package/Examples/SampleUI/src/components/TextInput/Adornment/enums.tsx +0 -12
  310. package/Examples/SampleUI/src/components/TextInput/Adornment/types.tsx +0 -11
  311. package/Examples/SampleUI/src/components/TextInput/Adornment/utils.ts +0 -48
  312. package/Examples/SampleUI/src/components/TextInput/Label/InputLabel.tsx +0 -217
  313. package/Examples/SampleUI/src/components/TextInput/Label/LabelBackground.tsx +0 -100
  314. package/Examples/SampleUI/src/components/TextInput/TextInput.tsx +0 -572
  315. package/Examples/SampleUI/src/components/TextInput/TextInputFlat.tsx +0 -475
  316. package/Examples/SampleUI/src/components/TextInput/TextInputOutlined.tsx +0 -450
  317. package/Examples/SampleUI/src/components/TextInput/constants.tsx +0 -48
  318. package/Examples/SampleUI/src/components/TextInput/helpers.tsx +0 -612
  319. package/Examples/SampleUI/src/components/TextInput/types.tsx +0 -155
  320. package/Examples/SampleUI/src/components/ToggleButton/ToggleButton.tsx +0 -187
  321. package/Examples/SampleUI/src/components/ToggleButton/ToggleButtonGroup.tsx +0 -72
  322. package/Examples/SampleUI/src/components/ToggleButton/ToggleButtonRow.tsx +0 -107
  323. package/Examples/SampleUI/src/components/ToggleButton/index.ts +0 -16
  324. package/Examples/SampleUI/src/components/ToggleButton/utils.ts +0 -26
  325. package/Examples/SampleUI/src/components/Tooltip/Tooltip.tsx +0 -249
  326. package/Examples/SampleUI/src/components/Tooltip/utils.ts +0 -129
  327. package/Examples/SampleUI/src/components/TouchableRipple/Pressable.tsx +0 -41
  328. package/Examples/SampleUI/src/components/TouchableRipple/TouchableRipple.native.tsx +0 -145
  329. package/Examples/SampleUI/src/components/TouchableRipple/TouchableRipple.tsx +0 -317
  330. package/Examples/SampleUI/src/components/TouchableRipple/utils.ts +0 -66
  331. package/Examples/SampleUI/src/components/Typography/AnimatedText.tsx +0 -107
  332. package/Examples/SampleUI/src/components/Typography/Text.tsx +0 -184
  333. package/Examples/SampleUI/src/components/Typography/types.tsx +0 -5
  334. package/Examples/SampleUI/src/components/Typography/v2/Caption.tsx +0 -50
  335. package/Examples/SampleUI/src/components/Typography/v2/Headline.tsx +0 -52
  336. package/Examples/SampleUI/src/components/Typography/v2/Paragraph.tsx +0 -49
  337. package/Examples/SampleUI/src/components/Typography/v2/StyledText.tsx +0 -56
  338. package/Examples/SampleUI/src/components/Typography/v2/Subheading.tsx +0 -50
  339. package/Examples/SampleUI/src/components/Typography/v2/Text.tsx +0 -62
  340. package/Examples/SampleUI/src/components/Typography/v2/Title.tsx +0 -49
  341. package/Examples/SampleUI/src/components/Typography/v2/index.ts +0 -5
  342. package/Examples/SampleUI/src/core/PaperProvider.tsx +0 -122
  343. package/Examples/SampleUI/src/core/SafeAreaProviderCompat.tsx +0 -65
  344. package/Examples/SampleUI/src/core/settings.tsx +0 -23
  345. package/Examples/SampleUI/src/core/theming.tsx +0 -170
  346. package/Examples/SampleUI/src/index.native.tsx +0 -285
  347. package/Examples/SampleUI/src/index.tsx +0 -226
  348. package/Examples/SampleUI/src/react-navigation/index.tsx +0 -19
  349. package/Examples/SampleUI/src/react-navigation/navigators/createMaterialBottomTabNavigator.tsx +0 -72
  350. package/Examples/SampleUI/src/react-navigation/types.tsx +0 -126
  351. package/Examples/SampleUI/src/react-navigation/views/MaterialBottomTabView.tsx +0 -140
  352. package/Examples/SampleUI/src/styles/__tests__/fonts.test.js +0 -290
  353. package/Examples/SampleUI/src/styles/fonts.tsx +0 -143
  354. package/Examples/SampleUI/src/styles/overlay.tsx +0 -70
  355. package/Examples/SampleUI/src/styles/shadow.tsx +0 -109
  356. package/Examples/SampleUI/src/styles/themes/index.ts +0 -4
  357. package/Examples/SampleUI/src/styles/themes/v2/DarkTheme.tsx +0 -30
  358. package/Examples/SampleUI/src/styles/themes/v2/LightTheme.tsx +0 -30
  359. package/Examples/SampleUI/src/styles/themes/v2/colors.tsx +0 -277
  360. package/Examples/SampleUI/src/styles/themes/v3/DarkTheme.tsx +0 -66
  361. package/Examples/SampleUI/src/styles/themes/v3/LightTheme.tsx +0 -69
  362. package/Examples/SampleUI/src/styles/themes/v3/tokens.tsx +0 -230
  363. package/Examples/SampleUI/src/utils/BackHandler/BackHandler.native.tsx +0 -3
  364. package/Examples/SampleUI/src/utils/BackHandler/BackHandler.tsx +0 -11
  365. package/Examples/SampleUI/src/utils/addEventListener.tsx +0 -56
  366. package/Examples/SampleUI/src/utils/forwardRef.tsx +0 -23
  367. package/Examples/SampleUI/src/utils/getContrastingColor.tsx +0 -15
  368. package/Examples/SampleUI/src/utils/hasTouchHandler.tsx +0 -23
  369. package/Examples/SampleUI/src/utils/roundLayoutSize.ts +0 -2
  370. package/Examples/SampleUI/src/utils/splitStyles.ts +0 -60
  371. package/Examples/SampleUI/src/utils/useAnimatedValue.tsx +0 -9
  372. package/Examples/SampleUI/src/utils/useAnimatedValueArray.tsx +0 -13
  373. package/Examples/SampleUI/src/utils/useIsKeyboardShown.tsx +0 -55
  374. package/Examples/SampleUI/src/utils/useLayout.tsx +0 -29
  375. package/Examples/SampleUI/src/utils/useLazyRef.tsx +0 -11
  376. package/Examples/SampleUI/tsconfig.json +0 -3
  377. package/Examples/SampleUI/utils/index.ts +0 -1426
  378. package/cli/__tests__/doctor.test.mjs +0 -88
@@ -62,6 +62,7 @@ import com.margelo.nitro.acousticconnectrn.PushPermissionResult
62
62
  import com.margelo.nitro.acousticconnectrn.Variant_Boolean_String_Double
63
63
  import com.margelo.nitro.acousticconnectrn.Variant_NullType_Boolean
64
64
  import com.margelo.nitro.acousticconnectrn.Variant_NullType_String
65
+ import com.margelo.nitro.core.AnyMap
65
66
  import com.margelo.nitro.core.ArrayBuffer
66
67
  import com.margelo.nitro.core.NullType
67
68
  import com.margelo.nitro.core.Promise
@@ -70,6 +71,9 @@ import com.tl.uic.model.ScreenviewType
70
71
  import com.tl.uic.util.DialogUtil
71
72
  import com.tl.uic.util.LayoutUtil
72
73
  import com.tl.uic.util.keyboardview.KeyboardView
74
+ import org.json.JSONArray
75
+ import org.json.JSONException
76
+ import org.json.JSONObject
73
77
  import java.util.Objects
74
78
 
75
79
 
@@ -575,7 +579,12 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
575
579
  value: Double,
576
580
  moduleName: String
577
581
  ): Boolean {
578
- val result = EOCore.updateConfig(key, value.toString(), EOCore.getLifecycleObject(moduleName))
582
+ // Rendered through formatJsNumber, not Double.toString: EOCore stores
583
+ // config items as strings, and a JS 0 spelled "0.0" is not the same
584
+ // token as the "0" the JSON config files carry, so a consumer setting
585
+ // a whole-number item at runtime wrote a value that no longer matched
586
+ // what the same key looks like on iOS (a native number) or on disk.
587
+ val result = EOCore.updateConfig(key, formatJsNumber(value), EOCore.getLifecycleObject(moduleName))
579
588
  return result
580
589
  }
581
590
 
@@ -592,7 +601,8 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
592
601
  value: Variant_Boolean_String_Double,
593
602
  moduleName: String
594
603
  ): Boolean {
595
- val result = EOCore.updateConfig(key, value.toString(), EOCore.getLifecycleObject(moduleName))
604
+ val result =
605
+ EOCore.updateConfig(key, variantToString(value), EOCore.getLifecycleObject(moduleName))
596
606
  return result
597
607
  }
598
608
 
@@ -662,21 +672,59 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
662
672
  level: Double
663
673
  ): Boolean {
664
674
  val result = Connect.logCustomEvent(eventName, convertToMap(values), level.toInt())
665
- return result
675
+ return warnIfRejected(result, "logCustomEvent", eventName)
666
676
  }
667
677
 
668
678
  /**
669
679
  * Logs a signal with the specified values.
670
680
  *
671
- * @param values A map of values associated with the signal.
681
+ * Takes an [AnyMap] rather than a map of Nitro variants so JS callers can
682
+ * send arbitrary JSON — nested objects and arrays included. See
683
+ * [toSignalPayload] for why the nesting has to be rebuilt as
684
+ * [JSONObject]/[JSONArray] rather than handed over as plain Kotlin
685
+ * collections.
686
+ *
687
+ * @param values The signal payload; objects, arrays and scalars are all carried through.
672
688
  * @param level Set a custom log level to the event. This will override the configured log level for that event.
673
689
  * @return True if the operation was successful, false otherwise.
674
690
  */
675
691
  override fun logSignal(
676
- values: Map<String, Variant_Boolean_String_Double>,
692
+ values: AnyMap,
677
693
  level: Double
678
694
  ): Boolean {
679
- val result = Connect.logSignal(convertToMapAny(values), level.toInt())
695
+ val result = Connect.logSignal(toSignalPayload(values.toHashMap()), level.toInt())
696
+ return warnIfRejected(result, "logSignal")
697
+ }
698
+
699
+ /**
700
+ * Surfaces a `false` returned by a native logging call, and passes it
701
+ * through unchanged.
702
+ *
703
+ * The bridge's boolean means "the SDK accepted this for delivery", never
704
+ * "the collector received it" — nothing on the device knows the latter. But
705
+ * the *accepted* half was itself invisible: a `false` propagated to JS as a
706
+ * bare return value that the wrapper's callers almost never inspect, with
707
+ * nothing in logcat. Callers reporting "the event never arrived" had no way
708
+ * to tell a rejected call from a delivery problem. One line at warn level
709
+ * distinguishes them.
710
+ *
711
+ * Deliberately does not change the return value or throw: an analytics
712
+ * bridge must not turn a rejected event into an app-visible failure.
713
+ *
714
+ * @param result The value the native call returned.
715
+ * @param api Name of the bridge method, for the log line.
716
+ * @param detail Optional extra identifier, e.g. an event name.
717
+ * @return [result], unchanged.
718
+ */
719
+ private fun warnIfRejected(result: Boolean, api: String, detail: String? = null): Boolean {
720
+ if (!result) {
721
+ val suffix = if (detail != null) " ($detail)" else ""
722
+ Log.w(
723
+ TAG,
724
+ "[bridge] $api$suffix: the Connect SDK did not accept the event; nothing was queued " +
725
+ "for delivery. Check that the SDK is enabled and the payload is valid."
726
+ )
727
+ }
680
728
  return result
681
729
  }
682
730
 
@@ -697,8 +745,11 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
697
745
  * @param identifierValue Identifier value, e.g. "user@example.com".
698
746
  * @param signalType Optional signal type; defaults to "loggedIn" when omitted.
699
747
  * @param additionalParameters Optional extra key/value pairs merged into the
700
- * signal. Defaults to `{ "registrationMethod": "email" }` only when null
701
- * (omitted); an explicit map — including an empty one — is used as-is.
748
+ * signal. Defaults, only when null (omitted), to the method attribute the
749
+ * resolved signal type requires — `{ "loginMethod": "email" }` for
750
+ * `loggedIn`, `{ "registrationMethod": "email" }` otherwise (see
751
+ * [defaultIdentityParameters]). An explicit map — including an empty one
752
+ * — is used as-is.
702
753
  * @return A promise resolving to true if the signal was queued, false otherwise.
703
754
  */
704
755
  override fun logIdentity(
@@ -707,8 +758,8 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
707
758
  signalType: String?,
708
759
  additionalParameters: Map<String, String>?
709
760
  ): Promise<Boolean> {
710
- val params = additionalParameters ?: mapOf("registrationMethod" to "email")
711
761
  val resolvedSignalType = signalType ?: "loggedIn"
762
+ val params = additionalParameters ?: defaultIdentityParameters(resolvedSignalType)
712
763
  val result = params["url"]?.let { url ->
713
764
  Connect.logIdentificationEvent(
714
765
  identifierName,
@@ -723,7 +774,11 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
723
774
  signalType = resolvedSignalType,
724
775
  additionalParameters = params
725
776
  )
726
- return Promise.resolved(result)
777
+ // An identity signal that the SDK accepts can still be rejected
778
+ // downstream by schema validation — a mismatched method attribute has
779
+ // cost a customer 22 signals while every call reported success. The
780
+ // bridge cannot see that; it can at least report the half it does see.
781
+ return Promise.resolved(warnIfRejected(result, "logIdentity", resolvedSignalType))
727
782
  }
728
783
 
729
784
  /**
@@ -863,7 +918,27 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
863
918
  * @param logicalPageName The logical page name to be set.
864
919
  * @return True if the operation was successful, false otherwise.
865
920
  */
921
+ /**
922
+ * Whether the bridge may touch capture at all.
923
+ *
924
+ * `disable()` reaches `Tealeaf.disable()`, which unregisters the activity
925
+ * lifecycle callbacks and clears the enabled flag — enough on iOS, where
926
+ * `<Connect>` only advances the current screen name. On Android the same
927
+ * component also drives capture explicitly on every navigation
928
+ * (`logScreenViewPageName` + `logScreenLayout`), and those paths used to run
929
+ * regardless of the flag: `setCurrentScreenName` calls through to
930
+ * `Tealeaf.resumeTealeaf`, which resumes logging, and `logScreenLayout`
931
+ * captured a full layout. The net effect was that `disable()` silenced
932
+ * capture on iOS but not on Android, for an app doing nothing unusual.
933
+ *
934
+ * Checked here rather than in JS so every caller is covered, including apps
935
+ * that call the bridge methods directly.
936
+ */
937
+ private fun isCaptureAllowed(): Boolean = Connect.isEnabled()
938
+
866
939
  override fun setCurrentScreenName(logicalPageName: String): Boolean {
940
+ // resumeConnect resumes logging, so this must not run while disabled.
941
+ if (!isCaptureAllowed()) return false
867
942
  val result = resumeConnect(getCurrentActivity(), logicalPageName, false)
868
943
  return result
869
944
  }
@@ -876,8 +951,14 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
876
951
  * @return True if the operation was successful, false otherwise.
877
952
  */
878
953
  override fun logScreenViewContextLoad(logicalPageName: Variant_NullType_String?, referrer: Variant_NullType_String?): Boolean {
879
- val result = logScreenview(getCurrentActivity()!!, logicalPageName?.asSecondOrNull().toString(), ScreenviewType.LOAD, referrer?.asSecondOrNull());
880
- return result
954
+ // Emits a screenview message; nothing should reach the queue while disabled.
955
+ if (!isCaptureAllowed()) return false
956
+ // No activity means nothing to log a screenview against. This used to be
957
+ // a force-unwrap, which turned a backgrounded or not-yet-attached activity
958
+ // into a crash; the sample now calls this method directly, so the path is
959
+ // easy to reach from JS.
960
+ val activity = getCurrentActivity() ?: return false
961
+ return logScreenview(activity, logicalPageName?.asSecondOrNull().toString(), ScreenviewType.LOAD, referrer?.asSecondOrNull())
881
962
  }
882
963
 
883
964
  /**
@@ -888,32 +969,134 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
888
969
  * @return True if the operation was successful, false otherwise.
889
970
  */
890
971
  override fun logScreenViewContextUnload(logicalPageName: Variant_NullType_String?, referrer: Variant_NullType_String?): Boolean {
891
- val result = logScreenview(getCurrentActivity()!!, logicalPageName?.asSecondOrNull().toString(), ScreenviewType.UNLOAD, referrer?.asSecondOrNull());
892
- return result
972
+ // Emits a screenview message; nothing should reach the queue while disabled.
973
+ if (!isCaptureAllowed()) return false
974
+ // No activity means nothing to log a screenview against. This used to be
975
+ // a force-unwrap, which turned a backgrounded or not-yet-attached activity
976
+ // into a crash; the sample now calls this method directly, so the path is
977
+ // easy to reach from JS.
978
+ val activity = getCurrentActivity() ?: return false
979
+ return logScreenview(activity, logicalPageName?.asSecondOrNull().toString(), ScreenviewType.UNLOAD, referrer?.asSecondOrNull())
893
980
  }
894
981
 
895
982
  /**
896
983
  * Log Current Screen Layout using native side background thread.
897
984
  *
898
985
  * @param name Page name or title e.g. "Login View Controller"; Must not be empty.
899
- * @param delay The delay in milliseconds before logging the event.
986
+ * @param delay The delay in milliseconds before logging the event. A negative
987
+ * value means "use the `CaptureLayoutDelay` configured for this
988
+ * screen", which is what the JS wrapper sends when the caller
989
+ * names no delay.
900
990
  * @return True if the operation was successful, false otherwise.
901
991
  */
902
992
  override fun logScreenLayout(name: String, delay: Double): Boolean {
993
+ // The wrapper calls this on every Android navigation.
994
+ if (!isCaptureAllowed()) return false
995
+ // Advisory on purpose: a false here means the screen name did not advance,
996
+ // which is not a reason to skip the screenview and layout that follow — they
997
+ // are what the caller asked for. Treating it as fatal would suppress capture
998
+ // in cases that capture fine today. The guard inside setCurrentScreenName is
999
+ // redundant against the check above and deliberately left in, so the method
1000
+ // stays safe for callers that reach it directly.
903
1001
  setCurrentScreenName(name)
1002
+ // The 3-arg overload takes a nullable Activity, so this one is safe to pass
1003
+ // through — unlike the 4-arg overload the context methods use.
904
1004
  logScreenview(getCurrentActivity(), name, ScreenviewType.LOAD)
905
1005
  var result = false
906
- if (LayoutUtil.canCaptureUserEvents(null, name)) {
907
- result = logScreenLayout(
908
- Objects.requireNonNull<Activity?>(getCurrentActivity()),
1006
+ // The layout capture below needs a real activity: it used to go through
1007
+ // Objects.requireNonNull, which threw when the activity had gone away
1008
+ // between the check above and here. Skip the capture instead and report
1009
+ // false — this runs on every Android navigation, so a throw here is a
1010
+ // crash on an ordinary screen change.
1011
+ val activity = getCurrentActivity()
1012
+ if (activity != null && LayoutUtil.canCaptureUserEvents(null, name)) {
1013
+ result = logAutomaticScreenLayout(
1014
+ activity,
909
1015
  name,
910
- if (delay.toInt() < 0) 300 else delay.toInt(),
911
- true
1016
+ resolveCaptureLayoutDelayMs(name, delay)
912
1017
  )
913
1018
  }
914
1019
  return result
915
1020
  }
916
1021
 
1022
+ /**
1023
+ * Captures the layout of [activity] as an *automatic* capture — the kind
1024
+ * the wrapper triggers itself, on navigation or behind a dialog — rather
1025
+ * than a manual `logScreenLayout` API call from the host app.
1026
+ *
1027
+ * Every wrapper-initiated capture must go through here, because the
1028
+ * distinction is what makes the configured `ScreenShot` value reach the
1029
+ * native screenshot gate at all:
1030
+ *
1031
+ * - `Connect`'s four-argument overload hardcodes `manualLog = true`, and
1032
+ * the native gate reads the configured `ScreenShot` only on the
1033
+ * `manualLog = false` branch. Passing a literal `true` for the screenshot
1034
+ * flag — which every wrapper call site used to do — therefore took the
1035
+ * manual branch unconditionally, so `ScreenShot: false` could not be
1036
+ * honoured from config and a full-page image shipped in every layout
1037
+ * message regardless. Hence the five-argument overload, with
1038
+ * `manualLog = false`.
1039
+ * - [LayoutUtil.canTakeScreenShot] resolves the same merged layout rule the
1040
+ * native automatic path uses (global settings as a baseline, any
1041
+ * per-screen rule applied over them). It is preferred over reading
1042
+ * `ScreenShot` directly because it is `has()`-guarded: a per-screen rule
1043
+ * that omits the key defaults to capturing rather than throwing a
1044
+ * `JSONException`, which higher up is swallowed and costs the whole
1045
+ * layout message. Its first argument may be null while the page name is
1046
+ * non-empty, the same pattern as `canCaptureUserEvents(null, name)`.
1047
+ *
1048
+ * Note `CaptureScreenshotOn` is not consulted anywhere on Android: its only
1049
+ * native reader has no callers, so `ScreenShot` is the one wired-up switch.
1050
+ *
1051
+ * [activity] is nullable to match the five-argument overload; callers that
1052
+ * need a non-null one check or assert before calling.
1053
+ */
1054
+ private fun logAutomaticScreenLayout(
1055
+ activity: Activity?,
1056
+ name: String,
1057
+ delayMs: Int
1058
+ ): Boolean {
1059
+ return logScreenLayout(
1060
+ activity,
1061
+ name,
1062
+ delayMs,
1063
+ false,
1064
+ LayoutUtil.canTakeScreenShot(null, name)
1065
+ )
1066
+ }
1067
+
1068
+ /**
1069
+ * Resolves the capture delay, in milliseconds, to apply for [name].
1070
+ *
1071
+ * A non-negative [delay] is the caller's explicit choice and passes
1072
+ * straight through. A negative one defers to `CaptureLayoutDelay` in the
1073
+ * layout config, which is what makes that setting reach the React Native
1074
+ * wrapper at all — the wrapper used to hardcode 0 here, so the capture
1075
+ * fired at the start of the screen transition and the configured value
1076
+ * was inert.
1077
+ *
1078
+ * [LayoutUtil.getLayoutInfo] returns the merged rule for the screen: the
1079
+ * global settings as a baseline with any per-screen rule applied over
1080
+ * them, so this picks up either without re-implementing the precedence.
1081
+ * It reads the config off disk, so a malformed or absent block falls back
1082
+ * to [DEFAULT_CAPTURE_LAYOUT_DELAY_MS] rather than propagating a throw
1083
+ * into a logging call.
1084
+ */
1085
+ internal fun resolveCaptureLayoutDelayMs(name: String, delay: Double): Int {
1086
+ if (delay >= 0) {
1087
+ return delay.toInt()
1088
+ }
1089
+ return try {
1090
+ LayoutUtil.getLayoutInfo(name)
1091
+ ?.optInt(CAPTURE_LAYOUT_DELAY_KEY, DEFAULT_CAPTURE_LAYOUT_DELAY_MS)
1092
+ ?.coerceAtLeast(0)
1093
+ ?: DEFAULT_CAPTURE_LAYOUT_DELAY_MS
1094
+ } catch (e: Exception) {
1095
+ Log.w(TAG, "Could not read $CAPTURE_LAYOUT_DELAY_KEY for \"$name\"; using ${DEFAULT_CAPTURE_LAYOUT_DELAY_MS}ms.", e)
1096
+ DEFAULT_CAPTURE_LAYOUT_DELAY_MS
1097
+ }
1098
+ }
1099
+
917
1100
  /**
918
1101
  * Logs a dialog show event with the specified dialog information.
919
1102
  *
@@ -950,12 +1133,12 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
950
1133
  } else {
951
1134
  Log.v(TAG, "Warning: Could not find dialog object for $dialogId after delay")
952
1135
  // Fallback to regular screen layout capture
953
- logScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 0, true)
1136
+ logAutomaticScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 0)
954
1137
  }
955
1138
  } catch (e: Exception) {
956
1139
  Log.v(TAG, "Error in delayed dialog capture: ${e.message}")
957
1140
  // Fallback to regular screen layout capture
958
- logScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 0, true)
1141
+ logAutomaticScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 0)
959
1142
  }
960
1143
  }, DIALOG_CAPTURE_DELAY_MS) // Use configurable delay
961
1144
 
@@ -974,7 +1157,7 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
974
1157
  }
975
1158
  } else {
976
1159
  // Default fallback
977
- result = logScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 300, true)
1160
+ result = logAutomaticScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 300)
978
1161
  }
979
1162
  }
980
1163
  } catch (e: Exception) {
@@ -1187,7 +1370,7 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
1187
1370
  for (key in values.keys) {
1188
1371
  val value = values[key]
1189
1372
  if (value != null) {
1190
- eventValues[key] = value.toString()
1373
+ eventValues[key] = variantToString(value)
1191
1374
  }
1192
1375
  }
1193
1376
 
@@ -1200,9 +1383,83 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
1200
1383
  return result
1201
1384
  }
1202
1385
 
1386
+ /**
1387
+ * Unwraps a Nitro variant to the underlying JS value it carries — a
1388
+ * [Boolean], [String], or [Double].
1389
+ *
1390
+ * The generated `Variant_*` type is a sealed **data** class, so calling
1391
+ * `toString()` on the variant itself yields the case wrapper
1392
+ * (`"Second(value=pro)"`) instead of the value (`"pro"`). Every conversion
1393
+ * that reads a variant must unwrap it first. Mirrors the iOS bridge's
1394
+ * `ConnectRNParsing.convertVariantToAny`, keeping emitted payloads
1395
+ * identical across platforms.
1396
+ *
1397
+ * @param value The variant to unwrap.
1398
+ * @return The wrapped Boolean, String, or Double.
1399
+ */
1400
+ private fun unwrapVariant(value: Variant_Boolean_String_Double): Any =
1401
+ value.match(first = { it }, second = { it }, third = { it })
1402
+
1403
+ /**
1404
+ * Unwraps a Nitro variant (see [unwrapVariant]) and renders it as a string,
1405
+ * for the SDK entry points that take `HashMap<String, String>` payloads.
1406
+ *
1407
+ * Booleans render as `"true"`/`"false"`, strings pass through unchanged,
1408
+ * and numbers go through [formatJsNumber] so they read the way the same
1409
+ * JS value reads on iOS.
1410
+ *
1411
+ * @param value The variant to stringify.
1412
+ * @return The wrapped value's string form.
1413
+ */
1414
+ private fun variantToString(value: Variant_Boolean_String_Double): String =
1415
+ when (val unwrapped = unwrapVariant(value)) {
1416
+ is Double -> formatJsNumber(unwrapped)
1417
+ else -> unwrapped.toString()
1418
+ }
1419
+
1420
+ /**
1421
+ * Renders a JS number the way JS itself — and therefore the iOS bridge —
1422
+ * renders it: `2` stays `"2"`, `2.5` stays `"2.5"`.
1423
+ *
1424
+ * Every JS number crosses Nitro as a [Double], so a JS `2` arrives as
1425
+ * `2.0`, and Kotlin's [Double.toString] spells that `"2.0"`. iOS hands the
1426
+ * same value to the SDK as a native number, which `NSJSONSerialization`
1427
+ * writes as `2`. The result was a cross-platform payload split on any
1428
+ * whole number — `"seats": "2.0"` on Android against `"seats": 2` on iOS —
1429
+ * which breaks dashboards and Composer rules that compare the two.
1430
+ * Dropping the trailing `.0` closes the *textual* half of that gap.
1431
+ *
1432
+ * It does not close the *type* half on the custom-event path: the SDK's
1433
+ * `logCustomEvent` chain is typed `HashMap<String, String>` end to end, so
1434
+ * an Android custom-event number is a JSON string (`"2"`) where iOS sends a
1435
+ * JSON number (`2`). Only `logSignal` carries native types on Android, and
1436
+ * that path deliberately does not come through here — see [toSignalPayload].
1437
+ *
1438
+ * Integral values are rendered through [Long] only below 2^53, which spans
1439
+ * every integer JS itself represents exactly; beyond that the [Double] form
1440
+ * is kept rather than inventing digits a `Long` round-trip would imply.
1441
+ * Non-finite values keep Kotlin's spelling (`"NaN"`, `"Infinity"`) — there
1442
+ * is no JSON representation to match, and stringifying is strictly safer
1443
+ * than throwing out of an analytics call.
1444
+ *
1445
+ * @param value The number to render.
1446
+ * @return Its string form, without a trailing `.0` for whole numbers.
1447
+ */
1448
+ internal fun formatJsNumber(value: Double): String {
1449
+ if (!value.isFinite()) {
1450
+ return value.toString()
1451
+ }
1452
+ if (value == Math.floor(value) && Math.abs(value) < 9007199254740992.0) {
1453
+ return value.toLong().toString()
1454
+ }
1455
+ return value.toString()
1456
+ }
1457
+
1203
1458
  /**
1204
1459
  * Converts a map of Variant_Boolean_String_Double to a HashMap<String?, String?>.
1205
1460
  *
1461
+ * Values are unwrapped before stringifying (see [variantToString]).
1462
+ *
1206
1463
  * @param values The map to be converted.
1207
1464
  * @return A HashMap<String?, String?> representation of the input map which library can use.
1208
1465
  */
@@ -1212,30 +1469,114 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
1212
1469
  for (key in values.keys) {
1213
1470
  val value = values[key]
1214
1471
  if (value != null) {
1215
- map[key] = value.toString()
1472
+ map[key] = variantToString(value)
1216
1473
  }
1217
1474
  }
1218
1475
  return map
1219
1476
  }
1220
1477
 
1221
1478
  /**
1222
- * Converts a map of Variant_Boolean_String_Double to a HashMap<String?, String?>.
1479
+ * Converts an [AnyMap]-derived map into the payload `Connect.logSignal`
1480
+ * expects, rebuilding nested structures as [JSONObject] / [JSONArray].
1223
1481
  *
1224
- * @param values The map to be converted.
1225
- * @return A HashMap<String?, String?> representation of the input map which library can use.
1482
+ * The rebuild is mandatory, not cosmetic. The SDK serializes the signal
1483
+ * through EOCore's `JsonUtil.getHashValues`, which walks the top-level
1484
+ * entries and accumulates only `String`, `Boolean`, `Number` (from Connect
1485
+ * Android 11.0.24-beta), `JSONObject`, `JSONArray` and `ByteArray` —
1486
+ * anything else is **silently dropped**. So a nested `Map`/`List` handed
1487
+ * over as-is would vanish from the emitted signal without any error.
1488
+ * Converting here is what makes nested payloads survive the wire.
1489
+ *
1490
+ * `null` becomes [JSONObject.NULL] rather than a Kotlin `null`, which
1491
+ * `org.json` requires for an explicit JSON `null`.
1492
+ *
1493
+ * Version boundary — **top-level** numbers. `getHashValues` gained a
1494
+ * `Number` branch in Connect Android 11.0.24-beta and accumulates the boxed
1495
+ * value as-is, so a top-level number now reaches the wire. On earlier builds
1496
+ * its `instanceof` ladder had no such branch, the entry was skipped with no
1497
+ * error, and nothing here could rescue it. Numbers nested inside an object
1498
+ * or array were never affected — the enclosing [JSONObject]/[JSONArray] is
1499
+ * built here, so `org.json` serializes them normally — and iOS has always
1500
+ * carried top-level numbers. Both sides of the boundary sit inside the
1501
+ * `[11.0.11, 12.0.0)` range this bridge accepts, so an integration pinning
1502
+ * an older Connect version still sees the old behaviour; nesting a number
1503
+ * is portable across the whole range.
1504
+ *
1505
+ * A [JSONException] aborts the whole payload rather than escaping to the
1506
+ * caller. Non-finite numbers are the case that raises it: `org.json`
1507
+ * rejects them, and [toJsonValue] raises them explicitly so a top-level one
1508
+ * behaves like a nested one. Either way a JS `Infinity` or `NaN` would
1509
+ * otherwise throw straight out of `logSignal` and take the host app's call
1510
+ * site down — unacceptable for an analytics SDK, and a behaviour change
1511
+ * from the scalar-only bridge, which could not throw. Dropping the whole
1512
+ * payload also matches iOS, where a single non-finite value fails
1513
+ * `isValidJSONObject:` and the `signal` key is omitted entirely.
1514
+ *
1515
+ * @param values The map from [AnyMap.toHashMap].
1516
+ * @return A HashMap the SDK's signal serializer can consume, or an empty
1517
+ * map if the payload could not be represented as JSON.
1226
1518
  */
1227
1519
  // internal (not private) so the unit tests in src/test can exercise it.
1228
- internal fun convertToMapAny(values: Map<String, Variant_Boolean_String_Double>): java.util.HashMap<String?, Any?>? {
1229
- val map = HashMap<String?, Any?>()
1230
- for (key in values.keys) {
1231
- val value = values[key]
1232
- if (value != null) {
1233
- map[key] = value
1520
+ internal fun toSignalPayload(values: Map<String, Any?>): java.util.HashMap<String?, Any?> {
1521
+ val map = HashMap<String?, Any?>(values.size)
1522
+ try {
1523
+ for ((key, value) in values) {
1524
+ map[key] = toJsonValue(value)
1234
1525
  }
1526
+ } catch (e: JSONException) {
1527
+ Log.w(TAG, "[bridge] logSignal payload is not representable as JSON — dropping it: ${e.message}")
1528
+ return HashMap()
1235
1529
  }
1236
1530
  return map
1237
1531
  }
1238
1532
 
1533
+ /**
1534
+ * Recursive helper for [toSignalPayload]. Maps Kotlin containers onto their
1535
+ * `org.json` equivalents and leaves scalars alone.
1536
+ *
1537
+ * Nitro's JNI layer converts the whole tree to plain Java types before it
1538
+ * reaches Kotlin — a JS object becomes a `HashMap`, a JS array an
1539
+ * `ArrayList`, and scalars become `Double` / `Boolean` / `Long` / `String`
1540
+ * — so there are no `AnyValue` wrappers left to unwrap here. [List] is
1541
+ * therefore the branch a JS array actually takes; [Array] is handled too,
1542
+ * to guard against a future Nitro representation change.
1543
+ *
1544
+ * @param value A value from an [AnyMap]-derived container.
1545
+ * @return The `org.json`-compatible equivalent.
1546
+ */
1547
+ private fun toJsonValue(value: Any?): Any =
1548
+ when (value) {
1549
+ null -> JSONObject.NULL
1550
+ is Map<*, *> -> JSONObject().apply {
1551
+ for ((nestedKey, nestedValue) in value) {
1552
+ put(nestedKey.toString(), toJsonValue(nestedValue))
1553
+ }
1554
+ }
1555
+ is Array<*> -> JSONArray().apply {
1556
+ for (element in value) put(toJsonValue(element))
1557
+ }
1558
+ is List<*> -> JSONArray().apply {
1559
+ for (element in value) put(toJsonValue(element))
1560
+ }
1561
+ // Checked here rather than left to `org.json`. A non-finite number
1562
+ // nested in an object or array is rejected by that container's
1563
+ // `put`, but a TOP-LEVEL one is only ever handed to `HashMap.put`,
1564
+ // which accepts anything — so without this the payload would reach
1565
+ // the SDK, and what happened there would depend on the resolved
1566
+ // Connect version: before 11.0.24-beta it lost just that one key
1567
+ // while the nested case lost everything; from 11.0.24-beta the
1568
+ // SDK's own `Number` branch rejects it and drops the whole payload.
1569
+ // Raising it here keeps the two cases consistent across the
1570
+ // supported range and matches iOS, where one non-finite value fails
1571
+ // `isValidJSONObject:` for the entire signal.
1572
+ is Double -> if (value.isFinite()) {
1573
+ value
1574
+ } else {
1575
+ throw JSONException("non-finite number: $value")
1576
+ }
1577
+ else -> value
1578
+ }
1579
+
1239
1580
  /**
1240
1581
  * Gets the current activity from the ReactApplicationContext.
1241
1582
  *
@@ -1383,6 +1724,15 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
1383
1724
  const val TAG = "AcousticConnectRN"
1384
1725
  const val DIALOG_CAPTURE_DELAY_MS = 500L // Configurable delay for dialog screenshot capture
1385
1726
 
1727
+ /** Key holding the per-screen capture delay, in milliseconds, inside a layout-config rule. */
1728
+ const val CAPTURE_LAYOUT_DELAY_KEY = "CaptureLayoutDelay"
1729
+
1730
+ /**
1731
+ * Delay applied when the layout config names none. Matches the value the
1732
+ * Connect SDK ships in its own `TealeafLayoutConfig.json`.
1733
+ */
1734
+ const val DEFAULT_CAPTURE_LAYOUT_DELAY_MS = 500
1735
+
1386
1736
  // Class probed at runtime to detect whether the connect-push-fcm
1387
1737
  // transport artifact was included in the build (i.e. automatic mode,
1388
1738
  // where Connect's own FirebaseMessagingService is the PushReceived
@@ -1390,5 +1740,28 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
1390
1740
  // by the connect-push-fcm artifact.
1391
1741
  private const val CONNECT_PUSH_FCM_PROBE_CLASS =
1392
1742
  "com.acoustic.connect.android.connectmod.push.services.fcm.FCMPushService"
1743
+
1744
+ /**
1745
+ * Default `additionalParameters` for an identity signal, matched to the
1746
+ * signal type the bridge will actually send.
1747
+ *
1748
+ * Connect's signal schema requires a *method* attribute on identity
1749
+ * signals, and the required key differs per type: `loggedIn` requires
1750
+ * `loginMethod`, `accountRegistered` requires `registrationMethod`.
1751
+ * Supplying the wrong one fails schema validation and the signal is
1752
+ * discarded, while [Connect.logIdentificationEvent] still reports
1753
+ * success — so the caller sees nothing wrong. Before this mapping
1754
+ * existed the bridge paired its `loggedIn` default with
1755
+ * `registrationMethod`, which meant every defaulted identity call was
1756
+ * silently dropped.
1757
+ *
1758
+ * Only consulted when the caller omits `additionalParameters`
1759
+ * entirely; an explicitly-provided map is passed through untouched.
1760
+ */
1761
+ internal fun defaultIdentityParameters(signalType: String): Map<String, String> =
1762
+ when (signalType) {
1763
+ "loggedIn" -> mapOf("loginMethod" to "email")
1764
+ else -> mapOf("registrationMethod" to "email")
1765
+ }
1393
1766
  }
1394
1767
  }
package/app.plugin.js CHANGED
@@ -9,7 +9,7 @@
9
9
  // The plugin composition is defined in plugin/src/index.ts and compiled to
10
10
  // plugin/build/index.js (CommonJS) by `npm run build:plugin`.
11
11
  //
12
- // To add a new mod (e.g. withConnectNCE from CA-143488), extend the `mods`
13
- // array in plugin/src/index.ts — do not modify this shim.
12
+ // To add a new mod (e.g. a notification-content-extension mod), extend the
13
+ // `mods` array in plugin/src/index.ts — do not modify this shim.
14
14
 
15
15
  module.exports = require('./plugin/build/index').default
@@ -56,7 +56,7 @@
56
56
  "ScreenShot": false
57
57
  },
58
58
  "GlobalScreenSettings": {
59
- "CaptureLayoutDelay": 1,
59
+ "CaptureLayoutDelay": 500,
60
60
  "CaptureLayoutOn": 2,
61
61
  "CaptureScreenVisits": false,
62
62
  "CaptureScreenshotOn": 2,
@@ -129,7 +129,7 @@
129
129
  "ScreenShot": false
130
130
  },
131
131
  "GlobalScreenSettings": {
132
- "CaptureLayoutDelay": 1,
132
+ "CaptureLayoutDelay": 500,
133
133
  "CaptureLayoutOn": 2,
134
134
  "CaptureScreenVisits": false,
135
135
  "CaptureScreenshotOn": 2,