@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
@@ -7,17 +7,13 @@ import android.app.Activity
7
7
  import android.content.Context
8
8
  import android.content.pm.ApplicationInfo
9
9
  import android.graphics.Color
10
- import android.graphics.drawable.BitmapDrawable
11
10
  import android.graphics.drawable.Drawable
12
- import android.view.Menu
13
- import android.view.MenuItem
14
11
  import android.view.MotionEvent
15
12
  import android.view.View
16
13
  import android.view.ViewGroup
17
14
  import android.view.animation.LinearInterpolator
18
15
  import android.view.animation.PathInterpolator
19
16
  import android.widget.FrameLayout
20
- import android.widget.ImageView
21
17
  import androidx.appcompat.content.res.AppCompatResources
22
18
  import androidx.core.graphics.drawable.DrawableCompat
23
19
  import androidx.core.view.WindowInsetsCompat
@@ -41,7 +37,6 @@ import dev.apexnative.navigation.utils.ImageLoader
41
37
  import dev.apexnative.navigation.utils.ImageLoadingListenerAdapter
42
38
  import dev.apexnative.navigation.utils.TestIds
43
39
  import dev.apexnative.navigation.utils.UiUtils
44
- import dev.apexnative.navigation.viewcontrollers.component.ScreenReadiness
45
40
  import dev.apexnative.navigation.viewcontrollers.navigator.BackCallbackState
46
41
  import dev.apexnative.navigation.viewcontrollers.stack.StackDisplay
47
42
  import dev.apexnative.navigation.viewcontrollers.stack.StackDisplay.BarMotion
@@ -49,7 +44,9 @@ import dev.apexnative.navigation.viewcontrollers.stack.search.StackSearchPresent
49
44
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.IReactView
50
45
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ScrollEventListener
51
46
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
47
+ import dev.apexnative.navigation.views.animations.AnimationRules
52
48
  import dev.apexnative.navigation.views.animations.SideAnimator
49
+ import dev.apexnative.navigation.views.animations.FadeThrough
53
50
  import dev.apexnative.navigation.views.animations.SystemTransition
54
51
  import dev.apexnative.navigation.views.component.ComponentLayout
55
52
  import dev.apexnative.navigation.views.stack.StackLayout
@@ -58,8 +55,10 @@ import dev.apexnative.navigation.views.stack.topbar.TitleBar
58
55
  import dev.apexnative.navigation.views.stack.topbar.TopBar
59
56
  import dev.apexnative.navigation.views.stack.topbar.TopBarDefaults
60
57
  import dev.apexnative.navigation.views.stack.topbar.titlebar.BarButtonComponentCell
58
+ import dev.apexnative.navigation.views.stack.topbar.titlebar.BarMenu
61
59
  import dev.apexnative.navigation.views.stack.topbar.titlebar.ButtonBar
62
60
  import dev.apexnative.navigation.views.stack.topbar.titlebar.IconBackgroundDrawable
61
+ import kotlin.math.roundToInt
63
62
 
64
63
  /**
65
64
  * What the bar of one stack shows: the options of the screen on top of the stack, resolved (a pair's options screen),
@@ -123,8 +122,15 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
123
122
  private var largeTitleShown = false
124
123
  private var followed: ScrollEventListener? = null
125
124
  private var rowTarget: RowTarget? = null
125
+ // The large title opening with a push from a screen without one; none at rest.
126
+ private var largeTitleOpening: ValueAnimator? = null
126
127
  // The picture of the part under the row in a leaving screen's overlay: the screen and the picture.
127
128
  private var underRow: Pair<ViewController<*>, Drawable>? = null
129
+ // The bar goes with the screens of a transition of the stack's own, and the screen that leaves with its picture.
130
+ private var travelling = false
131
+ private var travelLeaving: ViewController<*>? = null
132
+ // The bar hides as it shows now, and the options of the screen it hides for wait until it is gone.
133
+ private var waitsForHide = false
128
134
 
129
135
  private enum class Part { Look, Title, Left, Right, Back, LargeTitle, Visible, TestId }
130
136
 
@@ -135,9 +141,9 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
135
141
  this.layout = layout
136
142
  val bar = layout.topBar
137
143
  this.bar = bar
138
- leftButtons = ButtonBar(bar.leftButtonBar, true, ::loadIcon, Buttons())
139
- rightButtons = ButtonBar(bar.rightButtonBar, false, ::loadIcon, Buttons())
140
- visibility = TopBarVisibility(VisibilityTarget(bar) { collapse?.reset() })
144
+ leftButtons = ButtonBar(bar.leftButtonBar, ::loadIcon, Buttons())
145
+ rightButtons = ButtonBar(bar.rightButtonBar, ::loadIcon, Buttons())
146
+ visibility = TopBarVisibility(VisibilityTarget(bar) { collapse?.reset() }, ::hidden)
141
147
  rowTransition = BarRowTransition(RowTarget(bar).also { rowTarget = it })
142
148
  collapse = TopBarCollapseBehavior(bar)
143
149
  bar.leftButtonBar.setNavigationOnClickListener { host.backPressed() }
@@ -160,12 +166,16 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
160
166
  * The stack's current child changes to [incoming] ([motion]: the default transition that brings it, none at once):
161
167
  * the row's picture is taken before the bar takes the new screen's options. A push from a large title to a screen
162
168
  * without one makes the bar lower at once: the part under the row rides with the leaving screen as a picture in its
163
- * overlay, and the row's picture holds the row only. So does a pop back to a screen whose large title is collapsed.
169
+ * overlay, and the row's picture holds the row only. So does a pop or a fade through (`setStackRoot`) to a screen
170
+ * without a large title or with its large title collapsed: a picture as tall as the large title would hold the bar
171
+ * at its height to the end. With a transition of the stack's own ([travel]) the bar goes with the screens instead
172
+ * ([beginTravel]).
164
173
  */
