@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
@@ -0,0 +1,49 @@
1
+ package dev.apexnative.navigation.viewcontrollers.bottomtabs
2
+
3
+ import dev.apexnative.navigation.utils.ImageKey
4
+
5
+ /**
6
+ * The last call of each kind for each item of the bar, by which [BottomTabsPresenter.run] skips a call equal to it: an
7
+ * icon isn't loaded and set again as a screen appears. The badge and the font always go (their defaults are read at
8
+ * each set). An icon whose load gave no image goes again ([failed]); a `file:` icon compares by its [ImageKey] (the
9
+ * file's modification time and size, read by [fileKey]), so a file written again at the same path shows. Main thread.
10
+ */
11
+ internal class AppliedTabCalls(private val fileKey: (String) -> ImageKey) {
12
+ /** A call that runs: [isChange], the item had a call of its kind before; [image], the key of a `file:` icon. */
13
+ class Next(val isChange: Boolean, val image: ImageKey?)
14
+
15
+ private class Applied(val call: TabItems.Call, val image: ImageKey?, var failed: Boolean = false)
16
+
17
+ private val last = HashMap<Pair<Int, Class<*>>, Applied>()
18
+
19
+ /** How [call] runs, and it is the last of its kind for its item from now on; none when it is skipped. */
20
+ fun next(call: TabItems.Call): Next? {
21
+ val key = call.index to call.javaClass
22
+ val before = last[key]
23
+ val image = uriOf(call)?.takeIf { it.startsWith(FILE_SCHEME) }?.let(fileKey)
24
+ val always = call is TabItems.Call.Badge || call is TabItems.Call.Font
25
+ if (!always && before != null && before.call == call && !before.failed && before.image == image) return null
26
+ last[key] = Applied(call, image)
27
+ return Next(isChange = before != null, image = image)
28
+ }
29
+
30
+ /** The icon of [call] didn't load: the same call goes again. */
31
+ fun failed(call: TabItems.Call) {
32
+ last[call.index to call.javaClass]?.takeIf { it.call == call }?.failed = true
33
+ }
34
+
35
+ /** The bar goes: every call goes again. */
36
+ fun clear() {
37
+ last.clear()
38
+ }
39
+
40
+ private fun uriOf(call: TabItems.Call): String? = when (call) {
41
+ is TabItems.Call.Icon -> call.uri
42
+ is TabItems.Call.SelectedIcon -> call.uri
43
+ else -> null
44
+ }
45
+
46
+ private companion object {
47
+ const val FILE_SCHEME = "file:"
48
+ }
49
+ }
@@ -2,6 +2,7 @@ package dev.apexnative.navigation.viewcontrollers.bottomtabs
2
2
 
3
3
  import android.view.View
4
4
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ScrollEventListener
5
+ import dev.apexnative.navigation.views.bottomtabs.BottomTabsLayout
5
6
 
