@apexnative/navigation 1.0.0-alpha.2 → 1.0.0-alpha.4

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 (226) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/android/CLAUDE.md +38 -9
  3. package/android/CORE.md +11 -4
  4. package/android/RECIPES.md +9 -3
  5. package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +29 -1
  6. package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
  7. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
  8. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
  9. package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
  10. package/android/src/main/java/dev/apexnative/navigation/options/ButtonMenuOptions.kt +2 -2
  11. package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +2 -2
  12. package/android/src/main/java/dev/apexnative/navigation/options/OptionsCache.kt +8 -4
  13. package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
  14. package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
  15. package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +2 -24
  16. package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
  17. package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +27 -19
  18. package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +5 -4
  19. package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
  20. package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +17 -7
  21. package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
  22. package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +4 -3
  23. package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
  24. package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
  25. package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
  26. package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
  27. package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
  28. package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
  29. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
  30. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
  31. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +92 -19
  32. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
  33. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
  34. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +1 -1
  35. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
  36. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
  37. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
  38. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +79 -13
  39. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
  40. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +29 -12
  41. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +22 -18
  42. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +4 -0
  43. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +45 -6
  44. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +35 -9
  45. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
  46. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
  47. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
  48. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +3 -0
  49. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +5 -1
  50. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
  51. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +72 -16
  52. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +287 -0
  53. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +28 -18
  54. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +164 -13
  55. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
  56. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +136 -40
  57. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
  58. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +107 -4
  59. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +7 -5
  60. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +3 -3
  61. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
  62. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +131 -9
  63. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
  64. package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
  65. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +4 -2
  66. package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +15 -0
  67. package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +137 -1
  68. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
  69. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +8 -1
  70. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +26 -4
  71. package/cli/doctor/checks/app.js +61 -13
  72. package/cli/migrate/native.js +18 -0
  73. package/cli/setup/source.js +2 -1
  74. package/cli/setup/steps/mainApplication.js +134 -19
  75. package/docs-md/architecture/transitions.md +12 -7
  76. package/docs-md/containers/modals.md +4 -2
  77. package/docs-md/containers/overlays.md +3 -1
  78. package/docs-md/containers/side-menu.md +4 -2
  79. package/docs-md/containers/tabs.md +2 -0
  80. package/docs-md/flows/forms-in-a-modal.md +1 -1
  81. package/docs-md/help/glossary.md +2 -2
  82. package/docs-md/help/troubleshooting.md +20 -3
  83. package/docs-md/index.json +12 -0
  84. package/docs-md/migration/from-react-native-navigation.md +8 -2
  85. package/docs-md/screen-ui/back-and-gestures.md +8 -2
  86. package/docs-md/screen-ui/system-ui.md +1 -1
  87. package/docs-md/start/installation.md +3 -1
  88. package/ios/CLAUDE.md +17 -5
  89. package/ios/CORE.md +13 -8
  90. package/ios/Contract/ANNCommandAnswer.mm +5 -20
  91. package/ios/Contract/ANNCommandContract.h +15 -0
  92. package/ios/Contract/ANNCommandContract.mm +78 -0
  93. package/ios/Core/ANNAppearanceDispatcher.mm +1 -1
  94. package/ios/Core/ANNErrorHandler.h +1 -1
  95. package/ios/Core/ANNErrorHandler.mm +3 -1
  96. package/ios/Core/ANNEventEmitter.h +1 -1
  97. package/ios/Core/ANNEventEmitter.mm +2 -2
  98. package/ios/Core/ANNJavaScriptCalls.h +34 -0
  99. package/ios/Core/ANNJavaScriptCalls.mm +61 -0
  100. package/ios/Core/ANNNavigationState.h +7 -3
  101. package/ios/Core/ANNNavigationState.mm +10 -5
  102. package/ios/Core/ANNNodeHelper.h +32 -12
  103. package/ios/Core/ANNNodeHelper.mm +100 -3
  104. package/ios/Core/ANNRenderWait.h +15 -1
  105. package/ios/Core/ANNRenderWait.mm +119 -17
  106. package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
  107. package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
  108. package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
  109. package/ios/Layouts/Modal/ANNModalCoordinator.mm +55 -14
  110. package/ios/Layouts/Screen/ANNComponentViewController.h +8 -0
  111. package/ios/Layouts/Screen/ANNComponentViewController.mm +32 -5
  112. package/ios/Layouts/Screen/ANNScreenPlace.h +41 -0
  113. package/ios/Layouts/Screen/ANNScreenPlace.mm +175 -0
  114. package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
  115. package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
  116. package/ios/Layouts/SplitView/ANNSplitViewController.mm +4 -2
  117. package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
  118. package/ios/Layouts/Stack/ANNStackController.mm +26 -3
  119. package/ios/Layouts/Stack/ANNStackQueue.h +3 -1
  120. package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
  121. package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
  122. package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
  123. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
  124. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
  125. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +13 -5
  126. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +2 -2
  127. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +109 -7
  128. package/ios/Options/ANNOptionsCache.h +7 -6
  129. package/ios/Options/ANNSearchBarOptions.h +4 -3
  130. package/ios/Options/ANNUserChoice.h +57 -0
  131. package/ios/Options/ANNUserChoice.mm +44 -0
  132. package/ios/Options/Params/ANNImageSource.h +61 -0
  133. package/ios/Options/Params/ANNImageSource.mm +101 -0
  134. package/ios/Options/Params/ANNOptionImages.h +37 -0
  135. package/ios/Options/Params/ANNOptionImages.mm +284 -0
  136. package/ios/Options/Params/Image.h +11 -2
  137. package/ios/Options/Params/Image.mm +15 -2
  138. package/ios/Options/Params/ImageParser.h +5 -5
  139. package/ios/Options/Params/ImageParser.mm +28 -46
  140. package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
  141. package/ios/RECIPES.md +11 -5
  142. package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
  143. package/ios/React/Slots/ANNSlotContainers.h +14 -6
  144. package/ios/React/Slots/ANNSlotContainers.mm +75 -2
  145. package/ios/TopBar/ANNBarButtons.h +9 -5
  146. package/ios/TopBar/ANNBarButtons.mm +211 -63
  147. package/ios/TopBar/ANNIconButtonImage.h +1 -0
  148. package/ios/TopBar/ANNIconButtonImage.mm +34 -1
  149. package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
  150. package/ios/TopBar/ANNLargeTitlePresenter.mm +26 -3
  151. package/ios/TopBar/ANNSearchPresenter.mm +170 -19
  152. package/ios/TopBar/ANNTopBarPresenter.h +5 -0
  153. package/ios/TopBar/ANNTopBarPresenter.mm +60 -11
  154. package/ios/TurboModules/ANNTurboModule.mm +39 -21
  155. package/lib/module/ARCHITECTURE.md +18 -18
  156. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  157. package/lib/module/api/hooks/useNavigation.js +8 -3
  158. package/lib/module/api/hooks/useNavigation.js.map +1 -1
  159. package/lib/module/api/navigation.js.map +1 -1
  160. package/lib/module/engine/commands.js +9 -7
  161. package/lib/module/engine/commands.js.map +1 -1
  162. package/lib/module/engine/layout.js +13 -9
  163. package/lib/module/engine/layout.js.map +1 -1
  164. package/lib/module/engine/options.js +44 -11
  165. package/lib/module/engine/options.js.map +1 -1
  166. package/lib/module/engine/places.js +44 -7
  167. package/lib/module/engine/places.js.map +1 -1
  168. package/lib/module/engine/props.js +30 -1
  169. package/lib/module/engine/props.js.map +1 -1
  170. package/lib/module/engine/rememberedOptions.js +1 -1
  171. package/lib/module/engine/rememberedOptions.js.map +1 -1
  172. package/lib/module/engine/screens.js +22 -12
  173. package/lib/module/engine/screens.js.map +1 -1
  174. package/lib/module/interfaces/contract/commands.json +101 -0
  175. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +5 -2
  176. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  177. package/lib/typescript/api/events/navigationEvents.d.ts +1 -1
  178. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  179. package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
  180. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  181. package/lib/typescript/api/navigation.d.ts +4 -1
  182. package/lib/typescript/api/navigation.d.ts.map +1 -1
  183. package/lib/typescript/engine/commands.d.ts.map +1 -1
  184. package/lib/typescript/engine/options.d.ts +5 -2
  185. package/lib/typescript/engine/options.d.ts.map +1 -1
  186. package/lib/typescript/engine/places.d.ts +5 -2
  187. package/lib/typescript/engine/places.d.ts.map +1 -1
  188. package/lib/typescript/engine/props.d.ts +8 -1
  189. package/lib/typescript/engine/props.d.ts.map +1 -1
  190. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  191. package/lib/typescript/engine/screens.d.ts.map +1 -1
  192. package/lib/typescript/interfaces/ComponentEvents.d.ts +2 -2
  193. package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
  194. package/lib/typescript/interfaces/Events.d.ts +19 -10
  195. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  196. package/lib/typescript/interfaces/options/animations.d.ts +15 -7
  197. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  198. package/lib/typescript/interfaces/options/buttons.d.ts +13 -5
  199. package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
  200. package/lib/typescript/interfaces/options/modals.d.ts +18 -13
  201. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  202. package/lib/typescript/interfaces/options/system.d.ts +6 -3
  203. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  204. package/lib/typescript/interfaces/options/topBar.d.ts +22 -9
  205. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  206. package/package.json +1 -1
  207. package/src/ARCHITECTURE.md +18 -18
  208. package/src/adapters/NativeANNTurboModule.ts +5 -2
  209. package/src/api/events/navigationEvents.ts +1 -1
  210. package/src/api/hooks/useNavigation.ts +9 -4
  211. package/src/api/navigation.ts +4 -1
  212. package/src/engine/commands.ts +19 -7
  213. package/src/engine/layout.ts +16 -9
  214. package/src/engine/options.ts +39 -11
  215. package/src/engine/places.ts +56 -7
  216. package/src/engine/props.ts +30 -1
  217. package/src/engine/rememberedOptions.ts +4 -1
  218. package/src/engine/screens.tsx +23 -13
  219. package/src/interfaces/ComponentEvents.ts +2 -2
  220. package/src/interfaces/Events.ts +19 -10
  221. package/src/interfaces/contract/commands.json +101 -0
  222. package/src/interfaces/options/animations.ts +15 -7
  223. package/src/interfaces/options/buttons.ts +13 -5
  224. package/src/interfaces/options/modals.ts +18 -13
  225. package/src/interfaces/options/system.ts +6 -3
  226. package/src/interfaces/options/topBar.ts +22 -9