165
174
  fun beginRowTransition(
166
175
  motion: BarMotion?,
167
176
  incoming: ViewController<*>?,
168
177
  visibility: StackDisplay.BarVisibility = StackDisplay.BarVisibility.AT_ONCE,
178
+ travel: StackDisplay.BarTravel? = null,
169
179
  ) {
170
180
  this.motion = motion
171
181
  this.visibilityChange = visibility
@@ -174,18 +184,82 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
174
184
  val bar = bar
175
185
  val leaving = shownEntry
176
186
  val lowers = bar != null && bar.isLargeTitleShown && incoming != null && leaving != null &&
187
+ !hidesMoving(host.resolvedOf(incoming), visibility, travel != null) &&
177
188
  lowersBar(motion, incoming, host.resolvedOf(incoming))
178
189
  rowTarget?.withLargeTitle = !lowers
179
190
  if (lowers) pictureUnderRow(bar, leaving)
180
191
  rowTransition?.begin(motion)
192
+ endTravel()
193
+ if (travel != null && bar != null && incoming != null) beginTravel(bar, leaving, incoming, travel, visibility)
194
+ }
195
+
196
+ // Whether a screen with [options] hides the bar, shown now, by a move of [change]: a slide, or the transition's
197
+ // side. The bar then leaves as it shows, its large title too (`applyAll`); while it goes with the screens of a
198
+ // transition of the stack's own ([travels]) only a side of its own moves it.
199
+ private fun hidesMoving(options: Options, change: StackDisplay.BarVisibility, travels: Boolean): Boolean {
200
+ val exit = change.side?.exit
201
+ return options.topBar.visible.isFalse && !options.topBar.animate.isFalse && change.animated &&
202
+ !AnimationRules.isTurnedOff(exit) && (!travels || AnimationRules.barSideGiven(exit))
181
203
  }
182
204
 
183
205
  /** The transition that brought the current child ended: the row at rest, the picture under it gone. */
