@apexnative/navigation 1.0.0-alpha.1 → 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 (573) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +120 -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/docs-md/architecture/native-screens.md +4 -0
  175. package/docs-md/architecture/theme-and-context.md +131 -12
  176. package/docs-md/architecture/transitions.md +58 -12
  177. package/docs-md/containers/modals.md +8 -4
  178. package/docs-md/containers/overlays.md +3 -1
  179. package/docs-md/containers/side-menu.md +19 -2
  180. package/docs-md/containers/tabs.md +5 -1
  181. package/docs-md/flows/bottom-sheets.md +4 -2
  182. package/docs-md/flows/forms-in-a-modal.md +1 -1
  183. package/docs-md/fundamentals/screens-and-props.md +9 -1
  184. package/docs-md/fundamentals/starting-the-app.md +1 -1
  185. package/docs-md/guides/cli.md +4 -3
  186. package/docs-md/guides/deep-links.md +15 -33
  187. package/docs-md/help/glossary.md +4 -4
  188. package/docs-md/help/troubleshooting.md +44 -6
  189. package/docs-md/index.json +57 -1
  190. package/docs-md/migration/from-expo-router.md +1 -1
  191. package/docs-md/migration/from-react-native-navigation.md +9 -3
  192. package/docs-md/migration/from-react-navigation.md +2 -2
  193. package/docs-md/screen-ui/back-and-gestures.md +46 -2
  194. package/docs-md/screen-ui/bar-buttons.md +5 -5
  195. package/docs-md/screen-ui/search.md +1 -1
  196. package/docs-md/screen-ui/system-ui.md +17 -12
  197. package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
  198. package/docs-md/screen-ui/top-bar.md +8 -4
  199. package/docs-md/start/installation.md +21 -3
  200. package/ios/Animations/ANNFrameDriver.h +55 -15
  201. package/ios/Animations/ANNFrameDriver.mm +216 -60
  202. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  203. package/ios/Animations/ANNTransitionAnimator.mm +61 -13
  204. package/ios/Animations/ANNTransitionPlan.h +2 -2
  205. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  206. package/ios/Animations/ANNTransitionWait.mm +6 -7
  207. package/ios/Animations/Elements/ANNElementFinder.h +57 -0
  208. package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
  209. package/ios/Animations/Elements/ANNElementTransition.h +10 -8
  210. package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
  211. package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
  212. package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
  213. package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
  214. package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
  215. package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
  216. package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
  217. package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
  218. package/ios/CLAUDE.md +60 -24
  219. package/ios/CORE.md +44 -34
  220. package/ios/Contract/ANNCommandAnswer.h +13 -5
  221. package/ios/Contract/ANNCommandAnswer.mm +40 -32
  222. package/ios/Contract/ANNCommandContract.h +15 -0
  223. package/ios/Contract/ANNCommandContract.mm +78 -0
  224. package/ios/Contract/ANNCommandRunner.h +10 -9
  225. package/ios/Contract/ANNCommandRunner.mm +22 -28
  226. package/ios/Contract/ANNErrorTexts.h +6 -2
  227. package/ios/Contract/ANNErrorTexts.mm +18 -10
  228. package/ios/Contract/ANNLayoutNode.h +3 -3
  229. package/ios/Contract/ANNLayoutReader.h +3 -3
  230. package/ios/Core/ANNAppDelegate.mm +0 -2
  231. package/ios/Core/ANNAppearanceDispatcher.h +5 -4
  232. package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
  233. package/ios/Core/ANNDeepLinkQueue.h +22 -2
  234. package/ios/Core/ANNDeepLinkQueue.mm +121 -14
  235. package/ios/Core/ANNErrorHandler.h +9 -4
  236. package/ios/Core/ANNErrorHandler.mm +20 -2
  237. package/ios/Core/ANNEventContract.h +246 -0
  238. package/ios/Core/ANNEventContract.mm +225 -0
  239. package/ios/Core/ANNEventEmitter.h +6 -2
  240. package/ios/Core/ANNEventEmitter.mm +117 -80
  241. package/ios/Core/ANNHinge.h +6 -0
  242. package/ios/Core/ANNHinge.mm +15 -4
  243. package/ios/Core/ANNJavaScriptCalls.h +33 -0
  244. package/ios/Core/ANNJavaScriptCalls.mm +52 -0
  245. package/ios/Core/ANNLayoutProtocol.h +5 -5
  246. package/ios/Core/ANNNavigationState.h +7 -5
  247. package/ios/Core/ANNNavigationState.mm +8 -7
  248. package/ios/Core/ANNNodeHelper.h +32 -12
  249. package/ios/Core/ANNNodeHelper.mm +100 -3
  250. package/ios/Core/ANNParking.h +5 -4
  251. package/ios/Core/ANNReloadCoordinator.mm +5 -12
  252. package/ios/Core/ANNRenderWait.h +20 -6
  253. package/ios/Core/ANNRenderWait.mm +143 -56
  254. package/ios/Core/ANNSceneDelegate.mm +25 -15
  255. package/ios/Core/ANNSystemUI.h +3 -2
  256. package/ios/Core/ANNSystemUI.mm +7 -0
  257. package/ios/Core/ANNUtils.h +7 -0
  258. package/ios/Core/ANNUtils.mm +10 -0
  259. package/ios/Core/ApexNavigation+Internal.h +1 -1
  260. package/ios/Core/ApexNavigation.mm +7 -6
  261. package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
  262. package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
  263. package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
  264. package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
  265. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +10 -8
  266. package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
  267. package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
  268. package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
  269. package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
  270. package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
  271. package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
  272. package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
  273. package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
  274. package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
  275. package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
  276. package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
  277. package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
  278. package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
  279. package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
  280. package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
  281. package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
  282. package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
  283. package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
  284. package/ios/Layouts/Screen/ANNScreenPlace.h +53 -0
  285. package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
  286. package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
  287. package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
  288. package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
  289. package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
  290. package/ios/Layouts/Screen/ANNScreenSettling.h +32 -0
  291. package/ios/Layouts/Screen/ANNScreenSettling.mm +137 -0
  292. package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
  293. package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
  294. package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
  295. package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
  296. package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
  297. package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
  298. package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
  299. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  300. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  301. package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
  302. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  303. package/ios/Layouts/Stack/ANNStackController.mm +184 -16
  304. package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
  305. package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
  306. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  307. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  308. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  309. package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
  310. package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
  311. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
  312. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
  313. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
  314. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
  315. package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
  316. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
  317. package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
  318. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
  319. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
  320. package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
  321. package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
  322. package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
  323. package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
  324. package/ios/Options/ANNAnimationOptions.h +2 -1
  325. package/ios/Options/ANNAnimationOptions.mm +1 -1
  326. package/ios/Options/ANNBottomTabsOptions.h +2 -0
  327. package/ios/Options/ANNBottomTabsOptions.mm +1 -0
  328. package/ios/Options/ANNOptions.h +25 -0
  329. package/ios/Options/ANNOptions.mm +157 -1
  330. package/ios/Options/ANNOptionsCache.h +7 -6
  331. package/ios/Options/ANNOptionsReader.mm +108 -0
  332. package/ios/Options/ANNSearchBarOptions.h +4 -3
  333. package/ios/Options/ANNSheetOptions.h +4 -1
  334. package/ios/Options/ANNSideMenuOptions.h +2 -0
  335. package/ios/Options/ANNSideMenuOptions.mm +2 -0
  336. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  337. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  338. package/ios/Options/ANNUserChoice.h +57 -0
  339. package/ios/Options/ANNUserChoice.mm +44 -0
  340. package/ios/Options/Params/ANNImageSource.h +61 -0
  341. package/ios/Options/Params/ANNImageSource.mm +101 -0
  342. package/ios/Options/Params/ANNOptionImages.h +37 -0
  343. package/ios/Options/Params/ANNOptionImages.mm +284 -0
  344. package/ios/Options/Params/ANNParam.h +15 -0
  345. package/ios/Options/Params/ANNParam.mm +61 -0
  346. package/ios/Options/Params/Color.h +3 -0
  347. package/ios/Options/Params/Color.mm +21 -0
  348. package/ios/Options/Params/ColorParser.h +4 -3
  349. package/ios/Options/Params/ColorParser.mm +22 -4
  350. package/ios/Options/Params/Image.h +15 -2
  351. package/ios/Options/Params/Image.mm +35 -2
  352. package/ios/Options/Params/ImageParser.h +5 -5
  353. package/ios/Options/Params/ImageParser.mm +28 -46
  354. package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
  355. package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
  356. package/ios/RECIPES.md +13 -6
  357. package/ios/React/ANNReactView.mm +6 -25
  358. package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
  359. package/ios/React/ANNSurfaceHostingView.h +14 -0
  360. package/ios/React/ANNSurfaceHostingView.mm +144 -1
  361. package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
  362. package/ios/React/Slots/ANNSlotContainers.h +14 -6
  363. package/ios/React/Slots/ANNSlotContainers.mm +75 -2
  364. package/ios/React/Slots/ANNSlotHost.mm +1 -3
  365. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  366. package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
  367. package/ios/TopBar/ANNBarAppearance.h +2 -1
  368. package/ios/TopBar/ANNBarAppearance.mm +111 -30
  369. package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
  370. package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
  371. package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
  372. package/ios/TopBar/ANNBarButtons.h +14 -8
  373. package/ios/TopBar/ANNBarButtons.mm +397 -80
  374. package/ios/TopBar/ANNIconButtonImage.h +1 -0
  375. package/ios/TopBar/ANNIconButtonImage.mm +34 -1
  376. package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
  377. package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
  378. package/ios/TopBar/ANNMainList.h +3 -0
  379. package/ios/TopBar/ANNMainList.mm +4 -0
  380. package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
  381. package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
  382. package/ios/TopBar/ANNSearchPresenter.mm +172 -21
  383. package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
  384. package/ios/TopBar/ANNTopBarPresenter.h +8 -2
  385. package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
  386. package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
  387. package/ios/TurboModules/ANNTurboModule.mm +104 -33
  388. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  389. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  390. package/lib/module/ARCHITECTURE.md +40 -27
  391. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  392. package/lib/module/api/app/AppRegistry.js +14 -2
  393. package/lib/module/api/app/AppRegistry.js.map +1 -1
  394. package/lib/module/api/app/createNavigation.js +190 -66
  395. package/lib/module/api/app/createNavigation.js.map +1 -1
  396. package/lib/module/api/commands/commands.js +54 -6
  397. package/lib/module/api/commands/commands.js.map +1 -1
  398. package/lib/module/api/events/navigationEvents.js +6 -2
  399. package/lib/module/api/events/navigationEvents.js.map +1 -1
  400. package/lib/module/api/hooks/useNavigation.js +8 -3
  401. package/lib/module/api/hooks/useNavigation.js.map +1 -1
  402. package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
  403. package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
  404. package/lib/module/api/linking/dispatchedLinks.js +23 -0
  405. package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
  406. package/lib/module/api/linking/linking.js +11 -0
  407. package/lib/module/api/linking/linking.js.map +1 -1
  408. package/lib/module/api/navigation.js.map +1 -1
  409. package/lib/module/api/options/OptionsChain.js +2 -2
  410. package/lib/module/api/screens/defineScreen.js +45 -3
  411. package/lib/module/api/screens/defineScreen.js.map +1 -1
  412. package/lib/module/api/screens/nativeScreens.js +31 -6
  413. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  414. package/lib/module/api/screens/registerScreens.js +193 -35
  415. package/lib/module/api/screens/registerScreens.js.map +1 -1
  416. package/lib/module/api/theme/theme.js +5 -0
  417. package/lib/module/api/theme/theme.js.map +1 -1
  418. package/lib/module/engine/commands.js +51 -9
  419. package/lib/module/engine/commands.js.map +1 -1
  420. package/lib/module/engine/layout.js +20 -11
  421. package/lib/module/engine/layout.js.map +1 -1
  422. package/lib/module/engine/nativeScreens.js +9 -0
  423. package/lib/module/engine/nativeScreens.js.map +1 -1
  424. package/lib/module/engine/options.js +49 -15
  425. package/lib/module/engine/options.js.map +1 -1
  426. package/lib/module/engine/optionsChange.js +102 -0
  427. package/lib/module/engine/optionsChange.js.map +1 -0
  428. package/lib/module/engine/places.js +52 -7
  429. package/lib/module/engine/places.js.map +1 -1
  430. package/lib/module/engine/props.js +30 -1
  431. package/lib/module/engine/props.js.map +1 -1
  432. package/lib/module/engine/refresh.js +85 -0
  433. package/lib/module/engine/refresh.js.map +1 -0
  434. package/lib/module/engine/rememberedOptions.js +61 -1
  435. package/lib/module/engine/rememberedOptions.js.map +1 -1
  436. package/lib/module/engine/screens.js +77 -16
  437. package/lib/module/engine/screens.js.map +1 -1
  438. package/lib/module/interfaces/contract/commands.json +101 -0
  439. package/lib/module/interfaces/contract/errors.json +275 -0
  440. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
  441. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  442. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  443. package/lib/typescript/api/app/createNavigation.d.ts +8 -3
  444. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  445. package/lib/typescript/api/commands/commands.d.ts.map +1 -1
  446. package/lib/typescript/api/commands/presentation.d.ts +4 -3
  447. package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
  448. package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
  449. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  450. package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
  451. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  452. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
  453. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
  454. package/lib/typescript/api/index.d.ts +1 -1
  455. package/lib/typescript/api/index.d.ts.map +1 -1
  456. package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
  457. package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
  458. package/lib/typescript/api/linking/linking.d.ts +8 -0
  459. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  460. package/lib/typescript/api/navigation.d.ts +4 -1
  461. package/lib/typescript/api/navigation.d.ts.map +1 -1
  462. package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
  463. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  464. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  465. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  466. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  467. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  468. package/lib/typescript/api/theme/theme.d.ts +2 -0
  469. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  470. package/lib/typescript/engine/commands.d.ts +5 -0
  471. package/lib/typescript/engine/commands.d.ts.map +1 -1
  472. package/lib/typescript/engine/layout.d.ts.map +1 -1
  473. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  474. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  475. package/lib/typescript/engine/options.d.ts +5 -2
  476. package/lib/typescript/engine/options.d.ts.map +1 -1
  477. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  478. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  479. package/lib/typescript/engine/places.d.ts +7 -2
  480. package/lib/typescript/engine/places.d.ts.map +1 -1
  481. package/lib/typescript/engine/props.d.ts +8 -1
  482. package/lib/typescript/engine/props.d.ts.map +1 -1
  483. package/lib/typescript/engine/refresh.d.ts +35 -0
  484. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  485. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  486. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  487. package/lib/typescript/engine/screens.d.ts +27 -6
  488. package/lib/typescript/engine/screens.d.ts.map +1 -1
  489. package/lib/typescript/interfaces/ComponentEvents.d.ts +4 -4
  490. package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
  491. package/lib/typescript/interfaces/Events.d.ts +28 -10
  492. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  493. package/lib/typescript/interfaces/Options.d.ts +1 -1
  494. package/lib/typescript/interfaces/Options.d.ts.map +1 -1
  495. package/lib/typescript/interfaces/options/animations.d.ts +80 -22
  496. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  497. package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
  498. package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
  499. package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
  500. package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
  501. package/lib/typescript/interfaces/options/modals.d.ts +34 -26
  502. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  503. package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
  504. package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
  505. package/lib/typescript/interfaces/options/stack.d.ts +17 -3
  506. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  507. package/lib/typescript/interfaces/options/system.d.ts +18 -11
  508. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  509. package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
  510. package/lib/typescript/interfaces/options/topBar.d.ts +68 -38
  511. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  512. package/metro/acceptPlugin.js +57 -0
  513. package/metro/babelTransformer.js +45 -0
  514. package/metro/index.js +36 -0
  515. package/package.json +3 -1
  516. package/src/ARCHITECTURE.md +40 -27
  517. package/src/adapters/NativeANNTurboModule.ts +12 -2
  518. package/src/api/app/AppRegistry.ts +16 -2
  519. package/src/api/app/createNavigation.ts +203 -69
  520. package/src/api/commands/commands.ts +48 -7
  521. package/src/api/commands/presentation.ts +4 -3
  522. package/src/api/events/navigationEvents.ts +10 -4
  523. package/src/api/hooks/useNavigation.ts +9 -4
  524. package/src/api/hooks/useSafeAreaInsets.ts +4 -3
  525. package/src/api/index.ts +1 -0
  526. package/src/api/linking/dispatchedLinks.ts +18 -0
  527. package/src/api/linking/linking.ts +22 -1
  528. package/src/api/navigation.ts +4 -1
  529. package/src/api/options/OptionsChain.ts +2 -2
  530. package/src/api/screens/defineScreen.ts +49 -5
  531. package/src/api/screens/nativeScreens.ts +40 -4
  532. package/src/api/screens/registerScreens.tsx +185 -42
  533. package/src/api/theme/theme.ts +5 -0
  534. package/src/engine/commands.ts +70 -13
  535. package/src/engine/layout.ts +27 -11
  536. package/src/engine/nativeScreens.ts +10 -1
  537. package/src/engine/options.ts +45 -19
  538. package/src/engine/optionsChange.ts +107 -0
  539. package/src/engine/places.ts +65 -7
  540. package/src/engine/props.ts +30 -1
  541. package/src/engine/refresh.ts +97 -0
  542. package/src/engine/rememberedOptions.ts +74 -1
  543. package/src/engine/screens.tsx +76 -21
  544. package/src/interfaces/ComponentEvents.ts +4 -4
  545. package/src/interfaces/Events.ts +29 -10
  546. package/src/interfaces/Options.ts +1 -0
  547. package/src/interfaces/contract/commands.json +101 -0
  548. package/src/interfaces/contract/errors.json +275 -0
  549. package/src/interfaces/options/animations.ts +81 -22
  550. package/src/interfaces/options/bottomTabs.ts +21 -7
  551. package/src/interfaces/options/buttons.ts +23 -15
  552. package/src/interfaces/options/modals.ts +34 -26
  553. package/src/interfaces/options/sideMenu.ts +24 -6
  554. package/src/interfaces/options/stack.ts +17 -3
  555. package/src/interfaces/options/system.ts +18 -11
  556. package/src/interfaces/options/toolbar.ts +2 -2
  557. package/src/interfaces/options/topBar.ts +68 -38
  558. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
  559. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
  560. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
  561. package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
  562. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
  563. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  564. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -138
  565. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
  566. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  567. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -66
  568. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
  569. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
  570. package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
  571. package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
  572. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
  573. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