@@ -2,6 +2,7 @@ package dev.apexnative.navigation.viewcontrollers.stack
2
2
 
3
3
  import android.app.Activity
4
4
  import android.util.Log
5
+ import android.view.View
5
6
  import dev.apexnative.navigation.NavigationActivity
6
7
  import dev.apexnative.navigation.options.AnimationsOptions
7
8
  import dev.apexnative.navigation.options.BottomTabsEnterExitAnimationOptions
@@ -11,6 +12,7 @@ import dev.apexnative.navigation.options.Options
11
12
  import dev.apexnative.navigation.options.TopBarOptions
12
13
  import dev.apexnative.navigation.react.CommandListener
13
14
  import dev.apexnative.navigation.react.ErrorTexts
15
+ import dev.apexnative.navigation.react.PendingCalls
14
16
  import dev.apexnative.navigation.react.events.AppearanceDispatcher
15
17
  import dev.apexnative.navigation.utils.NavigationLog
16
18
  import dev.apexnative.navigation.utils.UiThread
@@ -20,8 +22,8 @@ import dev.apexnative.navigation.viewcontrollers.child.ChildControllersRegistry
20
22
  import dev.apexnative.navigation.viewcontrollers.component.ComponentViewController
21
23
  import dev.apexnative.navigation.viewcontrollers.component.ContentReadiness
