@apexnative/navigation 1.0.0-alpha.0 → 1.0.0-alpha.10

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 (574) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +128 -0
  3. package/README.md +147 -51
  4. package/android/CLAUDE.md +78 -25
  5. package/android/CORE.md +49 -25
  6. package/android/RECIPES.md +13 -6
  7. package/android/consumer-rules.pro +6 -0
  8. package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +85 -10
  9. package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
  10. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
  11. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
  12. package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
  13. package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
  14. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
  15. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
  16. package/android/src/main/java/dev/apexnative/navigation/options/ButtonMenuOptions.kt +2 -2
  17. package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +3 -3
  18. package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -1
  19. package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
  20. package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
  21. package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
  22. package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
  23. package/android/src/main/java/dev/apexnative/navigation/options/OptionsCache.kt +8 -4
  24. package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
  25. package/android/src/main/java/dev/apexnative/navigation/options/SideMenuOptions.kt +6 -1
  26. package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
  27. package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
  28. package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
  29. package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
  30. package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
  31. package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
  32. package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +29 -36
  33. package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
  34. package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
  35. package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
  36. package/android/src/main/java/dev/apexnative/navigation/react/ErrorTexts.kt +75 -60
  37. package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +35 -23
  38. package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +12 -7
  39. package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +42 -4
  40. package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
  41. package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +54 -20
  42. package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +7 -6
  43. package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
  44. package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +19 -50
  45. package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
  46. package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +50 -81
  47. package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
  48. package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +135 -94
  49. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
  50. package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
  51. package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +12 -10
  52. package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
  53. package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +39 -19
  54. package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +16 -4
  55. package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
  56. package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
  57. package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
  58. package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
  59. package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
  60. package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
  61. package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
  62. package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
  63. package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
  64. package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
  65. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +10 -7
  66. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
  67. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
  68. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
  69. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +108 -34
  70. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
  71. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
  72. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
  73. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
  74. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
  75. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +12 -9
  76. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
  77. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
  78. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
  79. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
  80. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
  81. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
  82. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
  83. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +109 -21
  84. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
  85. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +476 -73
  86. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +57 -25
  87. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
  88. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +83 -0
  89. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
  90. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +49 -14
  91. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +71 -12
  92. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +37 -11
  93. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
  94. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
  95. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
  96. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +6 -6
  97. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +42 -9
  98. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +19 -8
  99. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
  100. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +43 -4
  101. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
  102. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +77 -17
  103. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +315 -0
  104. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
  105. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +30 -20
  106. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +216 -18
  107. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
  108. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +149 -41
  109. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
  110. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +115 -6
  111. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
  112. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +222 -48
  113. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
  114. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +30 -34
  115. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
  116. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
  117. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
  118. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
  119. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +219 -54
  120. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
  121. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
  122. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
  123. package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
  124. package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
  125. package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
  126. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +9 -7
  127. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
  128. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
  129. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
  130. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
  131. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +143 -135
  132. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +13 -5
  133. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
  134. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
  135. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
  136. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +112 -4
  137. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
  138. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
  139. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +56 -41
  140. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
  141. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
  142. package/android/src/main/java/dev/apexnative/navigation/views/sidemenu/SideMenuView.kt +12 -3
  143. package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +45 -0
  144. package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +140 -1
  145. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
  146. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
  147. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
  148. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -17
  149. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +73 -34
  150. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
  151. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
  152. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
  153. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +125 -178
  154. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
  155. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
  156. package/android/src/main/jni/ANNContentHeights.cpp +82 -0
  157. package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
  158. package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
  159. package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
  160. package/android/src/main/res/values/styles.xml +1 -1
  161. package/android/src/main/res/values-night/styles.xml +1 -1
  162. package/cli/app.js +1 -1
  163. package/cli/doctor/checks/app.js +77 -14
  164. package/cli/doctor/checks/splash.js +4 -22
  165. package/cli/migrate/native.js +18 -0
  166. package/cli/project.js +10 -2
  167. package/cli/setup/index.js +18 -0
  168. package/cli/setup/source.js +2 -1
  169. package/cli/setup/steps/appDelegate.js +66 -11
  170. package/cli/setup/steps/mainApplication.js +134 -19
  171. package/cli/setup/steps/metro.js +46 -0
  172. package/cli/setup/steps/sceneDelegate.js +108 -0
  173. package/cli/splash/index.js +3 -1
  174. package/cli/upgrade/changelog.js +2 -2
  175. package/docs-md/architecture/native-screens.md +4 -0
  176. package/docs-md/architecture/theme-and-context.md +131 -12
  177. package/docs-md/architecture/transitions.md +58 -12
  178. package/docs-md/containers/modals.md +8 -4
  179. package/docs-md/containers/overlays.md +3 -1
  180. package/docs-md/containers/side-menu.md +19 -2
  181. package/docs-md/containers/tabs.md +5 -1
  182. package/docs-md/flows/bottom-sheets.md +4 -2
  183. package/docs-md/flows/forms-in-a-modal.md +1 -1
  184. package/docs-md/fundamentals/screens-and-props.md +9 -1
  185. package/docs-md/fundamentals/starting-the-app.md +1 -1
  186. package/docs-md/guides/cli.md +4 -3
  187. package/docs-md/guides/deep-links.md +15 -33
  188. package/docs-md/help/glossary.md +4 -4
  189. package/docs-md/help/troubleshooting.md +44 -6
  190. package/docs-md/index.json +57 -1
  191. package/docs-md/migration/from-expo-router.md +1 -1
  192. package/docs-md/migration/from-react-native-navigation.md +9 -3
  193. package/docs-md/migration/from-react-navigation.md +2 -2
  194. package/docs-md/screen-ui/back-and-gestures.md +46 -2
  195. package/docs-md/screen-ui/bar-buttons.md +5 -5
  196. package/docs-md/screen-ui/search.md +1 -1
  197. package/docs-md/screen-ui/system-ui.md +17 -12
  198. package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
  199. package/docs-md/screen-ui/top-bar.md +8 -4
  200. package/docs-md/start/installation.md +21 -3
  201. package/ios/Animations/ANNFrameDriver.h +55 -15
  202. package/ios/Animations/ANNFrameDriver.mm +216 -60
  203. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  204. package/ios/Animations/ANNTransitionAnimator.mm +61 -13
  205. package/ios/Animations/ANNTransitionPlan.h +2 -2
  206. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  207. package/ios/Animations/ANNTransitionWait.mm +6 -7
  208. package/ios/Animations/Elements/ANNElementFinder.h +57 -0
  209. package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
  210. package/ios/Animations/Elements/ANNElementTransition.h +10 -8
  211. package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
  212. package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
  213. package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
  214. package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
  215. package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
  216. package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
  217. package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
  218. package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
  219. package/ios/CLAUDE.md +60 -24
  220. package/ios/CORE.md +44 -34
  221. package/ios/Contract/ANNCommandAnswer.h +13 -5
  222. package/ios/Contract/ANNCommandAnswer.mm +40 -32
  223. package/ios/Contract/ANNCommandContract.h +15 -0
  224. package/ios/Contract/ANNCommandContract.mm +78 -0
  225. package/ios/Contract/ANNCommandRunner.h +10 -9
  226. package/ios/Contract/ANNCommandRunner.mm +22 -28
  227. package/ios/Contract/ANNErrorTexts.h +6 -2
  228. package/ios/Contract/ANNErrorTexts.mm +18 -10
  229. package/ios/Contract/ANNLayoutNode.h +3 -3
  230. package/ios/Contract/ANNLayoutReader.h +3 -3
  231. package/ios/Core/ANNAppDelegate.mm +0 -2
  232. package/ios/Core/ANNAppearanceDispatcher.h +5 -4
  233. package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
  234. package/ios/Core/ANNDeepLinkQueue.h +22 -2
  235. package/ios/Core/ANNDeepLinkQueue.mm +121 -14
  236. package/ios/Core/ANNErrorHandler.h +9 -4
  237. package/ios/Core/ANNErrorHandler.mm +20 -2
  238. package/ios/Core/ANNEventContract.h +246 -0
  239. package/ios/Core/ANNEventContract.mm +225 -0
  240. package/ios/Core/ANNEventEmitter.h +6 -2
  241. package/ios/Core/ANNEventEmitter.mm +117 -80
  242. package/ios/Core/ANNHinge.h +6 -0
  243. package/ios/Core/ANNHinge.mm +15 -4
  244. package/ios/Core/ANNJavaScriptCalls.h +33 -0
  245. package/ios/Core/ANNJavaScriptCalls.mm +52 -0
  246. package/ios/Core/ANNLayoutProtocol.h +5 -5
  247. package/ios/Core/ANNNavigationState.h +7 -5
  248. package/ios/Core/ANNNavigationState.mm +8 -7
  249. package/ios/Core/ANNNodeHelper.h +32 -12
  250. package/ios/Core/ANNNodeHelper.mm +100 -3
  251. package/ios/Core/ANNParking.h +5 -4
  252. package/ios/Core/ANNReloadCoordinator.mm +5 -12
  253. package/ios/Core/ANNRenderWait.h +20 -6
  254. package/ios/Core/ANNRenderWait.mm +143 -56
  255. package/ios/Core/ANNSceneDelegate.mm +25 -15
  256. package/ios/Core/ANNSystemUI.h +3 -2
  257. package/ios/Core/ANNSystemUI.mm +7 -0
  258. package/ios/Core/ANNUtils.h +7 -0
  259. package/ios/Core/ANNUtils.mm +10 -0
  260. package/ios/Core/ApexNavigation+Internal.h +1 -1
  261. package/ios/Core/ApexNavigation.mm +7 -6
  262. package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
  263. package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
  264. package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
  265. package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
  266. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +10 -8
  267. package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
  268. package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
  269. package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
  270. package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
  271. package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
  272. package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
  273. package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
  274. package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
  275. package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
  276. package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
  277. package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
  278. package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
  279. package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
  280. package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
  281. package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
  282. package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
  283. package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
  284. package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
  285. package/ios/Layouts/Screen/ANNScreenPlace.h +53 -0
  286. package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
  287. package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
  288. package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
  289. package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
  290. package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
  291. package/ios/Layouts/Screen/ANNScreenSettling.h +32 -0
  292. package/ios/Layouts/Screen/ANNScreenSettling.mm +137 -0
  293. package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
  294. package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
  295. package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
  296. package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
  297. package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
  298. package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
  299. package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
  300. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  301. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  302. package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
  303. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  304. package/ios/Layouts/Stack/ANNStackController.mm +184 -16
  305. package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
  306. package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
  307. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  308. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  309. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  310. package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
  311. package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
  312. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
  313. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
  314. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
  315. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
  316. package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
  317. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
  318. package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
  319. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
  320. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
  321. package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
  322. package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
  323. package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
  324. package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
  325. package/ios/Options/ANNAnimationOptions.h +2 -1
  326. package/ios/Options/ANNAnimationOptions.mm +1 -1
  327. package/ios/Options/ANNBottomTabsOptions.h +2 -0
  328. package/ios/Options/ANNBottomTabsOptions.mm +1 -0
  329. package/ios/Options/ANNOptions.h +25 -0
  330. package/ios/Options/ANNOptions.mm +157 -1
  331. package/ios/Options/ANNOptionsCache.h +7 -6
  332. package/ios/Options/ANNOptionsReader.mm +108 -0
  333. package/ios/Options/ANNSearchBarOptions.h +4 -3
  334. package/ios/Options/ANNSheetOptions.h +4 -1
  335. package/ios/Options/ANNSideMenuOptions.h +2 -0
  336. package/ios/Options/ANNSideMenuOptions.mm +2 -0
  337. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  338. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  339. package/ios/Options/ANNUserChoice.h +57 -0
  340. package/ios/Options/ANNUserChoice.mm +44 -0
  341. package/ios/Options/Params/ANNImageSource.h +61 -0
  342. package/ios/Options/Params/ANNImageSource.mm +101 -0
  343. package/ios/Options/Params/ANNOptionImages.h +37 -0
  344. package/ios/Options/Params/ANNOptionImages.mm +284 -0
  345. package/ios/Options/Params/ANNParam.h +15 -0
  346. package/ios/Options/Params/ANNParam.mm +61 -0
  347. package/ios/Options/Params/Color.h +3 -0
  348. package/ios/Options/Params/Color.mm +21 -0
  349. package/ios/Options/Params/ColorParser.h +4 -3
  350. package/ios/Options/Params/ColorParser.mm +22 -4
  351. package/ios/Options/Params/Image.h +15 -2
  352. package/ios/Options/Params/Image.mm +35 -2
  353. package/ios/Options/Params/ImageParser.h +5 -5
  354. package/ios/Options/Params/ImageParser.mm +28 -46
  355. package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
  356. package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
  357. package/ios/RECIPES.md +13 -6
  358. package/ios/React/ANNReactView.mm +6 -25
  359. package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
  360. package/ios/React/ANNSurfaceHostingView.h +14 -0
  361. package/ios/React/ANNSurfaceHostingView.mm +144 -1
  362. package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
  363. package/ios/React/Slots/ANNSlotContainers.h +14 -6
  364. package/ios/React/Slots/ANNSlotContainers.mm +75 -2
  365. package/ios/React/Slots/ANNSlotHost.mm +1 -3
  366. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  367. package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
  368. package/ios/TopBar/ANNBarAppearance.h +2 -1
  369. package/ios/TopBar/ANNBarAppearance.mm +111 -30
  370. package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
  371. package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
  372. package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
  373. package/ios/TopBar/ANNBarButtons.h +14 -8
  374. package/ios/TopBar/ANNBarButtons.mm +397 -80
  375. package/ios/TopBar/ANNIconButtonImage.h +1 -0
  376. package/ios/TopBar/ANNIconButtonImage.mm +34 -1
  377. package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
  378. package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
  379. package/ios/TopBar/ANNMainList.h +3 -0
  380. package/ios/TopBar/ANNMainList.mm +4 -0
  381. package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
  382. package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
  383. package/ios/TopBar/ANNSearchPresenter.mm +172 -21
  384. package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
  385. package/ios/TopBar/ANNTopBarPresenter.h +8 -2
  386. package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
  387. package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
  388. package/ios/TurboModules/ANNTurboModule.mm +104 -33
  389. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  390. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  391. package/lib/module/ARCHITECTURE.md +40 -27
  392. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  393. package/lib/module/api/app/AppRegistry.js +14 -2
  394. package/lib/module/api/app/AppRegistry.js.map +1 -1
  395. package/lib/module/api/app/createNavigation.js +190 -66
  396. package/lib/module/api/app/createNavigation.js.map +1 -1
  397. package/lib/module/api/commands/commands.js +54 -6
  398. package/lib/module/api/commands/commands.js.map +1 -1
  399. package/lib/module/api/events/navigationEvents.js +6 -2
  400. package/lib/module/api/events/navigationEvents.js.map +1 -1
  401. package/lib/module/api/hooks/useNavigation.js +8 -3
  402. package/lib/module/api/hooks/useNavigation.js.map +1 -1
  403. package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
  404. package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
  405. package/lib/module/api/linking/dispatchedLinks.js +23 -0
  406. package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
  407. package/lib/module/api/linking/linking.js +11 -0
  408. package/lib/module/api/linking/linking.js.map +1 -1
  409. package/lib/module/api/navigation.js.map +1 -1
  410. package/lib/module/api/options/OptionsChain.js +2 -2
  411. package/lib/module/api/screens/defineScreen.js +45 -3
  412. package/lib/module/api/screens/defineScreen.js.map +1 -1
  413. package/lib/module/api/screens/nativeScreens.js +31 -6
  414. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  415. package/lib/module/api/screens/registerScreens.js +193 -35
  416. package/lib/module/api/screens/registerScreens.js.map +1 -1
  417. package/lib/module/api/theme/theme.js +5 -0
  418. package/lib/module/api/theme/theme.js.map +1 -1
  419. package/lib/module/engine/commands.js +51 -9
  420. package/lib/module/engine/commands.js.map +1 -1
  421. package/lib/module/engine/layout.js +20 -11
  422. package/lib/module/engine/layout.js.map +1 -1
  423. package/lib/module/engine/nativeScreens.js +9 -0
  424. package/lib/module/engine/nativeScreens.js.map +1 -1
  425. package/lib/module/engine/options.js +49 -15
  426. package/lib/module/engine/options.js.map +1 -1
  427. package/lib/module/engine/optionsChange.js +102 -0
  428. package/lib/module/engine/optionsChange.js.map +1 -0
  429. package/lib/module/engine/places.js +52 -7
  430. package/lib/module/engine/places.js.map +1 -1
  431. package/lib/module/engine/props.js +30 -1
  432. package/lib/module/engine/props.js.map +1 -1
  433. package/lib/module/engine/refresh.js +85 -0
  434. package/lib/module/engine/refresh.js.map +1 -0
  435. package/lib/module/engine/rememberedOptions.js +61 -1
  436. package/lib/module/engine/rememberedOptions.js.map +1 -1
  437. package/lib/module/engine/screens.js +77 -16
  438. package/lib/module/engine/screens.js.map +1 -1
  439. package/lib/module/interfaces/contract/commands.json +101 -0
  440. package/lib/module/interfaces/contract/errors.json +275 -0
  441. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
  442. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  443. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  444. package/lib/typescript/api/app/createNavigation.d.ts +8 -3
  445. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  446. package/lib/typescript/api/commands/commands.d.ts.map +1 -1
  447. package/lib/typescript/api/commands/presentation.d.ts +4 -3
  448. package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
  449. package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
  450. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  451. package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
  452. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  453. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
  454. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
  455. package/lib/typescript/api/index.d.ts +1 -1
  456. package/lib/typescript/api/index.d.ts.map +1 -1
  457. package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
  458. package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
  459. package/lib/typescript/api/linking/linking.d.ts +8 -0
  460. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  461. package/lib/typescript/api/navigation.d.ts +4 -1
  462. package/lib/typescript/api/navigation.d.ts.map +1 -1
  463. package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
  464. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  465. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  466. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  467. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  468. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  469. package/lib/typescript/api/theme/theme.d.ts +2 -0
  470. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  471. package/lib/typescript/engine/commands.d.ts +5 -0
  472. package/lib/typescript/engine/commands.d.ts.map +1 -1
  473. package/lib/typescript/engine/layout.d.ts.map +1 -1
  474. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  475. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  476. package/lib/typescript/engine/options.d.ts +5 -2
  477. package/lib/typescript/engine/options.d.ts.map +1 -1
  478. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  479. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  480. package/lib/typescript/engine/places.d.ts +7 -2
  481. package/lib/typescript/engine/places.d.ts.map +1 -1
  482. package/lib/typescript/engine/props.d.ts +8 -1
  483. package/lib/typescript/engine/props.d.ts.map +1 -1
  484. package/lib/typescript/engine/refresh.d.ts +35 -0
  485. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  486. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  487. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  488. package/lib/typescript/engine/screens.d.ts +27 -6
  489. package/lib/typescript/engine/screens.d.ts.map +1 -1
  490. package/lib/typescript/interfaces/ComponentEvents.d.ts +4 -4
  491. package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
  492. package/lib/typescript/interfaces/Events.d.ts +28 -10
  493. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  494. package/lib/typescript/interfaces/Options.d.ts +1 -1
  495. package/lib/typescript/interfaces/Options.d.ts.map +1 -1
  496. package/lib/typescript/interfaces/options/animations.d.ts +80 -22
  497. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  498. package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
  499. package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
  500. package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
  501. package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
  502. package/lib/typescript/interfaces/options/modals.d.ts +34 -26
  503. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  504. package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
  505. package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
  506. package/lib/typescript/interfaces/options/stack.d.ts +17 -3
  507. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  508. package/lib/typescript/interfaces/options/system.d.ts +18 -11
  509. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  510. package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
  511. package/lib/typescript/interfaces/options/topBar.d.ts +68 -38
  512. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  513. package/metro/acceptPlugin.js +57 -0
  514. package/metro/babelTransformer.js +45 -0
  515. package/metro/index.js +36 -0
  516. package/package.json +4 -25
  517. package/src/ARCHITECTURE.md +40 -27
  518. package/src/adapters/NativeANNTurboModule.ts +12 -2
  519. package/src/api/app/AppRegistry.ts +16 -2
  520. package/src/api/app/createNavigation.ts +203 -69
  521. package/src/api/commands/commands.ts +48 -7
  522. package/src/api/commands/presentation.ts +4 -3
  523. package/src/api/events/navigationEvents.ts +10 -4
  524. package/src/api/hooks/useNavigation.ts +9 -4
  525. package/src/api/hooks/useSafeAreaInsets.ts +4 -3
  526. package/src/api/index.ts +1 -0
  527. package/src/api/linking/dispatchedLinks.ts +18 -0
  528. package/src/api/linking/linking.ts +22 -1
  529. package/src/api/navigation.ts +4 -1
  530. package/src/api/options/OptionsChain.ts +2 -2
  531. package/src/api/screens/defineScreen.ts +49 -5
  532. package/src/api/screens/nativeScreens.ts +40 -4
  533. package/src/api/screens/registerScreens.tsx +185 -42
  534. package/src/api/theme/theme.ts +5 -0
  535. package/src/engine/commands.ts +70 -13
  536. package/src/engine/layout.ts +27 -11
  537. package/src/engine/nativeScreens.ts +10 -1
  538. package/src/engine/options.ts +45 -19
  539. package/src/engine/optionsChange.ts +107 -0
  540. package/src/engine/places.ts +65 -7
  541. package/src/engine/props.ts +30 -1
  542. package/src/engine/refresh.ts +97 -0
  543. package/src/engine/rememberedOptions.ts +74 -1
  544. package/src/engine/screens.tsx +76 -21
  545. package/src/interfaces/ComponentEvents.ts +4 -4
  546. package/src/interfaces/Events.ts +29 -10
  547. package/src/interfaces/Options.ts +1 -0
  548. package/src/interfaces/contract/commands.json +101 -0
  549. package/src/interfaces/contract/errors.json +275 -0
  550. package/src/interfaces/options/animations.ts +81 -22
  551. package/src/interfaces/options/bottomTabs.ts +21 -7
  552. package/src/interfaces/options/buttons.ts +23 -15
  553. package/src/interfaces/options/modals.ts +34 -26
  554. package/src/interfaces/options/sideMenu.ts +24 -6
  555. package/src/interfaces/options/stack.ts +17 -3
  556. package/src/interfaces/options/system.ts +18 -11
  557. package/src/interfaces/options/toolbar.ts +2 -2
  558. package/src/interfaces/options/topBar.ts +68 -38
  559. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
  560. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
  561. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
  562. package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
  563. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
  564. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  565. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -138
  566. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
  567. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  568. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -66
  569. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
  570. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
  571. package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
  572. package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
  573. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
  574. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
