@apexnative/navigation 1.0.0-alpha.1 → 1.0.0-alpha.11

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 (581) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +132 -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/ArrangementDefinition.kt +9 -3
  67. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementPlanner.kt +20 -15
  68. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
  69. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
  70. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
  71. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +108 -34
  72. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
  73. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
  74. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
  75. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
  76. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
  77. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +12 -9
  78. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
  79. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
  80. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
  81. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
  82. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
  83. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
  84. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
  85. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +109 -21
  86. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
  87. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +476 -73
  88. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +57 -25
  89. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
  90. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +83 -0
  91. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
  92. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +49 -14
  93. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +71 -12
  94. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +37 -11
  95. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
  96. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
  97. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
  98. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +6 -6
  99. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +42 -9
  100. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +19 -8
  101. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
  102. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +43 -4
  103. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
  104. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +77 -17
  105. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +315 -0
  106. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
  107. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +30 -20
  108. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +216 -18
  109. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
  110. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +149 -41
  111. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
  112. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +115 -6
  113. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
  114. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +222 -48
  115. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
  116. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +30 -34
  117. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
  118. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
  119. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
  120. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
  121. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +219 -54
  122. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
  123. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
  124. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
  125. package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
  126. package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
  127. package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
  128. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +9 -7
  129. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
  130. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
  131. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
  132. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
  133. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +143 -135
  134. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +13 -5
  135. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
  136. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
  137. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
  138. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +112 -4
  139. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
  140. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
  141. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +56 -41
  142. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
  143. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
  144. package/android/src/main/java/dev/apexnative/navigation/views/sidemenu/SideMenuView.kt +12 -3
  145. package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +45 -0
  146. package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +140 -1
  147. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
  148. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
  149. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
  150. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -17
  151. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +73 -34
  152. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
  153. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
  154. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
  155. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +125 -178
  156. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
  157. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
  158. package/android/src/main/jni/ANNContentHeights.cpp +82 -0
  159. package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
  160. package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
  161. package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
  162. package/android/src/main/res/values/styles.xml +1 -1
  163. package/android/src/main/res/values-night/styles.xml +1 -1
  164. package/cli/app.js +1 -1
  165. package/cli/doctor/checks/app.js +77 -14
  166. package/cli/doctor/checks/splash.js +4 -22
  167. package/cli/migrate/native.js +18 -0
  168. package/cli/project.js +10 -2
  169. package/cli/setup/index.js +18 -0
  170. package/cli/setup/source.js +2 -1
  171. package/cli/setup/steps/appDelegate.js +66 -11
  172. package/cli/setup/steps/mainApplication.js +134 -19
  173. package/cli/setup/steps/metro.js +46 -0
  174. package/cli/setup/steps/sceneDelegate.js +108 -0
  175. package/cli/splash/index.js +3 -1
  176. package/docs-md/architecture/native-screens.md +4 -0
  177. package/docs-md/architecture/theme-and-context.md +131 -12
  178. package/docs-md/architecture/transitions.md +58 -12
  179. package/docs-md/containers/arrangement.md +17 -1
  180. package/docs-md/containers/modals.md +8 -4
  181. package/docs-md/containers/overlays.md +3 -1
  182. package/docs-md/containers/side-menu.md +19 -2
  183. package/docs-md/containers/tabs.md +5 -1
  184. package/docs-md/flows/bottom-sheets.md +4 -2
  185. package/docs-md/flows/forms-in-a-modal.md +1 -1
  186. package/docs-md/fundamentals/screens-and-props.md +9 -1
  187. package/docs-md/fundamentals/starting-the-app.md +1 -1
  188. package/docs-md/guides/cli.md +4 -3
  189. package/docs-md/guides/deep-links.md +15 -33
  190. package/docs-md/help/glossary.md +4 -4
  191. package/docs-md/help/troubleshooting.md +44 -6
  192. package/docs-md/index.json +61 -1
  193. package/docs-md/migration/from-expo-router.md +1 -1
  194. package/docs-md/migration/from-react-native-navigation.md +9 -3
  195. package/docs-md/migration/from-react-navigation.md +2 -2
  196. package/docs-md/screen-ui/back-and-gestures.md +46 -2
  197. package/docs-md/screen-ui/bar-buttons.md +5 -5
  198. package/docs-md/screen-ui/search.md +1 -1
  199. package/docs-md/screen-ui/system-ui.md +17 -12
  200. package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
  201. package/docs-md/screen-ui/top-bar.md +8 -4
  202. package/docs-md/start/installation.md +21 -3
  203. package/ios/Animations/ANNFrameDriver.h +55 -15
  204. package/ios/Animations/ANNFrameDriver.mm +216 -60
  205. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  206. package/ios/Animations/ANNTransitionAnimator.mm +61 -13
  207. package/ios/Animations/ANNTransitionPlan.h +2 -2
  208. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  209. package/ios/Animations/ANNTransitionWait.mm +6 -7
  210. package/ios/Animations/Elements/ANNElementFinder.h +57 -0
  211. package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
  212. package/ios/Animations/Elements/ANNElementTransition.h +10 -8
  213. package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
  214. package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
  215. package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
  216. package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
  217. package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
  218. package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
  219. package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
  220. package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
  221. package/ios/CLAUDE.md +60 -24
  222. package/ios/CORE.md +44 -34
  223. package/ios/Contract/ANNCommandAnswer.h +13 -5
  224. package/ios/Contract/ANNCommandAnswer.mm +40 -32
  225. package/ios/Contract/ANNCommandContract.h +15 -0
  226. package/ios/Contract/ANNCommandContract.mm +78 -0
  227. package/ios/Contract/ANNCommandRunner.h +10 -9
  228. package/ios/Contract/ANNCommandRunner.mm +22 -28
  229. package/ios/Contract/ANNErrorTexts.h +6 -2
  230. package/ios/Contract/ANNErrorTexts.mm +18 -10
  231. package/ios/Contract/ANNLayoutNode.h +3 -3
  232. package/ios/Contract/ANNLayoutReader.h +3 -3
  233. package/ios/Core/ANNAppDelegate.mm +0 -2
  234. package/ios/Core/ANNAppearanceDispatcher.h +5 -4
  235. package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
  236. package/ios/Core/ANNDeepLinkQueue.h +22 -2
  237. package/ios/Core/ANNDeepLinkQueue.mm +121 -14
  238. package/ios/Core/ANNErrorHandler.h +9 -4
  239. package/ios/Core/ANNErrorHandler.mm +20 -2
  240. package/ios/Core/ANNEventContract.h +246 -0
  241. package/ios/Core/ANNEventContract.mm +225 -0
  242. package/ios/Core/ANNEventEmitter.h +6 -2
  243. package/ios/Core/ANNEventEmitter.mm +117 -80
  244. package/ios/Core/ANNHinge.h +6 -0
  245. package/ios/Core/ANNHinge.mm +15 -4
  246. package/ios/Core/ANNJavaScriptCalls.h +33 -0
  247. package/ios/Core/ANNJavaScriptCalls.mm +52 -0
  248. package/ios/Core/ANNLayoutProtocol.h +5 -5
  249. package/ios/Core/ANNNavigationState.h +7 -5
  250. package/ios/Core/ANNNavigationState.mm +8 -7
  251. package/ios/Core/ANNNodeHelper.h +32 -12
  252. package/ios/Core/ANNNodeHelper.mm +100 -3
  253. package/ios/Core/ANNParking.h +5 -4
  254. package/ios/Core/ANNReloadCoordinator.mm +5 -12
  255. package/ios/Core/ANNRenderWait.h +20 -6
  256. package/ios/Core/ANNRenderWait.mm +143 -56
  257. package/ios/Core/ANNSceneDelegate.mm +25 -15
  258. package/ios/Core/ANNSystemUI.h +3 -2
  259. package/ios/Core/ANNSystemUI.mm +7 -0
  260. package/ios/Core/ANNUtils.h +7 -0
  261. package/ios/Core/ANNUtils.mm +10 -0
  262. package/ios/Core/ApexNavigation+Internal.h +1 -1
  263. package/ios/Core/ApexNavigation.mm +7 -6
  264. package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
  265. package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
  266. package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
  267. package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
  268. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +195 -21
  269. package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
  270. package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
  271. package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
  272. package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
  273. package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
  274. package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
  275. package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
  276. package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
  277. package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
  278. package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
  279. package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
  280. package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
  281. package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
  282. package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
  283. package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
  284. package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
  285. package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
  286. package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
  287. package/ios/Layouts/Screen/ANNScreenPlace.h +53 -0
  288. package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
  289. package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
  290. package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
  291. package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
  292. package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
  293. package/ios/Layouts/Screen/ANNScreenSettling.h +34 -0
  294. package/ios/Layouts/Screen/ANNScreenSettling.mm +171 -0
  295. package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
  296. package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
  297. package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
  298. package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
  299. package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
  300. package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
  301. package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
  302. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  303. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  304. package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
  305. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  306. package/ios/Layouts/Stack/ANNStackController.mm +184 -16
  307. package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
  308. package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
  309. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  310. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  311. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  312. package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
  313. package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
  314. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
  315. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
  316. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
  317. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
  318. package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
  319. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
  320. package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
  321. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
  322. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
  323. package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
  324. package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
  325. package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
  326. package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
  327. package/ios/Options/ANNAnimationOptions.h +2 -1
  328. package/ios/Options/ANNAnimationOptions.mm +1 -1
  329. package/ios/Options/ANNBottomTabsOptions.h +2 -0
  330. package/ios/Options/ANNBottomTabsOptions.mm +1 -0
  331. package/ios/Options/ANNOptions.h +25 -0
  332. package/ios/Options/ANNOptions.mm +157 -1
  333. package/ios/Options/ANNOptionsCache.h +7 -6
  334. package/ios/Options/ANNOptionsReader.mm +108 -0
  335. package/ios/Options/ANNSearchBarOptions.h +4 -3
  336. package/ios/Options/ANNSheetOptions.h +4 -1
  337. package/ios/Options/ANNSideMenuOptions.h +2 -0
  338. package/ios/Options/ANNSideMenuOptions.mm +2 -0
  339. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  340. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  341. package/ios/Options/ANNUserChoice.h +57 -0
  342. package/ios/Options/ANNUserChoice.mm +44 -0
  343. package/ios/Options/Params/ANNImageSource.h +61 -0
  344. package/ios/Options/Params/ANNImageSource.mm +101 -0
  345. package/ios/Options/Params/ANNOptionImages.h +37 -0
  346. package/ios/Options/Params/ANNOptionImages.mm +284 -0
  347. package/ios/Options/Params/ANNParam.h +15 -0
  348. package/ios/Options/Params/ANNParam.mm +61 -0
  349. package/ios/Options/Params/Color.h +3 -0
  350. package/ios/Options/Params/Color.mm +21 -0
  351. package/ios/Options/Params/ColorParser.h +4 -3
  352. package/ios/Options/Params/ColorParser.mm +22 -4
  353. package/ios/Options/Params/Image.h +15 -2
  354. package/ios/Options/Params/Image.mm +35 -2
  355. package/ios/Options/Params/ImageParser.h +5 -5
  356. package/ios/Options/Params/ImageParser.mm +28 -46
  357. package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
  358. package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
  359. package/ios/RECIPES.md +13 -6
  360. package/ios/React/ANNReactView.mm +6 -25
  361. package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
  362. package/ios/React/ANNSurfaceHostingView.h +14 -0
  363. package/ios/React/ANNSurfaceHostingView.mm +144 -1
  364. package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
  365. package/ios/React/Slots/ANNSlotContainers.h +14 -6
  366. package/ios/React/Slots/ANNSlotContainers.mm +75 -2
  367. package/ios/React/Slots/ANNSlotHost.mm +1 -3
  368. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  369. package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
  370. package/ios/TopBar/ANNBarAppearance.h +2 -1
  371. package/ios/TopBar/ANNBarAppearance.mm +111 -30
  372. package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
  373. package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
  374. package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
  375. package/ios/TopBar/ANNBarButtons.h +14 -8
  376. package/ios/TopBar/ANNBarButtons.mm +397 -80
  377. package/ios/TopBar/ANNIconButtonImage.h +1 -0
  378. package/ios/TopBar/ANNIconButtonImage.mm +34 -1
  379. package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
  380. package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
  381. package/ios/TopBar/ANNMainList.h +3 -0
  382. package/ios/TopBar/ANNMainList.mm +4 -0
  383. package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
  384. package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
  385. package/ios/TopBar/ANNSearchPresenter.mm +172 -21
  386. package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
  387. package/ios/TopBar/ANNTopBarPresenter.h +8 -2
  388. package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
  389. package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
  390. package/ios/TurboModules/ANNTurboModule.mm +104 -33
  391. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  392. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  393. package/lib/module/ARCHITECTURE.md +40 -27
  394. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  395. package/lib/module/api/app/AppRegistry.js +14 -2
  396. package/lib/module/api/app/AppRegistry.js.map +1 -1
  397. package/lib/module/api/app/createNavigation.js +190 -66
  398. package/lib/module/api/app/createNavigation.js.map +1 -1
  399. package/lib/module/api/commands/commands.js +54 -6
  400. package/lib/module/api/commands/commands.js.map +1 -1
  401. package/lib/module/api/events/navigationEvents.js +6 -2
  402. package/lib/module/api/events/navigationEvents.js.map +1 -1
  403. package/lib/module/api/hooks/useNavigation.js +8 -3
  404. package/lib/module/api/hooks/useNavigation.js.map +1 -1
  405. package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
  406. package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
  407. package/lib/module/api/linking/dispatchedLinks.js +23 -0
  408. package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
  409. package/lib/module/api/linking/linking.js +11 -0
  410. package/lib/module/api/linking/linking.js.map +1 -1
  411. package/lib/module/api/navigation.js.map +1 -1
  412. package/lib/module/api/options/OptionsChain.js +2 -2
  413. package/lib/module/api/screens/arrangement.js +5 -2
  414. package/lib/module/api/screens/arrangement.js.map +1 -1
  415. package/lib/module/api/screens/defineScreen.js +45 -3
  416. package/lib/module/api/screens/defineScreen.js.map +1 -1
  417. package/lib/module/api/screens/nativeScreens.js +31 -6
  418. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  419. package/lib/module/api/screens/registerScreens.js +193 -35
  420. package/lib/module/api/screens/registerScreens.js.map +1 -1
  421. package/lib/module/api/theme/theme.js +5 -0
  422. package/lib/module/api/theme/theme.js.map +1 -1
  423. package/lib/module/engine/commands.js +51 -9
  424. package/lib/module/engine/commands.js.map +1 -1
  425. package/lib/module/engine/layout.js +20 -11
  426. package/lib/module/engine/layout.js.map +1 -1
  427. package/lib/module/engine/nativeScreens.js +9 -0
  428. package/lib/module/engine/nativeScreens.js.map +1 -1
  429. package/lib/module/engine/options.js +49 -15
  430. package/lib/module/engine/options.js.map +1 -1
  431. package/lib/module/engine/optionsChange.js +102 -0
  432. package/lib/module/engine/optionsChange.js.map +1 -0
  433. package/lib/module/engine/places.js +52 -7
  434. package/lib/module/engine/places.js.map +1 -1
  435. package/lib/module/engine/props.js +30 -1
  436. package/lib/module/engine/props.js.map +1 -1
  437. package/lib/module/engine/refresh.js +85 -0
  438. package/lib/module/engine/refresh.js.map +1 -0
  439. package/lib/module/engine/rememberedOptions.js +61 -1
  440. package/lib/module/engine/rememberedOptions.js.map +1 -1
  441. package/lib/module/engine/screens.js +77 -16
  442. package/lib/module/engine/screens.js.map +1 -1
  443. package/lib/module/interfaces/contract/commands.json +101 -0
  444. package/lib/module/interfaces/contract/errors.json +275 -0
  445. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
  446. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  447. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  448. package/lib/typescript/api/app/createNavigation.d.ts +8 -3
  449. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  450. package/lib/typescript/api/commands/commands.d.ts.map +1 -1
  451. package/lib/typescript/api/commands/presentation.d.ts +4 -3
  452. package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
  453. package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
  454. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  455. package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
  456. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  457. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
  458. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
  459. package/lib/typescript/api/index.d.ts +1 -1
  460. package/lib/typescript/api/index.d.ts.map +1 -1
  461. package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
  462. package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
  463. package/lib/typescript/api/linking/linking.d.ts +8 -0
  464. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  465. package/lib/typescript/api/navigation.d.ts +4 -1
  466. package/lib/typescript/api/navigation.d.ts.map +1 -1
  467. package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
  468. package/lib/typescript/api/screens/arrangement.d.ts +12 -2
  469. package/lib/typescript/api/screens/arrangement.d.ts.map +1 -1
  470. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  471. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  472. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  473. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  474. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  475. package/lib/typescript/api/theme/theme.d.ts +2 -0
  476. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  477. package/lib/typescript/engine/commands.d.ts +5 -0
  478. package/lib/typescript/engine/commands.d.ts.map +1 -1
  479. package/lib/typescript/engine/layout.d.ts.map +1 -1
  480. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  481. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  482. package/lib/typescript/engine/options.d.ts +5 -2
  483. package/lib/typescript/engine/options.d.ts.map +1 -1
  484. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  485. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  486. package/lib/typescript/engine/places.d.ts +7 -2
  487. package/lib/typescript/engine/places.d.ts.map +1 -1
  488. package/lib/typescript/engine/props.d.ts +8 -1
  489. package/lib/typescript/engine/props.d.ts.map +1 -1
  490. package/lib/typescript/engine/refresh.d.ts +35 -0
  491. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  492. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  493. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  494. package/lib/typescript/engine/screens.d.ts +27 -6
  495. package/lib/typescript/engine/screens.d.ts.map +1 -1
  496. package/lib/typescript/interfaces/ComponentEvents.d.ts +4 -4
  497. package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
  498. package/lib/typescript/interfaces/Events.d.ts +28 -10
  499. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  500. package/lib/typescript/interfaces/Options.d.ts +1 -1
  501. package/lib/typescript/interfaces/Options.d.ts.map +1 -1
  502. package/lib/typescript/interfaces/options/animations.d.ts +80 -22
  503. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  504. package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
  505. package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
  506. package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
  507. package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
  508. package/lib/typescript/interfaces/options/modals.d.ts +34 -26
  509. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  510. package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
  511. package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
  512. package/lib/typescript/interfaces/options/stack.d.ts +17 -3
  513. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  514. package/lib/typescript/interfaces/options/system.d.ts +18 -11
  515. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  516. package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
  517. package/lib/typescript/interfaces/options/topBar.d.ts +68 -38
  518. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  519. package/metro/acceptPlugin.js +57 -0
  520. package/metro/babelTransformer.js +45 -0
  521. package/metro/index.js +36 -0
  522. package/package.json +3 -1
  523. package/src/ARCHITECTURE.md +40 -27
  524. package/src/adapters/NativeANNTurboModule.ts +12 -2
  525. package/src/api/app/AppRegistry.ts +16 -2
  526. package/src/api/app/createNavigation.ts +203 -69
  527. package/src/api/commands/commands.ts +48 -7
  528. package/src/api/commands/presentation.ts +4 -3
  529. package/src/api/events/navigationEvents.ts +10 -4
  530. package/src/api/hooks/useNavigation.ts +9 -4
  531. package/src/api/hooks/useSafeAreaInsets.ts +4 -3
  532. package/src/api/index.ts +1 -0
  533. package/src/api/linking/dispatchedLinks.ts +18 -0
  534. package/src/api/linking/linking.ts +22 -1
  535. package/src/api/navigation.ts +4 -1
  536. package/src/api/options/OptionsChain.ts +2 -2
  537. package/src/api/screens/arrangement.ts +17 -4
  538. package/src/api/screens/defineScreen.ts +49 -5
  539. package/src/api/screens/nativeScreens.ts +40 -4
  540. package/src/api/screens/registerScreens.tsx +185 -42
  541. package/src/api/theme/theme.ts +5 -0
  542. package/src/engine/commands.ts +70 -13
  543. package/src/engine/layout.ts +27 -11
  544. package/src/engine/nativeScreens.ts +10 -1
  545. package/src/engine/options.ts +45 -19
  546. package/src/engine/optionsChange.ts +107 -0
  547. package/src/engine/places.ts +65 -7
  548. package/src/engine/props.ts +30 -1
  549. package/src/engine/refresh.ts +97 -0
  550. package/src/engine/rememberedOptions.ts +74 -1
  551. package/src/engine/screens.tsx +76 -21
  552. package/src/interfaces/ComponentEvents.ts +4 -4
  553. package/src/interfaces/Events.ts +29 -10
  554. package/src/interfaces/Options.ts +1 -0
  555. package/src/interfaces/contract/commands.json +101 -0
  556. package/src/interfaces/contract/errors.json +275 -0
  557. package/src/interfaces/options/animations.ts +81 -22
  558. package/src/interfaces/options/bottomTabs.ts +21 -7
  559. package/src/interfaces/options/buttons.ts +23 -15
  560. package/src/interfaces/options/modals.ts +34 -26
  561. package/src/interfaces/options/sideMenu.ts +24 -6
  562. package/src/interfaces/options/stack.ts +17 -3
  563. package/src/interfaces/options/system.ts +18 -11
  564. package/src/interfaces/options/toolbar.ts +2 -2
  565. package/src/interfaces/options/topBar.ts +68 -38
  566. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
  567. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
  568. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
  569. package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
  570. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
  571. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  572. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -138
  573. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
  574. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  575. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -66
  576. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
  577. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
  578. package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
  579. package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
  580. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
  581. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
