@apexnative/navigation 1.0.0-alpha.5 → 1.0.0-alpha.7
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.
- package/ApexNavigation.podspec +2 -1
- package/CHANGELOG.md +32 -0
- package/README.md +1 -1
- package/android/CLAUDE.md +31 -20
- package/android/CORE.md +12 -8
- package/android/consumer-rules.pro +6 -0
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +36 -5
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
- package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
- package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
- package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
- package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +7 -3
- package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +41 -3
- package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +16 -1
- package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +0 -2
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +12 -49
- package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
- package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +27 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +12 -1
- package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
- package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +9 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +13 -10
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +7 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +20 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +443 -58
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +33 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +60 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +4 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +3 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +8 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +32 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +50 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +15 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +10 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +215 -43
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +25 -26
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +36 -38
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
- package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
- package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +129 -179
- package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +8 -1
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +67 -3
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +55 -42
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -24
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +51 -34
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +121 -175
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
- package/android/src/main/jni/ANNContentHeights.cpp +82 -0
- package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
- package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
- package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
- package/android/src/main/res/values/styles.xml +1 -1
- package/android/src/main/res/values-night/styles.xml +1 -1
- package/cli/doctor/checks/app.js +16 -1
- package/cli/project.js +4 -0
- package/cli/setup/index.js +5 -0
- package/cli/setup/steps/metro.js +46 -0
- package/docs-md/architecture/native-screens.md +4 -0
- package/docs-md/architecture/theme-and-context.md +131 -12
- package/docs-md/architecture/transitions.md +46 -5
- package/docs-md/containers/modals.md +2 -0
- package/docs-md/containers/overlays.md +1 -1
- package/docs-md/containers/side-menu.md +1 -1
- package/docs-md/containers/tabs.md +2 -0
- package/docs-md/flows/bottom-sheets.md +4 -2
- package/docs-md/fundamentals/screens-and-props.md +9 -1
- package/docs-md/fundamentals/starting-the-app.md +1 -1
- package/docs-md/guides/cli.md +3 -1
- package/docs-md/help/glossary.md +2 -2
- package/docs-md/help/troubleshooting.md +22 -1
- package/docs-md/index.json +41 -1
- package/docs-md/migration/from-expo-router.md +1 -1
- package/docs-md/migration/from-react-native-navigation.md +1 -1
- package/docs-md/migration/from-react-navigation.md +2 -2
- package/docs-md/screen-ui/back-and-gestures.md +17 -1
- package/docs-md/screen-ui/bar-buttons.md +5 -5
- package/docs-md/screen-ui/search.md +1 -1
- package/docs-md/screen-ui/system-ui.md +16 -11
- package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
- package/docs-md/screen-ui/top-bar.md +8 -4
- package/docs-md/start/installation.md +16 -1
- package/ios/Animations/ANNFrameDriver.h +55 -15
- package/ios/Animations/ANNFrameDriver.mm +216 -60
- package/ios/Animations/ANNTransitionAnimator.h +26 -5
- package/ios/Animations/ANNTransitionAnimator.mm +49 -3
- package/ios/Animations/ANNTransitionPlan.h +2 -2
- package/ios/Animations/ANNTransitionPlan.mm +10 -0
- package/ios/Animations/Elements/ANNElementFinder.h +2 -2
- package/ios/Animations/Elements/ANNElementFinder.mm +2 -2
- package/ios/Animations/Elements/ANNElementTransition.h +3 -3
- package/ios/Animations/Elements/ANNElementTransition.mm +2 -2
- package/ios/Animations/Elements/ANNSharedElementFlight.h +3 -3
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +249 -45
- package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
- package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
- package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
- package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
- package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
- package/ios/CLAUDE.md +32 -22
- package/ios/CORE.md +25 -21
- package/ios/Contract/ANNCommandRunner.h +8 -7
- package/ios/Contract/ANNCommandRunner.mm +21 -27
- package/ios/Contract/ANNLayoutNode.h +3 -3
- package/ios/Contract/ANNLayoutReader.h +3 -3
- package/ios/Core/ANNAppDelegate.mm +0 -2
- package/ios/Core/ANNDeepLinkQueue.h +6 -5
- package/ios/Core/ANNDeepLinkQueue.mm +22 -10
- package/ios/Core/ANNJavaScriptCalls.h +11 -12
- package/ios/Core/ANNJavaScriptCalls.mm +7 -16
- package/ios/Core/ANNReloadCoordinator.mm +4 -8
- package/ios/Core/ANNSceneDelegate.mm +2 -2
- package/ios/Core/ApexNavigation+Internal.h +1 -1
- package/ios/Core/ApexNavigation.mm +6 -2
- package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
- package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
- package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +4 -4
- package/ios/Layouts/Root/ANNRootCoordinator.mm +45 -15
- package/ios/Layouts/Screen/ANNComponentViewController.h +2 -2
- package/ios/Layouts/Screen/ANNComponentViewController.mm +13 -23
- package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
- package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
- package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
- package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
- package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
- package/ios/Layouts/Screen/ANNScreenRegions.mm +0 -38
- package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
- package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
- package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
- package/ios/Layouts/Stack/ANNPreviewPush.mm +57 -5
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
- package/ios/Layouts/Stack/ANNStackController.h +8 -0
- package/ios/Layouts/Stack/ANNStackController.mm +153 -11
- package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
- package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
- package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.mm +2 -1
- package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +4 -0
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +123 -36
- package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
- package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
- package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
- package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
- package/ios/Options/ANNAnimationOptions.h +2 -1
- package/ios/Options/ANNAnimationOptions.mm +1 -1
- package/ios/Options/ANNBottomTabsOptions.h +2 -0
- package/ios/Options/ANNBottomTabsOptions.mm +1 -0
- package/ios/Options/ANNOptions.h +25 -0
- package/ios/Options/ANNOptions.mm +157 -1
- package/ios/Options/ANNOptionsReader.mm +108 -0
- package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
- package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
- package/ios/Options/Params/ANNParam.h +15 -0
- package/ios/Options/Params/ANNParam.mm +61 -0
- package/ios/Options/Params/Color.h +3 -0
- package/ios/Options/Params/Color.mm +21 -0
- package/ios/Options/Params/ColorParser.h +4 -3
- package/ios/Options/Params/ColorParser.mm +22 -4
- package/ios/Options/Params/Image.h +4 -0
- package/ios/Options/Params/Image.mm +20 -0
- package/ios/React/ANNReactView.mm +6 -25
- package/ios/React/ANNSafeAreaViewComponentView.mm +26 -15
- package/ios/React/ANNSurfaceHostingView.h +14 -0
- package/ios/React/ANNSurfaceHostingView.mm +144 -1
- package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
- package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
- package/ios/TopBar/ANNBarAppearance.h +2 -1
- package/ios/TopBar/ANNBarAppearance.mm +111 -30
- package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
- package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
- package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
- package/ios/TopBar/ANNBarButtons.h +5 -3
- package/ios/TopBar/ANNBarButtons.mm +186 -17
- package/ios/TopBar/ANNLargeTitlePresenter.mm +24 -4
- package/ios/TopBar/ANNMainList.h +3 -0
- package/ios/TopBar/ANNMainList.mm +4 -0
- package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
- package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
- package/ios/TopBar/ANNSearchPresenter.mm +2 -2
- package/ios/TopBar/ANNSearchResultsViewController.mm +5 -5
- package/ios/TopBar/ANNTopBarPresenter.h +3 -2
- package/ios/TopBar/ANNTopBarPresenter.mm +95 -22
- package/ios/TurboModules/ANNTurboModule.mm +66 -16
- package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
- package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
- package/lib/module/ARCHITECTURE.md +17 -7
- package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
- package/lib/module/api/app/AppRegistry.js +14 -2
- package/lib/module/api/app/AppRegistry.js.map +1 -1
- package/lib/module/api/app/createNavigation.js +188 -66
- package/lib/module/api/app/createNavigation.js.map +1 -1
- package/lib/module/api/events/navigationEvents.js +6 -2
- package/lib/module/api/events/navigationEvents.js.map +1 -1
- package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
- package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
- package/lib/module/api/linking/linking.js +11 -0
- package/lib/module/api/linking/linking.js.map +1 -1
- package/lib/module/api/options/OptionsChain.js +2 -2
- package/lib/module/api/screens/defineScreen.js +45 -3
- package/lib/module/api/screens/defineScreen.js.map +1 -1
- package/lib/module/api/screens/nativeScreens.js +31 -6
- package/lib/module/api/screens/nativeScreens.js.map +1 -1
- package/lib/module/api/screens/registerScreens.js +172 -35
- package/lib/module/api/screens/registerScreens.js.map +1 -1
- package/lib/module/api/theme/theme.js +5 -0
- package/lib/module/api/theme/theme.js.map +1 -1
- package/lib/module/engine/commands.js +42 -2
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/layout.js +7 -2
- package/lib/module/engine/layout.js.map +1 -1
- package/lib/module/engine/nativeScreens.js +9 -0
- package/lib/module/engine/nativeScreens.js.map +1 -1
- package/lib/module/engine/options.js +5 -4
- package/lib/module/engine/options.js.map +1 -1
- package/lib/module/engine/optionsChange.js +102 -0
- package/lib/module/engine/optionsChange.js.map +1 -0
- package/lib/module/engine/refresh.js +85 -0
- package/lib/module/engine/refresh.js.map +1 -0
- package/lib/module/engine/rememberedOptions.js +60 -0
- package/lib/module/engine/rememberedOptions.js.map +1 -1
- package/lib/module/engine/screens.js +55 -4
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts +7 -0
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
- package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
- package/lib/typescript/api/app/createNavigation.d.ts +8 -3
- package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts +2 -2
- package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
- package/lib/typescript/api/index.d.ts +1 -1
- package/lib/typescript/api/index.d.ts.map +1 -1
- package/lib/typescript/api/linking/linking.d.ts +8 -0
- package/lib/typescript/api/linking/linking.d.ts.map +1 -1
- package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
- package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
- package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
- package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
- package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
- package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
- package/lib/typescript/api/theme/theme.d.ts +2 -0
- package/lib/typescript/api/theme/theme.d.ts.map +1 -1
- package/lib/typescript/engine/commands.d.ts +5 -0
- package/lib/typescript/engine/commands.d.ts.map +1 -1
- package/lib/typescript/engine/layout.d.ts.map +1 -1
- package/lib/typescript/engine/nativeScreens.d.ts +5 -0
- package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
- package/lib/typescript/engine/optionsChange.d.ts +28 -0
- package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
- package/lib/typescript/engine/refresh.d.ts +35 -0
- package/lib/typescript/engine/refresh.d.ts.map +1 -0
- package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
- package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
- package/lib/typescript/engine/screens.d.ts +27 -6
- package/lib/typescript/engine/screens.d.ts.map +1 -1
- package/lib/typescript/interfaces/ComponentEvents.d.ts +2 -2
- package/lib/typescript/interfaces/options/animations.d.ts +44 -14
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +19 -6
- package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/buttons.d.ts +10 -10
- package/lib/typescript/interfaces/options/modals.d.ts +6 -7
- package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/stack.d.ts +8 -3
- package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/system.d.ts +8 -5
- package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
- package/lib/typescript/interfaces/options/topBar.d.ts +46 -29
- package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
- package/metro/acceptPlugin.js +57 -0
- package/metro/babelTransformer.js +45 -0
- package/metro/index.js +36 -0
- package/package.json +3 -1
- package/src/ARCHITECTURE.md +17 -7
- package/src/adapters/NativeANNTurboModule.ts +7 -0
- package/src/api/app/AppRegistry.ts +16 -2
- package/src/api/app/createNavigation.ts +201 -69
- package/src/api/events/navigationEvents.ts +9 -3
- package/src/api/hooks/useSafeAreaInsets.ts +4 -3
- package/src/api/index.ts +1 -0
- package/src/api/linking/linking.ts +22 -1
- package/src/api/options/OptionsChain.ts +2 -2
- package/src/api/screens/defineScreen.ts +49 -5
- package/src/api/screens/nativeScreens.ts +40 -4
- package/src/api/screens/registerScreens.tsx +170 -42
- package/src/api/theme/theme.ts +5 -0
- package/src/engine/commands.ts +51 -6
- package/src/engine/layout.ts +11 -2
- package/src/engine/nativeScreens.ts +10 -1
- package/src/engine/options.ts +6 -8
- package/src/engine/optionsChange.ts +107 -0
- package/src/engine/refresh.ts +97 -0
- package/src/engine/rememberedOptions.ts +70 -0
- package/src/engine/screens.tsx +53 -8
- package/src/interfaces/ComponentEvents.ts +2 -2
- package/src/interfaces/options/animations.ts +44 -14
- package/src/interfaces/options/bottomTabs.ts +19 -6
- package/src/interfaces/options/buttons.ts +10 -10
- package/src/interfaces/options/modals.ts +6 -7
- package/src/interfaces/options/stack.ts +8 -3
- package/src/interfaces/options/system.ts +8 -5
- package/src/interfaces/options/toolbar.ts +2 -2
- package/src/interfaces/options/topBar.ts +46 -29
- package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -42
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -70
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -136
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -86
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -64
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -177
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -137
- package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
- package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -70
|
@@ -14,11 +14,15 @@ import android.widget.FrameLayout
|
|
|
14
14
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
15
15
|
import androidx.core.view.ViewCompat
|
|
16
16
|
import androidx.core.view.WindowInsetsCompat
|
|
17
|
+
import dev.apexnative.navigation.options.DefaultOptions
|
|
17
18
|
import dev.apexnative.navigation.options.ModalAnimationOptions
|
|
18
19
|
import dev.apexnative.navigation.options.Options
|
|
19
20
|
import dev.apexnative.navigation.utils.TestIds
|
|
20
21
|
import dev.apexnative.navigation.utils.dp
|
|
22
|
+
import dev.apexnative.navigation.viewcontrollers.component.ComponentViewController
|
|
23
|
+
import dev.apexnative.navigation.viewcontrollers.parent.ParentController
|
|
21
24
|
import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
|
|
25
|
+
import dev.apexnative.navigation.views.animations.AnimationLayer
|
|
22
26
|
import dev.apexnative.navigation.views.animations.AnimationRules
|
|
23
27
|
import dev.apexnative.navigation.views.animations.SideAnimator
|
|
24
28
|
import dev.apexnative.navigation.views.element.ElementTransition
|
|
@@ -95,7 +99,7 @@ internal class ModalViews(
|
|
|
95
99
|
val container = parts.container
|
|
96
100
|
container.isWaiting = false
|
|
97
101
|
container.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
|
|
98
|
-
if (record.isSheet) return presentSheet(record, parts, options, seen, events, onEnd)
|
|
102
|
+
if (record.isSheet) return presentSheet(record, parts, options, animated, seen, events, onEnd)
|
|
99
103
|
applyTestIds(record, parts, options)
|
|
100
104
|
if (!animated || !seen) {
|
|
101
105
|
SideAnimator.rest(container)
|
|
@@ -117,11 +121,13 @@ internal class ModalViews(
|
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
// The root's view leaves the container and goes into the sheet's, in one turn; the sheet slides to its first
|
|
120
|
-
// detent. Nobody sees the activity: the show counts as done now, the
|
|
124
|
+
// detent, or stands there at once when not [animated]. Nobody sees the activity: the show counts as done now, the
|
|
125
|
+
// sheet's later end does nothing.
|
|
121
126
|
private fun presentSheet(
|
|
122
127
|
record: ModalRecord,
|
|
123
128
|
parts: Parts,
|
|
124
129
|
options: Options,
|
|
130
|
+
animated: Boolean,
|
|
125
131
|
seen: Boolean,
|
|
126
132
|
events: ModalSheet.Events,
|
|
127
133
|
onEnd: () -> Unit,
|
|
@@ -129,7 +135,16 @@ internal class ModalViews(
|
|
|
129
135
|
val container = parts.container
|
|
130
136
|
val view = record.root.view
|
|
131
137
|
container.removeView(view)
|
|
132
|
-
val sheet = ModalSheet(
|
|
138
|
+
val sheet = ModalSheet(
|
|
139
|
+
container,
|
|
140
|
+
view,
|
|
141
|
+
events,
|
|
142
|
+
shownContent = { (shownScreen(record.root) as? ComponentViewController)?.content },
|
|
143
|
+
adjustsForKeyboard = {
|
|
144
|
+
val screen = shownScreen(record.root)
|
|
145
|
+
screen == null || !screen.resolveCurrentOptions(DefaultOptions.current).layout.adjustResize.isFalse
|
|
146
|
+
},
|
|
147
|
+
)
|
|
133
148
|
parts.sheet = sheet
|
|
134
149
|
container.alpha = 1f
|
|
135
150
|
applyTestIds(record, parts, options)
|
|
@@ -140,11 +155,18 @@ internal class ModalViews(
|
|
|
140
155
|
onEnd()
|
|
141
156
|
}
|
|
142
157
|
}
|
|
143
|
-
sheet.show(options.modal.sheet, swipeToDismissOf(options)) { shown() }
|
|
158
|
+
sheet.show(options.modal.sheet, swipeToDismissOf(options), animated) { shown() }
|
|
144
159
|
if (!seen) shown()
|
|
145
160
|
return { told = true }
|
|
146
161
|
}
|
|
147
162
|
|
|
163
|
+
// The screen a layout shows now: down through the child each parent shows.
|
|
164
|
+
private fun shownScreen(root: ViewController<*>): ViewController<*>? {
|
|
165
|
+
var node = root
|
|
166
|
+
while (node is ParentController<*>) node = node.currentChild ?: return null
|
|
167
|
+
return node
|
|
168
|
+
}
|
|
169
|
+
|
|
148
170
|
override fun dismiss(
|
|
149
171
|
record: ModalRecord,
|
|
150
172
|
animated: Boolean,
|
|
@@ -158,7 +180,7 @@ internal class ModalViews(
|
|
|
158
180
|
if (sheet != null) {
|
|
159
181
|
if (!seen) return none(onEnd)
|
|
160
182
|
var told = false
|
|
161
|
-
sheet.close {
|
|
183
|
+
sheet.close(animated) {
|
|
162
184
|
if (!told) {
|
|
163
185
|
told = true
|
|
164
186
|
onEnd()
|
|
@@ -263,6 +285,8 @@ internal class ModalViews(
|
|
|
263
285
|
parts[record]?.container?.requestLayout()
|
|
264
286
|
}
|
|
265
287
|
|
|
288
|
+
override fun sheetBack(record: ModalRecord): SheetBack? = parts[record]?.sheet
|
|
289
|
+
|
|
266
290
|
// `modal.testID` on the modal's view; a sheet's on the sheet's container, `modal.sheet.testID` first, and its
|
|
267
291
|
// grabber and scrim after it.
|
|
268
292
|
private fun applyTestIds(record: ModalRecord, parts: Parts, options: Options) {
|
|
@@ -293,7 +317,11 @@ internal class ModalViews(
|
|
|
293
317
|
val under = motion.underSide?.let { side -> underView?.let { SideAnimator.build(it, side, underBase) } }
|
|
294
318
|
if (under != null && underView != null) {
|
|
295
319
|
if (showing) moved[underView] = record else moved.remove(underView)
|
|
320
|
+
AnimationLayer.during(underView, under)
|
|
296
321
|
}
|
|
322
|
+
// A fade of the modal or of the layer under it draws it through a hardware layer, given back at its end and at
|
|
323
|
+
// any stop (the set's cancel cancels it).
|
|
324
|
+
for (animator in listOfNotNull(side, fade)) AnimationLayer.during(container, animator)
|
|
297
325
|
val fadeLength = motion.side?.takeIf(AnimationRules::isSingleAlpha)?.let(AnimationRules::lengthOf)
|
|
298
326
|
val elements = motion.elements?.let { animation ->
|
|
299
327
|
val content = modalsLayer.parent as? ViewGroup ?: return@let null
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
package dev.apexnative.navigation.viewcontrollers.modal
|
|
2
|
+
|
|
3
|
+
import androidx.activity.BackEventCompat
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A modal's sheet as back sees it ([ModalSheet]): whether a release of back would hide it, and the preview of that
|
|
7
|
+
* hide during the back gesture (Android 14+). [ModalCoordinator.backTargetSheet] gives the one back would dismiss now.
|
|
8
|
+
* Main thread only.
|
|
9
|
+
*/
|
|
10
|
+
internal interface SheetBack {
|
|
11
|
+
/**
|
|
12
|
+
* Back's release would hide the sheet, as a drag down does: it stands at a detent from which it goes down (its
|
|
13
|
+
* smallest, while it lets the user close it), laid out, and it isn't closing already. False at a larger detent:
|
|
14
|
+
* the Material behavior would only collapse it there.
|
|
15
|
+
*/
|
|
16
|
+
val hidesOnBack: Boolean
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Starts the preview of back on the sheet with the gesture's first [event]: the sheet shrinks a little toward the
|
|
20
|
+
* bottom with the progress, the scrim following it. None when [hidesOnBack] doesn't hold or a preview runs.
|
|
21
|
+
*/
|
|
22
|
+
fun startBackPreview(event: BackEventCompat): Gesture?
|
|
23
|
+
|
|
24
|
+
/** A back gesture over the sheet ([startBackPreview]). */
|
|
25
|
+
interface Gesture {
|
|
26
|
+
/** The sheet the gesture previews. */
|
|
27
|
+
val sheet: SheetBack
|
|
28
|
+
|
|
29
|
+
/** The gesture moved. */
|
|
30
|
+
fun progress(event: BackEventCompat)
|
|
31
|
+
|
|
32
|
+
/** Cancelled, or back went elsewhere: the sheet grows back to where it stood, the scrim with it. */
|
|
33
|
+
fun cancel()
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Released: the sheet slides down from where the preview left it and goes as one the user dragged down (its
|
|
37
|
+
* events, its dismissal). False when the preview stopped since it started (a command closed or moved the
|
|
38
|
+
* sheet): back goes the usual way.
|
|
39
|
+
*/
|
|
40
|
+
fun commit(): Boolean
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -3,10 +3,68 @@ package dev.apexnative.navigation.viewcontrollers.modal
|
|
|
3
3
|
import dev.apexnative.navigation.options.SheetDetent
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Where a
|
|
7
|
-
*
|
|
6
|
+
* Where a sheet rests: the stops it keeps of its detents, how the Material behavior stands at them, and where a shown
|
|
7
|
+
* sheet goes at new options, as on iOS: the sheet keeps the stop it stands at (the user's last drag included) until a
|
|
8
|
+
* `selectedDetent` arrives in a `mergeOptions`, or until its stop is no longer among the detents.
|
|
8
9
|
*/
|
|
9
10
|
internal object SheetStops {
|
|
11
|
+
/** The Material behavior has three resting states: collapsed, half expanded and expanded. */
|
|
12
|
+
const val MAX_STOPS = 3
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The stops of the sheet, from the lowest: [detents] by their height ([heightOf]), one of each height (the first
|
|
16
|
+
* the options give), and at most [MAX_STOPS] of them: the lowest, the highest, and between them [selected] when
|
|
17
|
+
* it stands there, else the lowest of the rest.
|
|
18
|
+
*/
|
|
19
|
+
fun stops(detents: List<SheetDetent>, heightOf: (SheetDetent) -> Int, selected: SheetDetent?): List<SheetDetent> {
|
|
20
|
+
val sorted = detents.sortedBy(heightOf).distinctBy(heightOf)
|
|
21
|
+
if (sorted.size <= MAX_STOPS) return sorted
|
|
22
|
+
val between = sorted.subList(1, sorted.size - 1)
|
|
23
|
+
val middle = selected?.takeIf { it in between } ?: between.first()
|
|
24
|
+
return listOf(sorted.first(), middle, sorted.last())
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* How the Material behavior stands at the stops: [fitToContents] with one or two (collapsed and expanded, the
|
|
29
|
+
* sheet as tall as the highest, [maxHeight]), else half expanded between them at [halfExpandedRatio] of the
|
|
30
|
+
* layout, and expanded [expandedOffset] below its top. [skipCollapsed] with one stop: the sheet has only that.
|
|
31
|
+
* The heights are in pixels, as is the rest.
|
|
32
|
+
*/
|
|
33
|
+
data class Material(
|
|
34
|
+
val fitToContents: Boolean,
|
|
35
|
+
val skipCollapsed: Boolean,
|
|
36
|
+
val peekHeight: Int,
|
|
37
|
+
val halfExpandedRatio: Float?,
|
|
38
|
+
val expandedOffset: Int,
|
|
39
|
+
val maxHeight: Int,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The behavior's settings for stops [heights] tall (from the lowest, each higher than the one before) in a layout
|
|
44
|
+
* [parentHeight] tall.
|
|
45
|
+
*/
|
|
46
|
+
fun material(heights: List<Int>, parentHeight: Int): Material {
|
|
47
|
+
val lowest = heights.first()
|
|
48
|
+
val highest = heights.last()
|
|
49
|
+
val three = heights.size == MAX_STOPS && parentHeight > 0
|
|
50
|
+
return Material(
|
|
51
|
+
fitToContents = !three,
|
|
52
|
+
skipCollapsed = heights.size == 1,
|
|
53
|
+
peekHeight = lowest,
|
|
54
|
+
halfExpandedRatio = if (three) heights[1].toFloat() / parentHeight else null,
|
|
55
|
+
expandedOffset = (parentHeight - highest).coerceAtLeast(0),
|
|
56
|
+
maxHeight = highest,
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The heights of stops [heights] tall (from the lowest, each higher) lifted by [lift] pixels, the part of the
|
|
62
|
+
* keyboard over the navigation bar: the sheet stands on the keyboard as it stood on the bottom. At most [full]
|
|
63
|
+
* each, and each still higher than the one below, so the behavior keeps all of its states.
|
|
64
|
+
*/
|
|
65
|
+
fun lifted(heights: List<Int>, lift: Int, full: Int): List<Int> =
|
|
66
|
+
heights.mapIndexed { i, height -> (height + lift).coerceAtMost(full - (heights.lastIndex - i)) }
|
|
67
|
+
|
|
10
68
|
/**
|
|
11
69
|
* The stop to move to, or null to stay: [arrived] (the `selectedDetent` the merge names) when it is among
|
|
12
70
|
* [detents]; else, when [settled] (the stop the sheet rests at) is no longer one of them, [selected] (the resolved
|
package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt
CHANGED
|
@@ -33,6 +33,7 @@ import dev.apexnative.navigation.viewcontrollers.externalcomponent.ExternalCompo
|
|
|
33
33
|
import dev.apexnative.navigation.viewcontrollers.modal.ModalCoordinator
|
|
34
34
|
import dev.apexnative.navigation.viewcontrollers.modal.ModalRecord
|
|
35
35
|
import dev.apexnative.navigation.viewcontrollers.modal.ModalViews
|
|
36
|
+
import dev.apexnative.navigation.viewcontrollers.modal.SheetBack
|
|
36
37
|
import dev.apexnative.navigation.viewcontrollers.overlay.OverlayCoordinator
|
|
37
38
|
import dev.apexnative.navigation.viewcontrollers.overlay.OverlayRecord
|
|
38
39
|
import dev.apexnative.navigation.viewcontrollers.overlay.OverlayViews
|
|
@@ -177,6 +178,9 @@ class Navigator(
|
|
|
177
178
|
return if (modalRoot != null) modalRoot.stackPoppedByBack() else root?.stackPoppedByBack()
|
|
178
179
|
}
|
|
179
180
|
|
|
181
|
+
/** The sheet [handleBack] would dismiss, as a drag down of the user would; none when back would do anything else. */
|
|
182
|
+
internal fun sheetDismissedByBack(): SheetBack? = modals.backTargetSheet()
|
|
183
|
+
|
|
180
184
|
/**
|
|
181
185
|
* [layer] may wait to show from now on ([WaitingLayer]): the nodes in it ask it through [isInWaitingLayer] and
|
|
182
186
|
* [shownScreensChanged]. The root's layer is there from the start.
|
package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt
CHANGED
|
@@ -129,12 +129,9 @@ abstract class ParentController<V : ViewGroup>(
|
|
|
129
129
|
open fun leavesTopEdgeFree(child: ViewController<*>): Boolean =
|
|
130
130
|
parentController?.leavesTopEdgeFree(this) ?: false
|
|
131
131
|
|
|
132
|
-
/**
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
*/
|
|
136
|
-
open fun leavesBottomEdgeFree(child: ViewController<*>, screen: ViewController<*> = child): Boolean =
|
|
137
|
-
parentController?.leavesBottomEdgeFree(this, screen) ?: false
|
|
132
|
+
/** Whether a large title shows over [child]: its stack shows the bar with one. No by default. */
|
|
133
|
+
open fun showsLargeTitleOver(child: ViewController<*>): Boolean =
|
|
134
|
+
parentController?.showsLargeTitleOver(this) ?: false
|
|
138
135
|
|
|
139
136
|
/**
|
|
140
137
|
* The tab bar at rest under [child]: where a stack's FAB keeps clear of it, by the options of [screen], the stack's
|
package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package dev.apexnative.navigation.viewcontrollers.sidemenu
|
|
2
2
|
|
|
3
3
|
import dev.apexnative.navigation.react.events.AppearanceDispatcher
|
|
4
|
+
import dev.apexnative.navigation.utils.SystemAnimations
|
|
4
5
|
import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -26,6 +27,8 @@ import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
|
|
|
26
27
|
internal class SideMenuMotion(
|
|
27
28
|
private val drawer: () -> Drawer,
|
|
28
29
|
private val host: Host,
|
|
30
|
+
/** The system's animations are off ([SystemAnimations]): a command or back moves the drawer at once. */
|
|
31
|
+
private val animationsOff: () -> Boolean = { SystemAnimations.areOff() },
|
|
29
32
|
) {
|
|
30
33
|
/** A side of the side menu: physical, `left` stays on the left in RTL too. */
|
|
31
34
|
enum class Side(
|
|
@@ -242,11 +245,14 @@ internal class SideMenuMotion(
|
|
|
242
245
|
drawer.lock(side, locked = !isOnScreen(side) && !host.isEnabled(side))
|
|
243
246
|
}
|
|
244
247
|
|
|
245
|
-
// The drawer opens or closes [side]; one that doesn't call back has its result recorded here.
|
|
248
|
+
// The drawer opens or closes [side]; one that doesn't call back has its result recorded here. With the system's
|
|
249
|
+
// animations off it jumps, unless it moves: the drag and the settle aren't animators, and it can't jump while it
|
|
250
|
+
// settles.
|
|
246
251
|
private fun move(side: Side, open: Boolean, animate: Boolean) {
|
|
247
252
|
val drawer = drawer()
|
|
253
|
+
val animated = animate && (moving || !animationsOff())
|
|
248
254
|
val silent = !drawer.callsBack
|
|
249
|
-
if (open) drawer.open(side,
|
|
255
|
+
if (open) drawer.open(side, animated) else drawer.close(side, animated)
|
|
250
256
|
if (silent) record(side, open)
|
|
251
257
|
}
|
|
252
258
|
|
package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt
CHANGED
|
@@ -2,6 +2,7 @@ package dev.apexnative.navigation.viewcontrollers.stack
|
|
|
2
2
|
|
|
3
3
|
import android.animation.Animator
|
|
4
4
|
import android.animation.AnimatorListenerAdapter
|
|
5
|
+
import android.animation.StateListAnimator
|
|
5
6
|
import android.animation.ValueAnimator
|
|
6
7
|
import android.content.res.Configuration
|
|
7
8
|
import android.graphics.Bitmap
|
|
@@ -29,7 +30,7 @@ import dev.apexnative.navigation.views.stack.StackLayout
|
|
|
29
30
|
* The preview of a pop while the user's back gesture runs (predictive back), as the system shows the activity under
|
|
30
31
|
* the one that closes: the screen on top with its bar, a picture taken as the gesture starts, shrinks toward the
|
|
31
32
|
* gesture's side with rounded corners and follows the finger up and down; the screen under it shows behind it with
|
|
32
|
-
* its own bar, smaller and dimmed. Released, the pop plays its end ([commit]); cancelled, everything goes back
|
|
33
|
+
* its own bar and FAB, smaller and dimmed. Released, the pop plays its end ([commit]); cancelled, everything goes back
|
|
33
34
|
* ([cancel]). The values are those of the system's cross-activity back animation (WMShell
|
|
34
35
|
* `DefaultCrossActivityBackAnimation` of Android 15 and 16, the smallest scale as Android 17 shows it), also on Android
|
|
35
36
|
* 14, whose own preview differs. Main thread only.
|
|
@@ -46,8 +47,13 @@ internal class BackPreview(
|
|
|
46
47
|
* corners, while the tab bar stays, as Gmail shows it.
|
|
47
48
|
*/
|
|
48
49
|
private val bottomRoom: Int,
|
|
49
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* The picture is there: the stack shows the screen under the top, with its bar and its FAB, before the preview
|
|
52
|
+
* draws.
|
|
53
|
+
*/
|
|
50
54
|
private val onReveal: () -> Unit,
|
|
55
|
+
/** The view of the FAB the stack shows now, which goes with the screen under the top; none. */
|
|
56
|
+
private val fab: () -> View? = { null },
|
|
51
57
|
) {
|
|
52
58
|
private val density = layout.resources.displayMetrics.density
|
|
53
59
|
private val bar = layout.topBar
|
|
@@ -58,6 +64,11 @@ internal class BackPreview(
|
|
|
58
64
|
private var animator: Animator? = null
|
|
59
65
|
private var ended = false
|
|
60
66
|
private var topAlpha = 1f
|
|
67
|
+
// The FAB that shows with the screen under the top, drawn flat under the dim and the picture, its own Z and the
|
|
68
|
+
// animator of its Z by its state.
|
|
69
|
+
private var flatFab: View? = null
|
|
70
|
+
private var fabZ = 0f
|
|
71
|
+
private var fabZByState: StateListAnimator? = null
|
|
61
72
|
// What puts the stack as it was after a cancel: once, as the preview ends.
|
|
62
73
|
private var onCancelled: (() -> Unit)? = null
|
|
63
74
|
// Forward is to the end of the line: right to left, the screens move the other way, as the stack's pop does.
|
|
@@ -175,10 +186,17 @@ internal class BackPreview(
|
|
|
175
186
|
card = null
|
|
176
187
|
(scrim.parent as? ViewGroup)?.removeView(scrim)
|
|
177
188
|
top.alpha = topAlpha
|
|
189
|
+
flatFab?.let {
|
|
190
|
+
flatFab = null
|
|
191
|
+
it.translationZ = fabZ
|
|
192
|
+
it.stateListAnimator = fabZByState
|
|
193
|
+
fabZByState = null
|
|
194
|
+
}
|
|
178
195
|
entering(1f, 0f)
|
|
179
196
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
180
197
|
target.resetPivot()
|
|
181
198
|
bar.resetPivot()
|
|
199
|
+
fab()?.resetPivot()
|
|
182
200
|
}
|
|
183
201
|
onCancelled?.let {
|
|
184
202
|
onCancelled = null
|
|
@@ -190,6 +208,16 @@ internal class BackPreview(
|
|
|
190
208
|
// the top's place, cut to rounded corners.
|
|
191
209
|
private fun show(picture: Bitmap) {
|
|
192
210
|
onReveal()
|
|
211
|
+
// A child with a Z draws over those without, whatever their order: the FAB, raised by its elevation, would lie
|
|
212
|
+
// over the dim and the picture. Its state's animator, which Material's FAB sets on the frame after it joins the
|
|
213
|
+
// window (and on a press, focus or hover), would raise it again: it stays off while the preview draws.
|
|
214
|
+
fab()?.takeIf { it.z > 0f }?.let {
|
|
215
|
+
flatFab = it
|
|
216
|
+
fabZ = it.translationZ
|
|
217
|
+
fabZByState = it.stateListAnimator
|
|
218
|
+
it.stateListAnimator = null
|
|
219
|
+
it.translationZ = -it.elevation
|
|
220
|
+
}
|
|
193
221
|
val dark = layout.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
|
|
194
222
|
Configuration.UI_MODE_NIGHT_YES
|
|
195
223
|
scrim.setBackgroundColor(Color.BLACK)
|
|
@@ -235,9 +263,9 @@ internal class BackPreview(
|
|
|
235
263
|
entering(scale, -SystemTransition.DISTANCE_DP * density * forward)
|
|
236
264
|
}
|
|
237
265
|
|
|
238
|
-
// The screen under the top and its
|
|
266
|
+
// The screen under the top, its bar and its FAB at [scale] around the stack's center, [x] along the line.
|
|
239
267
|
private fun entering(scale: Float, x: Float) {
|
|
240
|
-
for (view in
|
|
268
|
+
for (view in listOfNotNull(target, bar, fab())) {
|
|
241
269
|
view.pivotX = layout.width / 2f - view.left
|
|
242
270
|
view.pivotY = areaHeight / 2f - view.top
|
|
243
271
|
view.scaleX = scale
|
package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt
CHANGED
|
@@ -2,18 +2,18 @@ package dev.apexnative.navigation.viewcontrollers.stack
|
|
|
2
2
|
|
|
3
3
|
import android.view.View
|
|
4
4
|
import com.facebook.react.uimanager.PixelUtil.pxToDp
|
|
5
|
-
import dev.apexnative.navigation.react.
|
|
5
|
+
import dev.apexnative.navigation.react.ScreenEnvironment
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Where a screen prepared for a push (`preparePush`) shows, in dp: the size of the container its slot fills and the
|
|
9
9
|
* padding of its safe area view, as the push lays it out. JavaScript renders the screen with them before the push, and
|
|
10
10
|
* the slot and the safe area view start their states with them.
|
|
11
11
|
*/
|
|
12
|
-
internal data class PreparedFrame(val width: Float, val height: Float, val padding:
|
|
12
|
+
internal data class PreparedFrame(val width: Float, val height: Float, val padding: ScreenEnvironment.Insets) {
|
|
13
13
|
companion object {
|
|
14
14
|
/** The size of [container] as its slot measures it (`SlotView`), so the slot finds it equal. */
|
|
15
15
|
@JvmStatic
|
|
16
|
-
fun of(container: View, padding:
|
|
16
|
+
fun of(container: View, padding: ScreenEnvironment.Insets) =
|
|
17
17
|
PreparedFrame(container.width.toFloat().pxToDp(), container.height.toFloat().pxToDp(), padding)
|
|
18
18
|
}
|
|
19
19
|
}
|
package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt
CHANGED
|
@@ -11,7 +11,7 @@ import dev.apexnative.navigation.options.DefaultOptions
|
|
|
11
11
|
import dev.apexnative.navigation.react.CommandAnswer
|
|
12
12
|
import dev.apexnative.navigation.react.CommandListener
|
|
13
13
|
import dev.apexnative.navigation.react.ErrorTexts
|
|
14
|
-
import dev.apexnative.navigation.react.
|
|
14
|
+
import dev.apexnative.navigation.react.ScreenEnvironment
|
|
15
15
|
import dev.apexnative.navigation.slots.SlotScreenView
|
|
16
16
|
import dev.apexnative.navigation.utils.NavigationLog
|
|
17
17
|
import dev.apexnative.navigation.viewcontrollers.child.ChildControllersRegistry
|
|
@@ -318,7 +318,7 @@ internal class StackCommands(
|
|
|
318
318
|
layoutNow(stackView, screenView)
|
|
319
319
|
node.updateSafeArea()
|
|
320
320
|
val content = node.content?.asView()
|
|
321
|
-
val padding =
|
|
321
|
+
val padding = ScreenEnvironment.padding(node.id)
|
|
322
322
|
val noInsets = content == null || ViewCompat.getRootWindowInsets(content) == null
|
|
323
323
|
if (noInsets || padding == null || content.width <= 0 || content.height <= 0) {
|
|
324
324
|
prepared.discard(node.id)
|
package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt
CHANGED
|
@@ -31,6 +31,7 @@ import dev.apexnative.navigation.viewcontrollers.parent.OptionsScreen
|
|
|
31
31
|
import dev.apexnative.navigation.viewcontrollers.parent.ParentController
|
|
32
32
|
import dev.apexnative.navigation.viewcontrollers.parent.ReturnsScreenFromColumn
|
|
33
33
|
import dev.apexnative.navigation.viewcontrollers.parent.nodeWith
|
|
34
|
+
import dev.apexnative.navigation.viewcontrollers.stack.fab.FabMotion
|
|
34
35
|
import dev.apexnative.navigation.viewcontrollers.stack.fab.FabPresenter
|
|
35
36
|
import dev.apexnative.navigation.viewcontrollers.stack.topbar.LargeTitleCollapse
|
|
36
37
|
import dev.apexnative.navigation.viewcontrollers.stack.topbar.TopBarPresenter
|
|
@@ -207,6 +208,17 @@ class StackController(
|
|
|
207
208
|
screen.changeOptions { it.topBar.buttons.back.setVisible() }
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
/**
|
|
212
|
+
* `clearOptions` took options out of the own options of [node], an entry of this stack or the options screen of
|
|
213
|
+
* one: the back arrow's rule ([join]) writes its part of them again, so the first screen keeps its arrow hidden
|
|
214
|
+
* and another shows it unless its options say otherwise.
|
|
215
|
+
*/
|
|
216
|
+
internal fun ownOptionsCleared(node: ViewController<*>) {
|
|
217
|
+
val entries = queue.entries
|
|
218
|
+
val entry = entries.firstOrNull { it === node || optionsScreen(it) === node } ?: return
|
|
219
|
+
backRule(entry, first = entry === entries.first())
|
|
220
|
+
}
|
|
221
|
+
|
|
210
222
|
/** The key of [entry]; none without one. */
|
|
211
223
|
internal fun keyOf(entry: ViewController<*>): String? = keys[entry]
|
|
212
224
|
|
|
@@ -307,6 +319,9 @@ class StackController(
|
|
|
307
319
|
// The back gesture over this stack whose preview hasn't ended yet; none.
|
|
308
320
|
private var backGesture: BackGesture? = null
|
|
309
321
|
|
|
322
|
+
// A merge of `fab` into the top waits for the end of a back gesture's preview.
|
|
323
|
+
private var fabMergeWaits = false
|
|
324
|
+
|
|
310
325
|
/**
|
|
311
326
|
* A back gesture over the top of this stack ([startBackGesture]): its progress, its cancel, and its release, which
|
|
312
327
|
* pops the top through the queue with the preview's end. A command accepted meanwhile, or the stack's destroy,
|
|
@@ -326,6 +341,10 @@ class StackController(
|
|
|
326
341
|
private var revealed = false
|
|
327
342
|
private var aborted = false
|
|
328
343
|
|
|
344
|
+
/** The preview shows the screen under the top, with its bar and its FAB. */
|
|
345
|
+
val isRevealed: Boolean
|
|
346
|
+
get() = revealed && !aborted
|
|
347
|
+
|
|
329
348
|
/** The gesture moved: [progress] 0 … 1, the finger at [touchY]. */
|
|
330
349
|
fun progress(progress: Float, touchY: Float) {
|
|
331
350
|
if (!aborted) preview.progress(progress, touchY)
|
|
@@ -348,6 +367,9 @@ class StackController(
|
|
|
348
367
|
return true
|
|
349
368
|
}
|
|
350
369
|
if (backGesture === this) backGesture = null
|
|
370
|
+
// The top's FAB, set aside, leaves with it; a merge into it no longer matters.
|
|
371
|
+
fab.dropAside()
|
|
372
|
+
fabMergeWaits = false
|
|
351
373
|
queue.cut(target, null, id, "go back in the stack '$id'", null, gesture = true)
|
|
352
374
|
return true
|
|
353
375
|
}
|
|
@@ -360,7 +382,8 @@ class StackController(
|
|
|
360
382
|
restore()
|
|
361
383
|
}
|
|
362
384
|
|
|
363
|
-
// The preview's picture is there: the screen under the top shows under it, and the bar
|
|
385
|
+
// The preview's picture is there: the screen under the top shows under it, and the bar and the FAB show that
|
|
386
|
+
// screen, at once.
|
|
364
387
|
internal fun reveal() {
|
|
365
388
|
val view = target.peekView() ?: return
|
|
366
389
|
targetWasPlaced = view.parent === peekView() && view.visibility == View.VISIBLE
|
|
@@ -370,6 +393,8 @@ class StackController(
|
|
|
370
393
|
views.reveal(target, top)
|
|
371
394
|
view.alpha = 1f
|
|
372
395
|
topBar.apply(target)
|
|
396
|
+
fab.setAside()
|
|
397
|
+
showFab(FabMotion.Move.AtOnce, target)
|
|
373
398
|
}
|
|
374
399
|
|
|
375
400
|
private fun restore() {
|
|
@@ -386,9 +411,14 @@ class StackController(
|
|
|
386
411
|
views.detach(target)
|
|
387
412
|
}
|
|
388
413
|
}
|
|
389
|
-
// The bar
|
|
414
|
+
// The bar and the FAB show the top again, the bar's components appeared again.
|
|
390
415
|
val shown = queue.currentChild
|
|
391
416
|
topBar.apply(shown)
|
|
417
|
+
fab.bringBack()
|
|
418
|
+
if (fabMergeWaits) {
|
|
419
|
+
fabMergeWaits = false
|
|
420
|
+
mergeFab()
|
|
421
|
+
}
|
|
392
422
|
shown?.let {
|
|
393
423
|
topBar.screenWillAppear(optionsScreen(it))
|
|
394
424
|
topBar.screenDidAppear(optionsScreen(it))
|
|
@@ -462,7 +492,8 @@ class StackController(
|
|
|
462
492
|
ContainerBackground.apply(this, options)
|
|
463
493
|
updateBar()
|
|
464
494
|
takeKeptMerge(child)?.let(::applyTopMerge)
|
|
465
|
-
|
|
495
|
+
// A back gesture's preview shows the FAB of the screen under the top.
|
|
496
|
+
if (queue.isAtRest && backGesture?.isRevealed != true) showFab()
|
|
466
497
|
performOnParentController { it.applyChildOptions(withoutStackGroups(options), this) }
|
|
467
498
|
}
|
|
468
499
|
|
|
@@ -594,6 +625,10 @@ class StackController(
|
|
|
594
625
|
override fun leavesTopEdgeFree(child: ViewController<*>): Boolean =
|
|
595
626
|
TopBarRoom.leavesTopEdgeFree(resolvedOf(child), largeTitleShown(child)) || super.leavesTopEdgeFree(child)
|
|
596
627
|
|
|
628
|
+
/** A large title shows over [child] in this stack's bar. */
|
|
629
|
+
override fun showsLargeTitleOver(child: ViewController<*>): Boolean =
|
|
630
|
+
largeTitleShown(child) || super.showsLargeTitleOver(child)
|
|
631
|
+
|
|
597
632
|
/** A screen under another doesn't compute its safe area again; the prepared and waiting do. */
|
|
598
633
|
override fun isTopOfStack(child: ViewController<*>): Boolean =
|
|
599
634
|
child === queue.currentChild || child === queue.waitingScreen || isPrepared(child)
|
|
@@ -666,15 +701,20 @@ class StackController(
|
|
|
666
701
|
topBar.apply(queue.currentChild)
|
|
667
702
|
}
|
|
668
703
|
|
|
669
|
-
// The FAB follows the
|
|
670
|
-
|
|
704
|
+
// The FAB follows [top] (the current child) from the start of a transition by [move], with the screens; at rest, a
|
|
705
|
+
// FAB that comes by Material's swap.
|
|
706
|
+
private fun showFab(move: FabMotion.Move = FabMotion.Move.Swap, top: ViewController<*>? = queue.currentChild) {
|
|
671
707
|
val layout = peekView() ?: return
|
|
672
|
-
val top = queue.currentChild
|
|
673
708
|
val screen = top?.let(::optionsScreen)
|
|
674
|
-
fab.showFor(layout, screen, top?.let(::resolvedOf)?.fab ?: FabOptions(), scrollOf(screen))
|
|
709
|
+
fab.showFor(layout, screen, top?.let(::resolvedOf)?.fab ?: FabOptions(), scrollOf(screen), move)
|
|
675
710
|
}
|
|
676
711
|
|
|
677
712
|
private fun mergeFab() {
|
|
713
|
+
// A back gesture's preview shows the FAB of the screen under the top: the top's merge waits for a cancel.
|
|
714
|
+
if (backGesture?.isRevealed == true) {
|
|
715
|
+
fabMergeWaits = true
|
|
716
|
+
return
|
|
717
|
+
}
|
|
678
718
|
val layout = peekView() ?: return
|
|
679
719
|
val top = queue.currentChild ?: return
|
|
680
720
|
val screen = optionsScreen(top)
|
|
@@ -723,6 +763,9 @@ class StackController(
|
|
|
723
763
|
parentController?.tabBarTransition(this@StackController, move, side)
|
|
724
764
|
}
|
|
725
765
|
|
|
766
|
+
// The FAB of the new top arrives with its screen, the old one leaves with its own.
|
|
767
|
+
override fun fabTransition(move: FabMotion.Move) = showFab(move)
|
|
768
|
+
|
|
726
769
|
override fun operationEnded(topSettled: Boolean) {
|
|
727
770
|
BackCallbackState.update()
|
|
728
771
|
if (topSettled) parentController?.tabBarSettled(this@StackController)
|
|
@@ -21,6 +21,7 @@ import dev.apexnative.navigation.viewcontrollers.stack.StackDisplay.Custom
|
|
|
21
21
|
import dev.apexnative.navigation.viewcontrollers.stack.StackDisplay.Elements
|
|
22
22
|
import dev.apexnative.navigation.viewcontrollers.stack.StackDisplay.Fade
|
|
23
23
|
import dev.apexnative.navigation.viewcontrollers.stack.StackDisplay.Motion
|
|
24
|
+
import dev.apexnative.navigation.viewcontrollers.stack.fab.FabMotion
|
|
24
25
|
import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
|
|
25
26
|
import dev.apexnative.navigation.views.animations.AnimationRules
|
|
26
27
|
import java.util.WeakHashMap
|
|
@@ -58,7 +59,7 @@ private typealias Node = ViewController<*>
|
|
|
58
59
|
* made in the commit of that mount (its `mergeOptions`), so the transition starts with the options of that commit —
|
|
59
60
|
* content mounted already goes that way too. A push or a `setStackRoot` with elements waits for its targets after
|
|
60
61
|
* that, a wait like the others, within what is left of its limit without `waitForRender`: a cut or a replace during it
|
|
61
|
-
* interrupts the push, which
|
|
62
|
+
* interrupts the push, which starts no element.
|
|
62
63
|
*
|
|
63
64
|
* The transition is the screens' own when the options say so (`AnimationRules.stackIsOwn`): the display plays each
|
|
64
65
|
* screen's side ([StackDisplay.animateCustom]) with the same owners as the default transitions; the bar's row then
|
|
@@ -103,6 +104,12 @@ internal class StackQueue(
|
|
|
103
104
|
*/
|
|
104
105
|
fun tabBarTransition(move: TabBarMotion.Move, side: BottomTabsEnterExitAnimationOptions?) = Unit
|
|
105
106
|
|
|
107
|
+
/**
|
|
108
|
+
* The current child is about to change, right after [barTransition]: [move] is how the FAB goes, the new top's
|
|
109
|
+
* arriving with its screen and the old one's leaving with its own from the start of the transition.
|
|
110
|
+
*/
|
|
111
|
+
fun fabTransition(move: FabMotion.Move) = Unit
|
|
112
|
+
|
|
106
113
|
/** [node] was accepted to show as the top (a push, the new top of a replace). */
|
|
107
114
|
fun willShow(node: Node) = Unit
|
|
108
115
|
|
|
@@ -546,6 +553,7 @@ internal class StackQueue(
|
|
|
546
553
|
val ended = takeOver(listOfNotNull(covered, node), op)
|
|
547
554
|
host.tabBarTransition(TabBarMotion.Move.AtOnce, null)
|
|
548
555
|
host.barTransition(null, BarVisibility.AT_ONCE)
|
|
556
|
+
host.fabTransition(FabMotion.Move.AtOnce)
|
|
549
557
|
host.currentChildChanged()
|
|
550
558
|
finishTakenOver(ended)
|
|
551
559
|
if (display.hasView && covered != null) display.detach(covered)
|
|
@@ -785,6 +793,7 @@ internal class StackQueue(
|
|
|
785
793
|
val ended = takeOver(old + top, op)
|
|
786
794
|
host.tabBarTransition(TabBarMotion.Move.AtOnce, null)
|
|
787
795
|
host.barTransition(null, BarVisibility.AT_ONCE)
|
|
796
|
+
host.fabTransition(FabMotion.Move.AtOnce)
|
|
788
797
|
host.currentChildChanged()
|
|
789
798
|
finishTakenOver(ended)
|
|
790
799
|
op.done = true
|
|
@@ -1124,6 +1133,7 @@ internal class StackQueue(
|
|
|
1124
1133
|
reject(op, text)
|
|
1125
1134
|
host.tabBarTransition(TabBarMotion.Move.AtOnce, null)
|
|
1126
1135
|
host.barTransition(null, BarVisibility.AT_ONCE)
|
|
1136
|
+
host.fabTransition(FabMotion.Move.AtOnce)
|
|
1127
1137
|
host.currentChildChanged()
|
|
1128
1138
|
settled()
|
|
1129
1139
|
drain()
|
|
@@ -1174,7 +1184,7 @@ internal class StackQueue(
|
|
|
1174
1184
|
// The bars with a change of the current child. The row goes with the default transition; with an animation of its
|
|
1175
1185
|
// own the top bar goes with the screens ([travel]). The tab bar rides with the system's [system] move, slides with an
|
|
1176
1186
|
// animation of its own or a side of its own, and is where the new top wants it at once without animation; with
|
|
1177
|
-
// elements every bar changes at once.
|
|
1187
|
+
// elements every bar changes at once. The FAB goes with its screen, by Material's swap with an animation of its own.
|
|
1178
1188
|
private fun tellBars(
|
|
1179
1189
|
animated: Boolean,
|
|
1180
1190
|
own: Boolean,
|
|
@@ -1183,7 +1193,8 @@ internal class StackQueue(
|
|
|
1183
1193
|
system: TabBarMotion.Move,
|
|
1184
1194
|
row: BarMotion,
|
|
1185
1195
|
travel: BarTravel,
|
|
1186
|
-
// The top bar
|
|
1196
|
+
// The top bar and the FAB show the new top already (a back gesture's preview): they change at once, the tab bar
|
|
1197
|
+
// still moves.
|
|
1187
1198
|
barAtOnce: Boolean = false,
|
|
1188
1199
|
) {
|
|
1189
1200
|
val tabs = animation.bottomTabs
|
|
@@ -1200,6 +1211,7 @@ internal class StackQueue(
|
|
|
1200
1211
|
barVisibility(barMoves && !elements, animation.topBar),
|
|
1201
1212
|
travel.takeIf { barMoves && own && !elements },
|
|
1202
1213
|
)
|
|
1214
|
+
host.fabTransition(FabMotion.moveOf(animated, own, row, shown = barAtOnce))
|
|
1203
1215
|
}
|
|
1204
1216
|
|
|
1205
1217
|
private fun barVisibility(animated: Boolean, side: TopBarEnterExitAnimationOptions): BarVisibility =
|