184
206
  fun endRowTransition() {
207
+ // A large title still opening is open now.
208
+ largeTitleOpening?.let {
209
+ largeTitleOpening = null
210
+ it.end()
211
+ }
185
212
  motion = null
186
213
  visibilityChange = StackDisplay.BarVisibility.AT_ONCE
187
214
  rowTransition?.end()
188
215
  dropPictureUnderRow()
216
+ endTravel()
217
+ }
218
+
219
+ /**
220
+ * The bar goes with the screens of a transition of the stack's own, as each screen's bar would: a picture of the
221
+ * bar as it is goes with [leaving], and the bar, which takes [incoming]'s options next, is drawn flat as [incoming]
222
+ * moves — under [leaving] on a pop ([StackDisplay.BarTravel.Back]) (`StackLayout.barTravels`). No picture when the
223
+ * bar doesn't show. Nothing travels when the new top hides the bar by a side of its own
224
+ * (`animations.*.topBar.exit`), which plays instead, or when the bar can't be recorded (a `HARDWARE` bitmap in it
225
+ * on Android 8): the bar takes the options in its place.
226
+ */
227
+ private fun beginTravel(
228
+ bar: TopBar,
229
+ leaving: ViewController<*>?,
230
+ incoming: ViewController<*>,
231
+ direction: StackDisplay.BarTravel,
232
+ visibility: StackDisplay.BarVisibility,
233
+ ) {
234
+ val layout = layout ?: return
235
+ val screen = incoming.peekView()?.takeIf(layout::holds) ?: return
236
+ val leavingView = leaving?.peekView()?.takeIf(layout::holds)
237
+ // The new top hides the bar by a side of its own: the side plays on the bar in its place instead.
238
+ if (host.resolvedOf(incoming).topBar.visible.isFalse && AnimationRules.barSideGiven(visibility.side?.exit)) return
239
+ val shows = bar.visibility == View.VISIBLE && this.visibility?.isHidden != true
240
+ val picture = if (shows && leavingView != null) pictureOfBar(bar) ?: return else null
241
+ travelling = true
242
+ travelLeaving = leaving.takeIf { picture != null }
243
+ // Flat: with an elevation the renderer would draw the bar over every screen and out of its alpha layer.
244
+ bar.isFlat = true
245
+ layout.barTravels(screen, leavingView, picture, direction == StackDisplay.BarTravel.Back)
246
+ }
247
+
248
+ // The bar's picture where the bar is in the stack, its moves counted.
249
+ private fun pictureOfBar(bar: TopBar): Drawable? {
250
+ val picture = bar.picture() ?: return null
251
+ val left = (bar.left + bar.translationX).roundToInt()
252
+ val top = (bar.top + bar.translationY).roundToInt()
253
+ return picture.apply { setBounds(left, top, left + intrinsicWidth, top + intrinsicHeight) }
254
+ }
255
+
256
+ // The bar's travel ends: the picture goes, the bar is drawn in its place again with its shadow.
257
+ private fun endTravel() {
258
+ if (!travelling) return
259
+ travelling = false
260
+ travelLeaving = null
261
+ bar?.isFlat = false
262
+ layout?.endBarTravel()
189
263
  }
190
264
 
191
265
  /**
@@ -204,8 +278,9 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
204
278
  keys.clear()
205
279
  }
206
280
  shownEntry = entry
207
- // The screen that left with the picture under the row shows again: the picture goes.
281
+ // The screen that left with the picture under the row, or of the bar, shows again: the picture goes.
208
282
  if (underRow?.first === entry) dropPictureUnderRow()
283
+ if (travelLeaving === entry) endTravel()
209
284
  val options = host.resolvedOf(entry)
210
285
  applyAll(bar, entry, screen, options, merge = false)
211
286
  }
@@ -218,6 +293,8 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
218
293
  val bar = bar ?: return
219
294
  val screen = host.optionsScreen(entry)
220
295
  if (screen !== shownScreen) return apply(entry)
296
+ // An open menu has the colors of before.
297
+ if (delta.topBar.menuBackgroundColor.hasValue() || delta.topBar.menuTextColor.hasValue()) closeMenus()
221
298
  val options = host.resolvedOf(entry)
222
299
  applyAll(bar, entry, screen, options, merge = true, delta = delta)
223
300
  }
@@ -227,6 +304,8 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
227
304
  * now.
228
305
  */