@@ -4,12 +4,11 @@ import android.content.Context
4
4
  import android.content.res.ColorStateList
5
5
  import android.content.res.Configuration
6
6
  import android.graphics.Color
7
- import android.graphics.drawable.Drawable
8
7
  import com.google.android.material.floatingactionbutton.FloatingActionButton
9
8
  import dev.apexnative.navigation.options.params.ThemeColour
10
- import dev.apexnative.navigation.utils.ImageLoader
11
- import dev.apexnative.navigation.utils.ImageLoadingListenerAdapter
9
+ import dev.apexnative.navigation.utils.ImageRequests
12
10
  import dev.apexnative.navigation.utils.MaterialTheme
11
+ import dev.apexnative.navigation.utils.OptionImages
13
12
  import dev.apexnative.navigation.utils.UiUtils
14
13
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ScrollEventListener
15
14
  import androidx.appcompat.R as AppCompatR
@@ -29,6 +28,7 @@ class Fab(context: Context, val fabId: String) : FloatingActionButton(MaterialTh
29
28
  // The icon's color of the options: a container color merged later kept the theme's icon color instead.
30
29
  private var iconColor: Int? = null
31
30
  private var optionRippleColor: Int? = null
31
+ private val icons = ImageRequests<Unit>(OptionImages.source(this.context))
32
32
 
33
33
  init {
34
34
  // Material's theme overlay of the button is a copy of the theme, made once: it follows a light/dark switch too.
@@ -36,14 +36,18 @@ class Fab(context: Context, val fabId: String) : FloatingActionButton(MaterialTh
36
36
  MaterialTheme.followOverlay(this.context)
37
37
  }
38
38
 
39
- fun applyIcon(icon: String, color: ThemeColour) {
39
+ /**
40
+ * The icon of the options, with its color. [mayWait]: the button can show it when it is ready (it shows an icon
41
+ * already, it is hidden with `visible: false`, or it is an action of a closed menu), so an icon the cache doesn't
42
+ * have loads off the main thread; the last icon asked for wins. Otherwise it loads at once. An icon that doesn't
43
+ * load leaves the button without an icon.
44
+ */
45
+ fun applyIcon(icon: String, color: ThemeColour, mayWait: Boolean) {
40
46
  if (color.hasValue()) iconColor = color.get()
41
- ImageLoader().loadIcon(context, icon, object : ImageLoadingListenerAdapter() {
42
- override fun onComplete(drawable: Drawable) {
43
- setImageDrawable(drawable)
44
- iconColor?.let { imageTintList = ColorStateList.valueOf(it) }
45
- }
46
- })
47
+ icons.request(Unit, icon, mayWait) { drawable ->
48
+ setImageDrawable(drawable)
49
+ iconColor?.let { imageTintList = ColorStateList.valueOf(it) }
50
+ }
47
51
  }
48
52
 
49
53
  /** iconColor alone, without a new icon: it did nothing in a merge. */
@@ -0,0 +1,85 @@
1
+ package dev.apexnative.navigation.views.stack.fab
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.Context
5
+ import android.graphics.Canvas
6
+ import android.graphics.Outline
7
+ import android.graphics.Picture
8
+ import android.os.Build
9
+ import android.view.Gravity
10
+ import android.view.View
11
+ import android.view.ViewGroup
12
+ import android.view.ViewOutlineProvider
13
+ import androidx.coordinatorlayout.widget.CoordinatorLayout
14
+ import dev.apexnative.navigation.views.element.animators.recordPicture
15
+
16
+ /**
17
+ * The picture of a FAB that leaves with its screen while the new top's FAB arrives: drawn as the button was, with the
18
+ * shadow of its shape, taking no touches and hidden from accessibility. The live button goes from its parent at once.
19
+ */
20
+ @SuppressLint("ViewConstructor")
21
+ internal class FabCopy private constructor(
22
+ context: Context,
23
+ private val picture: Picture,
24
+ shape: Outline,
25
+ ) : View(context) {
26
+ init {
27
+ importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
28
+ outlineProvider = object : ViewOutlineProvider() {
29
+ override fun getOutline(view: View, outline: Outline) = outline.set(shape)
30
+ }
31
+ }
32
+
33
+ override fun onDraw(canvas: Canvas) {
34
+ canvas.drawPicture(picture)
35
+ }
36
+
37
+ companion object {
38
+ /**
39
+ * A copy of [button] in [container], a child of [parent] (the button itself, or its menu), as it shows now: in
40
+ * its place in [parent], moved, scaled and faded as it is. None when it doesn't show or can't be recorded (a
41
+ * hardware bitmap in its icon before Android 9).
42
+ */
43
+ fun of(button: View, container: View, parent: ViewGroup): FabCopy? {
44
+ if (container.parent !== parent || !button.isAttachedToWindow) return null
45
+ if (button.width <= 0 || button.height <= 0) return null
46
+ if (container.visibility != VISIBLE || button.visibility != VISIBLE) return null
47
+ val inner = button !== container
48
+ val alpha = container.alpha * if (inner) button.alpha else 1f
49
+ val scale = container.scaleX * if (inner) button.scaleX else 1f
50
+ if (alpha <= 0f || scale <= 0f) return null
51
+ val picture = recordPicture(button) ?: return null
52
+ val shape = Outline().apply {
53
+ // As the view counts its own outline: opaque unless the provider says otherwise.
54
+ this.alpha = 1f
55
+ button.outlineProvider?.getOutline(button, this)
56
+ }
57
+ val copy = FabCopy(button.context, picture, shape)
58
+ val left = container.left + if (inner) button.left else 0
59
+ val top = container.top + if (inner) button.top else 0
60
+ copy.translationX = container.translationX + if (inner) button.translationX else 0f
61
+ copy.translationY = container.translationY + if (inner) button.translationY else 0f
62
+ copy.scaleX = scale
63
+ copy.scaleY = scale
64
+ copy.alpha = alpha
65
+ copy.elevation = button.elevation
66
+ copy.translationZ = button.translationZ
67
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
68
+ copy.outlineAmbientShadowColor = button.outlineAmbientShadowColor
69
+ copy.outlineSpotShadowColor = button.outlineSpotShadowColor
70
+ }
71
+ parent.addView(copy, CoordinatorLayout.LayoutParams(button.width, button.height).apply {
72
+ gravity = Gravity.TOP or Gravity.LEFT
73
+ leftMargin = left
74
+ topMargin = top
75
+ })
76
+ // In its place before the next layout, so its first frame draws.
77
+ copy.measure(
78
+ MeasureSpec.makeMeasureSpec(button.width, MeasureSpec.EXACTLY),
79
+ MeasureSpec.makeMeasureSpec(button.height, MeasureSpec.EXACTLY),
80
+ )
81
+ copy.layout(left, top, left + button.width, top + button.height)
82
+ return copy
83
+ }
84
+ }
85
+ }
@@ -120,6 +120,19 @@ class FabMenu(context: Context, val fabId: String) : LinearLayout(context), FabA
120
120
  (view.parent as? ViewGroup)?.removeView(view)
121
121
  }
122
122
 
123
+ /**
124
+ * The menu closes and leaves its parent next: a scrim that shows fades out by itself and goes from the parent at
125
+ * the end of its fade, which the menu no longer owns; it takes no touches meanwhile, which belong to the new screen.
126
+ */
127
+ fun closeToLeave() {
128
+ close()
129
+ scrim?.apply {
130
+ setOnClickListener(null)
131
+ isClickable = false
132
+ }
133
+ scrim = null
134
+ }
135
+
123
136
  override fun show() = main.show()
124
137
 
125
138
  override fun hide() {
@@ -7,15 +7,14 @@ import android.util.TypedValue
7
7
  import android.view.View
8
8
  import android.view.ViewGroup
9
9
  import androidx.appcompat.widget.AppCompatTextView
10
- import com.google.android.material.appbar.MaterialToolbar
11
- import dev.apexnative.navigation.utils.MaterialTheme
12
10
  import dev.apexnative.navigation.utils.UiUtils
11
+ import dev.apexnative.navigation.views.stack.topbar.titlebar.ButtonRow
13
12
  import kotlin.math.max
14
13
  import kotlin.math.min
15
14
 
16
15
  /**
17
16
  * The row of the bar: the left buttons with the back button at the start ([leftButtonBar]), the right buttons and "⋮"
18
- * at the end ([rightButtonBar]), both Material 3 toolbars, and between them the title and the subtitle, or a React
17
+ * at the end ([rightButtonBar]), each a [ButtonRow], and between them the title and the subtitle, or a React
19
18
  * title ([titleComponent]). It lays them out in its own coordinates, so a shift of the row (`topBar.title.topMargin`)
20
19
  * moves them all; [sideInsets] keep them off the system bars and the cutout at the sides. Right to left, everything
21
20
  * mirrors. Main thread only.
@@ -26,10 +25,10 @@ class TitleBar(context: Context) : ViewGroup(context) {
26
25
  enum class Alignment { Start, Center, Fill }
27
26
 
28
27
  /** The back button (its navigation button) and the left buttons. */
29
- val leftButtonBar = MaterialToolbar(context).also(::plain)
28
+ val leftButtonBar = ButtonRow(context)
30
29
 
31
30
  /** The right buttons, the search's magnifier and "⋮". */
32
- val rightButtonBar = MaterialToolbar(context).also(::plain)
31
+ val rightButtonBar = ButtonRow(context)
33
32
 
34
33
  /** The title's text: one line, cut with "…" at its end (`topBar.title.text`). */
35
34
  val titleView = AppCompatTextView(context).apply {
@@ -152,7 +151,7 @@ class TitleBar(context: Context) : ViewGroup(context) {
152
151
  view.layout(x, top, x + w, top + view.measuredHeight)
153
152
  }
154
153
  // The back button and the left buttons at the start of the line, the right buttons at its end: right to left
155
- // the whole row mirrors, and each toolbar mirrors what it holds.
154
+ // the whole row mirrors, and each side mirrors what it holds.
156
155
  val startBar = leftButtonBar.measuredWidth
157
156
  val endBar = rightButtonBar.measuredWidth
158
157
  place(leftButtonBar, 0, 0)
@@ -192,17 +191,6 @@ class TitleBar(context: Context) : ViewGroup(context) {
192
191
  return min(max(middle, startBar), max(inner - endBar - width, startBar))
193
192
  }
194
193
 
195
- // A toolbar that holds only buttons: no insets of its own around them (the row places them).
196
- private fun plain(toolbar: MaterialToolbar) {
197
- // Before the toolbar makes its menu, which takes the popup theme once: "⋮" in the current mode.
198
- toolbar.popupTheme = MaterialTheme.popupTheme(toolbar.context)
199
- toolbar.setContentInsetsRelative(0, 0)
200
- toolbar.contentInsetStartWithNavigation = 0
201
- toolbar.contentInsetEndWithActions = 0
202
- toolbar.setPadding(0, 0, 0, 0)
203
- toolbar.minimumHeight = 0
204
- }
205
-
206
194
  private companion object {
207
195
  const val GAP_DP = 16
208
196
  const val TITLE_SIZE_SP = 22f
@@ -2,11 +2,12 @@ package dev.apexnative.navigation.views.stack.topbar
2
2
 
3
3
  import android.annotation.SuppressLint
4
4
  import android.content.Context
5
- import android.graphics.Bitmap
6
5
  import android.graphics.Canvas
7
6
  import android.graphics.Color
7
+ import android.graphics.Picture
8
8
  import android.graphics.Rect
9
9
  import android.graphics.drawable.ColorDrawable
10
+ import android.graphics.drawable.PictureDrawable
10
11
  import android.os.Build
11
12
  import android.view.ContextThemeWrapper
12
13
  import android.view.Gravity
@@ -16,10 +17,11 @@ import android.view.ViewGroup
16
17
  import android.widget.FrameLayout
17
18
  import android.widget.ImageView
18
19
  import android.widget.LinearLayout
19
- import com.google.android.material.appbar.MaterialToolbar
20
+ import androidx.appcompat.widget.AppCompatImageView
20
21
  import dev.apexnative.navigation.R
21
22
  import dev.apexnative.navigation.utils.MaterialTheme
22
23
  import dev.apexnative.navigation.utils.UiUtils
24
+ import dev.apexnative.navigation.views.stack.topbar.titlebar.ButtonRow
23
25
 
24
26
  /**
25
27
  * The top bar of a stack: one per stack, showing what its screen on top sets. Top to bottom: the strip under the status
@@ -47,7 +49,7 @@ class TopBar(context: Context) : FrameLayout(themed(context)) {
47
49
  private val largeTitleHolder = FrameLayout(this.context)
48
50
  private val searchHolder = FrameLayout(this.context)
49
51
  private val border = View(this.context)
50
- private val snapshot = ImageView(this.context)
52
+ private val snapshot = Snapshot(this.context)
51
53
  private var searchArea: View? = null
52
54
  private var barHeight = UiUtils.dpToPx(this.context, DEFAULT_HEIGHT_DP)
53
55
  private var searchTakesBar = false
@@ -55,13 +57,15 @@ class TopBar(context: Context) : FrameLayout(themed(context)) {
55
57
  private var heightChanged = false
56
58
  // How far the large title is collapsed, in pixels.
57
59
  private var largeTitleShift = 0
60
+ // `topBar.elevation`, in pixels: the bar's elevation unless it is flat.
61
+ private var shadow = 0f
58
62
 
59
- /** The toolbar of the right buttons: its menu holds them, the overflow items and the search's magnifier. */
60
- val rightButtonBar: MaterialToolbar
63
+ /** The right buttons, the search's magnifier and "⋮". */
64
+ val rightButtonBar: ButtonRow
61
65
  get() = titleBar.rightButtonBar
62
66
 
63
- /** The toolbar of the back button and the left buttons. */
64
- val leftButtonBar: MaterialToolbar
67
+ /** The back button and the left buttons. */
68
+ val leftButtonBar: ButtonRow
65
69
  get() = titleBar.leftButtonBar
66
70
 
67
71
  /** The strip under the status bar at the top of the bar, in pixels: the bar is under the status bar. */
@@ -187,14 +191,27 @@ class TopBar(context: Context) : FrameLayout(themed(context)) {
187
191
  * The shadow of `topBar.elevation`, in pixels: its colors are black (Android 9 and later read them), none at 0.
188
192
  */
189
193
  fun setShadow(elevation: Float) {
190
- if (this.elevation == elevation) return
191
- this.elevation = elevation
194
+ if (shadow == elevation) return
195
+ shadow = elevation
196
+ if (!isFlat) this.elevation = elevation
192
197
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
193
198
  outlineAmbientShadowColor = Color.BLACK
194
199
  outlineSpotShadowColor = Color.BLACK
195
200
  }
196
201
  }
197
202
 
203
+ /**
204
+ * The bar draws without its shadow, at the level of the screens, in a transition that draws it with a screen: a
205
+ * screen drawn after it covers it, and an alpha layer around it fades it (with an elevation the renderer would draw
206
+ * the bar over every screen and out of the layer).
207
+ */
208
+ var isFlat = false
209
+ set(value) {
210
+ if (field == value) return
211
+ field = value
212
+ elevation = if (value) 0f else shadow
213
+ }
214
+
198
215
  /** The line under the bar: [height] pixels of [color]. */
199
216
  fun setBorder(color: Int, height: Int) {
200
217
  border.setBackgroundColor(color)
@@ -290,32 +307,27 @@ class TopBar(context: Context) : FrameLayout(themed(context)) {
290
307
  layoutParams = params
291
308
  }
292
309
 
293
- // The row's picture in a transition.
310
+ // The row's picture in a transition: the drawing commands of the row as it is, not its pixels. Nothing as large
311
+ // as the bar is allocated or filled in on the main thread, and the renderer plays the commands each frame.
294
312
 
295
313
  /**
296
- * Lays a picture of the row and the large title over them, laid out at once; false when the bar can't be drawn in
297
- * software: no picture then.
314
+ * Lays a picture of the row and the large title over them, laid out at once; false when the bar can't be recorded:
315
+ * no picture then.
298
316
  */
299
317
  fun takeRowSnapshot(withLargeTitle: Boolean = true): Boolean {
300
318
  val width = rowArea.width
301
319
  val large = withLargeTitle && isLargeTitleShown
302
320
  val height = rowArea.height + if (large) largeTitleHolder.height else 0
303
321
  if (width <= 0 || height <= 0) return false
304
- val picture = try {
305
- Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also {
306
- val canvas = Canvas(it)
307
- rowArea.draw(canvas)
308
- if (large) {
309
- canvas.translate(0f, rowArea.height.toFloat())
310
- largeTitleHolder.draw(canvas)
311
- }
322
+ val picture = record(width, height) { canvas ->
323
+ rowArea.draw(canvas)
324
+ if (large) {
325
+ canvas.translate(0f, rowArea.height.toFloat())
326
+ largeTitleHolder.draw(canvas)
312
327
  }
313
- } catch (e: IllegalArgumentException) {
314
- // A HARDWARE bitmap in the bar: it can't be drawn on a software canvas.
315
- return false
316
- }
328
+ } ?: return false
317
329
  val top = content.top + rowArea.top
318
- snapshot.setImageBitmap(picture)
330
+ snapshot.setImageDrawable(PictureDrawable(picture))
319
331
  snapshot.alpha = 1f
320
332
  snapshot.translationX = 0f
321
333
  snapshot.translationY = rowArea.translationY
@@ -333,22 +345,43 @@ class TopBar(context: Context) : FrameLayout(themed(context)) {
333
345
 
334
346
  /**
335
347
  * A picture of the bar under its row — the background, the large title, the search, the line — and where it starts
336
- * in the bar, for a push to a screen without a large title; none when the bar can't be drawn in software.
348
+ * in the bar, for a push to a screen without a large title; none when the bar can't be recorded. Its intrinsic
349
+ * size is its size; it draws at the top left of its bounds.
337
350
  */
338
- fun pictureUnderRow(): Pair<Bitmap, Int>? {
339
- val top = content.top + rowArea.bottom
351
+ fun pictureUnderRow(): Pair<PictureDrawable, Int>? = pictureFrom(content.top + rowArea.bottom)
352
+
353
+ /**
354
+ * A picture of the whole bar, for the screen it leaves with in a transition of the stack's own; none when the bar
355
+ * can't be recorded.
356
+ */
357
+ fun picture(): PictureDrawable? = pictureFrom(0)?.first
358
+
359
+ private fun pictureFrom(top: Int): Pair<PictureDrawable, Int>? {
340
360
  val width = width
341
361
  val height = height - top
342
362
  if (width <= 0 || height <= 0) return null
343
- return try {
344
- val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
345
- val canvas = Canvas(bitmap)
363
+ val picture = record(width, height) { canvas ->
346
364
  canvas.translate(0f, -top.toFloat())
347
365
  draw(canvas)
348
- bitmap to top
349
- } catch (e: IllegalArgumentException) {
350
- null
366
+ } ?: return null
367
+ return PictureDrawable(picture) to top
368
+ }
369
+
370
+ // The commands [draw] gives, cut to [width] × [height]. A hardware bitmap in the bar is kept as it is from Android
371
+ // 9 on (the picture then plays only on the screen's hardware canvas, where the bar's pictures are drawn); Android 8
372
+ // can't record one, and there is no picture then.
373
+ private fun record(width: Int, height: Int, draw: (Canvas) -> Unit): Picture? = try {
374
+ Picture().also {
375
+ val canvas = it.beginRecording(width, height)
376
+ try {
377
+ canvas.clipRect(0, 0, width, height)
378
+ draw(canvas)
379
+ } finally {
380
+ it.endRecording()
381
+ }
351
382
  }
383
+ } catch (e: IllegalArgumentException) {
384
+ null
352
385
  }
353
386
 
354
387
  /** The row's picture goes. */
@@ -388,6 +421,12 @@ class TopBar(context: Context) : FrameLayout(themed(context)) {
388
421
  heightChanged = true
389
422
  }
390
423
 
424
+ // The row's picture: it fades as one image. Its commands overlap (a button's background under its icon), and drawn
425
+ // one by one at the view's opacity each would show through the next.
426
+ private class Snapshot(context: Context) : AppCompatImageView(context) {
427
+ override fun hasOverlappingRendering(): Boolean = true
428
+ }
429
+
391
430
  // The area of the row: it takes the touches without passing them on while the row is transparent.
392
431
  private class RowArea(context: Context) : FrameLayout(context) {
393
432
  var blocksTouches = false
@@ -8,12 +8,12 @@ import dev.apexnative.navigation.utils.UiUtils
8
8
  import kotlin.math.max
9
9
 
10
10
  /**
11
- * The cell of a React button in the bar (`topBar.leftButtons[].component`): the action view of the button's menu item,
12
- * as an icon's: 12 dp on each side, at least 48 dp wide, as high as the row, the content in its middle. The content (a
13
- * React root, or later a view of the screen's own tree) measures `AT_MOST` — the width at most what the row gives, the
14
- * height at most the row's — or exactly its `component.width` / `component.height` when the options give them
15
- * ([contentWidth], [contentHeight], pixels). The cell takes the menu's id; the content never gets one (React Native
16
- * rejects a root with an id). It never looks inside the content.
11
+ * The cell of a React button in the bar (`topBar.leftButtons[].component`), in the row of its side as an icon button
12
+ * stands there: 12 dp on each side, at least 48 dp wide, as high as the row gives, the content in its middle. The
13
+ * content (a React root, or later a view of the screen's own tree) measures `AT_MOST` — the width at most what the row
14
+ * gives, the height at most the row's — or exactly its `component.width` / `component.height` when the options give
15
+ * them ([contentWidth], [contentHeight], pixels). The cell takes the button's `testID`; the content never gets one
16
+ * (React Native rejects a root with an id). It never looks inside the content.
17
17
  */
18
18
  @SuppressLint("ViewConstructor")
19
19
  internal class BarButtonComponentCell(context: Context) : ViewGroup(context) {
@@ -0,0 +1,113 @@
1
+ package dev.apexnative.navigation.views.stack.topbar.titlebar
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.Context
5
+ import android.content.res.TypedArray
6
+ import android.graphics.drawable.Drawable
7
+ import android.view.Gravity
8
+ import android.widget.Button
9
+ import androidx.appcompat.R as AppCompatR
10
+ import androidx.appcompat.widget.AppCompatTextView
11
+ import androidx.appcompat.widget.TooltipCompat
12
+ import androidx.core.widget.TextViewCompat
13
+ import dev.apexnative.navigation.utils.UiUtils
14
+ import kotlin.math.roundToInt
15
+
16
+ /**
17
+ * A button of the bar with an icon or a text, drawn as a toolbar draws the items of its menu: the theme's
18
+ * `actionButtonStyle` (48 dp at least, 12 dp at the sides, the bar's ripple), its `actionMenuTextAppearance` and
19
+ * `actionMenuTextColor`, the icon at most 32 dp and in the middle. With an icon the text doesn't show; it labels the
20
+ * button for accessibility and is its tooltip instead, unless the button has a label of its own. Main thread only.
21
+ */
22
+ @SuppressLint("ViewConstructor")
23
+ internal class BarButtonView(context: Context) :
24
+ AppCompatTextView(context, null, AppCompatR.attr.actionButtonStyle) {
25
+ private val minimumWidth = minWidth
26
+ private val maxIconSize = UiUtils.dpToPx(context, MAX_ICON_DP).roundToInt()
27
+ private val sidePadding = UiUtils.dpToPx(context, SIDE_DP).roundToInt()
28
+ private var icon: Drawable? = null
29
+
30
+ init {
31
+ gravity = Gravity.CENTER
32
+ isFocusable = true
33
+ val vertical = UiUtils.dpToPx(context, VERTICAL_DP).roundToInt()
34
+ setPaddingRelative(sidePadding, vertical, sidePadding, vertical)
35
+ restyle()
36
+ }
37
+
38
+ /** The text appearance and color of the theme as it is now: a light/dark switch changes them. */
39
+ fun restyle() {
40
+ themed(AppCompatR.attr.actionMenuTextAppearance) { getResourceId(0, 0) }
41
+ .takeIf { it != 0 }
42
+ ?.let { TextViewCompat.setTextAppearance(this, it) }
43
+ themed(AppCompatR.attr.actionMenuTextColor) { getColorStateList(0) }?.let(::setTextColor)
44
+ }
45
+
46
+ private fun <T> themed(attr: Int, read: TypedArray.() -> T): T {
47
+ val values = context.obtainStyledAttributes(intArrayOf(attr))
48
+ return try {
49
+ values.read()
50
+ } finally {
51
+ values.recycle()
52
+ }
53
+ }
54
+
55
+ /**
56
+ * What the button shows: [icon], or [title] without one. [label] is its accessibility label, else the title when
57
+ * only the icon shows; that title is its tooltip too. [tooltip] false leaves the long press to the caller.
58
+ */
59
+ fun show(title: CharSequence, icon: Drawable?, label: CharSequence?, tooltip: Boolean) {
60
+ this.icon = icon?.also { fit(it) }
61
+ setCompoundDrawablesRelative(icon, null, null, null)
62
+ text = if (icon == null) title else null
63
+ val hidden = title.takeIf { icon != null && it.isNotEmpty() }
64
+ contentDescription = label?.takeIf { it.isNotEmpty() } ?: hidden
65
+ TooltipCompat.setTooltipText(this, if (tooltip) hidden else null)
66
+ requestLayout()
67
+ }
68
+
69
+ // TalkBack and UI tests see a button, as they see a toolbar's item.
70
+ override fun getAccessibilityClassName(): CharSequence = Button::class.java.name
71
+
72
+ // An icon larger than the bar's item takes keeps its shape at 32 dp.
73
+ private fun fit(icon: Drawable) {
74
+ var width = icon.intrinsicWidth.coerceAtLeast(0)
75
+ var height = icon.intrinsicHeight.coerceAtLeast(0)
76
+ if (width > maxIconSize) {
77
+ height = (height * maxIconSize.toFloat() / width).roundToInt()
78
+ width = maxIconSize
79
+ }
80
+ if (height > maxIconSize) {
81
+ width = (width * maxIconSize.toFloat() / height).roundToInt()
82
+ height = maxIconSize
83
+ }
84
+ icon.setBounds(0, 0, width, height)
85
+ }
86
+
87
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
88
+ val centered = icon?.takeIf { text.isNullOrEmpty() }
89
+ if (centered == null) setPaddingRelative(sidePadding, paddingTop, sidePadding, paddingBottom)
90
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
91
+ // At least the theme's width, within what the row gives.
92
+ val mode = MeasureSpec.getMode(widthMeasureSpec)
93
+ val target = if (mode == MeasureSpec.AT_MOST) {
94
+ minOf(MeasureSpec.getSize(widthMeasureSpec), minimumWidth)
95
+ } else {
96
+ minimumWidth
97
+ }
98
+ if (mode != MeasureSpec.EXACTLY && minimumWidth > 0 && measuredWidth < target) {
99
+ super.onMeasure(MeasureSpec.makeMeasureSpec(target, MeasureSpec.EXACTLY), heightMeasureSpec)
100
+ }
101
+ // The icon alone stands in the middle of the button.
102
+ if (centered != null) {
103
+ val start = (measuredWidth - centered.bounds.width()) / 2
104
+ setPaddingRelative(start, paddingTop, paddingEnd, paddingBottom)
105
+ }
106
+ }
107
+
108
+ private companion object {
109
+ const val MAX_ICON_DP = 32f
110
+ const val SIDE_DP = 12f
111
+ const val VERTICAL_DP = 4f
112
+ }
113
+ }