@apexnative/navigation 1.0.0-alpha.6 → 1.0.0-alpha.8

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 (242) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +15 -0
  3. package/android/CLAUDE.md +19 -10
  4. package/android/CORE.md +3 -2
  5. package/android/consumer-rules.pro +6 -0
  6. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
  7. package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +1 -1
  8. package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
  9. package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
  10. package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
  11. package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
  12. package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
  13. package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
  14. package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
  15. package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
  16. package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
  17. package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
  18. package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +4 -0
  19. package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +41 -3
  20. package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +16 -1
  21. package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +27 -7
  22. package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +12 -1
  23. package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
  24. package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
  25. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +329 -55
  26. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +26 -5
  27. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +60 -2
  28. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +8 -2
  29. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +32 -4
  30. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +46 -7
  31. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +15 -3
  32. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +7 -4
  33. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
  34. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +215 -43
  35. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +25 -26
  36. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
  37. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
  38. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +86 -39
  39. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
  40. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +124 -181
  41. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +8 -1
  42. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
  43. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +56 -3
  44. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +170 -153
  45. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
  46. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +55 -45
  47. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/{TextChangeAnimator.kt → TextMorph.kt} +79 -129
  48. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
  49. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
  50. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
  51. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -24
  52. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +51 -34
  53. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
  54. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
  55. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
  56. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +121 -175
  57. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
  58. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
  59. package/android/src/main/jni/ANNContentHeights.cpp +82 -0
  60. package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
  61. package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
  62. package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
  63. package/android/src/main/res/values/styles.xml +1 -1
  64. package/android/src/main/res/values-night/styles.xml +1 -1
  65. package/cli/doctor/checks/app.js +16 -1
  66. package/cli/project.js +4 -0
  67. package/cli/setup/index.js +5 -0
  68. package/cli/setup/steps/metro.js +46 -0
  69. package/docs-md/architecture/native-screens.md +4 -0
  70. package/docs-md/architecture/theme-and-context.md +131 -12
  71. package/docs-md/architecture/transitions.md +43 -4
  72. package/docs-md/flows/bottom-sheets.md +4 -2
  73. package/docs-md/fundamentals/screens-and-props.md +9 -1
  74. package/docs-md/guides/cli.md +3 -1
  75. package/docs-md/help/troubleshooting.md +1 -1
  76. package/docs-md/index.json +29 -1
  77. package/docs-md/screen-ui/back-and-gestures.md +3 -1
  78. package/docs-md/screen-ui/bar-buttons.md +1 -1
  79. package/docs-md/screen-ui/toolbar-and-fab.md +2 -0
  80. package/docs-md/start/installation.md +16 -1
  81. package/ios/Animations/ANNFrameDriver.h +55 -15
  82. package/ios/Animations/ANNFrameDriver.mm +214 -60
  83. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  84. package/ios/Animations/ANNTransitionAnimator.mm +49 -3
  85. package/ios/Animations/ANNTransitionPlan.h +2 -2
  86. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  87. package/ios/Animations/Elements/ANNElementFinder.h +2 -2
  88. package/ios/Animations/Elements/ANNElementFinder.mm +2 -2
  89. package/ios/Animations/Elements/ANNElementTransition.h +3 -3
  90. package/ios/Animations/Elements/ANNElementTransition.mm +2 -2
  91. package/ios/Animations/Elements/ANNSharedElementFlight.h +3 -3
  92. package/ios/Animations/Elements/ANNSharedElementFlight.mm +181 -43
  93. package/ios/Animations/Interpolators/ANNViewTracks.h +6 -5
  94. package/ios/Animations/Interpolators/ANNViewTracks.mm +51 -21
  95. package/ios/CLAUDE.md +19 -8
  96. package/ios/CORE.md +1 -1
  97. package/ios/Core/ANNAppDelegate.mm +0 -2
  98. package/ios/Core/ANNDeepLinkQueue.h +6 -5
  99. package/ios/Core/ANNDeepLinkQueue.mm +22 -10
  100. package/ios/Core/ANNSceneDelegate.mm +2 -2
  101. package/ios/Core/ANNUtils.h +7 -0
  102. package/ios/Core/ANNUtils.mm +10 -0
  103. package/ios/Core/ApexNavigation.mm +6 -2
  104. package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +1 -7
  105. package/ios/Layouts/Root/ANNRootCoordinator.mm +45 -15
  106. package/ios/Layouts/Screen/ANNComponentViewController.mm +4 -1
  107. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  108. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  109. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  110. package/ios/Layouts/Stack/ANNStackController.mm +153 -11
  111. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  112. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  113. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  114. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +2 -4
  115. package/ios/Options/ANNAnimationOptions.h +2 -1
  116. package/ios/Options/ANNAnimationOptions.mm +1 -1
  117. package/ios/Options/ANNOptions.h +7 -0
  118. package/ios/Options/ANNOptions.mm +45 -0
  119. package/ios/Options/ANNOptionsReader.mm +2 -4
  120. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  121. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  122. package/ios/Options/Params/ColorParser.h +4 -3
  123. package/ios/Options/Params/ColorParser.mm +22 -4
  124. package/ios/React/ANNSurfaceHostingView.h +8 -0
  125. package/ios/React/ANNSurfaceHostingView.mm +28 -1
  126. package/ios/React/Slots/ANNSlotHost.mm +1 -3
  127. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  128. package/ios/TurboModules/ANNTurboModule.mm +46 -0
  129. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  130. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  131. package/lib/module/ARCHITECTURE.md +9 -3
  132. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  133. package/lib/module/api/app/AppRegistry.js +14 -2
  134. package/lib/module/api/app/AppRegistry.js.map +1 -1
  135. package/lib/module/api/app/createNavigation.js +188 -66
  136. package/lib/module/api/app/createNavigation.js.map +1 -1
  137. package/lib/module/api/events/navigationEvents.js +6 -2
  138. package/lib/module/api/events/navigationEvents.js.map +1 -1
  139. package/lib/module/api/linking/linking.js +11 -0
  140. package/lib/module/api/linking/linking.js.map +1 -1
  141. package/lib/module/api/screens/defineScreen.js +45 -3
  142. package/lib/module/api/screens/defineScreen.js.map +1 -1
  143. package/lib/module/api/screens/nativeScreens.js +31 -6
  144. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  145. package/lib/module/api/screens/registerScreens.js +193 -35
  146. package/lib/module/api/screens/registerScreens.js.map +1 -1
  147. package/lib/module/api/theme/theme.js +5 -0
  148. package/lib/module/api/theme/theme.js.map +1 -1
  149. package/lib/module/engine/commands.js +21 -1
  150. package/lib/module/engine/commands.js.map +1 -1
  151. package/lib/module/engine/layout.js +7 -2
  152. package/lib/module/engine/layout.js.map +1 -1
  153. package/lib/module/engine/nativeScreens.js +9 -0
  154. package/lib/module/engine/nativeScreens.js.map +1 -1
  155. package/lib/module/engine/options.js +5 -4
  156. package/lib/module/engine/options.js.map +1 -1
  157. package/lib/module/engine/optionsChange.js +102 -0
  158. package/lib/module/engine/optionsChange.js.map +1 -0
  159. package/lib/module/engine/refresh.js +85 -0
  160. package/lib/module/engine/refresh.js.map +1 -0
  161. package/lib/module/engine/rememberedOptions.js +60 -0
  162. package/lib/module/engine/rememberedOptions.js.map +1 -1
  163. package/lib/module/engine/screens.js +26 -0
  164. package/lib/module/engine/screens.js.map +1 -1
  165. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +7 -0
  166. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  167. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  168. package/lib/typescript/api/app/createNavigation.d.ts +5 -0
  169. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  170. package/lib/typescript/api/events/navigationEvents.d.ts +2 -2
  171. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  172. package/lib/typescript/api/index.d.ts +1 -1
  173. package/lib/typescript/api/index.d.ts.map +1 -1
  174. package/lib/typescript/api/linking/linking.d.ts +8 -0
  175. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  176. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  177. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  178. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  179. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  180. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  181. package/lib/typescript/api/theme/theme.d.ts +2 -0
  182. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  183. package/lib/typescript/engine/commands.d.ts +5 -0
  184. package/lib/typescript/engine/commands.d.ts.map +1 -1
  185. package/lib/typescript/engine/layout.d.ts.map +1 -1
  186. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  187. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  188. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  189. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  190. package/lib/typescript/engine/refresh.d.ts +35 -0
  191. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  192. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  193. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  194. package/lib/typescript/engine/screens.d.ts +7 -0
  195. package/lib/typescript/engine/screens.d.ts.map +1 -1
  196. package/lib/typescript/interfaces/ComponentEvents.d.ts +2 -2
  197. package/lib/typescript/interfaces/options/animations.d.ts +40 -15
  198. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  199. package/lib/typescript/interfaces/options/bottomTabs.d.ts +2 -2
  200. package/lib/typescript/interfaces/options/buttons.d.ts +2 -2
  201. package/lib/typescript/interfaces/options/modals.d.ts +6 -7
  202. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  203. package/lib/typescript/interfaces/options/stack.d.ts +8 -3
  204. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  205. package/lib/typescript/interfaces/options/topBar.d.ts +14 -0
  206. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  207. package/metro/acceptPlugin.js +57 -0
  208. package/metro/babelTransformer.js +45 -0
  209. package/metro/index.js +36 -0
  210. package/package.json +3 -1
  211. package/src/ARCHITECTURE.md +9 -3
  212. package/src/adapters/NativeANNTurboModule.ts +7 -0
  213. package/src/api/app/AppRegistry.ts +16 -2
  214. package/src/api/app/createNavigation.ts +198 -66
  215. package/src/api/events/navigationEvents.ts +9 -3
  216. package/src/api/index.ts +1 -0
  217. package/src/api/linking/linking.ts +22 -1
  218. package/src/api/screens/defineScreen.ts +49 -5
  219. package/src/api/screens/nativeScreens.ts +40 -4
  220. package/src/api/screens/registerScreens.tsx +185 -42
  221. package/src/api/theme/theme.ts +5 -0
  222. package/src/engine/commands.ts +21 -0
  223. package/src/engine/layout.ts +11 -2
  224. package/src/engine/nativeScreens.ts +10 -1
  225. package/src/engine/options.ts +6 -8
  226. package/src/engine/optionsChange.ts +107 -0
  227. package/src/engine/refresh.ts +97 -0
  228. package/src/engine/rememberedOptions.ts +70 -0
  229. package/src/engine/screens.tsx +24 -0
  230. package/src/interfaces/ComponentEvents.ts +2 -2
  231. package/src/interfaces/options/animations.ts +40 -15
  232. package/src/interfaces/options/bottomTabs.ts +2 -2
  233. package/src/interfaces/options/buttons.ts +2 -2
  234. package/src/interfaces/options/modals.ts +6 -7
  235. package/src/interfaces/options/stack.ts +8 -3
  236. package/src/interfaces/options/topBar.ts +14 -0
  237. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  238. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -134
  239. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -78
  240. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  241. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -57
  242. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -146