229
306
  fun repaint(entry: ViewController<*>?) {
307
+ // An open menu has the old colors: it closes.
308
+ closeMenus()
230
309
  keys.clear()
231
310
  apply(entry)
232
311
  val options = entry?.let(host::resolvedOf) ?: return
@@ -239,6 +318,7 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
239
318
  * of the bar (the search) applies again.
240
319
  */
241
320
  fun onInsets() {
321
+ if (waitsForHide) return
242
322
  val bar = bar ?: return
243
323
  val entry = shownEntry ?: return
244
324
  val screen = shownScreen ?: return
@@ -313,6 +393,12 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
313
393
 
314
394
  /** [screen] is destroyed: its components and its search go. */
315
395
  fun screenDestroyed(screen: ViewController<*>, entryView: View?) {
396
+ // The bar may still show the components of the screen that goes: it is gone at once, with the options it held
397
+ // back, before they go; none when they are of the screen that goes.
398
+ if (waitsForHide) {
399
+ if (screen === shownScreen) waitsForHide = false
400
+ visibility?.hide(animated = false)
401
+ }
316
402
  if (screen === shownScreen) {
317
403
  shownScreen = null
318
404
  shownEntry = null
@@ -333,7 +419,9 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
333
419
  /** The stack is destroyed: every component stops. */
334
420
  fun destroy() {
335
421
  rowTransition?.end()
422
+ endTravel()
336
423
  largeTitleFollower.stop()
424
+ stopLargeTitleOpening()
337
425
  collapse?.disableCollapse()
338
426
  components.destroyAll()
339
427
  cells.clear()
@@ -369,6 +457,9 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
369
457
  )
370
458
  }
371
459
 
460
+ /** Whether the bar shows [entry]: its parts are applied, so its place in the layout is [entry]'s. */
461
+ fun shows(entry: ViewController<*>): Boolean = entry === shownEntry
462
+
372
463
  /** The height of the search under the row of [entry] when it is the screen the bar shows; 0 otherwise. */
373
464
  fun searchHeightOf(entry: ViewController<*>): Int =
374
465
  if (entry === shownEntry) bar?.searchAreaHeight ?: 0 else 0
@@ -394,6 +485,26 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
394
485
  merge: Boolean,
395
486
  delta: Options? = null,
396
487
  ) {
488
+ // A screen that hides the bar: the bar leaves as it shows, its look, title and buttons those of the screen
489
+ // before, and takes this screen's options once it is gone. Taken first, they would paint the leaving bar (the
490
+ // default color over a bar that was transparent).
491
+ val waited = waitsForHide
492
+ waitsForHide = false
493
+ if (options.topBar.visible.isFalse && (!merge || waited)) {
494
+ applyVisibility(options, merge)
495
+ waitsForHide = visibility?.isHiding == true
496
+ if (waitsForHide) {
497
+ // The list of the screen before no longer moves the bar: a move of it would stop the hide.
498
+ collapse?.disableCollapse(reset = false)
499
+ return
500
+ }
501
+ }
502
+ // Shown again by a merge before it was gone: none of this screen's options are on the bar yet. It shows as a
503
+ // merge shows it, by `animate`, not by the transition's side.
504
+ if (merge && waited) {
505
+ visibilityChange = StackDisplay.BarVisibility(true, null)
506
+ return applyAll(bar, entry, screen, options, merge = false)
507
+ }
397
508
  applyLook(bar, entry, options)
398
509
  applyTitle(bar, screen, options)
399
510
  // The search first: its magnifier takes a place among the right buttons. It gets a copy of the group: it
@@ -511,16 +622,15 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
511
622
  keys[Part.Left] = leftKey
512
623
  reportWithoutId(topBar.buttons.left, "leftButtons")
513
624
  leftButtons?.set(
514
- left.map { button(screen, it, roots) },
625
+ ButtonPlaces.line(left, left = true).map { button(screen, it, roots) },
515
626
  emptyList(),
516
627
  null,
517
628
  merge && topBar.animateLeftButtons.isTrue,
518
629
  )
519
630
  }
520
631
  val overflow = topBar.overflowMenu?.takeIf { it.items.isNotEmpty() }
521
- val menu = bar.rightButtonBar.menu
522
632
  search.applyMagnifier()
523
- val taken = (0 until menu.size()).count { menu.getItem(it).itemId != Menu.NONE }
633
+ val taken = if (bar.rightButtonBar.trailingView != null) 1 else 0
524
634
  val configuration = context.resources.configuration
525
635
  val plan = ButtonPlaces.plan(
526
636
  right.map { ButtonPlaces.Button(ButtonPlaces.priorityOf(it.priority.get(null)), it.pinned.isTrue) },
@@ -541,12 +651,11 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
541
651
  keys[Part.Right] = rightKey
542
652
  reportWithoutId(topBar.buttons.right, "rightButtons")
543
653
  rightButtons?.set(
544
- plan.inBar.map { button(screen, right[it], roots) },
654
+ ButtonPlaces.line(plan.inBar, left = false).map { button(screen, right[it], roots) },
545
655
  plan.inOverflow.map { button(screen, right[it], roots) },
546
656
  overflow,
547
657
  merge && topBar.animateRightButtons.isTrue,
548
658
  )
549
- search.applyMagnifier()
550
659
  rightButtons?.setOverflowColor(overflowColor)
551
660
  }
552
661
  }
@@ -568,9 +677,9 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
568
677
  ).joinToString()
569
678
  if (keys[Part.Back] == key) return
570
679
  keys[Part.Back] = key
571
- val toolbar = bar.leftButtonBar
680
+ val row = bar.leftButtonBar
572
681
  if (!shown) {
573
- toolbar.navigationIcon = null
682
+ row.navigationIcon = null
574
683
  return
575
684
  }
576
685
  val own = back.icon.get(null)?.let(::loadIcon)?.mutate()