@@ -3,13 +3,14 @@ package dev.apexnative.navigation.react
3
3
  import android.util.Log
4
4
  import com.facebook.react.bridge.Promise
5
5
  import dev.apexnative.navigation.react.events.EventEmitter
6
- import dev.apexnative.navigation.react.events.NavigationStateReporter
6
+ import dev.apexnative.navigation.react.events.NavigationState
7
7
  import dev.apexnative.navigation.utils.NavigationLog
8
8
 
9
9
  /**
10
10
  * The one answer of a command with a promise: [resolve] or [reject], once; after that, and once the JavaScript it came
11
- * from went ([generation]), nothing. [CommandRunner] makes it on the main thread for each command; area code that takes
12
- * a [CommandListener] answers through [asListener]. Main thread only.
11
+ * from went ([generation]), nothing. It owns the command's one state step ([reportStateNow]). [CommandRunner] makes it
12
+ * on the main thread for each command; area code that takes a [CommandListener] answers through [asListener]. Main
13
+ * thread only.
13
14
  */
14
15
  internal class CommandAnswer(
15
16
  /** The method of the command: `push`, `setRoot`, … */
@@ -27,22 +28,39 @@ internal class CommandAnswer(
27
28
  var isAnswered = false
28
29
  private set
29
30
 
31
+ // The state step of this answer ran ([reportStateNow]).
32
+ private var stateReported = false
33
+
30
34
  /** Whether an answer now would reach the JavaScript the command came from. */
31
35
  val canAnswer: Boolean
32
36
  get() = !isAnswered && ReloadCoordinator.isCurrent(generation)
33
37
 
34
38
  /**
35
- * Resolves the promise with [value]. For the commands that change what shows, the navigation state goes first,
36
- * when it changed, so JavaScript has it when its `await` goes on; `ANN.CommandCompleted` follows the promise, for
37
- * the commands that show or dismiss. A failure of either is logged; the promise goes all the same.
39
+ * The navigation state now, sent when it changed, once per answer: the end of the command's transition asks for it
40
+ * after the DidAppear it sends and before the transition's own events (`AppearanceDispatcher.endTransition`);
41
+ * otherwise [resolve] asks for it before the promise. A later call sends nothing, and nothing goes for a JavaScript
42
+ * that went. A failure of the step is logged and costs only the state.
43
+ */
44
+ fun reportStateNow() {
45
+ if (stateReported) return
46
+ stateReported = true
47
+ if (!ReloadCoordinator.isCurrent(generation)) return
48
+ guarded("report the navigation state") { events.stateNow() }
49
+ }
50
+
51
+ /**
52
+ * Resolves the promise with [value]. For the commands that change what shows (`CommandContract.STATE`), the
53
+ * navigation state goes first, when it changed and the command's transition didn't send it already
54
+ * ([reportStateNow]), so JavaScript has it when its `await` goes on; `ANN.CommandCompleted` follows the promise,
55
+ * for the commands that show or dismiss. A failure of either is logged; the promise goes all the same.
38
56
  */
39
57
  fun resolve(value: Any?) {
40
58
  if (!canAnswer) return
41
59
  isAnswered = true
42
- if (commandName in STATE_COMMANDS) guarded("report the navigation state") { events.beforeAnswer() }
60
+ if (commandName in CommandContract.STATE) reportStateNow()
43
61
  promise.resolve(value)
44
62
  val commandId = commandId
45
- if (commandName in COMPLETED_COMMANDS && commandId != null) {
63
+ if (commandName in CommandContract.COMPLETED && commandId != null) {
46
64
  guarded("send ANN.CommandCompleted") { events.commandCompleted(commandName, commandId, clock()) }
47
65
  }
48
66
  }
@@ -65,44 +83,19 @@ internal class CommandAnswer(
65
83
  log("[ApexNavigation] $commandName: ${ErrorTexts.couldNot(what, ErrorTexts.reasonOf(e))}")
66
84
  }
67
85
  }
68
-
69
- companion object {
70
- // The commands that send `ANN.CommandCompleted` (EVT-CommandCompleted).
71
- val COMPLETED_COMMANDS = setOf(
72
- "setRoot",
73
- "push",
74
- "pop",
75
- "popTo",
76
- "popToRoot",
77
- "setStackRoot",
78
- "showInColumn",
79
- "showModal",
80
- "dismissModal",
81
- "dismissAllModals",
82
- "showOverlay",
83
- "dismissOverlay",
84
- "dismissAllOverlays",
85
- )
86
-
87
- // The commands whose answer comes after the navigation state: those and `setColumnShown`.
88
- val STATE_COMMANDS = COMPLETED_COMMANDS + "setColumnShown"
89
- }
90
86
  }
91
87
 
92
88
  /** What goes to JavaScript around the answer of a command. Main thread only. */
93
89
  internal interface AnswerEvents {
94
- /** Right before the promise resolves: the navigation state, when it changed. */
95
- fun beforeAnswer()
90
+ /** The answer's one state step ([CommandAnswer.reportStateNow]): the navigation state now, when it changed. */
91
+ fun stateNow()
96
92
 
97
93
  /** After the promise resolved: `ANN.CommandCompleted`. */
98
94
  fun commandCompleted(commandName: String, commandId: String, completionTime: Long)
99
95
 
100
96
  /** Through the sender of the JavaScript that runs now. */
101
97
  object Current : AnswerEvents {
102
- override fun beforeAnswer() {
103
- val emitter = EventEmitter.current()
104
- if (emitter.canSend) NavigationStateReporter.updateNow(emitter)
105
- }
98
+ override fun stateNow() = NavigationState.updateNow()
106
99
 
107
100
  override fun commandCompleted(commandName: String, commandId: String, completionTime: Long) {
108
101
  EventEmitter.current().emitCommandCompleted(commandName, commandId, completionTime)
@@ -0,0 +1,59 @@
1
+ // Made by scripts/contract.mjs from src/interfaces/contract/commands.json: change that file and run the script again.
2
+
3
+ package dev.apexnative.navigation.react
4
+
5
+ /**
6
+ * What the commands with a promise answer, the same table as iOS. What each resolves with:
7
+ * - `setRoot`: the id of the root, once the root and the layout's modals and overlays show.
8
+ * - `push`: the id of the screen that shows; of a pair, the pair's id.
9
+ * - `preparePush`: the frame `{ width, height, padding }` of the prepared screen, or null; always null on iOS.
10
+ * - `pop`: the id of the screen that went.
11
+ * - `popTo`: the id of the screen it went back to.
12
+ * - `popToRoot`: the id of the first screen of the stack.
13
+ * - `setStackRoot`: the id of the new top screen.
14
+ * - `showModal`: the id of the modal's root.
15
+ * - `dismissModal`: the id of the modal's root.
16
+ * - `dismissAllModals`: an empty string.
17
+ * - `showOverlay`: the id of the overlay's root.
18
+ * - `dismissOverlay`: the id of the overlay's root.
19
+ * - `dismissAllOverlays`: an empty string.
20
+ * - `showInColumn`: the id of the screen that shows.
21
+ * - `setColumnShown`: nothing once the columns stopped moving (`undefined` on iOS, `null` on Android).
22
+ * - `getLaunchLink`: the link that launched the app, or null.
23
+ */
24
+ internal object CommandContract {
25
+ /** The commands whose answer comes after the navigation state: every one that may change what shows. */
26
+ val STATE: Set<String> = setOf(
27
+ "setRoot",
28
+ "push",
29
+ "pop",
30
+ "popTo",
31
+ "popToRoot",
32
+ "setStackRoot",
33
+ "showModal",
34
+ "dismissModal",
35
+ "dismissAllModals",
36
+ "showOverlay",
37
+ "dismissOverlay",
38
+ "dismissAllOverlays",
39
+ "showInColumn",
40
+ "setColumnShown",
41
+ )
42
+
43
+ /** The commands that send `ANN.CommandCompleted` after their answer: every one that shows or dismisses. */
44
+ val COMPLETED: Set<String> = setOf(
45
+ "setRoot",
46
+ "push",
47
+ "pop",
48
+ "popTo",
49
+ "popToRoot",
50
+ "setStackRoot",
51
+ "showModal",
52
+ "dismissModal",
53
+ "dismissAllModals",
54
+ "showOverlay",
55
+ "dismissOverlay",
56
+ "dismissAllOverlays",
57
+ "showInColumn",
58
+ )
59
+ }
@@ -0,0 +1,95 @@
1
+ package dev.apexnative.navigation.react
2
+
3
+ import android.content.Context
4
+ import android.util.Log
5
+ import com.facebook.react.interfaces.fabric.ReactSurface
6
+ import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
7
+ import com.facebook.react.modules.i18nmanager.I18nUtil
8
+ import com.facebook.react.runtime.ReactSurfaceImpl
9
+ import com.facebook.soloader.SoLoader
10
+ import dev.apexnative.navigation.utils.NavigationLog
11
+
12
+ /**
13
+ * The height of React content laid out at a width without a height limit, as iOS measures a sheet's `'content'`
14
+ * detent: Fabric lays out a copy of the tree, so the shown layout stays as it is. A React root's surface measures
15
+ * through `SurfaceHandler::measure`; a slot's content in the slot's own layout, once asked for ([requestSlot]), which
16
+ * keeps the height for [slotHeight] (`ANNSlotContentHeights`, the C++ iOS shares). The native half is the library's
17
+ * own C++ (`android/src/main/jni`), in the codegen library of its components; when that library doesn't load, nothing
18
+ * is measured. Main thread.
19
+ */
20
+ internal object ContentHeights {
21
+ private const val LIBRARY = "react_codegen_ApexNavigationSpec"
22
+
23
+ private val loaded: Boolean by lazy {
24
+ try {
25
+ SoLoader.loadLibrary(LIBRARY)
26
+ true
27
+ } catch (e: Throwable) {
28
+ Log.w(NavigationLog.TAG, "[ApexNavigation] $LIBRARY doesn't load: no content is measured", e)
29
+ false
30
+ }
31
+ }
32
+
33
+ /**
34
+ * The height of [surface]'s content at [width] pixels, in pixels, with the layout context the surface lays out
35
+ * with (`ReactSurfaceImpl.updateLayoutSpecs`); null before the surface runs or renders, or when it can't measure.
36
+ */
37
+ fun surfaceHeight(context: Context, surface: ReactSurface, width: Int): Int? {
38
+ if (width <= 0 || surface !is ReactSurfaceImpl || !loaded) return null
39
+ val density = context.resources.displayMetrics.density
40
+ val scalesFont = ReactNativeFeatureFlags.enableFontScaleChangesUpdatingLayout()
41
+ val fontScale = if (scalesFont) context.resources.configuration.fontScale else 1f
42
+ val height = try {
43
+ nativeSurfaceHeight(
44
+ surface,
45
+ width / density,
46
+ density,
47
+ fontScale,
48
+ I18nUtil.instance.isRTL(context),
49
+ I18nUtil.instance.doLeftAndRightSwapInRTL(context),
50
+ )
51
+ } catch (e: Throwable) {
52
+ Log.w(NavigationLog.TAG, "[ApexNavigation] the content of a surface can't be measured", e)
53
+ return null
54
+ }
55
+ return if (height > 0f) Math.round(height * density) else null
56
+ }
57
+
58
+ /** The content of the slot [slotId] is measured from its next layout on. */
59
+ fun requestSlot(slotId: String) {
60
+ if (loaded) nativeRequestSlot(slotId)
61
+ }
62
+
63
+ /** The content of the slot [slotId] is measured. */
64
+ fun isSlotRequested(slotId: String): Boolean = loaded && nativeIsSlotRequested(slotId)
65
+
66
+ /** The height of the content of the slot [slotId] at its last layout, in dp; null before it. */
67
+ fun slotHeight(slotId: String): Float? = if (loaded) nativeSlotHeight(slotId).takeIf { it >= 0f } else null
68
+
69
+ /** The screen of the slot [slotId] went: nothing more is measured for it. */
70
+ fun forgetSlot(slotId: String) {
71
+ if (loaded) nativeForgetSlot(slotId)
72
+ }
73
+
74
+ @JvmStatic
75
+ private external fun nativeRequestSlot(slotId: String)
76
+
77
+ @JvmStatic
78
+ private external fun nativeIsSlotRequested(slotId: String): Boolean
79
+
80
+ @JvmStatic
81
+ private external fun nativeSlotHeight(slotId: String): Float
82
+
83
+ @JvmStatic
84
+ private external fun nativeForgetSlot(slotId: String)
85
+
86
+ @JvmStatic
87
+ private external fun nativeSurfaceHeight(
88
+ surface: ReactSurfaceImpl,
89
+ width: Float,
90
+ pointScale: Float,
91
+ fontScale: Float,
92
+ rtl: Boolean,
93
+ swapLeftAndRight: Boolean,
94
+ ): Float
95
+ }
@@ -0,0 +1,66 @@
1
+ package dev.apexnative.navigation.react
2
+
3
+ import com.facebook.react.bridge.UIManager
4
+ import com.facebook.react.bridge.UIManagerListener
5
+ import com.facebook.react.common.annotations.UnstableReactNativeAPI
6
+ import com.facebook.react.uimanager.UIManagerHelper
7
+ import com.facebook.react.uimanager.common.UIManagerType
8
+ import dev.apexnative.navigation.NavigationApplication
9
+
10
+ /**
11
+ * The handlers of a screen's content that hear each mount of Fabric (`IReactView.setOnContentMounted`), by key, while
12
+ * [hears] holds (the content is in a window and not destroyed). Fabric tells every mount of the app, on the main
13
+ * thread, not those of one surface: the handlers measure and compare, so a mount elsewhere costs only that. It listens
14
+ * only while a handler waits. Main thread only.
15
+ */
16
+ internal class ContentMounts(private val hears: () -> Boolean) {
17
+ private val handlers = LinkedHashMap<String, Runnable>()
18
+ // The UI manager that tells the mounts; none while no handler waits.
19
+ private var uiManager: UIManager? = null
20
+
21
+ // React Native marks the listener unstable; it is the one place that tells a mount.
22
+ @OptIn(UnstableReactNativeAPI::class)
23
+ private val listener = object : UIManagerListener {
24
+ override fun willDispatchViewUpdates(uiManager: UIManager) = Unit
25
+
26
+ override fun willMountItems(uiManager: UIManager) = Unit
27
+
28
+ override fun didMountItems(uiManager: UIManager) {
29
+ if (hears()) run()
30
+ }
31
+
32
+ override fun didDispatchMountItems(uiManager: UIManager) = Unit
33
+
34
+ override fun didScheduleMountItems(uiManager: UIManager) = Unit
35
+ }
36
+
37
+ /** [handler] runs after each mount under [key]; null removes the handler of [key]. */
38
+ fun set(key: String, handler: Runnable?) {
39
+ if (handler == null) handlers.remove(key) else handlers[key] = handler
40
+ if (handlers.isEmpty()) stop() else start()
41
+ }
42
+
43
+ /** Runs the handlers now: a mount the content tells itself. */
44
+ fun run() = handlers.values.toList().forEach(Runnable::run)
45
+
46
+ /** The content goes: no handler runs again. */
47
+ fun clear() {
48
+ handlers.clear()
49
+ stop()
50
+ }
51
+
52
+ @OptIn(UnstableReactNativeAPI::class)
53
+ private fun start() {
54
+ if (uiManager != null) return
55
+ val reactContext = NavigationApplication.instanceOrNull?.reactGatewayOrNull?.currentReactContext ?: return
56
+ uiManager = UIManagerHelper.getUIManager(reactContext, UIManagerType.FABRIC)?.also {
57
+ it.addUIManagerEventListener(listener)
58
+ }
59
+ }
60
+
61
+ @OptIn(UnstableReactNativeAPI::class)
62
+ private fun stop() {
63
+ uiManager?.removeUIManagerEventListener(listener)
64
+ uiManager = null
65
+ }
66
+ }
@@ -1,3 +1,5 @@
1
+ // Made by scripts/contract.mjs from src/interfaces/contract/errors.json: change that file and run the script again.
2
+
1
3
  package dev.apexnative.navigation.react
2
4
 
3
5
  /**
@@ -6,116 +8,129 @@ package dev.apexnative.navigation.react
6
8
  * <command>:`.
7
9
  */
8
10
  internal object ErrorTexts {
9
- fun screenNotShown(id: String) = "the screen '$id' is not shown"
11
+ // Where the screen is.
12
+
13
+ fun screenNotShown(componentId: String) = "the screen '$componentId' is not shown"
10
14
 
11
- fun notInStack(id: String) = "the screen '$id' is not in a stack"
15
+ fun notInStack(componentId: String) = "the screen '$componentId' is not in a stack"
12
16
 
13
- fun firstScreenOfStack(id: String) = "the screen '$id' is the first screen of its stack"
17
+ fun firstScreenOfStack(componentId: String) = "the screen '$componentId' is the first screen of its stack"
14
18
 
15
- fun notInThisStack(id: String) = "the screen '$id' is not in this stack"
19
+ fun notInThisStack(componentId: String) = "the screen '$componentId' is not in this stack"
16
20
 
17
- fun notInModal(id: String) = "the screen '$id' is not in a modal"
21
+ fun notInModal(componentId: String) = "the screen '$componentId' is not in a modal"
18
22
 
19
- fun notInOverlay(id: String) = "the screen '$id' is not in an overlay"
23
+ fun notInOverlay(componentId: String) = "the screen '$componentId' is not in an overlay"
20
24
 
21
- fun notInSplitView(id: String) = "the screen '$id' is not in a split view"
25
+ fun notInSplitView(componentId: String) = "the screen '$componentId' is not in a split view"
22
26
 
23
- fun neitherSplitViewNorStack(id: String) = "the screen '$id' is neither in a split view nor in a stack"
27
+ fun neitherSplitViewNorStack(componentId: String) =
28
+ "the screen '$componentId' is neither in a split view nor in a stack"
24
29
 
25
- fun noSuchColumn(id: String, column: String) = "the split view of the screen '$id' has no '$column' column"
30
+ fun noSuchColumn(componentId: String, column: String) =
31
+ "the split view of the screen '$componentId' has no '$column' column"
26
32
 
27
- fun columnIsStack(id: String, column: String) =
28
- "the '$column' column of the split view of the screen '$id' is a stack: it takes a screen, not a stack"
33
+ fun columnIsStack(componentId: String, column: String) =
34
+ "the '$column' column of the split view of the screen '$componentId' is a stack: it takes a screen, not a stack"
29
35
 
30
- fun columnNotStack(id: String, column: String) =
31
- "the '$column' column of the split view of the screen '$id' is not a stack"
36
+ fun columnNotStack(componentId: String, column: String) =
37
+ "the '$column' column of the split view of the screen '$componentId' is not a stack"
32
38
 
33
- fun noScreensForStack(id: String) = "there are no screens to put in the stack of the screen '$id'"
39
+ fun noScreensForStack(componentId: String) = "there are no screens to put in the stack of the screen '$componentId'"
34
40
 
35
- fun alreadyShown(id: String) = "the screen '$id' shows already: an id goes to one screen"
41
+ fun alreadyShown(componentId: String) = "the screen '$componentId' shows already: an id goes to one screen"
36
42
 
37
- fun setRootReplaced(id: String) =
38
- "setRoot was replaced by a newer setRoot before the root '$id' finished showing"
43
+ // Root, modals, the app.
39
44
 
40
- fun rootDestroyed(id: String) = "the root '$id' was destroyed before it showed"
45
+ fun setRootReplaced(rootId: String) =
46
+ "setRoot was replaced by a newer setRoot before the root '$rootId' finished showing"
41
47
 
42
- fun modalWithoutRoot(id: String) = "the modal '$id' can't be dismissed: there is no root under it"
48
+ fun rootDestroyed(rootId: String) = "the root '$rootId' was destroyed before it showed"
49
+
50
+ fun modalWithoutRoot(componentId: String) = "the modal '$componentId' can't be dismissed: there is no root under it"
43
51
 
44
52
  fun nowhereToShow() = "the navigation has nowhere to show screens: the app has no activity or window"
45
53
 
54
+ // Native screens.
55
+
46
56
  fun nativeScreenNotRegistered(name: String) = "no native screen is registered as '$name'"
47
57
 
48
58
  fun nativeScreenNotCreated(name: String) =
49
59
  "the native screen '$name' could not be created: its creator returned nothing"
50
60
 
51
- fun unknownNodeType(type: String) = "the layout has a node of unknown type '$type'"
61
+ /** The error of a call of a native screen whose JavaScript reloaded before it answered. */
62
+ fun nativeCallReloaded(name: String, componentId: String) =
63
+ "JavaScript reloaded before the call '$name' of the screen '$componentId' was answered"
52
64
 
53
- fun nodeWithoutId(type: String) = "the layout has a node of type '$type' without an id"
65
+ /** The error of a call of a native screen while no JavaScript can answer it. */
66
+ fun nativeCallNotRunning(name: String, componentId: String) =
67
+ "the navigation is not running: the call '$name' of the screen '$componentId' can't be answered"
54
68
 
55
- fun sideMenuChild(id: String, type: String) =
56
- "the side menu '$id' has a child of type '$type': it takes SideMenuLeft, SideMenuCenter and SideMenuRight"
69
+ // The layout.
57
70
 
58
- fun stackTakesScreens(id: String, type: String) = "the stack '$id' takes screens, not a '$type'"
71
+ fun unknownNodeType(type: String) = "the layout has a node of unknown type '$type'"
59
72
 
60
- fun emptyStack(id: String) = "the stack '$id' has no screens"
73
+ fun nodeWithoutId(type: String) = "the layout has a node of type '$type' without an id"
61
74
 
62
- fun emptyTabs(id: String) = "the tabs '$id' have no tabs"
75
+ fun sideMenuChild(menuId: String, type: String) =
76
+ "the side menu '$menuId' has a child of type '$type': it takes SideMenuLeft, SideMenuCenter and SideMenuRight"
63
77
 
64
- fun tooManyTabs(id: String, count: Int) = "the tabs '$id' have $count tabs: Android shows at most 5"
78
+ fun stackTakesScreens(stackId: String, type: String) = "the stack '$stackId' takes screens, not a '$type'"
65
79
 
66
- fun splitViewColumns(id: String) = "the split view '$id' needs its primary and its secondary column"
80
+ fun emptyStack(stackId: String) = "the stack '$stackId' has no screens"
67
81
 
68
- fun pairUnsupported(id: String) = "the pair '$id' needs iOS 27.1 and an app built with its SDK"
82
+ fun emptyTabs(tabsId: String) = "the tabs '$tabsId' have no tabs"
69
83
 
70
- fun pairNeedsTwoScreens(id: String) = "the pair '$id' needs two screens: its primary and its secondary"
84
+ /** Only Android checks it: its tab bar shows at most 5 tabs. */
85
+ fun tooManyTabs(tabsId: String, count: Int) = "the tabs '$tabsId' have $count tabs: Android shows at most 5"
71
86
 
72
- fun unreadableOption(path: String, id: String) =
73
- "the option '$path' of the screen '$id' has a value the navigation can't read"
87
+ fun splitViewColumns(splitViewId: String) =
88
+ "the split view '$splitViewId' needs its primary and its secondary column"
74
89
 
75
- /** `setDefaultOptions` with a value it can't read; the default options before stay. */
76
- fun unreadableDefaultOption(path: String) =
77
- "the option '$path' of the default options has a value the navigation can't read"
90
+ /** Only iOS checks it: Android has pairs on every version. */
91
+ fun pairUnsupported(pairId: String) = "the pair '$pairId' needs iOS 27.1 and an app built with its SDK"
78
92
 
79
- fun previewGone(id: String) = "the preview '$id' went without being opened"
93
+ fun pairNeedsTwoScreens(pairId: String) = "the pair '$pairId' needs two screens: its primary and its secondary"
80
94
 
81
- /** Any other failure: [what] the command could not do, with its screen, and [reason]. */
82
- fun couldNot(what: String, reason: String) = "could not $what: $reason"
95
+ fun nodeWithoutName(type: String, nodeId: String) = "the layout has a node '$nodeId' of type '$type' without a name"
83
96
 
84
- fun nativeCallReloaded(name: String, id: String) =
85
- "JavaScript reloaded before the call '$name' of the screen '$id' was answered"
97
+ fun rootMissing() = "the layout of setRoot has no root"
86
98
 
87
- fun nativeCallNotRunning(name: String, id: String) =
88
- "the navigation is not running: the call '$name' of the screen '$id' can't be answered"
99
+ fun tabsInTabs(tabsId: String) = "the tabs '$tabsId' have a tab of type 'BottomTabs': tabs don't go inside tabs"
89
100
 
90
- /** `mergeOptions` without a navigation activity; written to the log, `mergeOptions` has no promise. */
91
- fun mergeOptionsNoActivity() = nowhereToShow()
101
+ fun sideMenuSides(menuId: String) =
102
+ "the side menu '$menuId' takes one SideMenuCenter and at most one SideMenuLeft and one SideMenuRight"
92
103
 
93
- /** A command whose area the native core doesn't do yet. */
94
- fun notDoneYet(method: String) = "could not run '$method': the native core doesn't do it yet"
104
+ fun sideChildCount(sideId: String, menuId: String) =
105
+ "the side '$sideId' of the side menu '$menuId' needs exactly one child"
95
106
 
96
- // The other cases of the layout checks: the same style.
107
+ fun sideMenuInSide(menuId: String) =
108
+ "the side menu '$menuId' has a side menu in a side: a side menu doesn't go inside a side menu"
97
109
 
98
- fun nodeWithoutName(type: String, id: String) = "the layout has a node '$id' of type '$type' without a name"
110
+ fun sideOutsideMenu(nodeId: String, type: String) =
111
+ "the layout has a node '$nodeId' of type '$type' outside a side menu"
99
112
 
100
- fun rootMissing() = "the layout of setRoot has no root"
113
+ fun splitViewInColumn(splitViewId: String) =
114
+ "the split view '$splitViewId' has a column of type 'SplitView': a split view doesn't go inside a split view"
101
115
 
102
- fun tabsInTabs(id: String) = "the tabs '$id' have a tab of type 'BottomTabs': tabs don't go inside tabs"
116
+ fun idGivenTwice(nodeId: String) = "the layout gives the id '$nodeId' to two nodes"
103
117
 
104
- fun sideMenuSides(id: String) =
105
- "the side menu '$id' takes one SideMenuCenter and at most one SideMenuLeft and one SideMenuRight"
118
+ // Options, previews, any other failure.
106
119
 
107
- fun sideChildCount(sideId: String, menuId: String) =
108
- "the side '$sideId' of the side menu '$menuId' needs exactly one child"
120
+ fun unreadableOption(path: String, componentId: String) =
121
+ "the option '$path' of the screen '$componentId' has a value the navigation can't read"
109
122
 
110
- fun sideMenuInSide(menuId: String) =
111
- "the side menu '$menuId' has a side menu in a side: a side menu doesn't go inside a side menu"
123
+ /** An unreadable value of `setDefaultOptions`: the default options belong to no screen. */
124
+ fun unreadableDefaultOption(path: String) =
125
+ "the option '$path' of the default options has a value the navigation can't read"
112
126
 
113
- fun sideOutsideMenu(id: String, type: String) = "the layout has a node '$id' of type '$type' outside a side menu"
127
+ fun previewGone(previewId: String) = "the preview '$previewId' went without being opened"
114
128
 
115
- fun splitViewInColumn(id: String) =
116
- "the split view '$id' has a column of type 'SplitView': a split view doesn't go inside a split view"
129
+ /** Any other failure: what could not be done and why, `could not <what>: <reason>`. */
130
+ fun couldNot(what: String, reason: String) = "could not $what: $reason"
117
131
 
118
- fun idGivenTwice(id: String) = "the layout gives the id '$id' to two nodes"
132
+ /** A command whose part of the native core is not written yet. */
133
+ fun notDoneYet(method: String) = "could not run '$method': the native core doesn't do it yet"
119
134
 
120
135
  /** The reason of [couldNot] for an exception: its message, else the name of its class. */
121
136
  fun reasonOf(e: Throwable): String =
@@ -9,26 +9,32 @@ import android.os.Build
9
9
  import androidx.lifecycle.DefaultLifecycleObserver
10
10
  import androidx.lifecycle.Lifecycle
11
11
  import androidx.lifecycle.LifecycleOwner
12
- import com.facebook.react.ReactApplication
13
12
  import com.facebook.react.bridge.Arguments
14
13
  import com.facebook.react.bridge.WritableMap
14
+ import dev.apexnative.navigation.react.events.EventContract
15
15
  import dev.apexnative.navigation.react.events.EventEmitter
16
16
  import dev.apexnative.navigation.utils.WindowFolds
17
17
  import java.lang.ref.WeakReference
18
18
 
19
19
  /**
20
20
  * The device's hinge (`useHinge`): its state from the fold in the activity's window, its angle from the hinge angle
21
- * sensor (Android 11+). Android has no public state of a closed device: closed is a window without a fold and an
22
- * angle under 90°. No sensor and no fold: no hinge, `{}`. It runs while JavaScript has a hook mounted
23
- * (`setHingeUpdates`), the sensor only while the activity is resumed too; the same value is not sent twice. Main
24
- * thread only, but [get].
21
+ * sensor (Android 11+), in degrees to a tenth as on iOS. Android has no public state of a closed device: closed is a
22
+ * window without a fold, or an angle under 90° ([valueOf]). No sensor and no fold: no hinge, `{}`. It runs while
23
+ * JavaScript has a hook mounted (`setHingeUpdates`), the sensor only while the activity is resumed too; the same value
24
+ * is not sent twice. The values go to the JavaScript that turned the updates on (`EventEmitter.current` then): after a
25
+ * reload, until the updates stop, they go nowhere. Main thread only, but [get].
25
26
  */
26
27
  internal object Hinge {
27
- data class Value(val state: String, val angle: Float?)
28
+ /** A value of the hinge: its state, and its angle in degrees to a tenth; none while the state is unknown. */
29
+ data class Value(val state: String, val angle: Double?)
30
+
31
+ private const val UNKNOWN = "unknown"
28
32
 
29
33
  private const val CLOSED_BELOW = 90f
30
34
 
31
35
  private var enabled = false
36
+ // The sender of the JavaScript that turned the updates on; none while they are off.
37
+ private var emitter: EventEmitter? = null
32
38
  private var activity: WeakReference<Activity>? = null
33
39
  private var folds: WindowFolds? = null
34
40
  private var sensorManager: SensorManager? = null
@@ -59,9 +65,11 @@ internal object Hinge {
59
65
  fun setEnabled(activity: Activity?, enabled: Boolean) {
60
66
  this.enabled = enabled
61
67
  if (!enabled) {
68
+ emitter = null
62
69
  detach()
63
70
  return
64
71
  }
72
+ emitter = EventEmitter.current()
65
73
  activity?.let(::attachTo)
66
74
  update()
67
75
  }
@@ -127,28 +135,32 @@ internal object Hinge {
127
135
  if (!enabled) return
128
136
  val folds = folds ?: return
129
137
  if (!folds.hasInfo || (listening && angle == null)) return
130
- val fold = folds.folds.firstOrNull()
131
- val angle = angle
132
- val value = if (fold == null && sensor == null) {
133
- null
134
- } else {
135
- val state = when {
136
- fold?.halfOpened == true -> "partiallyOpen"
137
- fold != null -> "fullyOpen"
138
- angle != null && angle < CLOSED_BELOW -> "closed"
139
- else -> "unknown"
140
- }
141
- Value(state, angle)
142
- }
138
+ val value = valueOf(folds.folds.firstOrNull(), sensor != null, angle)
143
139
  if (value == last) return
144
140
  last = value
145
- val reactContext = (activity?.get()?.application as? ReactApplication)?.reactHost?.currentReactContext ?: return
146
- EventEmitter(reactContext).emitHingeChanged(toMap(value))
141
+ emitter?.emitHingeChanged(toMap(value))
142
+ }
143
+
144
+ /**
145
+ * The value of the window's first [fold] and the sensor's [angle]: none without a fold and without a sensor
146
+ * ([hasSensor]). `closed` without a fold or under 90°, else `partiallyOpen` for a half-opened fold and `fullyOpen`
147
+ * for a flat one. The angle goes to a tenth, as iOS gives it: the sensor's noise doesn't make a new value, and it
148
+ * is left out while the state is unknown.
149
+ */
150
+ fun valueOf(fold: WindowFolds.Fold?, hasSensor: Boolean, angle: Float?): Value? {
151
+ if (fold == null && !hasSensor) return null
152
+ val state = when {
153
+ fold == null || (angle != null && angle < CLOSED_BELOW) -> "closed"
154
+ fold.halfOpened -> "partiallyOpen"
155
+ else -> "fullyOpen"
156
+ }
157
+ val tenths = angle?.let { Math.round(it * 10.0) / 10.0 }
158
+ return Value(state, tenths.takeIf { state != UNKNOWN })
147
159
  }
148
160
 
149
161
  private fun toMap(value: Value?): WritableMap = Arguments.createMap().apply {
150
162
  if (value == null) return@apply
151
- putString("state", value.state)
152
- value.angle?.let { putDouble("angle", it.toDouble()) }
163
+ putString(EventContract.HingeChanged.STATE, value.state)
164
+ if (value.state != UNKNOWN) value.angle?.let { putDouble(EventContract.HingeChanged.ANGLE, it) }
153
165
  }
154
166
  }