6
7
  /**
7
8
  * bottomTabs.hideOnScroll: the tabs hide after a drag that scrolls the screen's content down and come back after one
@@ -43,9 +44,10 @@ class BottomTabsCollapseBehavior(private val container: () -> View?) :
43
44
  override fun onHide() {
44
45
  val view = container() ?: return
45
46
  hiddenByScroll = true
46
- // Out of the screen with what is under it: a compact bar floats over its bottom margin and the navigation bar.
47
- val under = ((view.parent as? View)?.let { it.height - view.bottom } ?: 0).coerceAtLeast(0)
48
- view.animate().translationY((view.height + under).toFloat()).setDuration(DURATION).start()
47
+ // Out of the screen with what is under it (a compact bar floats over its bottom margin and the navigation bar)
48
+ // and the custom row that rises above it.
49
+ val distance = (view.parent as? BottomTabsLayout)?.hideDistance ?: view.height
50
+ view.animate().translationY(distance.toFloat()).setDuration(DURATION).start()
49
51
  }
50
52
 
51
53
  private companion object {
@@ -1,5 +1,8 @@
1
1
  package dev.apexnative.navigation.viewcontrollers.bottomtabs
2
2
 
3
+ import android.animation.Animator
4
+ import android.animation.AnimatorListenerAdapter
5
+ import android.animation.AnimatorSet
3
6
  import android.app.Activity
4
7
  import android.graphics.Color
5
8
  import android.util.Log
@@ -23,16 +26,16 @@ import dev.apexnative.navigation.utils.scrollToTop
23
26
  import dev.apexnative.navigation.viewcontrollers.child.ChildControllersRegistry
24
27
  import dev.apexnative.navigation.viewcontrollers.component.ComponentViewController
25
28
  import dev.apexnative.navigation.viewcontrollers.component.RestPlace
26
- import dev.apexnative.navigation.viewcontrollers.component.ScreenReadiness
27
29
  import dev.apexnative.navigation.viewcontrollers.navigator.BackCallbackState
28
30
  import dev.apexnative.navigation.viewcontrollers.navigator.Navigator
29
31
  import dev.apexnative.navigation.viewcontrollers.parent.ContainerBackground
30
32
  import dev.apexnative.navigation.viewcontrollers.parent.ParentController
31
33
  import dev.apexnative.navigation.viewcontrollers.stack.StackController
32
34
  import dev.apexnative.navigation.viewcontrollers.stack.fab.FabPlacement
33
- import dev.apexnative.navigation.viewcontrollers.stack.topbar.BarComponents
34
35
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.Presenter
35
36
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
37
+ import dev.apexnative.navigation.views.animations.AnimationLayer
38
+ import dev.apexnative.navigation.views.animations.FadeThrough
36
39
  import dev.apexnative.navigation.views.bottomtabs.BottomTabItem
37
40
  import dev.apexnative.navigation.views.bottomtabs.BottomTabsLayout
38
41
  import dev.apexnative.navigation.views.bottomtabs.CustomBottomTabItemView
@@ -68,6 +71,12 @@ class BottomTabsController(
68
71
  private var cells: List<CustomBottomTabItemView> = emptyList()
69
72
  // `ANN.BottomTabSelected` of a press that waits for the new tab's screen to appear.
70
73
  private var pendingSelected: (() -> Unit)? = null
74
+ // Ends the fade through of a switch still running, with its events.
75
+ private var endSwitch: (() -> Unit)? = null
76
+
77
+ // The made tabs that didn't show at the last repaint (new default options, a light/dark switch): each is repainted
78
+ // as it is selected, not while hidden.
79
+ private val staleTabs = mutableSetOf<ViewController<*>>()
71
80
  // The bar goes with a stack's transition: the options of the new top don't move it themselves.
72
81
  private var riding = false
73
82
  private var restAttached = false
@@ -150,8 +159,11 @@ class BottomTabsController(
150
159
  /** The view of [tab] joins, or is there already: [visible], or invisible but laid out. */
151
160
  fun attach(tab: ViewController<*>, visible: Boolean)
152
161
 
153
- /** The view of [shown] becomes visible and that of [hidden] invisible: the switch, at once. */
154
- fun switch(shown: ViewController<*>, hidden: ViewController<*>)
162
+ /**
163
+ * The view of [shown] becomes visible and that of [hidden] invisible: at once, or with Material's fade through
164
+ * when [animated]; then [onEnd]. The function returned ends a switch still running at once, [onEnd] included.
165
+ */
166
+ fun switch(shown: ViewController<*>, hidden: ViewController<*>, animated: Boolean, onEnd: () -> Unit): () -> Unit
155
167
  }
156
168
 
157
169
  /** The views of the tabs; none before the tabs' view is made. */
@@ -166,9 +178,45 @@ class BottomTabsController(
166
178
  tab.view.visibility = if (visible) View.VISIBLE else View.INVISIBLE
167
179
  }
168
180
 
169
- override fun switch(shown: ViewController<*>, hidden: ViewController<*>) {
170
- shown.view.visibility = View.VISIBLE
171
- hidden.peekView()?.visibility = View.INVISIBLE
181
+ override fun switch(
182
+ shown: ViewController<*>,
183
+ hidden: ViewController<*>,
184
+ animated: Boolean,
185
+ onEnd: () -> Unit,
186
+ ): () -> Unit {
187
+ val coming = shown.view
188
+ coming.visibility = View.VISIBLE
189
+ val going = hidden.peekView()
190
+ if (!animated || going == null) {
191
+ going?.visibility = View.INVISIBLE
192
+ onEnd()
193
+ return {}
194
+ }
195
+ val exit = FadeThrough.exit(going)
196
+ // Faded out, the tab that goes takes no more touches and no accessibility focus.
197
+ exit.addListener(object : AnimatorListenerAdapter() {
198
+ override fun onAnimationEnd(animation: Animator) {
199
+ going.visibility = View.INVISIBLE
200
+ }
201
+ })
202
+ val set = AnimatorSet()
203
+ // Each tab fades whole through a hardware layer; a switch ended early ([set]'s end) gives them back too.
204
+ val enter = FadeThrough.enter(coming)
205
+ set.playTogether(AnimationLayer.during(going, exit), AnimationLayer.during(coming, enter))
206
+ set.addListener(object : AnimatorListenerAdapter() {
207
+ override fun onAnimationEnd(animation: Animator) {
208
+ set.removeAllListeners()
209
+ // The tab that went keeps its look for its next selection; only its visibility hides it.
210
+ going.visibility = View.INVISIBLE
211
+ going.alpha = 1f
212
+ coming.alpha = 1f
213
+ coming.scaleX = 1f
214
+ coming.scaleY = 1f
215
+ onEnd()
216
+ }
217
+ })
218
+ set.start()
219
+ return set::end
172
220
  }
173
221
  }