@@ -7,17 +7,13 @@ import android.app.Activity
7
7
  import android.content.Context
8
8
  import android.content.pm.ApplicationInfo
9
9
  import android.graphics.Color
10
- import android.graphics.drawable.BitmapDrawable
11
10
  import android.graphics.drawable.Drawable
12
- import android.view.Menu
13
- import android.view.MenuItem
14
11
  import android.view.MotionEvent
15
12
  import android.view.View
16
13
  import android.view.ViewGroup
17
14
  import android.view.animation.LinearInterpolator
18
15
  import android.view.animation.PathInterpolator
19
16
  import android.widget.FrameLayout
20
- import android.widget.ImageView
21
17
  import androidx.appcompat.content.res.AppCompatResources
22
18
  import androidx.core.graphics.drawable.DrawableCompat
23
19
  import androidx.core.view.WindowInsetsCompat
@@ -59,6 +55,7 @@ import dev.apexnative.navigation.views.stack.topbar.TitleBar
59
55
  import dev.apexnative.navigation.views.stack.topbar.TopBar
60
56
  import dev.apexnative.navigation.views.stack.topbar.TopBarDefaults
61
57
  import dev.apexnative.navigation.views.stack.topbar.titlebar.BarButtonComponentCell
58
+ import dev.apexnative.navigation.views.stack.topbar.titlebar.BarMenu
62
59
  import dev.apexnative.navigation.views.stack.topbar.titlebar.ButtonBar