@@ -55,6 +55,10 @@ class NavigationTurboModule(reactContext: ReactApplicationContext) : NativeANNTu
55
55
  override fun mergeOptions(componentId: String, options: ReadableMap) =
56
56
  optionsCommands.mergeOptions(componentId, options)
57
57
 
58
+ // Development (Fast Refresh): the options an edit took out of a screen that shows; as mergeOptions without one.
59
+ override fun clearOptions(componentId: String, paths: ReadableArray) =
60
+ optionsCommands.clearOptions(componentId, paths)
61
+
58
62
  override fun push(commandId: String, componentId: String, layout: ReadableMap, promise: Promise) {
59
63
  val what = "push the screen '${LayoutReader.idOf(layout)}'"
60
64
  runner.run(
@@ -211,7 +215,7 @@ class NavigationTurboModule(reactContext: ReactApplicationContext) : NativeANNTu
211
215
  layout: ReadableMap,
212
216
  promise: Promise,
213
217
  ) {
214
- // Android has one column to show screens in: the secondary pane (`showInColumn`).
218
+ // Android's split view has the primary and the secondary pane; another column rejects (`showInColumn`).
215
219
  val what = "show the screen '${LayoutReader.idOf(layout)}' in the '$column' column"
216
220
  runner.run(
217
221
  name = "showInColumn",
@@ -219,7 +223,7 @@ class NavigationTurboModule(reactContext: ReactApplicationContext) : NativeANNTu
219
223
  what = what,
220
224
  promise = promise,
221
225
  check = { LayoutReader.node(layout, context = appContext()) },
222
- ) { node, answer -> navigator().stackCommands.showInColumn(componentId, node, answer, what) }
226
+ ) { node, answer -> navigator().stackCommands.showInColumn(componentId, column, node, answer, what) }
223
227
  }