174
222
 
@@ -204,7 +252,7 @@ class BottomTabsController(
204
252
  // `mergeOptions` with the tabs' id: their own options, then what they show, then the layouts around without
205
253
  // `bottomTabs`; the one-shot options act once, also while the view isn't shown.
206
254
  override fun mergeOptions(options: Options) {
207
- this.options = this.options.copy().mergeWith(options)
255
+ mergeOwnOptions(options)
208
256
  applyMerge(options, null)
209
257
  performOnParentController { it.mergeChildOptions(withoutBottomTabs(options), this) }
210
258
  }
@@ -268,8 +316,10 @@ class BottomTabsController(
268
316
  private enum class How { Press, Code, Back }
269
317
 
270
318
  /**
271
- * A tap on the tab at [index], on the bar or on its cell of the custom row: its `ANN.BottomTabPressed` first, then
272
- * the selection, the repeat, or nothing, as its resolved options say.
319
+ * A tap on the tab at [index], on the bar or on its cell of the custom row, the one path of both: a switch still
320
+ * running ends first, with its `ANN.BottomTabSelected`; then this press's `ANN.BottomTabPressed`, then the
321
+ * selection (`ANN.BottomTabSelected` after the new screen's DidAppear), the repeat (the pop's own events), or
322
+ * nothing, as its resolved options say. The same order as `-[ANNBottomTabsController pressTabAtIndex:source:]`.
273
323
  */
274
324
  internal fun onTabPressed(index: Int) {
275
325
  if (isDestroyed || index !in tabs.indices) return
@@ -302,10 +352,9 @@ class BottomTabsController(
302
352
  }
303
353
 
304
354
  /**
305
- * Selects the tab at [index]: what it shows appears, the tab it left disappears — at once, one container invisible
306
- * and the other visible —, then for a press `ANN.BottomTabSelected` right after the new screen's DidAppear and the
307
- * left tab's `popToRootOnBlur`, with the state as one update after them; from code and by back, `popToRootOnBlur`
308
- * and the state at once. The history of back follows.
355
+ * Selects the tab at [index]: the bar shows it at once; on screen the tab it left fades through to it (Material's
356
+ * fade through); off screen, or when the new tab's `bottomTabs.switchAnimation` is `'none'`, one container becomes
357
+ * invisible and the other visible at once; then [switched]. The history of back follows.
309
358
  */
310
359
  private fun select(index: Int, how: How) {
311
360
  if (index == selectedIndex || index !in tabs.indices || isDestroyed) return
@@ -321,6 +370,9 @@ class BottomTabsController(
321
370
  }
322
371
  selectedIndex = index
323
372
  attach(index)
373
+ // A tab hidden at a repaint takes it now, before its screens appear: its bar's parts, its search's and its
374
+ // FAB's colors follow the theme and the defaults only through a repaint.
375
+ if (staleTabs.remove(shown)) Navigator.repaintLayer(shown)
324
376
  peekView()?.bar?.let {
325
377
  it.setCurrentItem(index, false)
326
378
  it.onCustomItemViewSelectionChanged(index)
@@ -328,10 +380,30 @@ class BottomTabsController(
328
380
  // A layer that waits for the tabs waits for the tab they show now.
329
381
  navigator?.shownScreensChanged(this)
330
382
  if (onScreen) AppearanceDispatcher.beginTransition(listOf(shown))
331
- views?.switch(shown, left)
383
+ // From code and by back the state goes at once, as on iOS: `selectTab` resolves on it, and the command after
384
+ // it must act in this tab, not in the one still fading out.
385
+ if (how != How.Press) AppearanceDispatcher.reportState()
386
+ if (views == null) return switched(index, previous, how, onScreen, hasViews = false)
387
+ endSwitch = views.switch(shown, left, animated = onScreen && fadesThrough(shown)) {
388
+ endSwitch = null
389
+ if (!isDestroyed) switched(index, previous, how, onScreen, hasViews = true)
390
+ }
391
+ }
392
+
393
+ /**
394
+ * The switch to the tab at [index] from [previous] ended: what went disappears, what came appears — unless the tabs
395
+ * stopped showing during the fade (a modal over them): it appears when they show again; then for a press
396
+ * `ANN.BottomTabSelected` right after the new screen's DidAppear and the left tab's `popToRootOnBlur`, with the state
397
+ * as one update after them; from code and by back, `popToRootOnBlur` and the state, which went at the start too
398
+ * ([select]). [onScreen]: the switch started on screen.
399
+ */
400
+ private fun switched(index: Int, previous: Int, how: How, onScreen: Boolean, hasViews: Boolean) {
401
+ val left = tabs[previous]
402
+ val shown = tabs[index]
332
403
  if (onScreen) {
333
- AppearanceDispatcher.endTransition(listOf(left), listOf(shown), null, null, null, reportsState = false)
334
- } else if (views != null) {
404
+ val showing = if (isOnScreen) listOf(shown) else emptyList()
405
+ AppearanceDispatcher.endTransition(listOf(left), showing, null, null, null, reportsState = false)
406
+ } else if (hasViews) {
335
407
  // Not on screen: the bar takes the new tab's options as they are, without appearance events.
336
408
  val options = resolveShownOptions(DefaultOptions.current)
337
409
  bar.applyBar(options.bottomTabs, directionOf(options))
@@ -358,8 +430,15 @@ class BottomTabsController(
358
430
  if (screen == null) finish() else AppearanceDispatcher.afterDidAppear(screen, finish)
359
431
  }
360
432
 
361
- // A press's `ANN.BottomTabSelected` still waiting goes before anything newer on these tabs.
433
+ // `bottomTabs.switchAnimation` of the tab that shows, its shown screen's over its own, the tabs' and the defaults:
434
+ // `'platform'`, the default, fades through; `'none'` switches at once.
435
+ private fun fadesThrough(tab: ViewController<*>): Boolean =
436
+ tab.resolveShownOptions(DefaultOptions.current).bottomTabs.switchAnimation.get(null) != "none"
437
+
438
+ // A switch still running ends at once and a press's `ANN.BottomTabSelected` still waiting goes, before anything
439
+ // newer on these tabs.
362
440
  private fun flushPendingSelected() {
441
+ endSwitch?.invoke()
363
442
  pendingSelected?.invoke()
364
443
  }
365
444
 
@@ -477,9 +556,6 @@ class BottomTabsController(
477
556
  return TabsRoom.tabsTop(room(), screenOptions(screen), bottom)
478
557
  }
479
558
 
480
- override fun leavesBottomEdgeFree(child: ViewController<*>, screen: ViewController<*>): Boolean =
481
- TabsRoom.leavesBottomEdgeFree(screenOptions(screen)) || super.leavesBottomEdgeFree(child, screen)
482
-
483
559
  override fun tabsAtRestOf(child: ViewController<*>, screen: ViewController<*>): FabPlacement.Tabs? {
484
560
  if (peekView() == null) return super.tabsAtRestOf(child, screen)
485
561
  return TabsRoom.fabTabs(room(), screenOptions(screen))
@@ -531,8 +607,8 @@ class BottomTabsController(
531
607
  }
532
608
  }
533
609
 
534
- // The repaint: the bar, the items of every tab, the row, then the made tabs that don't show, which the pass over
535
- // what shows doesn't reach.
610
+ // The repaint: the bar, the items of every tab, the row. Only what shows is repainted (the pass over what shows
611
+ // reaches the selected tab); a made tab that doesn't show is repainted when it is selected ([staleTabs]).
536
612
  internal fun repaint(options: Options) {
537
613
  if (isDestroyed) return
538
614
  ContainerBackground.apply(this, options)
@@ -542,7 +618,7 @@ class BottomTabsController(
542
618
  if (usesRow) layout.bar.customRowOptions = options.bottomTabs.customRow.copy()
543
619
  }
544
620
  cells.forEachIndexed { index, cell -> cell.update(cellState(index)) }
545
- tabs.forEach { if (it !== currentChild && it.isViewCreated) Navigator.repaintLayer(it) }
621
+ tabs.forEach { if (it !== currentChild && it.isViewCreated) staleTabs += it }
546
622
  }
547
623
 
548
624
  // The custom row: the cells first into the bar's external host, then the row holds them; its look follows the tabs'
@@ -560,7 +636,6 @@ class BottomTabsController(
560
636
  layout.row = row
561
637
  layout.bar.customRowOptionsListener = { applyRow(row, it) }
562
638
  layout.bar.customRowOptions = resolveShownOptions(DefaultOptions.current).bottomTabs.customRow.copy()
563
- CustomTabRowPlacer.track(activity)
564
639
  }
565
640
 
566
641
  private fun applyRow(row: CustomTabRow, options: BottomTabsCustomRowOptions) {
@@ -590,15 +665,12 @@ class BottomTabsController(
590
665
  private fun makeCell(index: Int): CustomBottomTabItemView {
591
666
  val component = itemOptions(index).component
592
667
  val componentId = component.componentId.get(null) ?: "$id.$index"
593
- ScreenReadiness.setRendersAtOnce(componentId, true)
594
- // Another live root has the id (the same layout set again before the old one went): what it rendered isn't
595
- // this one's; the id's readiness goes only with its last root (as the bar's roots).
596
- if (BarComponents.isLive(componentId)) ScreenReadiness.forgetRender(componentId)
597
- BarComponents.rootMade(componentId)
598
668
  val cell = CustomBottomTabItemView(activity)
599
669
  val state = cellState(index)
600
- cell.show(ReactView(activity, componentId, component.name.get(""), cell.bundleOf(state)), state)
601
- cell.onDestroyed = { if (BarComponents.rootStopped(componentId)) ScreenReadiness.remove(componentId) }
670
+ // Another live root may have the id (the same layout set again before the old one went): each answers by the
671
+ // render of its own surface, and the id's readiness goes with its last root.
672
+ val root = ReactView(activity, componentId, component.name.get(""), cell.bundleOf(state), rendersAtOnce = true)
673
+ cell.show(root, state)
602
674
  return cell
603
675
  }
604
676
 
@@ -615,15 +687,17 @@ class BottomTabsController(
615
687
 
616
688
  /**
617
689
  * Destroys the tabs once: every tab and the registry first, then the cells (each stops its root once), the row out
618
- * of the window, the scroll it followed. A press's event still waiting goes with them.
690
+ * of the tabs' view, the scroll it followed. A press's event still waiting goes with them.
619
691
  */
620
692
  override fun destroy() {
621
693
  if (isDestroyed) return
622
694
  pendingSelected = null
695
+ staleTabs.clear()
623
696
  super.destroy()
697
+ // A switch still running ends with its views at rest, without events: the tabs are gone.
698
+ endSwitch?.invoke()
624
699
  peekView()?.let { layout ->
625
700
  layout.bar.destroyCustomItemViews()
626
- layout.row?.let(CustomTabRowPlacer::forget)
627
701
  layout.row = null
628
702
  }
629
703
  cells = emptyList()
@@ -6,7 +6,6 @@ import android.animation.AnimatorSet
6
6
  import android.animation.ObjectAnimator
7
7
  import android.app.Activity
8
8
  import android.graphics.Color
9
- import android.graphics.drawable.Drawable
10
9
  import android.view.View
11
10
  import android.view.animation.LinearInterpolator
12
11
  import android.view.animation.PathInterpolator
@@ -20,8 +19,8 @@ import dev.apexnative.navigation.options.params.LayoutDirection
20
19
  import dev.apexnative.navigation.options.params.ThemeColour
21
20
  import dev.apexnative.navigation.options.parsers.TypefaceLoader
22
21
  import dev.apexnative.navigation.system.SystemUiOwner
23
- import dev.apexnative.navigation.utils.ImageLoader
24
- import dev.apexnative.navigation.utils.ImageLoadingListenerAdapter
22
+ import dev.apexnative.navigation.utils.ImageRequests
23
+ import dev.apexnative.navigation.utils.OptionImages
25
24
  import dev.apexnative.navigation.utils.TestIds
26
25
  import dev.apexnative.navigation.utils.UiUtils
27
26
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.Presenter
@@ -67,8 +66,9 @@ internal open class BottomTabsPresenter(activity: Activity) : Presenter(activity
67
66
 
68
67
  private var layout: BottomTabsLayout? = null
69
68
  private val typefaces = TypefaceLoader(activity)
70
- private val icons = HashMap<String, Drawable>()
71
- private val applied = HashMap<Pair<Int, Class<*>>, TabItems.Call>()
69
+ // The icons of the items by item and kind (selected or not): those of the cache at once, the others as below.
70
+ private val icons = ImageRequests<Pair<Int, Boolean>>(OptionImages.source(activity))
71
+ private val applied = AppliedTabCalls(icons::key)
72
72
  private var motion: Animator? = null
73
73
  private var anyIcon = false
74
74
  private var testId: String? = null
@@ -100,25 +100,24 @@ internal open class BottomTabsPresenter(activity: Activity) : Presenter(activity
100
100
 
101
101
  /**
102
102
  * Runs [calls] on the bar's items; a call equal to the last of its kind for its item is skipped (an icon isn't
103
- * loaded and set again as a screen appears). The badge always goes: its default colors are read at each set.
103
+ * loaded and set again as a screen appears), except the badge and the font, an icon that didn't load and a `file:`
104
+ * icon whose file changed ([AppliedTabCalls]).
104
105
  */
105
106
  open fun run(calls: List<TabItems.Call>) {
106
107
  val bar = layout?.bar ?: return
107
108
  for (call in calls) {
108
109
  if (call is TabItems.Call.TestId && !itemTestIds) continue
109
- val key = call.index to call.javaClass
110
- if (call !is TabItems.Call.Badge && call !is TabItems.Call.Font && applied[key] == call) continue
111
- applied[key] = call
112
- run(bar, call)
110
+ val next = applied.next(call) ?: continue
111
+ run(bar, call, next)
113
112
  }
114
113
  }
115
114
 
116
- private fun run(bar: BottomTabs, call: TabItems.Call) {
115
+ private fun run(bar: BottomTabs, call: TabItems.Call, next: AppliedTabCalls.Next) {
117
116
  val index = call.index
118
117
  when (call) {
119
118
  is TabItems.Call.Title -> bar.setText(index, call.text)
120
- is TabItems.Call.Icon -> iconOf(call.uri)?.let { bar.setIcon(index, it) }
121
- is TabItems.Call.SelectedIcon -> iconOf(call.uri)?.let { bar.setSelectedIcon(index, it) }
119
+ is TabItems.Call.Icon -> icon(bar, call, call.uri, false, next)
120
+ is TabItems.Call.SelectedIcon -> icon(bar, call, call.uri, true, next)
122
121
  is TabItems.Call.Colors -> {
123
122
  bar.setIconActiveColor(index, call.iconActive)
124
123
  bar.setIconInactiveColor(index, call.iconInactive)
@@ -344,17 +343,19 @@ internal open class BottomTabsPresenter(activity: Activity) : Presenter(activity
344
343
 
345
344
  private fun colorOf(colour: ThemeColour): Int? = colour.get(activity, null)
346
345
 
347
- // Icons load as they apply and never throw: an icon that doesn't load leaves the item as it was.
348
- private fun iconOf(uri: String): Drawable? {
349
- icons[uri]?.let { return it.constantState?.newDrawable()?.mutate() ?: it }
350
- var loaded: Drawable? = null
351
- ImageLoader().loadIcon(activity, uri, object : ImageLoadingListenerAdapter() {
352
- override fun onComplete(drawable: Drawable) {
353
- loaded = drawable
354
- }
355
- })
356
- loaded?.let { icons[uri] = it }
357
- return loaded
346
+ // Icons never throw: one that doesn't load leaves the item without it (without its selected icon, the item shows
347
+ // its icon when selected). An item's first icon loads at once, its tab's first frame shows it; a change of it on
348
+ // the bar that shows loads off the main thread when it can, and the item takes it when ready, unless a newer icon
349
+ // of the item came first.
350
+ // The key of a `file:` icon was built for the comparison: the request takes it, its file read once.
351
+ private fun icon(bar: BottomTabs, call: TabItems.Call, uri: String, selected: Boolean, next: AppliedTabCalls.Next) {
352
+ val index = call.index
353
+ val key = next.image ?: icons.key(uri)
354
+ icons.request(index to selected, key, mayWait = next.isChange && bar.isAttachedToWindow) { icon ->
355
+ if (icon == null) applied.failed(call)
356
+ val shown = layout?.bar ?: return@request
357
+ if (selected) shown.setSelectedIcon(index, icon) else shown.setIcon(index, icon)
358
+ }
358
359
  }
359
360
 
360
361
  private companion object {
@@ -49,6 +49,22 @@ internal object CustomTabRowGeometry {
49
49
  content = content,
50
50
  )
51
51
 
52
+ /**
53
+ * The row over the bar as the tabs' view lays it out: the bar's [barLeft], [barRight] and [barBottom] in that
54
+ * view, whose height is [tabsHeight] and whose bottom [navigationBar] pixels lie under the navigation bar — the
55
+ * row's bottom never goes over them —, with [margin], [content] and [bottomMargin] as [place] takes them.
56
+ */
57
+ fun inTabs(
58
+ barLeft: Int,
59
+ barRight: Int,
60
+ barBottom: Int,
61
+ tabsHeight: Int,
62
+ navigationBar: Int,
63
+ margin: Int,
64
+ content: Int,
65
+ bottomMargin: Int,
66
+ ): Place = place(barLeft, barRight, minOf(barBottom, tabsHeight - navigationBar), margin, content, bottomMargin)
67
+
52
68
  /**
53
69
  * The part of the row's frame at [place] below its visible part, in pixels: `bottomMargin`. The row draws and takes
54
70
  * touches only above it.
@@ -61,6 +77,12 @@ internal object CustomTabRowGeometry {
61
77
  */
62
78
  fun needsPlacing(last: Place?, next: Place): Boolean = last != next
63
79
 
80
+ /**
81
+ * The row's own lift over its [elevation] while the bar's container stands at [barZ]: as high as the container, so
82
+ * the row, after it in the tabs' view, draws over it and takes the touches first even under a raised bar.
83
+ */
84
+ fun lift(barZ: Float, elevation: Float): Float = (barZ - elevation).coerceAtLeast(0f)
85
+
64
86
  /**
65
87
  * The row's background: `customRow.backgroundColor` ([color]; `null` and `'NoColor'` are none); without it
66
88
  * `backgroundEffect: 'none'` ([effect]) is clear, any other effect or none the theme's `android:colorBackground`
@@ -36,7 +36,7 @@ internal class TabItems(private val color: (ThemeColour) -> Int?) {
36
36
  ) : Call()
37
37
 
38
38
  /** The icon's size in dp, width over height. */
39
- data class IconSize(override val index: Int, val width: Int?, val height: Int?) : Call()
39
+ data class IconSize(override val index: Int, val width: Double?, val height: Double?) : Call()
40
40
 
41
41
  data class Font(override val index: Int, val font: FontOptions) : Call()
42
42
 
@@ -86,7 +86,7 @@ internal class TabItems(private val color: (ThemeColour) -> Int?) {
86
86
  options.icon.get(null)?.let { Call.Icon(index, it) },
87
87
  options.selectedIcon.get(null)?.let { Call.SelectedIcon(index, it) },
88
88
  colors(index, options),
89
- Call.IconSize(index, options.iconWidth.get(null)?.toInt(), options.iconHeight.get(null)?.toInt()),
89
+ Call.IconSize(index, options.iconWidth.get(null), options.iconHeight.get(null)),
90
90
  Call.Font(index, options.font.copy()),
91
91
  Call.FontSizes(index, options.selectedFontSize.get(null)?.toFloat(), options.fontSize.get(null)?.toFloat()),
92
92
  Call.TestId(index, options.testID.get(null)),
@@ -110,7 +110,7 @@ internal class TabItems(private val color: (ThemeColour) -> Int?) {
110
110
  calls += colors(index, resolved)
111
111
  }
112
112
  if (merge.iconWidth.hasValue() || merge.iconHeight.hasValue()) {
113
- calls += Call.IconSize(index, resolved.iconWidth.get(null)?.toInt(), resolved.iconHeight.get(null)?.toInt())
113
+ calls += Call.IconSize(index, resolved.iconWidth.get(null), resolved.iconHeight.get(null))
114
114
  }
115
115
  if (merge.font.hasValue()) calls += Call.Font(index, resolved.font.copy())
116
116
  if (merge.fontSize.hasValue() || merge.selectedFontSize.hasValue()) {
@@ -58,11 +58,6 @@ internal object TabsRoom {
58
58
  fun tabsTop(bar: Bar, screen: Screen, tabsBottom: Int): Int? =
59
59
  if (screen.hidden) null else tabsBottom - bar.reach - bar.rowOvershoot
60
60
 
61
- /**
62
- * The safe area of the screen leaves its bottom edge free: the bar hides on scroll and shows for it.
63
- */
64
- fun leavesBottomEdgeFree(screen: Screen): Boolean = screen.hideOnScroll && !screen.hidden
65
-
66
61
  /**
67
62
  * The bar at rest under a stack's FAB: also when the screen is under it (`drawBehind`, `hideOnScroll`); none when
68
63
  * the screen hides it.
@@ -6,6 +6,7 @@ import android.graphics.drawable.ColorDrawable
6
6
  import android.graphics.drawable.Drawable
7
7
  import android.graphics.drawable.LayerDrawable
8
8
  import android.view.View
9
+ import com.google.android.material.color.MaterialColors
9
10
  import dev.apexnative.navigation.options.DefaultOptions
10
11
  import dev.apexnative.navigation.options.Options
11
12
  import dev.apexnative.navigation.options.params.ThemeColour
@@ -15,9 +16,9 @@ import dev.apexnative.navigation.viewcontrollers.viewcontroller.Presenter
15
16
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
16
17
 
17
18
  /**
18
- * The presenter of a screen, React or native: its background — the screen's view takes `layout.backgroundColor`, kept
19
- * out of the status bar's height where the status bar shows over it, and the React content takes
20
- * `layout.componentBackgroundColor` over it —, its room for the bars, and its safe area again on `mergeOptions`
19
+ * The presenter of a screen, React or native: its background — the screen's view takes `layout.backgroundColor` (a
20
+ * React screen without it the theme's background), kept out of the status bar's height where the status bar shows over
21
+ * it, and the React content takes `layout.componentBackgroundColor` over it —, its room for the bars, and its safe area again on `mergeOptions`
21
22
  * (`mergeOptions` step 4). It applies as the screen appears, on `mergeOptions` of what it covers, and again with new
22
23
  * default options or after a light/dark switch from the resolved options it is given, which it never writes. Each
23
24
  * appearance tells the activity's system UI owner, which follows the screen on top. Main thread only.
@@ -49,8 +50,8 @@ open class ComponentPresenter(activity: Activity) : Presenter(activity, DefaultO
49
50
  applyBackground(controller, options)
50
51
 
51
52
  /**
52
- * The colors of [screen] from its resolved [options]: `layout.backgroundColor` on the screen's view, none without
53
- * it (the window shows); `layout.componentBackgroundColor` on its React content.
53
+ * The colors of [screen] from its resolved [options]: `layout.backgroundColor` on the screen's view, without it the
54
+ * theme's background for a React screen ([defaultColorOf]); `layout.componentBackgroundColor` on its React content.
54
55
  */
55
56
  fun applyBackground(screen: ViewController<*>, options: Options) {
56
57
  val view = screen.peekView() ?: return
@@ -59,11 +60,11 @@ open class ComponentPresenter(activity: Activity) : Presenter(activity, DefaultO
59
60
  }
60
61
 
61
62
  private fun screenBackground(screen: ViewController<*>, options: Options): Drawable? {
62
- val color = colorOf(options.layout.backgroundColor) ?: return null
63
+ val color = colorOf(options.layout.backgroundColor) ?: defaultColorOf(screen) ?: return null
63
64
  val frame = frameOf(screen) ?: return ColorDrawable(color)
64
65
  val band = ScreenSafeArea.backgroundBand(
65
66
  statusBarHeight = frame.statusBarHeight,
66
- hiddenOrDrawBehind = options.statusBar.isHiddenOrDrawBehind,
67
+ hiddenOrDrawBehind = options.statusBar.isHiddenOrDrawBehind(screen.isInOverlay),
67
68
  inSideMenu = screen.isInSideMenu,
68
69
  inSheet = screen.isInSheet,
69
70
  inPair = frame.isInPair,
@@ -79,6 +80,15 @@ open class ComponentPresenter(activity: Activity) : Presenter(activity, DefaultO
79
80
  private fun colorOf(colour: ThemeColour): Int? =
80
81
  if (colour.hasValue()) colour.get(activity, Color.TRANSPARENT) ?: Color.TRANSPARENT else null
81
82
 
83
+ // A React screen is opaque without a color of its own, as iOS gives it the system background: the screen under it
84
+ // never shows through, also while a push slides it aside. The app theme's `android:colorBackground`, read now, so a
85
+ // light/dark switch takes the new mode's. A screen of a sheet shows the sheet's surface; a native screen paints its
86
+ // own view.
87
+ private fun defaultColorOf(screen: ViewController<*>): Int? {
88
+ if (screen !is ComponentViewController || screen.isInSheet) return null
89
+ return themeBackgroundOf(activity)
90
+ }
91
+
82
92
  private fun frameOf(screen: ViewController<*>): ScreenFrame? = when (screen) {
83
93
  is ComponentViewController -> screen.frame
84
94
  is ExternalComponentViewController -> screen.frame
@@ -87,4 +97,15 @@ open class ComponentPresenter(activity: Activity) : Presenter(activity, DefaultO
87
97
 
88
98
  // The view under the React content: the React root, or the container of a slot screen. A native screen has none.
89
99
  private fun contentOf(screen: ViewController<*>): View? = (screen as? ComponentViewController)?.content?.asView()
100
+
101
+ internal companion object {
102
+ /**
103
+ * The background of a React screen without `layout.backgroundColor`: `android:colorBackground` of [activity]'s
104
+ * theme now. None for an activity without a theme (the unit tests' fakes).
105
+ */
106
+ fun themeBackgroundOf(activity: Activity): Int? {
107
+ if (activity.theme == null) return null
108
+ return MaterialColors.getColor(activity, android.R.attr.colorBackground, Color.WHITE)
109
+ }
110
+ }
90
111
  }