@apexnative/navigation 1.0.0-alpha.0 → 1.0.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ApexNavigation.podspec +2 -1
- package/CHANGELOG.md +128 -0
- package/README.md +147 -51
- package/android/CLAUDE.md +78 -25
- package/android/CORE.md +49 -25
- package/android/RECIPES.md +13 -6
- package/android/consumer-rules.pro +6 -0
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +85 -10
- package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
- package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
- 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/ButtonMenuOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -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/OptionsCache.kt +8 -4
- package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
- package/android/src/main/java/dev/apexnative/navigation/options/SideMenuOptions.kt +6 -1
- package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
- package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
- 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/options/UserChoices.kt +159 -0
- package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +29 -36
- package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
- 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/ErrorTexts.kt +75 -60
- package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +35 -23
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +12 -7
- package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +42 -4
- package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +54 -20
- package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +7 -6
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +19 -50
- package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
- package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +50 -81
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +135 -94
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
- package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
- package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +12 -10
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +39 -19
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +16 -4
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
- package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
- 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 +10 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
- 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 +108 -34
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +12 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
- 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/ModalAnimations.kt +22 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +109 -21
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +476 -73
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +57 -25
- 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 +83 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +49 -14
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +71 -12
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +37 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +42 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +19 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +43 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +77 -17
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +315 -0
- 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 +30 -20
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +216 -18
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +149 -41
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +115 -6
- 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 +222 -48
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +30 -34
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
- 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/MenuChecks.kt +13 -56
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +219 -54
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
- package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
- package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
- package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +9 -7
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +143 -135
- package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +112 -4
- 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 +56 -41
- 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/sidemenu/SideMenuView.kt +12 -3
- package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +45 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +140 -1
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
- 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 -17
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +73 -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 +125 -178
- 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/app.js +1 -1
- package/cli/doctor/checks/app.js +77 -14
- package/cli/doctor/checks/splash.js +4 -22
- package/cli/migrate/native.js +18 -0
- package/cli/project.js +10 -2
- package/cli/setup/index.js +18 -0
- package/cli/setup/source.js +2 -1
- package/cli/setup/steps/appDelegate.js +66 -11
- package/cli/setup/steps/mainApplication.js +134 -19
- package/cli/setup/steps/metro.js +46 -0
- package/cli/setup/steps/sceneDelegate.js +108 -0
- package/cli/splash/index.js +3 -1
- package/cli/upgrade/changelog.js +2 -2
- 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 +58 -12
- package/docs-md/containers/modals.md +8 -4
- package/docs-md/containers/overlays.md +3 -1
- package/docs-md/containers/side-menu.md +19 -2
- package/docs-md/containers/tabs.md +5 -1
- package/docs-md/flows/bottom-sheets.md +4 -2
- package/docs-md/flows/forms-in-a-modal.md +1 -1
- 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 +4 -3
- package/docs-md/guides/deep-links.md +15 -33
- package/docs-md/help/glossary.md +4 -4
- package/docs-md/help/troubleshooting.md +44 -6
- package/docs-md/index.json +57 -1
- package/docs-md/migration/from-expo-router.md +1 -1
- package/docs-md/migration/from-react-native-navigation.md +9 -3
- package/docs-md/migration/from-react-navigation.md +2 -2
- package/docs-md/screen-ui/back-and-gestures.md +46 -2
- 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 +17 -12
- 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 +21 -3
- 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 +61 -13
- package/ios/Animations/ANNTransitionPlan.h +2 -2
- package/ios/Animations/ANNTransitionPlan.mm +10 -0
- package/ios/Animations/ANNTransitionWait.mm +6 -7
- package/ios/Animations/Elements/ANNElementFinder.h +57 -0
- package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
- package/ios/Animations/Elements/ANNElementTransition.h +10 -8
- package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
- package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
- 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 +60 -24
- package/ios/CORE.md +44 -34
- package/ios/Contract/ANNCommandAnswer.h +13 -5
- package/ios/Contract/ANNCommandAnswer.mm +40 -32
- package/ios/Contract/ANNCommandContract.h +15 -0
- package/ios/Contract/ANNCommandContract.mm +78 -0
- package/ios/Contract/ANNCommandRunner.h +10 -9
- package/ios/Contract/ANNCommandRunner.mm +22 -28
- package/ios/Contract/ANNErrorTexts.h +6 -2
- package/ios/Contract/ANNErrorTexts.mm +18 -10
- package/ios/Contract/ANNLayoutNode.h +3 -3
- package/ios/Contract/ANNLayoutReader.h +3 -3
- package/ios/Core/ANNAppDelegate.mm +0 -2
- package/ios/Core/ANNAppearanceDispatcher.h +5 -4
- package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
- package/ios/Core/ANNDeepLinkQueue.h +22 -2
- package/ios/Core/ANNDeepLinkQueue.mm +121 -14
- package/ios/Core/ANNErrorHandler.h +9 -4
- package/ios/Core/ANNErrorHandler.mm +20 -2
- package/ios/Core/ANNEventContract.h +246 -0
- package/ios/Core/ANNEventContract.mm +225 -0
- package/ios/Core/ANNEventEmitter.h +6 -2
- package/ios/Core/ANNEventEmitter.mm +117 -80
- package/ios/Core/ANNHinge.h +6 -0
- package/ios/Core/ANNHinge.mm +15 -4
- package/ios/Core/ANNJavaScriptCalls.h +33 -0
- package/ios/Core/ANNJavaScriptCalls.mm +52 -0
- package/ios/Core/ANNLayoutProtocol.h +5 -5
- package/ios/Core/ANNNavigationState.h +7 -5
- package/ios/Core/ANNNavigationState.mm +8 -7
- package/ios/Core/ANNNodeHelper.h +32 -12
- package/ios/Core/ANNNodeHelper.mm +100 -3
- package/ios/Core/ANNParking.h +5 -4
- package/ios/Core/ANNReloadCoordinator.mm +5 -12
- package/ios/Core/ANNRenderWait.h +20 -6
- package/ios/Core/ANNRenderWait.mm +143 -56
- package/ios/Core/ANNSceneDelegate.mm +25 -15
- package/ios/Core/ANNSystemUI.h +3 -2
- package/ios/Core/ANNSystemUI.mm +7 -0
- package/ios/Core/ANNUtils.h +7 -0
- package/ios/Core/ANNUtils.mm +10 -0
- package/ios/Core/ApexNavigation+Internal.h +1 -1
- package/ios/Core/ApexNavigation.mm +7 -6
- package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
- package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
- package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
- package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
- package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +10 -8
- package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
- package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
- package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
- package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
- package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
- package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
- package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
- package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
- package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
- package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
- package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
- package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
- package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
- package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
- 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/ANNScreenPlace.h +53 -0
- package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
- package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
- package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
- package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
- package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
- package/ios/Layouts/Screen/ANNScreenSettling.h +32 -0
- package/ios/Layouts/Screen/ANNScreenSettling.mm +137 -0
- package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
- package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
- package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
- package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
- package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
- package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
- package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
- package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
- package/ios/Layouts/Stack/ANNStackController.h +8 -0
- package/ios/Layouts/Stack/ANNStackController.mm +184 -16
- package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
- package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
- 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/Stack/UINavigationController+ANNCommands.h +4 -2
- package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
- package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
- 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/ANNOptionsCache.h +7 -6
- package/ios/Options/ANNOptionsReader.mm +108 -0
- package/ios/Options/ANNSearchBarOptions.h +4 -3
- package/ios/Options/ANNSheetOptions.h +4 -1
- package/ios/Options/ANNSideMenuOptions.h +2 -0
- package/ios/Options/ANNSideMenuOptions.mm +2 -0
- package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
- package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
- package/ios/Options/ANNUserChoice.h +57 -0
- package/ios/Options/ANNUserChoice.mm +44 -0
- package/ios/Options/Params/ANNImageSource.h +61 -0
- package/ios/Options/Params/ANNImageSource.mm +101 -0
- package/ios/Options/Params/ANNOptionImages.h +37 -0
- package/ios/Options/Params/ANNOptionImages.mm +284 -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 +15 -2
- package/ios/Options/Params/Image.mm +35 -2
- package/ios/Options/Params/ImageParser.h +5 -5
- package/ios/Options/Params/ImageParser.mm +28 -46
- package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
- package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
- package/ios/RECIPES.md +13 -6
- package/ios/React/ANNReactView.mm +6 -25
- package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
- package/ios/React/ANNSurfaceHostingView.h +14 -0
- package/ios/React/ANNSurfaceHostingView.mm +144 -1
- package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
- package/ios/React/Slots/ANNSlotContainers.h +14 -6
- package/ios/React/Slots/ANNSlotContainers.mm +75 -2
- package/ios/React/Slots/ANNSlotHost.mm +1 -3
- 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 +14 -8
- package/ios/TopBar/ANNBarButtons.mm +397 -80
- package/ios/TopBar/ANNIconButtonImage.h +1 -0
- package/ios/TopBar/ANNIconButtonImage.mm +34 -1
- package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
- package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
- 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 +172 -21
- package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
- package/ios/TopBar/ANNTopBarPresenter.h +8 -2
- package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
- package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
- package/ios/TurboModules/ANNTurboModule.mm +104 -33
- 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 +40 -27
- 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 +190 -66
- package/lib/module/api/app/createNavigation.js.map +1 -1
- package/lib/module/api/commands/commands.js +54 -6
- package/lib/module/api/commands/commands.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/useNavigation.js +8 -3
- package/lib/module/api/hooks/useNavigation.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/dispatchedLinks.js +23 -0
- package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
- package/lib/module/api/linking/linking.js +11 -0
- package/lib/module/api/linking/linking.js.map +1 -1
- package/lib/module/api/navigation.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 +193 -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 +51 -9
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/layout.js +20 -11
- 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 +49 -15
- 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/places.js +52 -7
- package/lib/module/engine/places.js.map +1 -1
- package/lib/module/engine/props.js +30 -1
- package/lib/module/engine/props.js.map +1 -1
- package/lib/module/engine/refresh.js +85 -0
- package/lib/module/engine/refresh.js.map +1 -0
- package/lib/module/engine/rememberedOptions.js +61 -1
- package/lib/module/engine/rememberedOptions.js.map +1 -1
- package/lib/module/engine/screens.js +77 -16
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/module/interfaces/contract/commands.json +101 -0
- package/lib/module/interfaces/contract/errors.json +275 -0
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
- 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/commands/commands.d.ts.map +1 -1
- package/lib/typescript/api/commands/presentation.d.ts +4 -3
- package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
- package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
- package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
- package/lib/typescript/api/hooks/useNavigation.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/dispatchedLinks.d.ts +7 -0
- package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
- 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/navigation.d.ts +4 -1
- package/lib/typescript/api/navigation.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/options.d.ts +5 -2
- package/lib/typescript/engine/options.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/places.d.ts +7 -2
- package/lib/typescript/engine/places.d.ts.map +1 -1
- package/lib/typescript/engine/props.d.ts +8 -1
- package/lib/typescript/engine/props.d.ts.map +1 -1
- 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 +4 -4
- package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
- package/lib/typescript/interfaces/Events.d.ts +28 -10
- package/lib/typescript/interfaces/Events.d.ts.map +1 -1
- package/lib/typescript/interfaces/Options.d.ts +1 -1
- package/lib/typescript/interfaces/Options.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/animations.d.ts +80 -22
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
- package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
- package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/modals.d.ts +34 -26
- package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
- package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/stack.d.ts +17 -3
- package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/system.d.ts +18 -11
- 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 +68 -38
- 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 +4 -25
- package/src/ARCHITECTURE.md +40 -27
- package/src/adapters/NativeANNTurboModule.ts +12 -2
- package/src/api/app/AppRegistry.ts +16 -2
- package/src/api/app/createNavigation.ts +203 -69
- package/src/api/commands/commands.ts +48 -7
- package/src/api/commands/presentation.ts +4 -3
- package/src/api/events/navigationEvents.ts +10 -4
- package/src/api/hooks/useNavigation.ts +9 -4
- package/src/api/hooks/useSafeAreaInsets.ts +4 -3
- package/src/api/index.ts +1 -0
- package/src/api/linking/dispatchedLinks.ts +18 -0
- package/src/api/linking/linking.ts +22 -1
- package/src/api/navigation.ts +4 -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 +185 -42
- package/src/api/theme/theme.ts +5 -0
- package/src/engine/commands.ts +70 -13
- package/src/engine/layout.ts +27 -11
- package/src/engine/nativeScreens.ts +10 -1
- package/src/engine/options.ts +45 -19
- package/src/engine/optionsChange.ts +107 -0
- package/src/engine/places.ts +65 -7
- package/src/engine/props.ts +30 -1
- package/src/engine/refresh.ts +97 -0
- package/src/engine/rememberedOptions.ts +74 -1
- package/src/engine/screens.tsx +76 -21
- package/src/interfaces/ComponentEvents.ts +4 -4
- package/src/interfaces/Events.ts +29 -10
- package/src/interfaces/Options.ts +1 -0
- package/src/interfaces/contract/commands.json +101 -0
- package/src/interfaces/contract/errors.json +275 -0
- package/src/interfaces/options/animations.ts +81 -22
- package/src/interfaces/options/bottomTabs.ts +21 -7
- package/src/interfaces/options/buttons.ts +23 -15
- package/src/interfaces/options/modals.ts +34 -26
- package/src/interfaces/options/sideMenu.ts +24 -6
- package/src/interfaces/options/stack.ts +17 -3
- package/src/interfaces/options/system.ts +18 -11
- package/src/interfaces/options/toolbar.ts +2 -2
- package/src/interfaces/options/topBar.ts +68 -38
- package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
- package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
- 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 -138
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
- 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 -66
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
- package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
- package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
- package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
- package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
|
@@ -4,9 +4,9 @@ import android.animation.Animator
|
|
|
4
4
|
import android.animation.AnimatorListenerAdapter
|
|
5
5
|
import android.animation.AnimatorSet
|
|
6
6
|
import android.animation.ObjectAnimator
|
|
7
|
-
import android.animation.PropertyValuesHolder
|
|
8
7
|
import android.animation.TimeInterpolator
|
|
9
8
|
import android.content.Context
|
|
9
|
+
import android.view.Gravity
|
|
10
10
|
import android.view.View
|
|
11
11
|
import android.view.ViewGroup
|
|
12
12
|
import android.view.animation.LinearInterpolator
|
|
@@ -14,10 +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
|
|
21
|
+
import dev.apexnative.navigation.utils.dp
|
|
22
|
+
import dev.apexnative.navigation.viewcontrollers.component.ComponentViewController
|
|
23
|
+
import dev.apexnative.navigation.viewcontrollers.parent.ParentController
|
|
20
24
|
import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
|
|
25
|
+
import dev.apexnative.navigation.views.animations.AnimationLayer
|
|
21
26
|
import dev.apexnative.navigation.views.animations.AnimationRules
|
|
22
27
|
import dev.apexnative.navigation.views.animations.SideAnimator
|
|
23
28
|
import dev.apexnative.navigation.views.element.ElementTransition
|
|
@@ -62,9 +67,15 @@ internal class ModalViews(
|
|
|
62
67
|
try {
|
|
63
68
|
val view = record.root.view
|
|
64
69
|
(view.parent as? ViewGroup)?.removeView(view)
|
|
65
|
-
// A sheet's content waits at the sheet's full height, under the status bar.
|
|
70
|
+
// A sheet's content waits at the sheet's full height, under the status bar, and at its width.
|
|
66
71
|
val params = CoordinatorLayout.LayoutParams(MATCH, MATCH)
|
|
67
|
-
if (record.isSheet)
|
|
72
|
+
if (record.isSheet) {
|
|
73
|
+
params.topMargin = statusBarTop()
|
|
74
|
+
params.gravity = Gravity.CENTER_HORIZONTAL
|
|
75
|
+
// The modals layer is hidden while it has no modal: the window's content gives the width.
|
|
76
|
+
val maxWidth = ModalSheet.MAX_WIDTH_DP.dp
|
|
77
|
+
if (((modalsLayer.parent as? View)?.width ?: 0) > maxWidth) params.width = maxWidth
|
|
78
|
+
}
|
|
68
79
|
container.addView(view, params)
|
|
69
80
|
modalsLayer.addView(container, FrameLayout.LayoutParams(MATCH, MATCH))
|
|
70
81
|
} catch (e: Throwable) {
|
|
@@ -88,7 +99,7 @@ internal class ModalViews(
|
|
|
88
99
|
val container = parts.container
|
|
89
100
|
container.isWaiting = false
|
|
90
101
|
container.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
|
|
91
|
-
if (record.isSheet) return presentSheet(record, parts, options, seen, events, onEnd)
|
|
102
|
+
if (record.isSheet) return presentSheet(record, parts, options, animated, seen, events, onEnd)
|
|
92
103
|
applyTestIds(record, parts, options)
|
|
93
104
|
if (!animated || !seen) {
|
|
94
105
|
SideAnimator.rest(container)
|
|
@@ -100,22 +111,23 @@ internal class ModalViews(
|
|
|
100
111
|
container.translationY = 0f
|
|
101
112
|
return playOwn(record, parts, motion, showing = true, onEnd)
|
|
102
113
|
}
|
|
114
|
+
// The system's slide over the window below: the modal comes up whole, without a fade.
|
|
103
115
|
val distance = distanceOf(container)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
)
|
|
109
|
-
animator.interpolator = TimeInterpolator { ModalAnimations.decelerate(it) }
|
|
110
|
-
return play(parts, animator, onEnd)
|
|
116
|
+
container.alpha = 1f
|
|
117
|
+
container.translationY = distance
|
|
118
|
+
val animator = ObjectAnimator.ofFloat(container, View.TRANSLATION_Y, distance, 0f)
|
|
119
|
+
animator.interpolator = TimeInterpolator { ModalAnimations.linearOutSlowIn(it) }
|
|
120
|
+
return play(parts, animator, ModalAnimations.SHOW_DURATION, onEnd)
|
|
111
121
|
}
|
|
112
122
|
|
|
113
123
|
// The root's view leaves the container and goes into the sheet's, in one turn; the sheet slides to its first
|
|
114
|
-
// 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.
|
|
115
126
|
private fun presentSheet(
|
|
116
127
|
record: ModalRecord,
|
|
117
128
|
parts: Parts,
|
|
118
129
|
options: Options,
|
|
130
|
+
animated: Boolean,
|
|
119
131
|
seen: Boolean,
|
|
120
132
|
events: ModalSheet.Events,
|
|
121
133
|
onEnd: () -> Unit,
|
|
@@ -123,7 +135,16 @@ internal class ModalViews(
|
|
|
123
135
|
val container = parts.container
|
|
124
136
|
val view = record.root.view
|
|
125
137
|
container.removeView(view)
|
|
126
|
-
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
|
+
)
|
|
127
148
|
parts.sheet = sheet
|
|
128
149
|
container.alpha = 1f
|
|
129
150
|
applyTestIds(record, parts, options)
|
|
@@ -134,11 +155,18 @@ internal class ModalViews(
|
|
|
134
155
|
onEnd()
|
|
135
156
|
}
|
|
136
157
|
}
|
|
137
|
-
sheet.show(options.modal.sheet, swipeToDismissOf(options)) { shown() }
|
|
158
|
+
sheet.show(options.modal.sheet, swipeToDismissOf(options), animated) { shown() }
|
|
138
159
|
if (!seen) shown()
|
|
139
160
|
return { told = true }
|
|
140
161
|
}
|
|
141
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
|
+
|
|
142
170
|
override fun dismiss(
|
|
143
171
|
record: ModalRecord,
|
|
144
172
|
animated: Boolean,
|
|
@@ -152,7 +180,7 @@ internal class ModalViews(
|
|
|
152
180
|
if (sheet != null) {
|
|
153
181
|
if (!seen) return none(onEnd)
|
|
154
182
|
var told = false
|
|
155
|
-
sheet.close {
|
|
183
|
+
sheet.close(animated) {
|
|
156
184
|
if (!told) {
|
|
157
185
|
told = true
|
|
158
186
|
onEnd()
|
|
@@ -163,13 +191,11 @@ internal class ModalViews(
|
|
|
163
191
|
if (!animated || !seen) return none(onEnd)
|
|
164
192
|
if (motion != null) return playOwn(record, parts, motion, showing = false, onEnd)
|
|
165
193
|
val container = parts.container
|
|
166
|
-
val animator = ObjectAnimator.
|
|
167
|
-
container,
|
|
168
|
-
PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, container.translationY, distanceOf(container)),
|
|
169
|
-
PropertyValuesHolder.ofFloat(View.ALPHA, container.alpha, 0f),
|
|
194
|
+
val animator = ObjectAnimator.ofFloat(
|
|
195
|
+
container, View.TRANSLATION_Y, container.translationY, distanceOf(container),
|
|
170
196
|
)
|
|
171
|
-
animator.interpolator = TimeInterpolator { ModalAnimations.
|
|
172
|
-
return play(parts, animator, onEnd)
|
|
197
|
+
animator.interpolator = TimeInterpolator { ModalAnimations.accelerate(it) }
|
|
198
|
+
return play(parts, animator, ModalAnimations.DISMISS_DURATION, onEnd)
|
|
173
199
|
}
|
|
174
200
|
|
|
175
201
|
override fun awaitTargets(
|
|
@@ -245,10 +271,10 @@ internal class ModalViews(
|
|
|
245
271
|
hideEmptyLayer()
|
|
246
272
|
}
|
|
247
273
|
|
|
248
|
-
override fun update(record: ModalRecord, options: Options,
|
|
274
|
+
override fun update(record: ModalRecord, options: Options, merge: Options?) {
|
|
249
275
|
val parts = parts[record] ?: return
|
|
250
276
|
applyTestIds(record, parts, options)
|
|
251
|
-
parts.sheet?.update(options.modal.sheet, swipeToDismissOf(options),
|
|
277
|
+
parts.sheet?.update(options.modal.sheet, swipeToDismissOf(options), merge?.modal?.sheet)
|
|
252
278
|
}
|
|
253
279
|
|
|
254
280
|
override fun repaint(record: ModalRecord) {
|
|
@@ -259,6 +285,8 @@ internal class ModalViews(
|
|
|
259
285
|
parts[record]?.container?.requestLayout()
|
|
260
286
|
}
|
|
261
287
|
|
|
288
|
+
override fun sheetBack(record: ModalRecord): SheetBack? = parts[record]?.sheet
|
|
289
|
+
|
|
262
290
|
// `modal.testID` on the modal's view; a sheet's on the sheet's container, `modal.sheet.testID` first, and its
|
|
263
291
|
// grabber and scrim after it.
|
|
264
292
|
private fun applyTestIds(record: ModalRecord, parts: Parts, options: Options) {
|
|
@@ -289,7 +317,11 @@ internal class ModalViews(
|
|
|
289
317
|
val under = motion.underSide?.let { side -> underView?.let { SideAnimator.build(it, side, underBase) } }
|
|
290
318
|
if (under != null && underView != null) {
|
|
291
319
|
if (showing) moved[underView] = record else moved.remove(underView)
|
|
320
|
+
AnimationLayer.during(underView, under)
|
|
292
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)
|
|
293
325
|
val fadeLength = motion.side?.takeIf(AnimationRules::isSingleAlpha)?.let(AnimationRules::lengthOf)
|
|
294
326
|
val elements = motion.elements?.let { animation ->
|
|
295
327
|
val content = modalsLayer.parent as? ViewGroup ?: return@let null
|
|
@@ -355,8 +387,8 @@ internal class ModalViews(
|
|
|
355
387
|
private fun viewOf(node: ViewController<*>): View? =
|
|
356
388
|
parts.entries.firstOrNull { it.key.root === node }?.value?.container ?: node.peekView()
|
|
357
389
|
|
|
358
|
-
private fun play(parts: Parts, animator: Animator, onEnd: () -> Unit): () -> Unit {
|
|
359
|
-
animator.duration =
|
|
390
|
+
private fun play(parts: Parts, animator: Animator, duration: Long, onEnd: () -> Unit): () -> Unit {
|
|
391
|
+
animator.duration = duration
|
|
360
392
|
animator.addListener(object : AnimatorListenerAdapter() {
|
|
361
393
|
override fun onAnimationEnd(animation: Animator) {
|
|
362
394
|
if (parts.animator === animation) parts.animator = 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
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
package dev.apexnative.navigation.viewcontrollers.modal
|
|
2
|
+
|
|
3
|
+
import dev.apexnative.navigation.options.SheetDetent
|
|
4
|
+
|
|
5
|
+
/**
|
|
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.
|
|
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
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The stop to move to, or null to stay: [arrived] (the `selectedDetent` the merge names) when it is among
|
|
70
|
+
* [detents]; else, when [settled] (the stop the sheet rests at) is no longer one of them, [selected] (the resolved
|
|
71
|
+
* `selectedDetent`) when it is, or the lowest.
|
|
72
|
+
*/
|
|
73
|
+
fun target(
|
|
74
|
+
settled: SheetDetent?,
|
|
75
|
+
detents: List<SheetDetent>,
|
|
76
|
+
arrived: SheetDetent?,
|
|
77
|
+
selected: SheetDetent?,
|
|
78
|
+
): SheetDetent? = when {
|
|
79
|
+
arrived != null && arrived in detents -> arrived
|
|
80
|
+
settled != null && settled !in detents -> selected?.takeIf { it in detents } ?: detents.first()
|
|
81
|
+
else -> null
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package dev.apexnative.navigation.viewcontrollers.navigator
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import dev.apexnative.navigation.utils.NavigationLog
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The check of [BackCallbackState]'s triggers in debug builds (`NavigationActivity` makes it only when
|
|
8
|
+
* `BuildConfig.DEBUG`): it compares an activity's back callback with what back does now
|
|
9
|
+
* ([BackCallbackState.mismatchOf]) and writes a mismatch to the log once per state, with the screen on top. It never
|
|
10
|
+
* changes the callback, so a missing trigger behaves as in a release build. A [sample] before a frame runs at most
|
|
11
|
+
* every [SAMPLE_MILLIS] and reports a mismatch only when the sample before saw the same one: a change whose trigger
|
|
12
|
+
* comes at the end of its motion (a pane that slides, a menu dragged open) isn't reported while it moves. A back event
|
|
13
|
+
* ([atBack]) reports at once. Main thread only.
|
|
14
|
+
*/
|
|
15
|
+
internal class BackCallbackCheck(
|
|
16
|
+
private val log: (String) -> Unit = { Log.w(NavigationLog.TAG, it) },
|
|
17
|
+
) {
|
|
18
|
+
private var lastSample: Long? = null
|
|
19
|
+
private var previous: String? = null
|
|
20
|
+
private val logged = HashSet<String>()
|
|
21
|
+
|
|
22
|
+
/** Before a frame of the activity of [navigator], at [now] (`SystemClock.uptimeMillis`). */
|
|
23
|
+
fun sample(navigator: Navigator, now: Long) {
|
|
24
|
+
val last = lastSample
|
|
25
|
+
if (last != null && now - last < SAMPLE_MILLIS) return
|
|
26
|
+
lastSample = now
|
|
27
|
+
val mismatch = BackCallbackState.mismatchOf(navigator)
|
|
28
|
+
if (mismatch != null && mismatch == previous) report(mismatch)
|
|
29
|
+
previous = mismatch
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A back event reached the callback of the activity of [navigator], before it acts. */
|
|
33
|
+
fun atBack(navigator: Navigator) {
|
|
34
|
+
BackCallbackState.mismatchOf(navigator)?.let(::report)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Once per state, and not without end.
|
|
38
|
+
private fun report(mismatch: String) {
|
|
39
|
+
if (logged.size >= MAX_LOGGED || !logged.add(mismatch)) return
|
|
40
|
+
log("[ApexNavigation] $mismatch: a change of what back does came without its trigger")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
companion object {
|
|
44
|
+
/** The least time between two samples. */
|
|
45
|
+
const val SAMPLE_MILLIS = 500L
|
|
46
|
+
|
|
47
|
+
// The states logged at most: a debug check, not a second log.
|
|
48
|
+
private const val MAX_LOGGED = 32
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -2,21 +2,38 @@ package dev.apexnative.navigation.viewcontrollers.navigator
|
|
|
2
2
|
|
|
3
3
|
import android.util.Log
|
|
4
4
|
import androidx.activity.OnBackPressedCallback
|
|
5
|
+
import dev.apexnative.navigation.react.events.AppearanceDispatcher
|
|
5
6
|
import dev.apexnative.navigation.utils.NavigationLog
|
|
6
7
|
import java.lang.ref.WeakReference
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Keeps the back callback of each navigation activity enabled only while back has something to do in the app: its
|
|
10
|
-
* navigation can go back ([Navigator.canHandleBack]),
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* navigation can go back ([Navigator.canHandleBack]), the screen back acts on keeps it from the system
|
|
12
|
+
* (`hardwareBackButton.systemAnimation: false`, [Navigator.keepsBackFromSystem]), or JavaScript listens to it
|
|
13
|
+
* (`BackHandler`). Otherwise the callback is disabled and the system does its own back. The system plays its back
|
|
14
|
+
* animation (to the home screen, to another task) only when no callback of the app is enabled as the gesture starts,
|
|
15
|
+
* and it decides that before the app hears of the gesture.
|
|
14
16
|
*
|
|
15
17
|
* A stale "enabled" only loses that animation; a stale "disabled" would leave the app where back has to go back. So
|
|
16
|
-
* the value is computed again
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* the value is computed again on every event that can change what back does, never by walking the layouts before
|
|
19
|
+
* each frame:
|
|
20
|
+
* - the end of each command's main-thread task, `setDefaultOptions` and `mergeOptions` too (`CommandRunner`);
|
|
21
|
+
* - a stack's operation accepted, its current child changed, and the operation ended or rejected
|
|
22
|
+
* (`StackController`'s queue host), which covers a push or a `setStackRoot` that waited for its screen, a prepared
|
|
23
|
+
* push, back of the user and the back arrow;
|
|
24
|
+
* - a layout that changed the screens it shows (`Navigator.shownScreensChanged`: the tabs, a side menu, a split view,
|
|
25
|
+
* a pair) and the end of a tab's switch;
|
|
26
|
+
* - every change of the modals (`ModalCoordinator.Host.backChanged`): a show, a dismissal by a command, by back or by
|
|
27
|
+
* the user (a sheet dragged down, its scrim), a failure, a `setRoot` that takes them;
|
|
28
|
+
* - a root that changed or showed, and the layers that went (a reload: `Navigator.destroy`);
|
|
29
|
+
* - a side menu, the panes of a split view or a search that opened or closed (the first two after their last frame),
|
|
30
|
+
* and a split view's width that changed;
|
|
31
|
+
* - the release and the cancel of a back gesture, and each back press;
|
|
32
|
+
* - JavaScript's listeners ([setJsListeners]), and the activity resumed or focused, as a safety net.
|
|
33
|
+
*
|
|
34
|
+
* Overlays don't count: back never goes to them. Each activity has its own navigator and callback; the listeners of
|
|
35
|
+
* JavaScript count for all of them. Debug builds check the triggers ([mismatchOf], `BackCallbackCheck`). Main thread
|
|
36
|
+
* only.
|
|
20
37
|
*/
|
|
21
38
|
internal object BackCallbackState {
|
|
22
39
|
private class Entry(navigator: Navigator, callback: OnBackPressedCallback) {
|
|
@@ -41,6 +58,10 @@ internal object BackCallbackState {
|
|
|
41
58
|
entries.removeAll { it.navigator.get().let { attached -> attached == null || attached === navigator } }
|
|
42
59
|
}
|
|
43
60
|
|
|
61
|
+
/** JavaScript listens to back (`BackHandler`): it hears a press before the navigation does. */
|
|
62
|
+
val hasJsListeners: Boolean
|
|
63
|
+
get() = jsListeners
|
|
64
|
+
|
|
44
65
|
/** `setBackListeners` of JavaScript; false again when its JavaScript goes. */
|
|
45
66
|
fun setJsListeners(active: Boolean) {
|
|
46
67
|
jsListeners = active
|
|
@@ -52,22 +73,36 @@ internal object BackCallbackState {
|
|
|
52
73
|
for (entry in entries.toList()) update(entry)
|
|
53
74
|
}
|
|
54
75
|
|
|
55
|
-
/** The callback of the activity of [navigator]:
|
|
76
|
+
/** The callback of the activity of [navigator]: after a change in its navigation. */
|
|
56
77
|
fun update(navigator: Navigator) {
|
|
57
78
|
entries.firstOrNull { it.navigator.get() === navigator }?.let(::update)
|
|
58
79
|
}
|
|
59
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Debug builds only: a callback of [navigator]'s activity that differs from what back does now — a change without
|
|
83
|
+
* its trigger —, described with the screen on top; null when it is right or not attached. It changes nothing.
|
|
84
|
+
*/
|
|
85
|
+
fun mismatchOf(navigator: Navigator): String? {
|
|
86
|
+
val callback = entries.firstOrNull { it.navigator.get() === navigator }?.callback?.get() ?: return null
|
|
87
|
+
val expected = jsListeners || takesBack(navigator)
|
|
88
|
+
if (callback.isEnabled == expected) return null
|
|
89
|
+
val top = navigator.visibleLayout?.let { AppearanceDispatcher.visibleNode(it).id } ?: "none"
|
|
90
|
+
val state = if (callback.isEnabled) "enabled" else "disabled"
|
|
91
|
+
val back = if (expected) "back stays in the app" else "back leaves the app"
|
|
92
|
+
return "the back callback is $state where $back (on top: '$top')"
|
|
93
|
+
}
|
|
94
|
+
|
|
60
95
|
// Enables or disables the callback when what back does changed.
|
|
61
96
|
private fun update(entry: Entry) {
|
|
62
97
|
val callback = entry.callback.get() ?: return
|
|
63
|
-
val enabled = jsListeners ||
|
|
98
|
+
val enabled = jsListeners || takesBack(entry.navigator.get())
|
|
64
99
|
if (callback.isEnabled != enabled) callback.isEnabled = enabled
|
|
65
100
|
}
|
|
66
101
|
|
|
67
|
-
// A layout that fails to answer leaves back to the navigation, as before: this runs
|
|
68
|
-
// exception here would end the app.
|
|
69
|
-
private fun
|
|
70
|
-
navigator
|
|
102
|
+
// A layout that fails to answer leaves back to the navigation, as before: this runs from the triggers of layouts
|
|
103
|
+
// and animators, and an exception here would end the app.
|
|
104
|
+
private fun takesBack(navigator: Navigator?): Boolean = try {
|
|
105
|
+
navigator != null && (navigator.canHandleBack() || navigator.keepsBackFromSystem())
|
|
71
106
|
} catch (e: RuntimeException) {
|
|
72
107
|
if (!failureLogged) {
|
|
73
108
|
failureLogged = true
|
package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt
CHANGED
|
@@ -31,14 +31,16 @@ import dev.apexnative.navigation.viewcontrollers.component.ContentReadiness
|
|
|
31
31
|
import dev.apexnative.navigation.viewcontrollers.component.ScreenReadiness
|
|
32
32
|
import dev.apexnative.navigation.viewcontrollers.externalcomponent.ExternalComponentViewController
|
|
33
33
|
import dev.apexnative.navigation.viewcontrollers.modal.ModalCoordinator
|
|
34
|
+
import dev.apexnative.navigation.viewcontrollers.modal.ModalRecord
|
|
34
35
|
import dev.apexnative.navigation.viewcontrollers.modal.ModalViews
|
|
36
|
+
import dev.apexnative.navigation.viewcontrollers.modal.SheetBack
|
|
35
37
|
import dev.apexnative.navigation.viewcontrollers.overlay.OverlayCoordinator
|
|
36
38
|
import dev.apexnative.navigation.viewcontrollers.overlay.OverlayRecord
|
|
37
39
|
import dev.apexnative.navigation.viewcontrollers.overlay.OverlayViews
|
|
38
40
|
import dev.apexnative.navigation.viewcontrollers.parent.ParentController
|
|
39
41
|
import dev.apexnative.navigation.viewcontrollers.stack.PreparedPushes
|
|
40
42
|
import dev.apexnative.navigation.viewcontrollers.stack.StackCommands
|
|
41
|
-
import dev.apexnative.navigation.viewcontrollers.stack.
|
|
43
|
+
import dev.apexnative.navigation.viewcontrollers.stack.StackController
|
|
42
44
|
import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
|
|
43
45
|
import dev.apexnative.navigation.views.animations.FadeThrough
|
|
44
46
|
import dev.apexnative.navigation.views.animations.SideAnimator
|
|
@@ -103,7 +105,10 @@ class Navigator(
|
|
|
103
105
|
readiness = ContentReadiness,
|
|
104
106
|
scheduler = scheduler,
|
|
105
107
|
firstRoot = firstRootDraw,
|
|
106
|
-
onRootChanged = {
|
|
108
|
+
onRootChanged = {
|
|
109
|
+
root = it
|
|
110
|
+
BackCallbackState.update(this)
|
|
111
|
+
},
|
|
107
112
|
onRootShown = {
|
|
108
113
|
onRootShown?.invoke()
|
|
109
114
|
BackCallbackState.update(this)
|
|
@@ -140,10 +145,21 @@ class Navigator(
|
|
|
140
145
|
|
|
141
146
|
/**
|
|
142
147
|
* Whether back has something to do in the navigation: the mirror of [handleBack], without acting — the top modal
|
|
143
|
-
* first, then the root. The back callback asks it
|
|
148
|
+
* first, then the root. The back callback asks it whenever what back does can have changed (`BackCallbackState`).
|
|
144
149
|
*/
|
|
145
150
|
fun canHandleBack(): Boolean = modals.canHandleBack() ?: (root?.canHandleBack() == true)
|
|
146
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Whether back stays in the app also when the navigation has nothing to do: the layout back acts on — the top
|
|
154
|
+
* modal's, else the root — shows a screen with `hardwareBackButton.systemAnimation: false`. The system then doesn't
|
|
155
|
+
* play its animation of going home, and the press does the activity's own back ([handleBack] is false). The back
|
|
156
|
+
* callback asks it with [canHandleBack] (`BackCallbackState`).
|
|
157
|
+
*/
|
|
158
|
+
fun keepsBackFromSystem(): Boolean {
|
|
159
|
+
val layout = modals.backTargetRoot() ?: root ?: return false
|
|
160
|
+
return layout.resolveShownOptions(DefaultOptions.current).hardwareBackButton.systemAnimation.isFalse
|
|
161
|
+
}
|
|
162
|
+
|
|
147
163
|
/**
|
|
148
164
|
* The navigation's step of back, after JavaScript's listeners didn't take it: the top modal first (its content,
|
|
149
165
|
* else it closes or holds), else the root does the first thing it can (a stack's top leaves or holds, an open side
|
|
@@ -153,6 +169,18 @@ class Navigator(
|
|
|
153
169
|
fun handleBack(listener: CommandListener): Boolean =
|
|
154
170
|
modals.handleBack(listener) ?: (root?.handleBack(listener) == true)
|
|
155
171
|
|
|
172
|
+
/**
|
|
173
|
+
* The stack whose top [handleBack] would take away with the default pop: in the top modal, else in the root; none
|
|
174
|
+
* when back would do anything else.
|
|
175
|
+
*/
|
|
176
|
+
internal fun stackPoppedByBack(): StackController? {
|
|
177
|
+
val modalRoot = modals.backTargetRoot()
|
|
178
|
+
return if (modalRoot != null) modalRoot.stackPoppedByBack() else root?.stackPoppedByBack()
|
|
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
|
+
|
|
156
184
|
/**
|
|
157
185
|
* [layer] may wait to show from now on ([WaitingLayer]): the nodes in it ask it through [isInWaitingLayer] and
|
|
158
186
|
* [shownScreensChanged]. The root's layer is there from the start.
|
|
@@ -176,12 +204,14 @@ class Navigator(
|
|
|
176
204
|
* A layout of [node] (a stack, the tabs, a side menu, a split view, a pair) changed the screens it shows: when it
|
|
177
205
|
* is in a layer that still waits, the layer waits for the screens it shows now, and no longer for one that went
|
|
178
206
|
* ([WaitingLayer.shownScreensChanged]); so does the operation of its stack that waits for [node] as its entry (a
|
|
179
|
-
* pushed pair); a modal's sheet takes the hold of the screen it shows now
|
|
207
|
+
* pushed pair); a modal's sheet takes the hold of the screen it shows now; what back does is computed again (the
|
|
208
|
+
* tab, the pane or the menu back goes to, and the options of the screen it shows).
|
|
180
209
|
*/
|
|
181
210
|
internal fun shownScreensChanged(node: ViewController<*>) {
|
|
182
211
|
waitingLayerOf(node)?.shownScreensChanged()
|
|
183
212
|
node.findParentStack()?.queue?.shownScreensChanged(node)
|
|
184
213
|
modals.visibleScreenChanged(node)
|
|
214
|
+
BackCallbackState.update(this)
|
|
185
215
|
}
|
|
186
216
|
|
|
187
217
|
// The waiting layer [node] is in, up through the layouts around it; none.
|
|
@@ -214,7 +244,7 @@ class Navigator(
|
|
|
214
244
|
* it itself, `ComponentPresenter`); the system UI follows (only what changed is written).
|
|
215
245
|
*/
|
|
216
246
|
internal fun optionsMerged(node: ViewController<*>, options: Options = Options()) {
|
|
217
|
-
modals.optionsMergedInto(node)
|
|
247
|
+
modals.optionsMergedInto(node, options)
|
|
218
248
|
overlays.optionsMergedInto(node)
|
|
219
249
|
val navigationBar = options.navigationBar
|
|
220
250
|
val padding = navigationBar.drawBehind.hasValue() || navigationBar.backgroundColor.hasValue()
|
|
@@ -264,9 +294,7 @@ class Navigator(
|
|
|
264
294
|
if (!made) return answer.reject(ErrorTexts.notDoneYet("setRoot"))
|
|
265
295
|
val steps = layout.modals.mapIndexed { index, node ->
|
|
266
296
|
val last = index == layout.modals.lastIndex
|
|
267
|
-
|
|
268
|
-
modals.showInChain(node.id, { makeLayer(node, isOverlay = false) }, last, done)
|
|
269
|
-
}
|
|
297
|
+
ModalLayerStep(node, last)
|
|
270
298
|
} + layout.overlays.map { node ->
|
|
271
299
|
RootCoordinator.LayerStep { done ->
|
|
272
300
|
overlays.showInChain(node.id, { makeLayer(node, isOverlay = true) }, done)
|
|
@@ -275,6 +303,35 @@ class Navigator(
|
|
|
275
303
|
roots.setRoot({ factory.create(layout.root) }, answer, steps)
|
|
276
304
|
}
|
|
277
305
|
|
|
306
|
+
// A modal of a `setRoot`'s layout: made with the root and held until its turn, so it renders while the root waits
|
|
307
|
+
// and comes in; made in its turn instead while an id of it still shows (a modal of the old root with that id goes
|
|
308
|
+
// with the old root). A modal that couldn't be made is skipped in its turn.
|
|
309
|
+
private inner class ModalLayerStep(private val node: LayoutNode, private val animated: Boolean) :
|
|
310
|
+
RootCoordinator.LayerStep {
|
|
311
|
+
private var prepared = false
|
|
312
|
+
private var held: ModalRecord? = null
|
|
313
|
+
|
|
314
|
+
override fun prepare() {
|
|
315
|
+
if (LayoutChecks.firstShownId(listOf(node), ::isShownNow) { false } != null) return
|
|
316
|
+
prepared = true
|
|
317
|
+
held = modals.hold(node.id, { factory.create(node) }, animated)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
override fun discard() {
|
|
321
|
+
held?.let(modals::drop)
|
|
322
|
+
held = null
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
override fun show(done: () -> Unit): () -> Unit {
|
|
326
|
+
val record = held
|
|
327
|
+
held = null
|
|
328
|
+
if (record != null) return modals.release(record, done)
|
|
329
|
+
if (!prepared) return modals.showInChain(node.id, { makeLayer(node, isOverlay = false) }, animated, done)
|
|
330
|
+
done()
|
|
331
|
+
return {}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
278
335
|
// A modal or an overlay of a `setRoot`'s layout, made as its turn comes: an id that shows by then fails it.
|
|
279
336
|
private fun makeLayer(node: LayoutNode, isOverlay: Boolean): ViewController<*> {
|
|
280
337
|
val shown = LayoutChecks.firstShownId(listOf(node), ::isShownNow) { isOverlay && isReplacedOverlay(node, it) }
|
|
@@ -397,13 +454,15 @@ class Navigator(
|
|
|
397
454
|
destroyLayers(answerPending = false)
|
|
398
455
|
// Nothing the old screens told of their readiness holds for the screens of the new JavaScript.
|
|
399
456
|
ScreenReadiness.reset()
|
|
400
|
-
|
|
457
|
+
// Without layers back leaves the app until the new JavaScript sets its root.
|
|
458
|
+
BackCallbackState.update(this)
|
|
401
459
|
}
|
|
402
460
|
|
|
403
461
|
/**
|
|
404
|
-
* The activity is destroyed: every layer goes, with the events of a destroy; a `setRoot`
|
|
405
|
-
* `''` (JavaScript sets its root again in the next activity),
|
|
406
|
-
* wait for a modal with their roots' ids.
|
|
462
|
+
* The activity is destroyed: every layer goes, with the events of a destroy; a `setRoot` whose root still waited
|
|
463
|
+
* resolves with `''` (JavaScript sets its root again in the next activity), one whose root showed resolves with
|
|
464
|
+
* its id, and a modal's or an overlay's show and the commands that wait for a modal resolve with their roots' ids.
|
|
465
|
+
* Main thread only.
|
|
407
466
|
*/
|
|
408
467
|
internal fun destroyWithActivity() {
|
|
409
468
|
destroyLayers(answerPending = true)
|