@@ -597,19 +706,13 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
597
706
  dp(background.height.get(0.0)),
598
707
  )
599
708
  } ?: icon
600
- toolbar.navigationIcon = drawable
601
- // Taking the icon, the navigation button gives it its own direction, which is stale while the button is new
602
- // or the bar's direction has just changed; the toolbar corrects it only after the icon was drawn. So the arrow
603
- // gets the bar's direction at once, on the drawable the button shows; a background passes it to the arrow.
604
- val held = toolbar.navigationIcon ?: drawable
605
- DrawableCompat.setLayoutDirection(held, arrowDirection)
606
- if (held !== drawable) DrawableCompat.setLayoutDirection(drawable, arrowDirection)
607
- toolbar.navigationContentDescription = label
608
- // The toolbar uses its navigation button again from screen to screen: its id is set every time.
609
- for (index in 0 until toolbar.childCount) {
610
- val child = toolbar.getChildAt(index)
611
- if ((child as? ImageView)?.drawable === held) TestIds.apply(child, testId)
612
- }
709
+ row.navigationIcon = drawable
710
+ // Taking the icon, the back button gives it its own direction, which is stale while the button is new or the
711
+ // bar's direction has just changed; the button corrects it only once its direction is resolved again. So the
712
+ // arrow gets the bar's direction at once; a background passes it to the arrow.
713
+ DrawableCompat.setLayoutDirection(drawable, arrowDirection)
714
+ row.navigationContentDescription = label
715
+ row.navigationButton?.let { TestIds.apply(it, testId) }
613
716
  }
614
717
 
615
718
  // The background (`topBar.background.component`).
@@ -632,11 +735,13 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
632
735
  }
633
736
 
634
737
  // Whether [incoming] shows less of the bar under the row than the large title now: a push to a screen without a
635
- // large title, or a pop back to one whose large title is collapsed. The lower bar would cut the row's picture.
738
+ // large title, or a pop or a fade through to one without a large title or with its large title collapsed. The lower
739
+ // bar would cut the row's picture.
636
740
  private fun lowersBar(motion: BarMotion?, incoming: ViewController<*>, options: Options): Boolean = when (motion) {
637
741
  BarMotion.Push -> !largeTitleShownFor(incoming, options)
638
- BarMotion.Pop -> largeTitleShownFor(incoming, options) && collapseOf(incoming, options) > 0f
639
- else -> false
742
+ BarMotion.Pop, BarMotion.FadeThrough ->
743
+ !largeTitleShownFor(incoming, options) || collapseOf(incoming, options) > 0f
744
+ null -> false
640
745
  }
641
746
 
642
747
  // How far [entry]'s large title is collapsed as it shows: by the offset its list had last, unless it doesn't follow
@@ -646,15 +751,14 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
646
751
 
647
752
  private fun pictureUnderRow(bar: TopBar, leaving: ViewController<*>) {
648
753
  val view = leaving.peekView() ?: return
649
- val (bitmap, top) = bar.pictureUnderRow() ?: return
754
+ val (picture, top) = bar.pictureUnderRow() ?: return
650
755
  val barPlace = IntArray(2)
651
756
  val viewPlace = IntArray(2)
652
757
  bar.getLocationInWindow(barPlace)
653
758
  view.getLocationInWindow(viewPlace)
654
- val picture = BitmapDrawable(bar.resources, bitmap)
655
759
  val left = barPlace[0] - viewPlace[0]
656
760
  val y = barPlace[1] + top - viewPlace[1]
657
- picture.setBounds(left, y, left + bitmap.width, y + bitmap.height)
761
+ picture.setBounds(left, y, left + picture.intrinsicWidth, y + picture.intrinsicHeight)
658
762
  view.overlay.add(picture)
659
763
  underRow = leaving to picture
660
764
  }
@@ -674,6 +778,11 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
674
778
  large.fontSize.get(null), fontKey(large.font), large.collapseOnScroll.get(null), testId).joinToString()
675
779
  if (keys[Part.LargeTitle] == key) return
676
780
  keys[Part.LargeTitle] = key
781
+ // The default push or fade through from a screen without a large title opens it with the screens, on a bar that
782
+ // shows at rest: the bar's show and its hide on scroll move the same translation.
783
+ val opening = motion.takeIf { it == BarMotion.Push || it == BarMotion.FadeThrough }
784
+ val opens = shown && !largeTitleShown && bar.visibility == View.VISIBLE && bar.translationY == 0f
785
+ stopLargeTitleOpening()
677
786
  largeTitleShown = shown
