@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
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
#import "ANNPreviewPush.h"
|
|
2
2
|
#import "ANNAssert.h"
|
|
3
|
+
#import "ANNCommandRunner.h"
|
|
4
|
+
#import "ANNComponentViewController.h"
|
|
3
5
|
#import "ANNErrorTexts.h"
|
|
6
|
+
#import "ANNExternalViewController.h"
|
|
4
7
|
#import "ANNLayoutFactory.h"
|
|
5
8
|
#import "ANNParking.h"
|
|
6
9
|
#import "ANNPopoverPresenter.h"
|
|
7
10
|
#import "ANNPreviewInteraction.h"
|
|
8
11
|
#import "ANNReloadCoordinator.h"
|
|
12
|
+
#import "ANNSlotContainers.h"
|
|
9
13
|
#import "ANNSlotScreenView.h"
|
|
10
14
|
#import "ANNStackCommands.h"
|
|
11
15
|
#import "ANNStackController.h"
|
|
@@ -34,6 +38,10 @@ static const NSTimeInterval ANNPreviewSearchInterval = 1.0 / 60;
|
|
|
34
38
|
@property(nonatomic, weak, nullable) UIView<ANNComponentProtocol> *watched;
|
|
35
39
|
@property(nonatomic) BOOL attached;
|
|
36
40
|
@property(nonatomic) BOOL done;
|
|
41
|
+
// The size of the preview, taken at the push.
|
|
42
|
+
@property(nonatomic) CGSize size;
|
|
43
|
+
// The screen rendered: at the push, or at the press for a screen of its own React root.
|
|
44
|
+
@property(nonatomic) BOOL rendered;
|
|
37
45
|
// The screen's unseen place in the main window, at its preview size, until UIKit takes its view for the menu.
|
|
38
46
|
@property(nonatomic, strong, nullable) UIView *host;
|
|
39
47
|
@property(nonatomic, strong, nullable) ANNParking *parking;
|
|
@@ -51,6 +59,15 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
51
59
|
return records;
|
|
52
60
|
}
|
|
53
61
|
|
|
62
|
+
// A React screen with a root of its own renders at the press: a view with a preview costs no React root, no render and
|
|
63
|
+
// no effects of the screen until the user presses it. A native screen (a kind of component screen) renders as it is
|
|
64
|
+
// made, and a screen of the app's one tree renders in JavaScript as its slot is added: both render at the push.
|
|
65
|
+
static BOOL ANNPreviewRendersAtPress(UIViewController *screen) {
|
|
66
|
+
return [screen isKindOfClass:ANNComponentViewController.class] &&
|
|
67
|
+
![screen isKindOfClass:ANNExternalViewController.class] &&
|
|
68
|
+
![screen.layoutInfo.name hasPrefix:ANNSlotPrefix];
|
|
69
|
+
}
|
|
70
|
+
|
|
54
71
|
@implementation ANNPreviewPush
|
|
55
72
|
|
|
56
73
|
+ (void)push:(ANNLayoutNode *)layout
|
|
@@ -71,6 +88,7 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
71
88
|
ANNPreviewRecord *record = [ANNPreviewRecord new];
|
|
72
89
|
record.previewId = layout.nodeId;
|
|
73
90
|
record.screen = screen;
|
|
91
|
+
record.size = size;
|
|
74
92
|
record.source = source;
|
|
75
93
|
record.answer = answer;
|
|
76
94
|
// The key applies only once the tap made the preview a screen of the stack.
|
|
@@ -81,7 +99,9 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
81
99
|
record.generation = answer.generation;
|
|
82
100
|
ANNPreviewRecords()[record.previewId] = record;
|
|
83
101
|
@try {
|
|
84
|
-
|
|
102
|
+
if (!ANNPreviewRendersAtPress(screen)) {
|
|
103
|
+
[self parkAndRender:record];
|
|
104
|
+
}
|
|
85
105
|
} @catch (NSException *exception) {
|
|
86
106
|
[self finish:record];
|
|
87
107
|
[screen destroy];
|
|
@@ -90,9 +110,11 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
90
110
|
[self startSearch:record];
|
|
91
111
|
}
|
|
92
112
|
|
|
93
|
-
// The screen renders
|
|
113
|
+
// The screen renders, once: its view waits unseen in the main window, at the size of the preview, so that its content
|
|
94
114
|
// lays out; nothing waits for it.
|
|
95
|
-
+ (void)parkAndRender:(ANNPreviewRecord *)record
|
|
115
|
+
+ (void)parkAndRender:(ANNPreviewRecord *)record {
|
|
116
|
+
record.rendered = YES;
|
|
117
|
+
CGSize size = record.size;
|
|
96
118
|
UIWindow *window = ApexNavigation.mainWindow;
|
|
97
119
|
if (window) {
|
|
98
120
|
UIView *host = [[UIView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
|
|
@@ -207,6 +229,9 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
207
229
|
record.attached = YES;
|
|
208
230
|
[self stopWatching:record];
|
|
209
231
|
__weak ANNPreviewRecord *weakRecord = record;
|
|
232
|
+
BOOL (^prepare)(void) = ^BOOL {
|
|
233
|
+
return [ANNPreviewPush renderAtPress:weakRecord];
|
|
234
|
+
};
|
|
210
235
|
BOOL (^commit)(void) = ^BOOL {
|
|
211
236
|
return [ANNPreviewPush commit:weakRecord];
|
|
212
237
|
};
|
|
@@ -217,10 +242,35 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
217
242
|
toView:view
|
|
218
243
|
reactTag:view.tag
|
|
219
244
|
source:source
|
|
245
|
+
prepare:prepare
|
|
220
246
|
commit:commit
|
|
221
247
|
dismissed:dismissed];
|
|
222
248
|
}
|
|
223
249
|
|
|
250
|
+
#pragma mark - The press
|
|
251
|
+
|
|
252
|
+
// The press starts (UIKit asks for the menu's configuration, about half a second before it shows the preview): the
|
|
253
|
+
// screen renders now if it hasn't yet, so that its content is there when the preview shows. Out of the command's
|
|
254
|
+
// runner, a failure rejects the push with its text and the preview goes. YES when the screen rendered. A preview of the
|
|
255
|
+
// JavaScript before a reload renders nothing: its screen would start in the new one.
|
|
256
|
+
+ (BOOL)renderAtPress:(ANNPreviewRecord *)record {
|
|
257
|
+
if (!record || record.done || !record.answer.isCurrent) {
|
|
258
|
+
return NO;
|
|
259
|
+
}
|
|
260
|
+
if (record.rendered) {
|
|
261
|
+
return YES;
|
|
262
|
+
}
|
|
263
|
+
@try {
|
|
264
|
+
[self parkAndRender:record];
|
|
265
|
+
} @catch (NSException *exception) {
|
|
266
|
+
[self finish:record];
|
|
267
|
+
[record.screen destroy];
|
|
268
|
+
[record.answer reject:[ANNCommandRunner rejectionOf:exception what:record.what]];
|
|
269
|
+
return NO;
|
|
270
|
+
}
|
|
271
|
+
return YES;
|
|
272
|
+
}
|
|
273
|
+
|
|
224
274
|
#pragma mark - The tap
|
|
225
275
|
|
|
226
276
|
// YES once the core took the preview: a key that leads back to an entry, or the push the queue accepted. From then on
|
|
@@ -267,7 +317,9 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
267
317
|
return YES;
|
|
268
318
|
}
|
|
269
319
|
// The preview grows into the screen: a push without an animation, and without a wait, as the screen rendered
|
|
270
|
-
// already; its answer at the end of the transaction.
|
|
320
|
+
// already; its answer at the end of the transaction. A screen that rendered only as the menu opened (a pointer's
|
|
321
|
+
// right click, then a quick tap) may have no content yet: its push waits for it as a push does.
|
|
322
|
+
BOOL waits = ANNPreviewRendersAtPress(screen) && !screen.reactView.isReady;
|
|
271
323
|
[stack setKey:key ofEntry:screen];
|
|
272
324
|
[stack.queue push:screen
|
|
273
325
|
answer:record.answer
|
|
@@ -275,7 +327,7 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
275
327
|
componentId:record.componentId
|
|
276
328
|
source:entry
|
|
277
329
|
animated:NO
|
|
278
|
-
waits:
|
|
330
|
+
waits:waits];
|
|
279
331
|
return YES;
|
|
280
332
|
}
|
|
281
333
|
|
|
@@ -12,13 +12,18 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
12
12
|
from:(UIViewController *)from
|
|
13
13
|
to:(UIViewController *)to;
|
|
14
14
|
|
|
15
|
+
/// The interaction of the swipe back that plays `animator`; nil for any other transition.
|
|
16
|
+
- (nullable id<UIViewControllerInteractiveTransitioning>)interactionForAnimator:
|
|
17
|
+
(id<UIViewControllerAnimatedTransitioning>)animator;
|
|
18
|
+
|
|
15
19
|
@end
|
|
16
20
|
|
|
17
21
|
/// The stack's delegate while a custom animation may be needed: it answers what the stack answers as its own delegate —
|
|
18
22
|
/// every method the stack implements goes to the stack — and also the choice of the transition object. A delegate with
|
|
19
23
|
/// that method turns the iOS 26 content swipe off, so the stack sets this one only while the top's `animations.pop`,
|
|
20
|
-
/// the pushed screen's `animations.push` or a running `setStackRoot` is its own, and itself otherwise.
|
|
21
|
-
///
|
|
24
|
+
/// the pushed screen's `animations.push` or a running `setStackRoot` is its own, and itself otherwise. An interaction
|
|
25
|
+
/// controller only while `answersInteraction`: the stack's own swipe back then plays the top's own pop under the
|
|
26
|
+
/// finger; otherwise UIKit doesn't see the method, and the swipe stays UIKit's.
|
|
22
27
|
@interface ANNStackAnimatingDelegate : NSObject <UINavigationControllerDelegate>
|
|
23
28
|
|
|
24
29
|
- (instancetype)initWithStack:(UINavigationController<ANNStackAnimating> *)stack
|
|
@@ -27,6 +32,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
27
32
|
- (instancetype)init NS_UNAVAILABLE;
|
|
28
33
|
+ (instancetype)new NS_UNAVAILABLE;
|
|
29
34
|
|
|
35
|
+
/// The top's pop follows the swipe back (`animations.pop.interactive`). UIKit reads the delegate's methods when it is
|
|
36
|
+
/// set: the stack sets the delegate again after a change.
|
|
37
|
+
@property(nonatomic) BOOL answersInteraction;
|
|
38
|
+
|
|
30
39
|
@end
|
|
31
40
|
|
|
32
41
|
NS_ASSUME_NONNULL_END
|
|
@@ -12,16 +12,16 @@
|
|
|
12
12
|
return self;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
// The choice of the transition object is this delegate's own; the interaction controller
|
|
16
|
-
// methods of `UINavigationControllerDelegate` are the stack's when the
|
|
17
|
-
// forwarded (design 11).
|
|
15
|
+
// The choice of the transition object is this delegate's own; the interaction controller too, answered only while
|
|
16
|
+
// the top's pop follows the swipe. The other methods of `UINavigationControllerDelegate` are the stack's when the
|
|
17
|
+
// stack has them; nothing outside the protocol is forwarded (design 11).
|
|
18
18
|
static BOOL ANNIsOwnSelector(SEL selector) {
|
|
19
19
|
SEL animation = @selector(navigationController:
|
|
20
20
|
animationControllerForOperation:fromViewController:toViewController:);
|
|
21
21
|
return selector == animation;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
static BOOL
|
|
24
|
+
static BOOL ANNIsInteractionSelector(SEL selector) {
|
|
25
25
|
return selector == @selector(navigationController:interactionControllerForAnimationController:);
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -33,7 +33,7 @@ static BOOL ANNIsDelegateSelector(SEL selector) {
|
|
|
33
33
|
|
|
34
34
|
// A method of the protocol this delegate passes to the stack.
|
|
35
35
|
- (BOOL)forwardsToStack:(SEL)selector {
|
|
36
|
-
return !ANNIsOwnSelector(selector) && !
|
|
36
|
+
return !ANNIsOwnSelector(selector) && !ANNIsInteractionSelector(selector) &&
|
|
37
37
|
ANNIsDelegateSelector(selector) && [_stack respondsToSelector:selector];
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -41,8 +41,8 @@ static BOOL ANNIsDelegateSelector(SEL selector) {
|
|
|
41
41
|
if (ANNIsOwnSelector(selector)) {
|
|
42
42
|
return YES;
|
|
43
43
|
}
|
|
44
|
-
if (
|
|
45
|
-
return
|
|
44
|
+
if (ANNIsInteractionSelector(selector)) {
|
|
45
|
+
return _answersInteraction;
|
|
46
46
|
}
|
|
47
47
|
if ([super respondsToSelector:selector]) {
|
|
48
48
|
return YES;
|
|
@@ -89,4 +89,11 @@ static BOOL ANNIsDelegateSelector(SEL selector) {
|
|
|
89
89
|
return [_stack animatorForOperation:operation from:fromVC to:toVC];
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
- (id<UIViewControllerInteractiveTransitioning>)
|
|
93
|
+
navigationController:(UINavigationController *)navigationController
|
|
94
|
+
interactionControllerForAnimationController:
|
|
95
|
+
(id<UIViewControllerAnimatedTransitioning>)animationController {
|
|
96
|
+
return [_stack interactionForAnimator:animationController];
|
|
97
|
+
}
|
|
98
|
+
|
|
92
99
|
@end
|
|
@@ -93,6 +93,14 @@ FOUNDATION_EXPORT NSString *_Nullable ANNStackKeyOfLayout(ANNLayoutNode *node);
|
|
|
93
93
|
/// it), or UIKit's More navigation shows the stack's first screen only (its swipe goes back to the More list).
|
|
94
94
|
- (BOOL)swipeBackIsUIKits:(UIGestureRecognizer *)recognizer;
|
|
95
95
|
|
|
96
|
+
/// The swipe of `recognizer` may play the pop: the stack's own swipe (from the leading edge, toward the trailing side)
|
|
97
|
+
/// only while the top's pop follows the finger (`animations.pop.interactive`) and the screen under is in place, UIKit's
|
|
98
|
+
/// swipes of the stack's navigation only while it doesn't. Every other swipe may.
|
|
99
|
+
- (BOOL)swipeBackTakes:(UIGestureRecognizer *)recognizer;
|
|
100
|
+
|
|
101
|
+
/// `recognizer` is the stack's own swipe back, not one of UIKit's.
|
|
102
|
+
- (BOOL)swipeBackIsStacks:(UIGestureRecognizer *)recognizer;
|
|
103
|
+
|
|
96
104
|
/// The stack has one entry: there is nowhere to go back to.
|
|
97
105
|
@property(nonatomic, readonly) BOOL hasOneEntry;
|
|
98
106
|
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
#import "ANNSheetPresenter.h"
|
|
13
13
|
#import "ANNShownScreens.h"
|
|
14
14
|
#import "ANNStackAnimatingDelegate.h"
|
|
15
|
+
#import "ANNStackPopAnimationOptions.h"
|
|
15
16
|
#import "ANNStackPresenter.h"
|
|
17
|
+
#import "ANNSwipePopInteraction.h"
|
|
16
18
|
#import "ANNSystemUI.h"
|
|
17
19
|
#import "ANNTopBarPresenter.h"
|
|
18
20
|
#import "ANNTransitionAnimator.h"
|
|
@@ -54,6 +56,10 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
|
|
|
54
56
|
return state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged;
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
// How far from the leading edge of the stack's view the stack's own swipe back starts, in points: the strip the side
|
|
60
|
+
// menu leaves to the swipe back (`ANNSideMenuEdgeWidth`).
|
|
61
|
+
static const CGFloat ANNOwnSwipeEdgeWidth = 20;
|
|
62
|
+
|
|
57
63
|
@interface ANNStackController () <ANNStackDisplay, ANNStackAnimating>
|
|
58
64
|
@end
|
|
59
65
|
|
|
@@ -90,6 +96,12 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
|
|
|
90
96
|
ANNTransitionPlan *_pendingPlan;
|
|
91
97
|
ANNStackChange _pendingChange;
|
|
92
98
|
__weak ANNTransitionAnimator *_runningAnimator;
|
|
99
|
+
// The interaction of the swipe back that plays the top's own pop, until UIKit asks for it.
|
|
100
|
+
__weak ANNSwipePopInteraction *_swipeInteraction;
|
|
101
|
+
// The stack's own swipe from the leading edge, on while the top's pop follows the finger: UIKit runs its swipe
|
|
102
|
+
// without asking the delegate for a transition, so that one would only slide.
|
|
103
|
+
UIPanGestureRecognizer *_ownSwipe;
|
|
104
|
+
InteractivePopGestureDelegate *_ownSwipeDelegate;
|
|
93
105
|
BOOL _gateUpdateScheduled;
|
|
94
106
|
// The stack is made (its helper set up): its options can be resolved.
|
|
95
107
|
BOOL _madeUp;
|
|
@@ -260,6 +272,16 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
|
|
|
260
272
|
content:YES
|
|
261
273
|
barSwipe:barSwipe];
|
|
262
274
|
}
|
|
275
|
+
if (!_ownSwipe) {
|
|
276
|
+
_ownSwipe = [[UIPanGestureRecognizer alloc] initWithTarget:self
|
|
277
|
+
action:@selector(ownSwipeBack:)];
|
|
278
|
+
_ownSwipe.enabled = _animatingDelegate.answersInteraction;
|
|
279
|
+
[self.view addGestureRecognizer:_ownSwipe];
|
|
280
|
+
}
|
|
281
|
+
_ownSwipeDelegate = [InteractivePopGestureDelegate installOn:_ownSwipe
|
|
282
|
+
stack:self
|
|
283
|
+
content:NO
|
|
284
|
+
barSwipe:barSwipe];
|
|
263
285
|
[self updateSwipeBack];
|
|
264
286
|
}
|
|
265
287
|
|
|
@@ -520,6 +542,9 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
|
|
|
520
542
|
|
|
521
543
|
- (BOOL)isSwipingBack {
|
|
522
544
|
UINavigationController *navigation = self.shownNavigationController;
|
|
545
|
+
if (navigation == self && ANNIsActive(_ownSwipe)) {
|
|
546
|
+
return YES;
|
|
547
|
+
}
|
|
523
548
|
if (ANNIsActive(navigation.interactivePopGestureRecognizer)) {
|
|
524
549
|
return YES;
|
|
525
550
|
}
|
|
@@ -813,15 +838,20 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
|
|
|
813
838
|
#pragma mark - The custom transitions
|
|
814
839
|
|
|
815
840
|
// UIKit asks while it starts the change the queue asked for: the queue's plan when the operation and the arriving
|
|
816
|
-
// entry are the plan's (the back button and the commands go through the queue, so its plan covers them);
|
|
817
|
-
//
|
|
841
|
+
// entry are the plan's (the back button and the commands go through the queue, so its plan covers them); the swipe
|
|
842
|
+
// back gets the top's own pop only with `animations.pop.interactive` (`swipeAnimatorFrom:to:`); nil for anything
|
|
843
|
+
// else — UIKit's own pops, a zoom alone.
|
|
818
844
|
- (id<UIViewControllerAnimatedTransitioning>)
|
|
819
845
|
animatorForOperation:(UINavigationControllerOperation)operation
|
|
820
846
|
from:(UIViewController *)from
|
|
821
847
|
to:(UIViewController *)to {
|
|
848
|
+
if ([self isSwipingBack]) {
|
|
849
|
+
return operation == UINavigationControllerOperationPop
|
|
850
|
+
? [self swipeAnimatorFrom:from to:to]
|
|
851
|
+
: nil;
|
|
852
|
+
}
|
|
822
853
|
ANNTransitionPlan *plan = _pendingPlan;
|
|
823
|
-
if (!plan || operation == UINavigationControllerOperationNone || to != plan.toNode
|
|
824
|
-
[self isSwipingBack]) {
|
|
854
|
+
if (!plan || operation == UINavigationControllerOperationNone || to != plan.toNode) {
|
|
825
855
|
return nil;
|
|
826
856
|
}
|
|
827
857
|
BOOL matches = _pendingChange == ANNStackChangeReplace ||
|
|
@@ -838,16 +868,73 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
|
|
|
838
868
|
return animator;
|
|
839
869
|
}
|
|
840
870
|
|
|
871
|
+
// The stack's own swipe back of a top whose pop follows the finger (`animations.pop.interactive`, not
|
|
872
|
+
// `enabled: false`): the pop plays under it. Nil otherwise, also when UIKit won't ask for the interaction (the gate
|
|
873
|
+
// hasn't seen the option yet: a change of the default options) or the screen under hasn't settled
|
|
874
|
+
// (`revealedEntrySettled:`): UIKit asks for the transition before the queue takes the swipe and moves those, and the
|
|
875
|
+
// frames take the views as they are now.
|
|
876
|
+
- (nullable ANNTransitionAnimator *)swipeAnimatorFrom:(UIViewController *)from
|
|
877
|
+
to:(UIViewController *)to {
|
|
878
|
+
if (!ANNIsActive(_ownSwipe) || !_animatingDelegate.answersInteraction ||
|
|
879
|
+
![self isOwnViewController:from] || ![self revealedEntrySettled:to]) {
|
|
880
|
+
return nil;
|
|
881
|
+
}
|
|
882
|
+
ANNStackPopAnimationOptions *pop = [from resolveOptionsWithDefault].animations.pop;
|
|
883
|
+
if (![ANNStackController popFollowsSwipe:pop]) {
|
|
884
|
+
return nil;
|
|
885
|
+
}
|
|
886
|
+
ANNTransitionPlan *plan = [ANNTransitionPlan stackPlanOfKind:ANNTransitionKindPop
|
|
887
|
+
animation:pop
|
|
888
|
+
waitForRender:nil
|
|
889
|
+
waitLimit:0
|
|
890
|
+
from:from
|
|
891
|
+
to:to];
|
|
892
|
+
if (!plan) {
|
|
893
|
+
return nil;
|
|
894
|
+
}
|
|
895
|
+
ANNTransitionAnimator *animator = [[ANNTransitionAnimator alloc] initWithPlan:plan];
|
|
896
|
+
// The interaction keeps itself while it follows the gesture; UIKit keeps it once it starts it.
|
|
897
|
+
ANNSwipePopInteraction *interaction =
|
|
898
|
+
[[ANNSwipePopInteraction alloc] initWithAnimator:animator recognizer:_ownSwipe view:self.view];
|
|
899
|
+
_swipeInteraction = interaction;
|
|
900
|
+
_runningAnimator = animator;
|
|
901
|
+
return animator;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// The screen under is in place for the frames: its view made, not parked, not rendering as a lower screen.
|
|
905
|
+
- (BOOL)revealedEntrySettled:(nullable UIViewController *)revealed {
|
|
906
|
+
return revealed.isViewLoaded && ![_lowerRendering objectForKey:revealed] &&
|
|
907
|
+
![_lowerToRender containsObject:revealed] &&
|
|
908
|
+
![[self parkedEntries] containsObject:revealed];
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
+ (BOOL)popFollowsSwipe:(nullable ANNStackPopAnimationOptions *)pop {
|
|
912
|
+
return [ANNAnimationRules stackIsOwn:pop] && [pop.interactive withDefault:NO] &&
|
|
913
|
+
[pop.enabled withDefault:YES];
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
- (nullable id<UIViewControllerInteractiveTransitioning>)interactionForAnimator:
|
|
917
|
+
(id<UIViewControllerAnimatedTransitioning>)animator {
|
|
918
|
+
ANNSwipePopInteraction *interaction = _swipeInteraction;
|
|
919
|
+
return interaction && interaction.animator == animator ? interaction : nil;
|
|
920
|
+
}
|
|
921
|
+
|
|
841
922
|
// The animating delegate while a custom animation may be needed: a change with its own plan now, or a top whose
|
|
842
923
|
// `animations.pop` is its own; the stack itself otherwise. UIKit reads the delegate's methods when it is set, so it is
|
|
843
|
-
// set again at each change
|
|
924
|
+
// set again at each change, and again when the interaction of the swipe comes or goes with the top's
|
|
925
|
+
// `animations.pop.interactive`.
|
|
844
926
|
- (void)updateAnimationGateWith:(ANNTransitionPlan *)plan {
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
927
|
+
UIViewController *top = [self getCurrentChild];
|
|
928
|
+
ANNStackPopAnimationOptions *pop = top ? [top resolveOptionsWithDefault].animations.pop : nil;
|
|
929
|
+
BOOL needed = plan != nil || [ANNAnimationRules stackIsOwn:pop];
|
|
930
|
+
BOOL interactive = [ANNStackController popFollowsSwipe:pop];
|
|
931
|
+
if (_animatingDelegate.answersInteraction != interactive) {
|
|
932
|
+
_animatingDelegate.answersInteraction = interactive;
|
|
933
|
+
if (self.delegate == _animatingDelegate) {
|
|
934
|
+
self.delegate = self;
|
|
935
|
+
}
|
|
850
936
|
}
|
|
937
|
+
_ownSwipe.enabled = interactive;
|
|
851
938
|
id<UINavigationControllerDelegate> delegate =
|
|
852
939
|
needed ? (id<UINavigationControllerDelegate>)_animatingDelegate : self;
|
|
853
940
|
if (self.delegate != delegate) {
|
|
@@ -934,13 +1021,66 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
|
|
|
934
1021
|
if (top != nil && top != [self getCurrentChild]) {
|
|
935
1022
|
return YES;
|
|
936
1023
|
}
|
|
937
|
-
BOOL own = recognizer == self.interactivePopGestureRecognizer;
|
|
1024
|
+
BOOL own = recognizer == self.interactivePopGestureRecognizer || recognizer == _ownSwipe;
|
|
938
1025
|
if (@available(iOS 26.0, *)) {
|
|
939
1026
|
own = own || recognizer == self.interactiveContentPopGestureRecognizer;
|
|
940
1027
|
}
|
|
941
1028
|
return !own && _queue.shown.count < 2;
|
|
942
1029
|
}
|
|
943
1030
|
|
|
1031
|
+
- (BOOL)swipeBackIsStacks:(UIGestureRecognizer *)recognizer {
|
|
1032
|
+
return recognizer != nil && recognizer == _ownSwipe;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
- (BOOL)swipeBackTakes:(UIGestureRecognizer *)recognizer {
|
|
1036
|
+
BOOL uikits = recognizer == self.interactivePopGestureRecognizer;
|
|
1037
|
+
if (@available(iOS 26.0, *)) {
|
|
1038
|
+
uikits = uikits || recognizer == self.interactiveContentPopGestureRecognizer;
|
|
1039
|
+
}
|
|
1040
|
+
if (recognizer != _ownSwipe && !uikits) {
|
|
1041
|
+
return YES;
|
|
1042
|
+
}
|
|
1043
|
+
NSArray<UIViewController *> *shown = _queue.shown;
|
|
1044
|
+
UIViewController *revealed = shown.count >= 2 ? shown[shown.count - 2] : nil;
|
|
1045
|
+
// The options as they are now, as `swipeAnimatorFrom:to:` reads them: the gate may lag a change of the defaults,
|
|
1046
|
+
// and a swipe of ours without the pop would be a pop the finger can't hold.
|
|
1047
|
+
UIViewController *top = self.topViewController;
|
|
1048
|
+
BOOL ownPlays = _ownSwipe.enabled && _animatingDelegate.answersInteraction && top &&
|
|
1049
|
+
top == [self getCurrentChild] && [self isOwnViewController:top] &&
|
|
1050
|
+
[ANNStackController
|
|
1051
|
+
popFollowsSwipe:[top resolveOptionsWithDefault].animations.pop] &&
|
|
1052
|
+
[self revealedEntrySettled:revealed];
|
|
1053
|
+
if (uikits) {
|
|
1054
|
+
return !ownPlays;
|
|
1055
|
+
}
|
|
1056
|
+
return ownPlays && [self panStartsAtLeadingEdge:_ownSwipe];
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
// A pan that starts near the leading edge of the stack's view and moves more across than along, toward the trailing
|
|
1060
|
+
// side: where UIKit's edge swipe starts.
|
|
1061
|
+
- (BOOL)panStartsAtLeadingEdge:(UIPanGestureRecognizer *)pan {
|
|
1062
|
+
UIView *view = self.view;
|
|
1063
|
+
CGPoint at = [pan locationInView:view];
|
|
1064
|
+
CGPoint move = [pan translationInView:view];
|
|
1065
|
+
BOOL rightToLeft =
|
|
1066
|
+
view.effectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft;
|
|
1067
|
+
CGFloat start = at.x - move.x;
|
|
1068
|
+
CGFloat fromEdge = rightToLeft ? view.bounds.size.width - start : start;
|
|
1069
|
+
if (move.x == 0 && move.y == 0) {
|
|
1070
|
+
move = [pan velocityInView:view];
|
|
1071
|
+
}
|
|
1072
|
+
CGFloat along = rightToLeft ? -move.x : move.x;
|
|
1073
|
+
return fromEdge <= ANNOwnSwipeEdgeWidth && along > fabs(move.y);
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// The stack's own swipe began: a pop as UIKit's swipe makes it, which the stack follows as the swipe back
|
|
1077
|
+
// (`followUIKitTransition`); the transition asks for the top's pop and its interaction (`swipeAnimatorFrom:to:`).
|
|
1078
|
+
- (void)ownSwipeBack:(UIPanGestureRecognizer *)recognizer {
|
|
1079
|
+
if (recognizer.state == UIGestureRecognizerStateBegan) {
|
|
1080
|
+
[self popViewControllerAnimated:YES];
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
944
1084
|
- (BOOL)hasOneEntry {
|
|
945
1085
|
return _queue.entries.count < 2;
|
|
946
1086
|
}
|
|
@@ -983,6 +1123,7 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
|
|
|
983
1123
|
BOOL edge = !(isBool && ![value boolValue]);
|
|
984
1124
|
BOOL content = !value || (isBool && [value boolValue]);
|
|
985
1125
|
_edgeSwipeDelegate.enabled = edge;
|
|
1126
|
+
_ownSwipeDelegate.enabled = edge;
|
|
986
1127
|
_moreEdgeSwipeDelegate.enabled = edge;
|
|
987
1128
|
_contentSwipeDelegate.enabled = content;
|
|
988
1129
|
_moreContentSwipeDelegate.enabled = content;
|
|
@@ -992,6 +1133,7 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
|
|
|
992
1133
|
- (void)swipeBackFollowsBar {
|
|
993
1134
|
BOOL hidden = [ANNSystemUI barHiddenOf:self.shownNavigationController];
|
|
994
1135
|
_edgeSwipeDelegate.barHidden = hidden;
|
|
1136
|
+
_ownSwipeDelegate.barHidden = hidden;
|
|
995
1137
|
_contentSwipeDelegate.barHidden = hidden;
|
|
996
1138
|
_moreEdgeSwipeDelegate.barHidden = hidden;
|
|
997
1139
|
_moreContentSwipeDelegate.barHidden = hidden;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#import <UIKit/UIKit.h>
|
|
2
|
+
|
|
3
|
+
@class ANNTransitionAnimator;
|
|
4
|
+
|
|
5
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
6
|
+
|
|
7
|
+
/// The interaction of a swipe back that plays the screen's own pop (`animations.pop.interactive`). It follows the
|
|
8
|
+
/// stack's own swipe from the leading edge (UIKit runs its swipe without asking the delegate for a transition), and
|
|
9
|
+
/// shows the animator's frames as far as the finger went across `view`, in the direction of the swipe back. Letting go
|
|
10
|
+
/// finishes the pop after a flick back or past half way, and puts the screen back otherwise; the rest plays faster
|
|
11
|
+
/// after a quick flick, never slower, and UIKit ends its part at the same pace. An interaction UIKit never starts goes
|
|
12
|
+
/// with the end of the gesture. Main queue.
|
|
13
|
+
@interface ANNSwipePopInteraction : NSObject <UIViewControllerInteractiveTransitioning>
|
|
14
|
+
|
|
15
|
+
- (instancetype)initWithAnimator:(ANNTransitionAnimator *)animator
|
|
16
|
+
recognizer:(UIPanGestureRecognizer *)recognizer
|
|
17
|
+
view:(UIView *)view NS_DESIGNATED_INITIALIZER;
|
|
18
|
+
|
|
19
|
+
- (instancetype)init NS_UNAVAILABLE;
|
|
20
|
+
+ (instancetype)new NS_UNAVAILABLE;
|
|
21
|
+
|
|
22
|
+
@property(nonatomic, weak, readonly, nullable) ANNTransitionAnimator *animator;
|
|
23
|
+
|
|
24
|
+
@end
|
|
25
|
+
|
|
26
|
+
NS_ASSUME_NONNULL_END
|