63
60
  import dev.apexnative.navigation.views.stack.topbar.titlebar.IconBackgroundDrawable
64
61
  import kotlin.math.roundToInt
@@ -132,6 +129,8 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
132
129
  // The bar goes with the screens of a transition of the stack's own, and the screen that leaves with its picture.
133
130
  private var travelling = false
134
131
  private var travelLeaving: ViewController<*>? = null
132
+ // The bar hides as it shows now, and the options of the screen it hides for wait until it is gone.
133
+ private var waitsForHide = false
135
134
 
136
135
  private enum class Part { Look, Title, Left, Right, Back, LargeTitle, Visible, TestId }
137
136
 
@@ -142,9 +141,9 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
142
141
  this.layout = layout
143
142
  val bar = layout.topBar
144
143
  this.bar = bar
145
- leftButtons = ButtonBar(bar.leftButtonBar, true, ::loadIcon, Buttons())
146
- rightButtons = ButtonBar(bar.rightButtonBar, false, ::loadIcon, Buttons())
147
- visibility = TopBarVisibility(VisibilityTarget(bar) { collapse?.reset() })
144
+ leftButtons = ButtonBar(bar.leftButtonBar, ::loadIcon, Buttons())
145
+ rightButtons = ButtonBar(bar.rightButtonBar, ::loadIcon, Buttons())
146
+ visibility = TopBarVisibility(VisibilityTarget(bar) { collapse?.reset() }, ::hidden)
148
147
  rowTransition = BarRowTransition(RowTarget(bar).also { rowTarget = it })