224
228
 
225
229
  override fun setColumnShown(
@@ -236,11 +240,11 @@ class NavigationTurboModule(reactContext: ReactApplicationContext) : NativeANNTu
236
240
  check = {},
237
241
  ) { _, answer -> navigator().stackCommands.setColumnShown(componentId, column, shown, answer) }
238
242
 
239
- override fun getArrangementState(componentId: String): WritableMap = ArrangementStates.get(componentId)
243
+ override fun getArrangementState(componentId: String): WritableMap = ScreenEnvironment.getArrangementState(componentId)
240
244
 
241
- override fun getScreenInsets(componentId: String): WritableMap = ScreenInsets.get(componentId)
245
+ override fun getScreenInsets(componentId: String): WritableMap = ScreenEnvironment.getScreenInsets(componentId)
242
246
 
243
- override fun getScreenRegions(componentId: String): WritableMap = ScreenRegions.get(componentId)
247
+ override fun getScreenRegions(componentId: String): WritableMap = ScreenEnvironment.getScreenRegions(componentId)
244
248
 
245
249
  // With the activity the user sees, if there is one; the hinge remembers it and goes on with the next activity
246
250
  // (`Hinge.attach`).
@@ -295,9 +299,10 @@ class NavigationTurboModule(reactContext: ReactApplicationContext) : NativeANNTu
295
299
  })