678
787
  bar.setLargeTitleShown(shown)
679
788
  largeTitleFollower.stop()
@@ -691,9 +800,49 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
691
800
  // same frame: back to the screen, after light or dark changed, after a merge.
692
801
  if (large.collapseOnScroll.isFalse) scrollOf(entry)?.forgetOffset()
693
802
  largeTitleFollower.collapse(collapseOf(entry, options))
803
+ if (opens) opening?.let { openLargeTitle(bar, collapseOf(entry, options), it) }
694
804
  if (!large.collapseOnScroll.isFalse) scrollOf(entry)?.let(largeTitleFollower::follow)
695
805
  }
696
806
 
807
+ // The bar grows with the screens' [motion], on its curve and in its time, from the row's height to the large title
808
+ // as the screen's list left it: the large title comes out from under the row as it does when the list scrolls
809
+ // back. No frame shows the tall bar before the screens move.
810
+ private fun openLargeTitle(bar: TopBar, offset: Float, motion: BarMotion) {
811
+ val range = UiUtils.dpToPx(bar.context, LargeTitleView.HEIGHT)
812
+ val to = LargeTitleCollapse.shift(offset, range)
813
+ if (to >= range) return
814
+ bar.setLargeTitleCollapse(range.toInt())
815
+ largeTitleOpening = ValueAnimator.ofFloat(range, to).apply {
816
+ duration = if (motion == BarMotion.FadeThrough) FadeThrough.DURATION else SystemTransition.DURATION
817
+ interpolator = if (motion == BarMotion.FadeThrough) FadeThrough.CURVE else SystemTransition.CURVE
818
+ addUpdateListener { bar.setLargeTitleCollapse((it.animatedValue as Float).toInt()) }
819
+ addListener(object : AnimatorListenerAdapter() {
820
+ override fun onAnimationEnd(animation: Animator) {
821
+ if (largeTitleOpening === animation) largeTitleOpening = null
822
+ }
823
+ })
824
+ start()
825
+ }
826
+ }
827
+
828
+ // Stopped where it is: what applies next sets the large title.
829
+ private fun stopLargeTitleOpening() {
830
+ val opening = largeTitleOpening ?: return
831
+ largeTitleOpening = null
832
+ opening.removeAllUpdateListeners()
833
+ opening.cancel()
834
+ }
835
+
836
+ // A hide that held the options back ended: the bar, gone now, takes them.
837
+ private fun hidden() {
838
+ if (!waitsForHide) return
839
+ waitsForHide = false
840
+ val bar = bar ?: return
841
+ val entry = shownEntry ?: return
842
+ val screen = shownScreen ?: return
843
+ applyAll(bar, entry, screen, host.resolvedOf(entry), merge = false)
844
+ }
845
+
697
846
  // Shown or hidden: with the transition by its side, or by `animate` in a merge.
698
847
  private fun applyVisibility(options: Options, merge: Boolean) {
699
848
  val visible = !options.topBar.visible.isFalse
@@ -701,7 +850,10 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
701
850
  if (keys[Part.Visible] == key) return
702
851
  keys[Part.Visible] = key
703
852
  val change = visibilityChange
704
- val animated = !options.topBar.animate.isFalse && (merge || change.animated)
853
+ // While the bar goes with the screens it shows or hides at once, unless its side of its own plays.
854
+ val travels = !merge && travelling &&
855
+ !AnimationRules.barSideGiven(if (visible) change.side?.enter else change.side?.exit)
856
+ val animated = !options.topBar.animate.isFalse && (merge || change.animated) && !travels
705
857
  visibility?.apply(visible, animated, if (merge) null else change.side)
706
858
  }
707
859
 
@@ -824,14 +976,10 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
824
976
  return resolved.component
825
977
  }
826
978
 
827
- private fun makeRoot(componentId: String, name: String): IReactView {
828
- // A component of the bar renders at once, without waiting for its layout, from before its surface starts.
829
- ScreenReadiness.setRendersAtOnce(componentId, true)
830
- // Another live root has this id (a component of the stack's options on two screens): what it rendered isn't
831
- // this root's, which answers by its own render.
832
- if (BarComponents.isLive(componentId)) ScreenReadiness.forgetRender(componentId)
833
- return ReactView(activity, componentId, name)
834
- }
979
+ // A component of the bar renders at once, without waiting for its layout. Another live root may show the same id
980
+ // (a component of the stack's options on two screens): each answers by the render of its own surface.
981
+ private fun makeRoot(componentId: String, name: String): IReactView =
982
+ ReactView(activity, componentId, name, rendersAtOnce = true)
835
983
 