149
148
  collapse = TopBarCollapseBehavior(bar)
150
149
  bar.leftButtonBar.setNavigationOnClickListener { host.backPressed() }
@@ -185,6 +184,7 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
185
184
  val bar = bar
186
185
  val leaving = shownEntry
187
186
  val lowers = bar != null && bar.isLargeTitleShown && incoming != null && leaving != null &&
187
+ !hidesMoving(host.resolvedOf(incoming), visibility, travel != null) &&
188
188
  lowersBar(motion, incoming, host.resolvedOf(incoming))
189
189
  rowTarget?.withLargeTitle = !lowers
190
190
  if (lowers) pictureUnderRow(bar, leaving)
@@ -193,6 +193,15 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
193
193
  if (travel != null && bar != null && incoming != null) beginTravel(bar, leaving, incoming, travel, visibility)
194
194
  }
195
195
 
196
+ // Whether a screen with [options] hides the bar, shown now, by a move of [change]: a slide, or the transition's
197
+ // side. The bar then leaves as it shows, its large title too (`applyAll`); while it goes with the screens of a
198
+ // transition of the stack's own ([travels]) only a side of its own moves it.
199
+ private fun hidesMoving(options: Options, change: StackDisplay.BarVisibility, travels: Boolean): Boolean {
200
+ val exit = change.side?.exit
201
+ return options.topBar.visible.isFalse && !options.topBar.animate.isFalse && change.animated &&
202
+ !AnimationRules.isTurnedOff(exit) && (!travels || AnimationRules.barSideGiven(exit))
203
+ }
204
+
196
205
  /** The transition that brought the current child ended: the row at rest, the picture under it gone. */