296
300
  }
297
301
 
298
- // The navigation of the activity the command runs in; the runner checked there is one.
302
+ // The navigation of the activity the command runs in; the runner checked there is an activity. One without its
303
+ // navigation yet (or any more) has nowhere to show screens either: the command rejects with the runner's own text.
299
304
  private fun navigator(): Navigator =
300
- requireNotNull(Navigators.current()?.navigator) { "the activity has no navigation" }
305
+ Navigators.current()?.navigator ?: throw LayoutException(ErrorTexts.nowhereToShow())
301
306
 
302
307
  // The app's context, which the colors of the options resolve platform colors with.
303
308
  private fun appContext(): Context = reactApplicationContext.applicationContext
@@ -1,8 +1,11 @@
1
1
  package dev.apexnative.navigation.react
2
2
 
3
3
  import android.content.Context
4
+ import com.facebook.react.bridge.ReadableArray
4
5
  import com.facebook.react.bridge.ReadableMap
6
+ import com.facebook.react.bridge.ReadableType
5
7
  import dev.apexnative.navigation.options.DefaultOptions
8
+ import dev.apexnative.navigation.options.OptionPaths
6
9
  import dev.apexnative.navigation.options.Options
7
10
  import dev.apexnative.navigation.options.OptionsReader
8
11
  import dev.apexnative.navigation.system.AppDirection
@@ -10,9 +13,9 @@ import dev.apexnative.navigation.viewcontrollers.navigator.Navigators
10
13
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
11
14
 
12
15
  /**
13
- * The commands of the options, `setDefaultOptions` and `mergeOptions`: both without a promise. Their options are read
14
- * on the module thread, in the runner's step before the main task; the main task stores and applies them. What can't be
15
- * read is logged (`[ApexNavigation] <method>: <text>`); the app goes on.
16
+ * The commands of the options, `setDefaultOptions`, `mergeOptions` and `clearOptions`: all without a promise. Their
17
+ * options and paths are read on the module thread, in the runner's step before the main task; the main task stores
18
+ * and applies them. What can't be read is logged (`[ApexNavigation] <method>: <text>`); the app goes on.
16
19
  */