836
984
  private fun loadIcon(uri: String): Drawable? {
837
985
  var loaded: Drawable? = null
@@ -881,7 +1029,7 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
881
1029
  else -> TitleBar.Alignment.Start
882
1030
  }
883
1031
 
884
- private fun dp(value: Double): Int = UiUtils.dpToPx(activity, value.toFloat()).toInt()
1032
+ private fun dp(value: Double): Int = UiUtils.dpToPx(activity, value.toFloat()).roundToInt()
885
1033
 
886
1034
  // What makes a button's look, as a text: the parts that differ make it apply again.
887
1035
  private fun buttonKey(context: Context, button: ButtonOptions): String = listOf(
@@ -896,8 +1044,16 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
896
1044
  button.priority.get(null),
897
1045
  ).joinToString("|")
898
1046
 
899
- private fun menuKey(menu: ButtonMenuOptions): String =
900
- menu.items.joinToString("|") { "${it.title}:${it.icon}:${it.testID}" } + menu.testID
1047
+ // What the overflow menu shows, its submenus and checks with it: a check the app moves, or one of the user layer
1048
+ // that leaves, fills the menu again.
1049
+ private fun menuKey(menu: ButtonMenuOptions): String = elementsKey(menu.items) + menu.testID
1050
+
1051
+ private fun elementsKey(elements: List<ButtonMenuOptions.Element>): String = elements.joinToString("|") {
1052
+ "${it.title}:${it.icon}:${it.testID}" + when (it) {
1053
+ is ButtonMenuOptions.Item -> ":${it.checked}:${it.disabled}"
1054
+ is ButtonMenuOptions.Submenu -> "[${elementsKey(it.items)}]"
1055
+ }
1056
+ }
901
1057
 
902
1058
  private fun fontKey(font: FontOptions): String =
903
1059
  listOf(font.fontFamily, font.fontStyle, font.fontWeight).joinToString { it.get(null).toString() }
@@ -922,11 +1078,16 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
922
1078
  return (buttons.left.orEmpty() + buttons.right.orEmpty()).firstOrNull { it.id.get(null) == buttonId }?.menu
923
1079
  }
924
1080
 
925
- // The search's magnifier, the one item of the bar with an id of its own: `<topBar.searchBar.testID>.button`.
926
- override fun testIdOf(item: MenuItem): String? {
927
- if (item.itemId == Menu.NONE) return null
928
- val entry = shownEntry ?: return null
929
- return host.resolvedOf(entry).topBar.searchBar.testID.get(null)?.let { "$it.button" }
1081
+ // Read as a menu opens, so they follow light and dark mode: `menuBackgroundColor`, else the bar's color as it
1082
+ // shows (none when it lets something through), and then `menuTextColor` or else the title's color, the pair
1083
+ // the bar shows; with neither, the theme's.
1084
+ override fun menuColors(): BarMenu.Colors {
1085
+ val topBar = shownEntry?.let(host::resolvedOf)?.topBar ?: return BarMenu.Colors(null, null)
1086
+ val context = bar?.context ?: activity
1087
+ val text = topBar.menuTextColor.get(context, null)
1088
+ topBar.menuBackgroundColor.get(context, null)?.let { return BarMenu.Colors(it, text) }
1089
+ val barColor = bar?.barColor?.takeIf { Color.alpha(it) == OPAQUE } ?: return BarMenu.Colors(null, text)
1090
+ return BarMenu.Colors(barColor, text ?: topBar.title.color.get(context, null))
930
1091
  }
931
1092
  }
932
1093
 
@@ -959,8 +1120,11 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
959
1120
  if (large) View.IMPORTANT_FOR_ACCESSIBILITY_NO else View.IMPORTANT_FOR_ACCESSIBILITY_YES
960
1121
  }
961
1122
 
1123
+ // The list scrolled while the large title opens: it follows the list from there.
962
1124
  override fun onScrollOffset(offsetY: Float) {
963
- if (largeTitleShown) collapse(offsetY)
1125
+ if (!largeTitleShown) return
1126
+ stopLargeTitleOpening()
1127
+ collapse(offsetY)
964
1128
  }
965
1129
 
966
1130
  override fun onScrollUp(nextTranslation: Float) = Unit
@@ -1065,6 +1229,7 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
1065
1229
 