197
206
  fun endRowTransition() {
198
207
  // A large title still opening is open now.
@@ -212,8 +221,8 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
212
221
  * bar as it is goes with [leaving], and the bar, which takes [incoming]'s options next, is drawn flat as [incoming]
213
222
  * moves — under [leaving] on a pop ([StackDisplay.BarTravel.Back]) (`StackLayout.barTravels`). No picture when the
214
223
  * bar doesn't show. Nothing travels when the new top hides the bar by a side of its own
215
- * (`animations.*.topBar.exit`), which plays instead, or when the bar can't be drawn in software (a `HARDWARE`
216
- * bitmap in it): the bar takes the options in its place.
224
+ * (`animations.*.topBar.exit`), which plays instead, or when the bar can't be recorded (a `HARDWARE` bitmap in it
225
+ * on Android 8): the bar takes the options in its place.
217
226
  */
218
227
  private fun beginTravel(
219
228
  bar: TopBar,
@@ -238,10 +247,10 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
238
247
 
239
248
  // The bar's picture where the bar is in the stack, its moves counted.
240
249
  private fun pictureOfBar(bar: TopBar): Drawable? {
241
- val bitmap = bar.picture() ?: return null
250
+ val picture = bar.picture() ?: return null
242
251
  val left = (bar.left + bar.translationX).roundToInt()
243
252
  val top = (bar.top + bar.translationY).roundToInt()
244
- return BitmapDrawable(bar.resources, bitmap).apply { setBounds(left, top, left + bitmap.width, top + bitmap.height) }
253
+ return picture.apply { setBounds(left, top, left + intrinsicWidth, top + intrinsicHeight) }
245
254
  }
246
255
 
247
256
  // The bar's travel ends: the picture goes, the bar is drawn in its place again with its shadow.
@@ -284,6 +293,8 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
284
293
  val bar = bar ?: return
285
294
  val screen = host.optionsScreen(entry)
286
295
  if (screen !== shownScreen) return apply(entry)
296
+ // An open menu has the colors of before.
297
+ if (delta.topBar.menuBackgroundColor.hasValue() || delta.topBar.menuTextColor.hasValue()) closeMenus()
287
298
  val options = host.resolvedOf(entry)
288
299
  applyAll(bar, entry, screen, options, merge = true, delta = delta)
289
300
  }
@@ -293,6 +304,8 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
293
304
  * now.
294
305
  */