22
24
  import dev.apexnative.navigation.viewcontrollers.component.Readiness
25
+ import dev.apexnative.navigation.viewcontrollers.component.RenderWait
23
26
  import dev.apexnative.navigation.viewcontrollers.component.RestPlace
24
- import dev.apexnative.navigation.viewcontrollers.component.ScreenContentFactory
25
27
  import dev.apexnative.navigation.viewcontrollers.navigator.BackCallbackState
26
28
  import dev.apexnative.navigation.viewcontrollers.navigator.Navigator
27
29
  import dev.apexnative.navigation.viewcontrollers.parent.ContainerBackground
@@ -35,6 +37,7 @@ import dev.apexnative.navigation.viewcontrollers.stack.topbar.TopBarPresenter
35
37
  import dev.apexnative.navigation.viewcontrollers.stack.topbar.TopBarRoom
36
38
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.Presenter
37
39
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
40
+ import dev.apexnative.navigation.views.animations.AnimationRules
38
41
  import dev.apexnative.navigation.views.component.ComponentLayout
39
42
  import dev.apexnative.navigation.views.stack.StackLayout
40
43
  import dev.apexnative.navigation.views.stack.topbar.LargeTitleView
@@ -79,26 +82,34 @@ class StackController(
79
82
 
80
83
  /** The one queue of the stack. */
81
84
  // The readiness of the screens reaches the queue's waits on the next turn of the main loop: a signal that comes
82
- // inside a layout pass or a view's attach moves no view of the container there.
85
+ // inside a layout pass or a view's attach moves no view of the container there. A pushed screen's mount reaches
86
+ // its push behind the calls JavaScript made before it (`PendingCalls`), on a later turn too.
83
87
  internal var queue = StackQueue(
84
88
  display = StackViews(this),
85
89
  readiness = ContentReadiness,
86
90
  scheduler = { delay, task -> AppearanceDispatcher.scheduler.schedule(delay, task) },
87
91
  host = QueueHost(),
88
92
  deliver = { signal -> UiThread.post { signal() } },
93
+ afterCalls = PendingCalls::after,
89
94
  )
90
95
  private set
91
96
 
92
97
  /**
93
98
  * The unit tests run the stack over their own display, readiness and host (views are stubs there), before any
94
- * screen joins it; the readiness signals come at once there.
99
+ * screen joins it; the readiness signals come at once there, and a push's behind the calls as [afterCalls] says.
95
100
  */
96
- internal fun useQueueParts(display: StackDisplay, readiness: Readiness, host: StackQueue.Host?) {
101
+ internal fun useQueueParts(
102
+ display: StackDisplay,
103
+ readiness: Readiness,
104
+ host: StackQueue.Host?,
105
+ afterCalls: (() -> Unit) -> Unit = { it() },
106
+ ) {
97
107
  queue = StackQueue(
98
108
  display = display,
99
109
  readiness = readiness,
100
110
  scheduler = { delay, task -> AppearanceDispatcher.scheduler.schedule(delay, task) },
101
111
  host = host ?: QueueHost(),
112
+ afterCalls = afterCalls,
102
113
  )
103
114
  }
104
115
 
@@ -257,6 +268,136 @@ class StackController(
257
268
  */
258
269
  override fun canHandleBack(): Boolean = topBar.isSearchOpen() || queue.entries.size >= 2
259
270
 
271
+ /**
272
+ * The default pop of the top is what back does now and it can be previewed: two entries or more, nothing running
273
+ * or waiting, no open search, the top doesn't hold back and pops with the default transition, the screen under it
274
+ * has its view, and the stack shows.
275
+ */
276
+ override fun stackPoppedByBack(): StackController? {
277
+ if (topBar.isSearchOpen() || !queue.isAtRest) return null
278
+ val entries = queue.entries
279
+ val top = queue.currentChild ?: return null
280
+ val target = entries.getOrNull(entries.size - 2) ?: return null
281
+ if (top !== entries.last() || target !in queue.shown || target.peekView() == null) return null
282
+ if (!queue.isRendered(target) || backGesture != null) return null
283
+ val options = resolvedOf(top)
284
+ val pop = options.animations.pop
285
+ if (options.hardwareBackButton.popStackOnPress.isFalse || pop.enabled.isFalse || AnimationRules.stackIsOwn(pop)) {
286
+ return null
287
+ }
288
+ val display = queue.display
289
+ return this.takeIf { display.isOnScreen && display.canAnimate }
290
+ }
291
+
292
+ /**
293
+ * Starts the preview of the pop a back gesture would make ([stackPoppedByBack] said yes): the top shrinks toward
294
+ * the gesture's side ([fromLeft]) and follows the finger from [touchY]; the screen under it shows with its bar.
295
+ * None when it can't be shown.
296
+ */
297
+ internal fun startBackGesture(fromLeft: Boolean, touchY: Float): BackGesture? {
298
+ val views = queue.display as? StackViews ?: return null
299
+ val top = queue.currentChild ?: return null
300
+ val target = queue.entries.getOrNull(queue.entries.size - 2) ?: return null
301
+ val gesture = BackGesture(views, top, target)
302
+ val preview = views.startBackPreview(top, target, fromLeft, touchY, gesture::reveal) ?: return null
303
+ gesture.preview = preview
304
+ backGesture = gesture
305
+ return gesture
306
+ }
307
+
308
+ // The back gesture over this stack whose preview hasn't ended yet; none.
309
+ private var backGesture: BackGesture? = null
310
+
311
+ /**
312
+ * A back gesture over the top of this stack ([startBackGesture]): its progress, its cancel, and its release, which
313
+ * pops the top through the queue with the preview's end. A command accepted meanwhile, or the stack's destroy,
314
+ * ends the preview at once ([abort]).
315
+ */
316
+ internal inner class BackGesture(
317
+ private val views: StackViews,
318
+ private val top: ViewController<*>,
319
+ private val target: ViewController<*>,
320
+ ) {
321
+ lateinit var preview: BackPreview
322
+ // How the screen under the top was before the preview showed it: in the container and seen, its alpha and
323
+ // accessibility.
324
+ private var targetWasPlaced = false
325
+ private var targetAlpha = 1f
326
+ private var targetAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
327
+ private var revealed = false
328
+ private var aborted = false
329
+
330
+ /** The gesture moved: [progress] 0 … 1, the finger at [touchY]. */
331
+ fun progress(progress: Float, touchY: Float) {
332
+ if (!aborted) preview.progress(progress, touchY)
333
+ }
334
+
335
+ /** Cancelled: the preview springs back, then the screen under the top and the bar are as they were. */
336
+ fun cancel() {
337
+ if (!aborted) preview.cancel(::restore)
338
+ }
339
+
340
+ /**
341
+ * Released: the top pops, the preview playing its end; the default pop when its picture isn't there yet. False
342
+ * when the stack changed since the gesture started (a command ran, the stack went): back goes the usual way.
343
+ */
344
+ fun commit(): Boolean {
345
+ if (aborted || isDestroyed) return false
346
+ if (!preview.isReady) {
347
+ abort()
348
+ queue.cut(target, null, id, "go back in the stack '$id'", null)
349
+ return true
350
+ }
351
+ if (backGesture === this) backGesture = null
352
+ queue.cut(target, null, id, "go back in the stack '$id'", null, gesture = true)
353
+ return true
354
+ }
355
+
356
+ /** The stack changed or goes: the preview ends at once and the stack is as it was. */
357
+ fun abort() {
358
+ if (aborted) return
359
+ aborted = true
360
+ preview.endAtOnce()
361
+ restore()
362
+ }
363
+
364
+ // The preview's picture is there: the screen under the top shows under it, and the bar shows that screen.
365
+ internal fun reveal() {
366
+ val view = target.peekView() ?: return
367
+ targetWasPlaced = view.parent === peekView() && view.visibility == View.VISIBLE
368
+ targetAlpha = view.alpha
369
+ targetAccessibility = view.importantForAccessibility
370
+ revealed = true
371
+ views.reveal(target, top)
372
+ view.alpha = 1f
373
+ topBar.apply(target)
374
+ }
375
+
376
+ private fun restore() {
377
+ views.previewEnded(preview)
378
+ if (backGesture === this) backGesture = null
379
+ if (!revealed || isDestroyed) return
380
+ revealed = false
381
+ if (target in queue.shown && target !== queue.currentChild) {
382
+ val view = target.peekView()
383
+ if (targetWasPlaced && view != null) {
384
+ view.alpha = targetAlpha
385
+ view.importantForAccessibility = targetAccessibility
386
+ } else {
387
+ views.detach(target)
388
+ }
389
+ }
390
+ // The bar shows the top again, its components appeared again.
391
+ val shown = queue.currentChild
392
+ topBar.apply(shown)
393
+ shown?.let {
394
+ topBar.screenWillAppear(optionsScreen(it))
395
+ topBar.screenDidAppear(optionsScreen(it))
396
+ }
397
+ BackCallbackState.update()
398
+ }
399
+ }
400
+
260
401
  /**
261
402
  * The back arrow of the bar was pressed: the screen the user sees holds it (`topBar.backButton.popStackOnPress:
262
403
  * false`: `ANN.NavigationButtonPressed` with `topBar.backButton.id` or `ApexNavigation.back`); on the first screen
@@ -338,7 +479,7 @@ class StackController(
338
479
 
339
480
  // `mergeOptions` with the stack's id: its own options, what it shows, then the layouts around.
340
481
  override fun mergeOptions(options: Options) {
341
- this.options = this.options.copy().mergeWith(options)
482
+ mergeOwnOptions(options)
342
483
  applyOrKeep(options, null)
343
484
  performOnParentController { it.mergeChildOptions(withoutStackGroups(options), this) }
344
485
  }
@@ -460,8 +601,9 @@ class StackController(
460
601
 
461
602
  /**
462
603
  * The bar's bottom in the window while [child] is under it and it shows, from the stack's place in the window: for
463
- * the screen on top where the bar is laid out (a move of the bar doesn't count); for another child (a prepared one)
464
- * as its own options set the bar.
604
+ * the screen on top that the bar shows, where the bar is laid out (a move of the bar doesn't count); for another
605
+ * child (a prepared one) and for a top the bar hasn't shown yet (in a tab not selected yet, which measures though
606
+ * invisible) as its own options set the bar, so its content doesn't move as the bar takes them.
465
607
  */
466
608
  override fun headerBottomOf(child: ViewController<*>): Int? {
467
609
  if (!isUnderBar(child)) return super.headerBottomOf(child)
@@ -471,7 +613,7 @@ class StackController(
471
613
  val layout = peekView() ?: return null
472
614
  // The stack's place at rest, as the screen's own: a modal sliding in or a sheet dragged doesn't move it.
473
615
  val top = RestPlace.topInWindow(layout)
474
- if (entry === queue.currentChild) return topBar.barBottomInStack()?.let { top + it }
616
+ if (entry === queue.currentChild && topBar.shows(entry)) return topBar.barBottomInStack()?.let { top + it }
475
617
  val bar = topBar.barOf(entry, options)
476
618
  val large = if (largeTitleShown(child)) UiUtils.dpToPx(activity, LargeTitleView.HEIGHT).toInt() else 0
477
619
  return top + bar.margin + bar.strip + bar.height + large
@@ -506,6 +648,7 @@ class StackController(
506
648
 
507
649
  override fun destroy() {
508
650
  if (isDestroyed) return
651
+ backGesture?.abort()
509
652
  queue.destroy()
510
653
  preparedPushes()?.discardFor(this)
511
654
  fab.destroy()
@@ -552,15 +695,23 @@ class StackController(
552
695
  (node as? OptionsScreen)?.optionsScreen ?: node
553
696
 
554
697
  private inner class QueueHost : StackQueue.Host {
698
+ override fun operationAccepted() {
699
+ backGesture?.abort()
700
+ }
701
+
555
702
  // The bar takes the options of the new top at once, also without appearance events.
556
703
  override fun currentChildChanged() {
557
704
  updateBar()
558
705
  navigator?.shownScreensChanged(this@StackController)
559
706
  }
560
707
 
561
- // Before the bar takes the new top's options: the row's picture, and how it shows or hides.
562
- override fun barTransition(motion: StackDisplay.BarMotion?, visibility: StackDisplay.BarVisibility) {
563
- if (peekView() != null) topBar.beginRowTransition(motion, queue.currentChild, visibility)
708
+ // Before the bar takes the new top's options: the row's picture or the bar's travel, and how it shows or hides.
709
+ override fun barTransition(
710
+ motion: StackDisplay.BarMotion?,
711
+ visibility: StackDisplay.BarVisibility,
712
+ travel: StackDisplay.BarTravel?,
713
+ ) {
714
+ if (peekView() != null) topBar.beginRowTransition(motion, queue.currentChild, visibility, travel)
564
715
  }
565
716
 
566
717
  // The tab bar of the tabs around goes with the transition; a takeover doesn't bring it to rest.
@@ -588,8 +739,8 @@ class StackController(
588
739
  if (peekView() != null) topBar.stage(node)
589
740
  }
590
741
 
591
- override fun isOwnRootScreen(node: ViewController<*>): Boolean =
592
- (node as? ComponentViewController)?.componentName?.startsWith(ScreenContentFactory.SLOT_PREFIX) == false
742
+ override fun hasReactContent(node: ViewController<*>): Boolean =
743
+ RenderWait.waitedScreens(node).any { it is ComponentViewController }
593
744
 
594
745
  override fun log(text: String) {
595
746
  Log.e(NavigationLog.TAG, text)
@@ -38,6 +38,12 @@ internal interface StackDisplay {
38
38
  */
39
39
  enum class BarMotion { Push, Pop, FadeThrough }
40
40
 
41
+ /**
42
+ * How the bar goes with a transition of the stack's own (`content`): with its screens. [Forward]: the screen that
43
+ * comes lies over the one that goes (a push, `setStackRoot`); [Back]: the one that goes lies over it (a pop).
44
+ */
45
+ enum class BarTravel { Forward, Back }
46
+
41
47
  /**
42
48
  * How the bar shows or hides when the new top's `topBar.visible` differs: at once (no animation, or a transition
43
49
  * with elements), or [animated] by the transition's [side] (`animations.push.topBar`, the leaving screen's
@@ -156,12 +162,31 @@ internal interface StackDisplay {
156
162
  done: () -> Unit,
157
163
  ): () -> Unit
158
164
 
165
+ /** The preview of a back gesture over [top], [target] under it, shows ([finishBackGesture] can end it). */
166
+ fun hasBackPreview(top: ViewController<*>, target: ViewController<*>): Boolean = false
167
+
168
+ /**
169
+ * The pop of a back gesture whose preview shows ([hasBackPreview]), released: the preview plays the end of [top]
170
+ * going and [target] coming. [topDone] and [targetDone] once each, as [animate]'s; [stop] of one screen ends the
171
+ * preview where it is and its other screen's part.
172
+ */
173
+ fun finishBackGesture(
174
+ top: ViewController<*>,
175
+ target: ViewController<*>,
176
+ topDone: () -> Unit,
177
+ targetDone: () -> Unit,
178
+ ) {
179
+ topDone()
180
+ targetDone()
181
+ }
182
+
159
183
  /** Stops the animator of [screen] where it is, without its end: a later transition takes the screen over. */
160
184
  fun stop(screen: ViewController<*>)
161
185
 
162
186
  /**
163
187
  * The push of a prepared slot screen: [mounted] as the slot's content mounts into the screen's container (or at the
164
- * limit of 0.5 s), then [start] on the pre-draw of that frame, while [waiting] holds.
188
+ * limit of 0.5 s), then [start] on the pre-draw of that frame, while [waiting] holds; the queue starts the
189
+ * transition from there behind the calls JavaScript made before, on a later turn.
165
190
  */
166
191
  fun awaitPrepared(screen: ViewController<*>, waiting: () -> Boolean, mounted: () -> Unit, start: () -> Unit)
167
192
  }