1066
1230
  private companion object {
1067
1231
  const val DEFAULT_HEIGHT_DP = 64.0
1232
+ const val OPAQUE = 255
1068
1233
  const val DEFAULT_TITLE_SP = 22.0
1069
1234
  const val DEFAULT_SUBTITLE_SP = 14.0
1070
1235
  const val CENTER = "center"
@@ -10,9 +10,10 @@ import dev.apexnative.navigation.views.animations.AnimationRules
10
10
  * stack its side (`animations.*.topBar`) plays instead — its `exit` hides, its `enter` shows; `enabled: false` shows or
11
11
  * hides at once. A show cancels a running hide and a hide a running show, each with its own token, so `visible: false`
12
12
  * then `true` leaves the bar shown; a motion cancelled leaves the bar at rest; a bar shown again stands in its place
13
- * with its row seen (the hide on scroll's shift and fade reset). Main thread only.
13
+ * with its row seen (the hide on scroll's shift and fade reset). [onHidden] runs once a hide has made the bar `GONE`.
14
+ * Main thread only.
14
15
  */
15
- internal class TopBarVisibility(private val target: Target) {
16
+ internal class TopBarVisibility(private val target: Target, private val onHidden: () -> Unit = {}) {
16
17
  /** What moves: the bar's view, or the unit tests' fake. */
17
18
  interface Target {
18
19
  /** How far up the bar goes to hide: its height and the room over it, in pixels. */
@@ -45,6 +46,10 @@ internal class TopBarVisibility(private val target: Target) {
45
46
  val isHidden: Boolean
46
47
  get() = hidden
47
48
 
49
+ /** The bar is on its way out: a hide moves it and it still shows. */
50
+ val isHiding: Boolean
51
+ get() = hidden && sliding != null
52
+
48
53
  /** Shows the bar: by [side] when it plays, sliding down when [animated], else at once. */
49
54
  fun show(animated: Boolean, side: TopBarAnimationOptions? = null) {
50
55
  val wasHidden = hidden
@@ -84,6 +89,7 @@ internal class TopBarVisibility(private val target: Target) {
84
89
  if (!moves || target.isGone) {
85
90
  target.translationY = 0f
86
91
  target.isGone = true
92
+ onHidden()
87
93
  return
88
94
  }
89
95
  val token = Any()
@@ -93,6 +99,7 @@ internal class TopBarVisibility(private val target: Target) {
93
99
  settle()
94
100
  target.isGone = true
95
101
  target.translationY = 0f
102
+ onHidden()
96
103
  }
97
104
  }
98
105
  val own = side?.takeIf { AnimationRules.sidePlays(it) }
@@ -13,8 +13,8 @@ import java.lang.ref.WeakReference
13
13
  * tag) is in the screen, found once per tag —, not the horizontal ones, nor those of a modal, an overlay or another
14
14
  * screen; a slot screen's lists are in its container too. While a list is dragged, each follower gets the drag as a
15
15
  * translation to follow; when the drag ends, the way to settle; at every scroll event, the drags' and the inertia's,
16
- * the offset. It listens to React Native's events only while it has followers; without React Native's event dispatcher
17
- * (around a reload) it waits and listens once there is one. Released with the screen. Main thread only.
16
+ * the offset. It listens to React Native's scroll views ([ScrollEvents]) only while it has followers and its screen's
17
+ * view. Released with the screen. Main thread only.
18
18
  */
19
19
  class ScrollEventListener() {
20
20
  /** Follows the content while it is dragged. */
@@ -105,15 +105,12 @@ class ScrollEventListener() {
105
105
  }
106
106
 
107
107
  /**
108
- * Listens to React Native's scroll events when followers wait for them and it doesn't yet: after a reload there may
109
- * be no event dispatcher at first: then it is asked again once React Native has one, and as the screen joins a
110
- * window.
108
+ * Listens to React Native's scroll views when followers wait for them and it doesn't yet, once it has the screen's
109
+ * view to tell its own lists by; asked again as the screen joins a window.
111
110
  */
112
111
  internal fun attachIfNeeded() {
113
- if (released || stopListening != null || registrations.isEmpty()) return
114
- val context = scope?.get()?.context ?: return
115
- stopListening = ScrollEvents.listen(context, ::onScrollEvent)
116
- if (stopListening == null) ScrollEvents.waitForDispatcher(this)
112
+ if (released || stopListening != null || registrations.isEmpty() || scope?.get() == null) return
113
+ stopListening = ScrollEvents.listen(::onScrollEvent)
117
114
  }
118
115
 
119
116
  /** The screen is destroyed: no follower hears it any more. */