295
306
  fun repaint(entry: ViewController<*>?) {
307
+ // An open menu has the old colors: it closes.
308
+ closeMenus()
296
309
  keys.clear()
297
310
  apply(entry)
298
311
  val options = entry?.let(host::resolvedOf) ?: return
@@ -305,6 +318,7 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
305
318
  * of the bar (the search) applies again.
306
319
  */
307
320
  fun onInsets() {
321
+ if (waitsForHide) return
308
322
  val bar = bar ?: return
309
323
  val entry = shownEntry ?: return
310
324
  val screen = shownScreen ?: return
@@ -379,6 +393,12 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
379
393
 
380
394
  /** [screen] is destroyed: its components and its search go. */
381
395
  fun screenDestroyed(screen: ViewController<*>, entryView: View?) {
396
+ // The bar may still show the components of the screen that goes: it is gone at once, with the options it held
397
+ // back, before they go; none when they are of the screen that goes.
398
+ if (waitsForHide) {
399
+ if (screen === shownScreen) waitsForHide = false
400
+ visibility?.hide(animated = false)
401
+ }
382
402
  if (screen === shownScreen) {
383
403
  shownScreen = null
384
404
  shownEntry = null
@@ -465,6 +485,26 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
465
485
  merge: Boolean,
466
486
  delta: Options? = null,
467
487
  ) {
488
+ // A screen that hides the bar: the bar leaves as it shows, its look, title and buttons those of the screen
489
+ // before, and takes this screen's options once it is gone. Taken first, they would paint the leaving bar (the
490
+ // default color over a bar that was transparent).
491
+ val waited = waitsForHide
492
+ waitsForHide = false
493
+ if (options.topBar.visible.isFalse && (!merge || waited)) {
494
+ applyVisibility(options, merge)
495
+ waitsForHide = visibility?.isHiding == true
496
+ if (waitsForHide) {
497
+ // The list of the screen before no longer moves the bar: a move of it would stop the hide.
498
+ collapse?.disableCollapse(reset = false)
499
+ return
500
+ }
501
+ }
502
+ // Shown again by a merge before it was gone: none of this screen's options are on the bar yet. It shows as a
503
+ // merge shows it, by `animate`, not by the transition's side.
504
+ if (merge && waited) {
505
+ visibilityChange = StackDisplay.BarVisibility(true, null)
506
+ return applyAll(bar, entry, screen, options, merge = false)
507
+ }
468
508
  applyLook(bar, entry, options)
469
509
  applyTitle(bar, screen, options)
470
510
  // The search first: its magnifier takes a place among the right buttons. It gets a copy of the group: it
@@ -582,16 +622,15 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
582
622
  keys[Part.Left] = leftKey
583
623
  reportWithoutId(topBar.buttons.left, "leftButtons")
584
624
  leftButtons?.set(
585
- left.map { button(screen, it, roots) },
625
+ ButtonPlaces.line(left, left = true).map { button(screen, it, roots) },
586
626
  emptyList(),
587
627
  null,
588
628
  merge && topBar.animateLeftButtons.isTrue,
589
629
  )
590
630
  }
591
631
  val overflow = topBar.overflowMenu?.takeIf { it.items.isNotEmpty() }
592
- val menu = bar.rightButtonBar.menu
593
632
  search.applyMagnifier()
594
- val taken = (0 until menu.size()).count { menu.getItem(it).itemId != Menu.NONE }
633
+ val taken = if (bar.rightButtonBar.trailingView != null) 1 else 0
595
634
  val configuration = context.resources.configuration
596
635
  val plan = ButtonPlaces.plan(
597
636
  right.map { ButtonPlaces.Button(ButtonPlaces.priorityOf(it.priority.get(null)), it.pinned.isTrue) },
@@ -612,12 +651,11 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
612
651
  keys[Part.Right] = rightKey
613
652
  reportWithoutId(topBar.buttons.right, "rightButtons")
614
653
  rightButtons?.set(
615
- plan.inBar.map { button(screen, right[it], roots) },
654
+ ButtonPlaces.line(plan.inBar, left = false).map { button(screen, right[it], roots) },
616
655
  plan.inOverflow.map { button(screen, right[it], roots) },
617
656
  overflow,
618
657
  merge && topBar.animateRightButtons.isTrue,
619
658
  )
620
- search.applyMagnifier()
621
659
  rightButtons?.setOverflowColor(overflowColor)
622
660
  }
623
661
  }
@@ -639,9 +677,9 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
639
677
  ).joinToString()
640
678
  if (keys[Part.Back] == key) return
641
679
  keys[Part.Back] = key
642
- val toolbar = bar.leftButtonBar
680
+ val row = bar.leftButtonBar
643
681
  if (!shown) {
644
- toolbar.navigationIcon = null
682
+ row.navigationIcon = null
645
683
  return
646
684
  }
647
685
  val own = back.icon.get(null)?.let(::loadIcon)?.mutate()
@@ -668,19 +706,13 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
668
706
  dp(background.height.get(0.0)),
669
707
  )