17
20
  internal class OptionsCommands(
18
21
  private val runner: CommandRunner,
@@ -30,6 +33,11 @@ internal class OptionsCommands(
30
33
  * system UI follows (`Navigator.optionsMerged`, `mergeOptions` step 5). Main thread.
31
34
  */
32
35
  private val merged: (ViewController<*>, Options) -> Unit = { _, _ -> },
36
+ /**
37
+ * Repaints what shows in the current navigation activity, as [repaint] does without new default options
38
+ * (`Navigator.repaint`), after `clearOptions`. Main thread.
39
+ */
40
+ private val repaintCurrent: () -> Unit = {},
33
41
  ) {
34
42
  constructor(runner: CommandRunner, context: () -> Context?) : this(
35
43
  runner = runner,
@@ -40,6 +48,7 @@ internal class OptionsCommands(
40
48
  Navigators.all().forEach { it.navigator?.defaultOptionsChanged(direction) }
41
49
  },
42
50
  merged = { node, options -> Navigators.current()?.navigator?.optionsMerged(node, options) },
51
+ repaintCurrent = { Navigators.current()?.navigator?.repaint() },
43
52
  )
44
53
 
45
54
  /**
@@ -73,7 +82,7 @@ internal class OptionsCommands(
73
82
  prepare = { OptionsReader.read(options, context()) },
74
83
  ) { read ->
75
84
  if (!runner.hasActivity()) {
76
- runner.logFailure(MERGE_OPTIONS, ErrorTexts.mergeOptionsNoActivity())
85
+ runner.logFailure(MERGE_OPTIONS, ErrorTexts.nowhereToShow())
77
86
  return@runVoid
78
87
  }
79
88
  val node = findNode(componentId) ?: return@runVoid
@@ -82,8 +91,37 @@ internal class OptionsCommands(
82
91
  merged(node, read.options)
83
92
  }
84
93
 
94
+ /**
95
+ * `clearOptions` (development: Fast Refresh, after an edit took options out of a screen that shows): the values at
96
+ * [paths] (`topBar.subtitle`; a group's path for the whole group) leave the own options of the node [componentId]
97
+ * names, through `ViewController.changeOptions` ([OptionPaths.clear]), so it resolves to what the layouts around it
98
+ * and the defaults give there; the user layer stays. The stack it is in writes its back arrow's visibility into
99
+ * them again (`StackController.ownOptionsCleared`), then what shows is repainted as after `setDefaultOptions`. No
100
+ * node with that id, or no path that names an option: nothing, not even a log line. Without an activity: one log
101
+ * line, as `mergeOptions`.
102
+ */
103
+ fun clearOptions(componentId: String, paths: ReadableArray) = runner.runVoid(
104
+ name = CLEAR_OPTIONS,
105
+ what = "clear the options of the screen '$componentId'",
106
+ prepare = {
107
+ (0 until paths.size()).filter { paths.getType(it) == ReadableType.String }.mapNotNull(paths::getString)
108
+ },
109
+ ) { read ->
110
+ if (!runner.hasActivity()) {
111
+ runner.logFailure(CLEAR_OPTIONS, ErrorTexts.nowhereToShow())
112
+ return@runVoid
113
+ }
114
+ val node = findNode(componentId) ?: return@runVoid
115
+ val known = read.filter { OptionPaths.find(node.options, it) != null }
116
+ if (known.isEmpty()) return@runVoid
117
+ node.changeOptions { own -> known.forEach { OptionPaths.clear(own, it) } }
118
+ node.findParentStack()?.ownOptionsCleared(node)
119
+ repaintCurrent()
120
+ }
121
+
85
122
  private companion object {
86
123
  const val SET_DEFAULT_OPTIONS = "setDefaultOptions"
87
124
  const val MERGE_OPTIONS = "mergeOptions"
125
+ const val CLEAR_OPTIONS = "clearOptions"
88
126
  }
89
127
  }
@@ -0,0 +1,48 @@
1
+ package dev.apexnative.navigation.react
2
+
3
+ import dev.apexnative.navigation.NavigationApplication
4
+ import dev.apexnative.navigation.utils.UiThread
5
+
6
+ /**
7
+ * The calls JavaScript made to the module that may not have reached the main thread yet: [after] runs a task on the
8
+ * main thread behind every one of them. A screen's first mount reaches the main thread from Fabric while a
9
+ * `mergeOptions` of the same React commit (its layout effects: `useScreenOptions`) may still be on its way: an
10
+ * asynchronous method goes from the JavaScript thread to the module's thread (`BridgelessNativeMethodCallInvoker`),
11
+ * which reads its options there and posts its body to the main thread ([CommandRunner]). The task goes the same way: a
12
+ * turn of the JavaScript thread, which comes after the task of the commit with its layout effects; then the module's
13
+ * thread, behind the calls that task made; then the main thread, behind their bodies. Each of the three runs its queue
14
+ * in order, so every call JavaScript made before the mount has applied when the task runs.
15
+ *
16
+ * Without JavaScript (none yet, a reload, a queue that ended) the task is posted to the main thread at once: nothing is
17
+ * on its way. A queue that ends while the task is on it drops it, and a wait with no limit of its own (a push with
18
+ * `waitForRender: true` whose content has mounted: the task is its only end) would not end; a queue ends only as the
19
+ * JavaScript goes (a reload, the host destroyed), and then the layouts go with it (`ReloadCoordinator`), the stack
20
+ * and its waiting push too. Main thread.
21
+ */
22
+ internal object PendingCalls {
23
+ /** A queue the task goes through: it runs what it takes in order, and says false when it ended and took nothing. */
24
+ fun interface Queue {
25
+ fun run(task: Runnable): Boolean
26
+ }
27
+
28
+ /** Runs [task] on the main thread, on a later turn, after every call JavaScript made so far has applied there. */
29
+ fun after(task: () -> Unit) {
30
+ val context = NavigationApplication.instanceOrNull?.reactGatewayOrNull?.currentReactContext
31
+ ?.takeIf { it.hasActiveReactInstance() }
32
+ val js = context?.jsMessageQueueThread?.let { Queue(it::runOnQueue) }
33
+ val module = context?.nativeModulesMessageQueueThread?.let { Queue(it::runOnQueue) }
34
+ after(js, module, UiThread::post, task)
35
+ }
36
+
37
+ /**
38
+ * The way of [after] over the queues given: [js], then [module], then [main]; straight to [main] without one of
39
+ * them, or from where a queue refused it. The unit tests run it over their own queues.
40
+ */
41
+ fun after(js: Queue?, module: Queue?, main: (Runnable) -> Unit, task: () -> Unit) {
42
+ val onMain = Runnable(task)
43
+ if (js == null || module == null) return main(onMain)
44
+ val toMain = Runnable { main(onMain) }
45
+ val toModule = Runnable { if (!module.run(toMain)) main(onMain) }
46
+ if (!js.run(toModule)) main(onMain)
47
+ }
48
+ }
@@ -3,6 +3,7 @@ package dev.apexnative.navigation.react
3
3
  import android.annotation.SuppressLint
4
4
  import android.content.Context
5
5
  import android.os.Bundle
6
+ import android.util.Size
6
7
  import android.view.MotionEvent
7
8
  import android.view.ViewGroup
8
9
  import android.widget.FrameLayout
@@ -23,11 +24,17 @@ import dev.apexnative.navigation.viewcontrollers.viewcontroller.ScrollEventListe
23
24
  * is made with the view, from the app's React host, and fills it; it starts once, as the view joins a window, and stops
24
25
  * once, on the main thread, as the view is destroyed.
25
26
  *
26
- * Ready once the safe area view of the screen told [ScreenReadiness] that the content rendered into it; a screen
27
- * without a safe area view (no view ever told anything of its id) once the root view of its surface has children, read
28
- * on this view's own layout passes. Ready once, ready for good; what waits for it ([whenReady]) runs then, once.
29
- * Without either, the limits of what waits decide: the view has no timer of its own. It owns the record of its
30
- * appearance, which the dispatcher of the appearance events holds until the content is ready (`AppearanceDispatcher`).
27
+ * Ready once the safe area view of the screen, in this view's own surface, told [ScreenReadiness] that the content
28
+ * rendered into it: the signal of another root with the same id (an old one, another live root of a bar component)
29
+ * never makes this one ready. A screen without a safe area view (no view ever told anything of its id) is ready once
30
+ * the root view of its surface has children, read on this view's own layout passes. A root that renders at once
31
+ * ([rendersAtOnce]: a component of a bar, a tab's cell) marks its id so from before its surface starts until it stops.
32
+ * Ready once, ready for good; what waits for it ([whenReady]) runs then, once. Its content measures without a height
33
+ * limit ([contentSize], `ContentHeights`), and the handlers of [setOnContentMounted] hear each mount of Fabric while
34
+ * the view is in a window.
35
+ * Without a signal or children, the limits of what waits decide: the view has no timer of its own. It owns the
36
+ * record of its appearance, which the dispatcher of the appearance events holds until the content is ready
37
+ * (`AppearanceDispatcher`).
31
38
  */
32
39
  @SuppressLint("ViewConstructor")
33
40
  class ReactView @JvmOverloads constructor(
@@ -36,6 +43,8 @@ class ReactView @JvmOverloads constructor(
36
43
  override val componentName: String,
37
44
  /** Props given by the native side, over `componentId`: the state of a tab's cell. */
38
45
  initialProps: Bundle? = null,
46
+ /** The root renders at once, without waiting for its layout: a component of a bar or a tab's cell. */
47
+ private val rendersAtOnce: Boolean = false,
39
48
  ) : FrameLayout(context), IReactView {
40
49
  private val scrollEventListener = ScrollEventListener()
41
50
  private var destroyed = false
@@ -44,7 +53,15 @@ class ReactView @JvmOverloads constructor(
44
53
  // What waited for the readiness was told; a question of isReady alone tells nothing, so nothing runs inside it.
45
54
  private var readyTold = false
46
55
  private val readyListeners = mutableListOf<Runnable>()
47
- private var readinessListener: ScreenReadiness.Listener? = null
56
+ private var listening = false
57
+ private val mounts = ContentMounts { !destroyed && isAttachedToWindow }
58
+
59
+ // What this root hears of its id: only the signals of its own surface.
60
+ private val readiness = object : ScreenReadiness.Listener {
61
+ override fun accepts(source: Int): Boolean = ownSource()?.let { it == source } ?: true
62
+
63
+ override fun onContentRendered() = checkReadiness()
64
+ }
48
65
 
49
66
  // None without the app's host (the unit tests).
50
67
  private val surface: ReactSurface?
@@ -59,8 +76,17 @@ class ReactView @JvmOverloads constructor(
59
76
  */
60
77
  internal var contentChildCount: () -> Int = { (surface?.view as? ViewGroup)?.childCount ?: 0 }
61
78
 
79
+ /**
80
+ * The id of this root's React surface, which the signals of its safe area view carry: React Native gives it as
81
+ * the surface starts (none matches before) and never gives it again. Null without a surface: every signal of the
82
+ * id is its own. The unit tests give their own.
83
+ */
84
+ internal var ownSource: () -> Int? = { surface?.surfaceID }
85
+
62
86
  init {
63
87
  require(componentId.isNotEmpty()) { "a React root needs the id of its screen" }
88
+ // Before the surface exists, so its safe area view never asks before the mark is there.
89
+ if (rendersAtOnce) ScreenReadiness.setRendersAtOnce(componentId, this, true)
64
90
  val props = Bundle().apply {
65
91
  initialProps?.let(::putAll)
66
92
  putString(COMPONENT_ID, componentId)
@@ -90,6 +116,16 @@ class ReactView @JvmOverloads constructor(
90
116
  override val touchRoot: ViewGroup?
91
117
  get() = surface?.view as? ViewGroup
92
118
 
119
+ override fun contentSize(maxWidth: Int): Size? {
120
+ val surface = surface ?: return null
121
+ val height = ContentHeights.surfaceHeight(context, surface, maxWidth) ?: return null
122
+ return Size(maxWidth, height)
123
+ }
124
+
125
+ override fun setOnContentMounted(key: String, handler: Runnable?) {
126
+ if (!destroyed) mounts.set(key, handler)
127
+ }
128
+
93
129
  override fun isReady(): Boolean {
94
130
  if (!ready && hasRendered()) ready = true
95
131
  return ready
@@ -103,14 +139,9 @@ class ReactView @JvmOverloads constructor(
103
139
  if (readyTold) return listener.run()
104
140
  readyListeners += listener
105
141
  if (isReady()) return checkReadiness()
106
- if (readinessListener != null) return
107
- val readiness = object : ScreenReadiness.Listener {
108
- override fun onLaidOut() = Unit
109
-
110
- override fun onContentRendered() = checkReadiness()
111
- }
112
- readinessListener = readiness
113
- ScreenReadiness.setListener(componentId, readiness)
142
+ if (listening) return
143
+ listening = true
144
+ ScreenReadiness.addListener(componentId, this, readiness)
114
145
  }
115
146
 
116
147
  /**
@@ -126,30 +157,33 @@ class ReactView @JvmOverloads constructor(
126
157
  waiting.forEach(Runnable::run)
127
158
  }
128
159
 
129
- // The safe area view said so; without one, the root view of the surface has children.
130
- private fun hasRendered(): Boolean = when (ScreenReadiness.isContentRendered(componentId)) {
160
+ // The safe area view of this root's surface said so; without one, the root view of the surface has children.
161
+ private fun hasRendered(): Boolean = when (ScreenReadiness.isContentRendered(componentId, readiness)) {
131
162
  true -> true
132
163
  false -> false
133
164
  null -> contentChildCount() > 0
134
165
  }
135
166
 
136
167
  private fun stopListening() {
137
- val readiness = readinessListener ?: return
138
- readinessListener = null
139
- ScreenReadiness.removeListener(componentId, readiness)
168
+ if (!listening) return
169
+ listening = false
170
+ ScreenReadiness.removeListener(componentId, this)
140
171
  }
141
172
 
142
173
  /**
143
174
  * Stops the content, once, on the main thread: its appearance ends first (DidDisappear if its WillAppear went,
144
175
  * else what is held goes with it), then the surface stops and leaves the host, so a reload doesn't start it again
145
- * in the new JavaScript.
176
+ * in the new JavaScript. A root that renders at once takes its mark away: the last one of its id takes what was
177
+ * said of the id with it.
146
178
  */
147
179
  override fun destroy() {
148
180
  if (destroyed) return
149
181
  AppearanceDispatcher.didDisappear(appearance)
150
182
  destroyed = true
151
183
  readyListeners.clear()
184
+ mounts.clear()
152
185
  stopListening()
186
+ if (rendersAtOnce) ScreenReadiness.setRendersAtOnce(componentId, this, false)
153
187
  val surface = surface ?: return
154
188
  if (started) surface.stop()
155
189
  surface.detach()
@@ -4,7 +4,7 @@ import com.facebook.react.bridge.ReactContext
4
4
  import dev.apexnative.navigation.NavigationActivity
5
5
  import dev.apexnative.navigation.nativescreen.NativeScreenCalls
6
6
  import dev.apexnative.navigation.react.events.EventEmitter
7
- import dev.apexnative.navigation.react.events.NavigationStateReporter
7
+ import dev.apexnative.navigation.react.events.NavigationState
8
8
  import dev.apexnative.navigation.utils.UiThread
9
9
  import dev.apexnative.navigation.viewcontrollers.navigator.BackCallbackState
10
10
  import dev.apexnative.navigation.viewcontrollers.navigator.Navigator
@@ -39,7 +39,7 @@ internal object ReloadCoordinator {
39
39
  /**
40
40
  * The JavaScript goes (a reload, or the host is destroyed). Any thread: the number grows at once; the layouts of
41
41
  * every navigation activity go on the main thread, with the "reloading" mark, and so do the listeners of the
42
- * JavaScript that went (back, hinge).
42
+ * JavaScript that went (back, hinge) and the holds of the navigation state its `setRoot` left.
43
43
  */
44
44
  fun onJavaScriptGoes() {
45
45
  advance()
@@ -48,6 +48,7 @@ internal object ReloadCoordinator {
48
48
  launches.contextGone()
49
49
  try {
50
50
  Navigators.all().forEach { it.onReload() }
51
+ NavigationState.javaScriptWent()
51
52
  BackCallbackState.setJsListeners(false)
52
53
  Hinge.setEnabled(Navigators.current(), false)
53
54
  } finally {
@@ -59,13 +60,15 @@ internal object ReloadCoordinator {
59
60
  /**
60
61
  * The developer tools of [activity] reload the JavaScript ("R R", the reload broadcast): the number grows first, so
61
62
  * the navigation of the activity goes without a word to the JavaScript that goes, then its layers go
62
- * ([NavigationActivity.onReload]). The host's own reset follows as the reload destroys it. Main thread.
63
+ * ([NavigationActivity.onReload]) with the holds of the navigation state. The host's own reset follows as the
64
+ * reload destroys it. Main thread.
63
65
  */
64
66
  fun resetForDeveloperReload(activity: NavigationActivity) {
65
67
  advance()
66
68
  Navigator.setReloading(true)
67
69
  try {
68
70
  activity.onReload()
71
+ NavigationState.javaScriptWent()
69
72
  } finally {
70
73
  Navigator.setReloading(false)
71
74
  }
@@ -79,8 +82,6 @@ internal object ReloadCoordinator {
79
82
  UiThread.runOnMain {
80
83
  launches.contextReady(context)
81
84
  NativeScreenCalls.failAll { name, componentId -> ErrorTexts.nativeCallReloaded(name, componentId) }
82
- // Scroll listeners that found no event dispatcher listen now.
83
- ScrollEvents.dispatcherReady()
84
85
  Navigators.all().filter { it.isNavigationResumed }.forEach(::launchIfDue)
85
86
  }
86
87
  }
@@ -92,7 +93,7 @@ internal object ReloadCoordinator {
92
93
  */
93
94
  fun launchIfDue(activity: NavigationActivity) {
94
95
  val context = launches.takeDue(activity, activity.isNavigationResumed) ?: return
95
- NavigationStateReporter.reset()
96
+ NavigationState.reset()
96
97
  EventEmitter(context).emitAppLaunched()
97
98
  }
98
99
  }
@@ -0,0 +1,177 @@
1
+ package dev.apexnative.navigation.react
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableArray
5
+ import com.facebook.react.bridge.WritableMap
6
+ import dev.apexnative.navigation.react.events.EventContract
7
+ import dev.apexnative.navigation.react.events.EventEmitter
8
+ import java.util.concurrent.ConcurrentHashMap
9
+
10
+ /**
11
+ * What JavaScript knows of each screen's place, by the screen's id, in one record: its safe area (the insets JavaScript
12
+ * gets and the padding of its safe area view, `useSafeAreaInsets`), its reserved regions (`useReservedRegions`) and,
13
+ * in a pair, its arrangement (`useArrangement`). The core measures them (`ScreenSafeArea`, [ScreenRegions], the pair's
14
+ * plan) on the main thread and keeps them here; JavaScript reads them from its own thread for a screen's first render
15
+ * and gets every change as an event. The record is immutable and replaced at once, so a reader on another thread sees
16
+ * one whole record. When the screen goes, [remove] clears all of it. As on iOS (`ANNScreenEnvironment`).
17
+ */
18
+ internal object ScreenEnvironment {
19
+ /** How much covers each edge of a screen's content, in dp. */
20
+ data class Insets(val top: Double, val right: Double, val bottom: Double, val left: Double)
21
+
22
+ /** A reserved region, in dp from the top left of the screen's content. */
23
+ data class Region(val x: Double, val y: Double, val width: Double, val height: Double)
24
+
25
+ /** Where a screen divides (`division`) and where hardware covers it (`occlusion`). */
26
+ data class Regions(val division: List<Region>, val occlusion: List<Region>) {
27
+ val isEmpty: Boolean get() = division.isEmpty() && occlusion.isEmpty()
28
+ }
29
+
30
+ /** Which screen of its pair a screen is, how the pair lies, whether it lies over the other one and is hidden. */
31
+ data class Arrangement(val placement: String, val layout: String, val front: Boolean, val hidden: Boolean)
32
+
33
+ /** Where the changes JavaScript hears go: the events of the screen's JavaScript, or a test's record. */
34
+ interface Changes {
35
+ fun insetsChanged(screenId: String, insets: Insets)
36
+
37
+ fun regionsChanged(screenId: String, regions: Regions)
38
+
39
+ fun arrangementChanged(screenId: String, arrangement: Arrangement)
40
+ }
41
+
42
+ // One screen's record; null for a fact not known yet (not laid out, outside a pair).
43
+ private data class Record(
44
+ val insets: Insets? = null,
45
+ val padding: Insets? = null,
46
+ val regions: Regions? = null,
47
+ val arrangement: Arrangement? = null,
48
+ )
49
+
50
+ private val NO_REGIONS = Regions(emptyList(), emptyList())
51
+ private val records = ConcurrentHashMap<String, Record>()
52
+ // Main thread only.
53
+ private val paddingListeners = HashMap<String, MutableSet<() -> Unit>>()
54
+
55
+ /**
56
+ * Keeps the screen's [insets] for JavaScript (what still covers its content) and the [padding] of its safe area
57
+ * view. Calls the screen's padding listeners when the padding changed, then tells JavaScript when the insets did.
58
+ * Main thread only.
59
+ */
60
+ fun setInsets(screenId: String, insets: Insets, padding: Insets, changes: Changes) {
61
+ val before = update(screenId) { it.copy(insets = insets, padding = padding) }
62
+ if (before?.padding != padding) paddingListeners[screenId]?.toList()?.forEach { it() }
63
+ if (before?.insets != insets) changes.insetsChanged(screenId, insets)
64
+ }
65
+
66
+ /**
67
+ * Keeps the screen's [regions], and tells JavaScript when they changed; none at first is what JavaScript reads
68
+ * before the first layout, so it isn't told. Main thread only.
69
+ */
70
+ fun setRegions(screenId: String, regions: Regions, changes: Changes) {
71
+ val before = update(screenId) { it.copy(regions = regions) }?.regions
72
+ if (before == regions || (before == null && regions.isEmpty)) return
73
+ changes.regionsChanged(screenId, regions)
74
+ }
75
+
76
+ /** Keeps the screen's [arrangement], and tells JavaScript when it changed and [notify] holds. Main thread only. */
77
+ fun setArrangement(screenId: String, arrangement: Arrangement, notify: Boolean, changes: Changes) {
78
+ val before = update(screenId) { it.copy(arrangement = arrangement) }?.arrangement
79
+ if (before == arrangement || !notify) return
80
+ changes.arrangementChanged(screenId, arrangement)
81
+ }
82
+
83
+ /** The padding of the screen's safe area view; none before the screen was laid out. Any thread. */
84
+ fun padding(screenId: String): Insets? = records[screenId]?.padding
85
+
86
+ /** The insets JavaScript gets; none before the screen was laid out. Any thread. */
87
+ fun insets(screenId: String): Insets? = records[screenId]?.insets
88
+
89
+ /** The screen's reserved regions; none before its first layout. Any thread. */
90
+ fun regions(screenId: String): Regions? = records[screenId]?.regions
91
+
92
+ /** The screen's arrangement; none outside a pair. Any thread. */
93
+ fun arrangement(screenId: String): Arrangement? = records[screenId]?.arrangement
94
+
95
+ /**
96
+ * Calls `listener` when the padding of the screen changes; returns the function that stops it. Main thread only.
97
+ */
98
+ fun listenToPadding(screenId: String, listener: () -> Unit): () -> Unit {
99
+ paddingListeners.getOrPut(screenId) { LinkedHashSet() }.add(listener)
100
+ return {
101
+ paddingListeners[screenId]?.let {
102
+ it.remove(listener)
103
+ if (it.isEmpty()) paddingListeners.remove(screenId)
104
+ }
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Forgets everything kept for the screen. Its padding listeners stay: a live safe area view keeps listening while
110
+ * it keeps the id, and stops itself.
111
+ */
112
+ fun remove(screenId: String) {
113
+ records.remove(screenId)
114
+ }
115
+
116
+ /** `getScreenInsets`: `{ top, right, bottom, left }`, empty before the screen was laid out. Any thread. */
117
+ fun getScreenInsets(screenId: String): WritableMap = insets(screenId)?.let(::toMap) ?: Arguments.createMap()
118
+
119
+ /** `getScreenRegions`: `{ division, occlusion }`, empty lists before the first layout. Any thread. */
120
+ fun getScreenRegions(screenId: String): WritableMap = toMap(regions(screenId) ?: NO_REGIONS)
121
+
122
+ /** `getArrangementState`: `{ placement, layout, front, hidden }`, empty outside a pair. Any thread. */
123
+ fun getArrangementState(screenId: String): WritableMap =
124
+ arrangement(screenId)?.let(::toMap) ?: Arguments.createMap()
125
+
126
+ /** The changes as events through [emitter], the one of the JavaScript the screen was made for. */
127
+ fun changesOf(emitter: EventEmitter): Changes = object : Changes {
128
+ override fun insetsChanged(screenId: String, insets: Insets) =
129
+ emitter.emitScreenInsetsChanged(screenId, toMap(insets))
130
+
131
+ override fun regionsChanged(screenId: String, regions: Regions) =
132
+ emitter.emitScreenRegionsChanged(screenId, toMap(regions))
133
+
134
+ override fun arrangementChanged(screenId: String, arrangement: Arrangement) =
135
+ emitter.emitArrangementChanged(screenId, toMap(arrangement))
136
+ }
137
+
138
+ // Replaces the screen's record at once with [change] of it; returns the record before, null for a new screen.
139
+ private fun update(screenId: String, change: (Record) -> Record): Record? {
140
+ var before: Record? = null
141
+ records.compute(screenId) { _, old ->
142
+ before = old
143
+ change(old ?: Record())
144
+ }
145
+ return before
146
+ }
147
+
148
+ private fun toMap(value: Insets): WritableMap = Arguments.createMap().apply {
149
+ putDouble(EventContract.ScreenInsetsChanged.TOP, value.top)
150
+ putDouble(EventContract.ScreenInsetsChanged.RIGHT, value.right)
151
+ putDouble(EventContract.ScreenInsetsChanged.BOTTOM, value.bottom)
152
+ putDouble(EventContract.ScreenInsetsChanged.LEFT, value.left)
153
+ }
154
+
155
+ private fun toMap(value: Regions): WritableMap = Arguments.createMap().apply {
156
+ putArray(EventContract.ScreenRegionsChanged.DIVISION, toArray(value.division))
157
+ putArray(EventContract.ScreenRegionsChanged.OCCLUSION, toArray(value.occlusion))
158
+ }
159
+
160
+ private fun toArray(regions: List<Region>): WritableArray = Arguments.createArray().apply {
161
+ for (region in regions) {
162
+ pushMap(Arguments.createMap().apply {
163
+ putDouble(EventContract.ScreenRegionRect.X, region.x)
164
+ putDouble(EventContract.ScreenRegionRect.Y, region.y)
165
+ putDouble(EventContract.ScreenRegionRect.WIDTH, region.width)
166
+ putDouble(EventContract.ScreenRegionRect.HEIGHT, region.height)
167
+ })
168
+ }
169
+ }
170
+
171
+ private fun toMap(value: Arrangement): WritableMap = Arguments.createMap().apply {
172
+ putString(EventContract.ArrangementChanged.PLACEMENT, value.placement)
173
+ putString(EventContract.ArrangementChanged.LAYOUT, value.layout)
174
+ putBoolean(EventContract.ArrangementChanged.FRONT, value.front)
175
+ putBoolean(EventContract.ArrangementChanged.HIDDEN, value.hidden)
176
+ }
177
+ }