670
708
  } ?: icon
671
- toolbar.navigationIcon = drawable
672
- // Taking the icon, the navigation button gives it its own direction, which is stale while the button is new
673
- // or the bar's direction has just changed; the toolbar corrects it only after the icon was drawn. So the arrow
674
- // gets the bar's direction at once, on the drawable the button shows; a background passes it to the arrow.
675
- val held = toolbar.navigationIcon ?: drawable
676
- DrawableCompat.setLayoutDirection(held, arrowDirection)
677
- if (held !== drawable) DrawableCompat.setLayoutDirection(drawable, arrowDirection)
678
- toolbar.navigationContentDescription = label
679
- // The toolbar uses its navigation button again from screen to screen: its id is set every time.
680
- for (index in 0 until toolbar.childCount) {
681
- val child = toolbar.getChildAt(index)
682
- if ((child as? ImageView)?.drawable === held) TestIds.apply(child, testId)
683
- }
709
+ row.navigationIcon = drawable
710
+ // Taking the icon, the back button gives it its own direction, which is stale while the button is new or the
711
+ // bar's direction has just changed; the button corrects it only once its direction is resolved again. So the
712
+ // arrow gets the bar's direction at once; a background passes it to the arrow.
713
+ DrawableCompat.setLayoutDirection(drawable, arrowDirection)
714
+ row.navigationContentDescription = label
715
+ row.navigationButton?.let { TestIds.apply(it, testId) }
684
716
  }
685
717
 
686
718
  // The background (`topBar.background.component`).
@@ -719,15 +751,14 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
719
751
 
720
752
  private fun pictureUnderRow(bar: TopBar, leaving: ViewController<*>) {
721
753
  val view = leaving.peekView() ?: return
722
- val (bitmap, top) = bar.pictureUnderRow() ?: return
754
+ val (picture, top) = bar.pictureUnderRow() ?: return
723
755
  val barPlace = IntArray(2)
724
756
  val viewPlace = IntArray(2)
725
757
  bar.getLocationInWindow(barPlace)
726
758
  view.getLocationInWindow(viewPlace)
727
- val picture = BitmapDrawable(bar.resources, bitmap)
728
759
  val left = barPlace[0] - viewPlace[0]
729
760
  val y = barPlace[1] + top - viewPlace[1]
730
- picture.setBounds(left, y, left + bitmap.width, y + bitmap.height)
761
+ picture.setBounds(left, y, left + picture.intrinsicWidth, y + picture.intrinsicHeight)
731
762
  view.overlay.add(picture)
732
763
  underRow = leaving to picture
733
764
  }
@@ -802,6 +833,16 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
802
833
  opening.cancel()
803
834
  }
804
835
 
836
+ // A hide that held the options back ended: the bar, gone now, takes them.
837
+ private fun hidden() {
838
+ if (!waitsForHide) return
839
+ waitsForHide = false
840
+ val bar = bar ?: return
841
+ val entry = shownEntry ?: return
842
+ val screen = shownScreen ?: return
843
+ applyAll(bar, entry, screen, host.resolvedOf(entry), merge = false)
844
+ }
845
+
805
846
  // Shown or hidden: with the transition by its side, or by `animate` in a merge.
806
847
  private fun applyVisibility(options: Options, merge: Boolean) {
807
848
  val visible = !options.topBar.visible.isFalse
@@ -1037,11 +1078,16 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
1037
1078
  return (buttons.left.orEmpty() + buttons.right.orEmpty()).firstOrNull { it.id.get(null) == buttonId }?.menu
1038
1079
  }
1039
1080
 
1040
- // The search's magnifier, the one item of the bar with an id of its own: `<topBar.searchBar.testID>.button`.
1041
- override fun testIdOf(item: MenuItem): String? {
1042
- if (item.itemId == Menu.NONE) return null
1043
- val entry = shownEntry ?: return null
1044
- return host.resolvedOf(entry).topBar.searchBar.testID.get(null)?.let { "$it.button" }
1081
+ // Read as a menu opens, so they follow light and dark mode: `menuBackgroundColor`, else the bar's color as it
1082
+ // shows (none when it lets something through), and then `menuTextColor` or else the title's color, the pair
1083
+ // the bar shows; with neither, the theme's.
1084
+ override fun menuColors(): BarMenu.Colors {
1085
+ val topBar = shownEntry?.let(host::resolvedOf)?.topBar ?: return BarMenu.Colors(null, null)
1086
+ val context = bar?.context ?: activity
1087
+ val text = topBar.menuTextColor.get(context, null)
1088
+ topBar.menuBackgroundColor.get(context, null)?.let { return BarMenu.Colors(it, text) }
1089
+ val barColor = bar?.barColor?.takeIf { Color.alpha(it) == OPAQUE } ?: return BarMenu.Colors(null, text)
1090
+ return BarMenu.Colors(barColor, text ?: topBar.title.color.get(context, null))
1045
1091
  }
1046
1092
  }
1047
1093
 
@@ -1183,6 +1229,7 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
1183
1229
 
1184
1230
  private companion object {
1185
1231
  const val DEFAULT_HEIGHT_DP = 64.0
1232
+ const val OPAQUE = 255
1186
1233
  const val DEFAULT_TITLE_SP = 22.0
1187
1234
  const val DEFAULT_SUBTITLE_SP = 14.0
1188
1235
  const val CENTER = "center"
@@ -10,9 +10,10 @@ import dev.apexnative.navigation.views.animations.AnimationRules
10
10
  * stack its side (`animations.*.topBar`) plays instead — its `exit` hides, its `enter` shows; `enabled: false` shows or
11
11
  * hides at once. A show cancels a running hide and a hide a running show, each with its own token, so `visible: false`
12
12
  * then `true` leaves the bar shown; a motion cancelled leaves the bar at rest; a bar shown again stands in its place
13
- * with its row seen (the hide on scroll's shift and fade reset). Main thread only.
13
+ * with its row seen (the hide on scroll's shift and fade reset). [onHidden] runs once a hide has made the bar `GONE`.
14
+ * Main thread only.
14
15
  */
15
- internal class TopBarVisibility(private val target: Target) {
16
+ internal class TopBarVisibility(private val target: Target, private val onHidden: () -> Unit = {}) {
16
17
  /** What moves: the bar's view, or the unit tests' fake. */
17
18
  interface Target {
18
19
  /** How far up the bar goes to hide: its height and the room over it, in pixels. */
@@ -45,6 +46,10 @@ internal class TopBarVisibility(private val target: Target) {
45
46
  val isHidden: Boolean
46
47
  get() = hidden
47
48
 
49
+ /** The bar is on its way out: a hide moves it and it still shows. */
50
+ val isHiding: Boolean
51
+ get() = hidden && sliding != null
52
+
48
53
  /** Shows the bar: by [side] when it plays, sliding down when [animated], else at once. */
49
54
  fun show(animated: Boolean, side: TopBarAnimationOptions? = null) {
50
55
  val wasHidden = hidden
@@ -84,6 +89,7 @@ internal class TopBarVisibility(private val target: Target) {
84
89
  if (!moves || target.isGone) {
85
90
  target.translationY = 0f
86
91
  target.isGone = true
92
+ onHidden()
87
93
  return
88
94
  }
89
95
  val token = Any()
@@ -93,6 +99,7 @@ internal class TopBarVisibility(private val target: Target) {
93
99
  settle()
94
100
  target.isGone = true
95
101
  target.translationY = 0f
102
+ onHidden()
96
103
  }
97
104
  }
98
105
  val own = side?.takeIf { AnimationRules.sidePlays(it) }