@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,136 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.views.element.animators
|
|
2
|
-
|
|
3
|
-
import android.animation.Animator
|
|
4
|
-
import android.graphics.Matrix
|
|
5
|
-
import android.view.View
|
|
6
|
-
import android.view.ViewOutlineProvider
|
|
7
|
-
import android.widget.ImageView
|
|
8
|
-
import com.facebook.react.views.view.ReactViewGroup
|
|
9
|
-
import dev.apexnative.navigation.utils.borderRadius
|
|
10
|
-
import dev.apexnative.navigation.views.animations.ValueInterpolation
|
|
11
|
-
import dev.apexnative.navigation.views.element.TransitionLayer
|
|
12
|
-
import kotlin.math.max
|
|
13
|
-
import kotlin.math.min
|
|
14
|
-
import kotlin.math.roundToInt
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* A shared image of another kind (an `ImageView` that isn't React Native's): its place by a translation; its image
|
|
18
|
-
* matrix from `from`'s fit (`centerCrop`, `fitXY`, `fitCenter`, `centerInside`) to its own, the part seen from `from`'s
|
|
19
|
-
* size to its own, the corner radius of the parent that clips it (`borderRadius` with `overflow: hidden`) by its
|
|
20
|
-
* outline. Another fit: the pair moves without the change of its matrix, and a line goes to the log. Everything goes
|
|
21
|
-
* back as it was at the end. Main thread only.
|
|
22
|
-
*/
|
|
23
|
-
internal class ImageMatrixAnimator(
|
|
24
|
-
private val from: ImageView,
|
|
25
|
-
private val to: ImageView,
|
|
26
|
-
private val layer: TransitionLayer,
|
|
27
|
-
/** The parents the views are clipped by in their screens: [to]'s is the one it had before the layer. */
|
|
28
|
-
private val fromParent: View?,
|
|
29
|
-
private val toParent: View?,
|
|
30
|
-
private val id: String,
|
|
31
|
-
private val log: (String) -> Unit,
|
|
32
|
-
) {
|
|
33
|
-
/** The animator; none when [to] has no place in the layer. */
|
|
34
|
-
fun create(): Animator? {
|
|
35
|
-
val geometry = FlightGeometry.of(from, to, layer) ?: return null
|
|
36
|
-
val toRect = geometry.to
|
|
37
|
-
val fromFit = from.scaleType
|
|
38
|
-
val toFit = to.scaleType
|
|
39
|
-
// The image whose matrix changes; none when a fit isn't one of the four or there is no image to fit.
|
|
40
|
-
val image = to.drawable?.takeIf {
|
|
41
|
-
fromFit in FITS && toFit in FITS && it.intrinsicWidth > 0 && it.intrinsicHeight > 0
|
|
42
|
-
}
|
|
43
|
-
val fits = image != null
|
|
44
|
-
if (!fits) log("The image '$id' fits by ${fromFit.name} and ${toFit.name}: it moves without a change of fit")
|
|
45
|
-
val fromRadius = clipRadius(fromParent) * geometry.fromScale
|
|
46
|
-
val toRadius = clipRadius(toParent)
|
|
47
|
-
val outline = FlightOutline()
|
|
48
|
-
var savedProvider: ViewOutlineProvider? = null
|
|
49
|
-
var savedClip = false
|
|
50
|
-
val savedMatrix = Matrix(to.imageMatrix)
|
|
51
|
-
val start = FloatArray(MATRIX)
|
|
52
|
-
val end = FloatArray(MATRIX)
|
|
53
|
-
val values = FloatArray(MATRIX)
|
|
54
|
-
val matrix = Matrix()
|
|
55
|
-
return MoveAnimator().apply {
|
|
56
|
-
fun frame(time: Float) {
|
|
57
|
-
val f = curve.getInterpolation(time)
|
|
58
|
-
val left = ValueInterpolation.number(geometry.from.left, toRect.left, f, time)
|
|
59
|
-
val top = ValueInterpolation.number(geometry.from.top, toRect.top, f, time)
|
|
60
|
-
val width = ValueInterpolation.number(geometry.from.width(), toRect.width(), f, time).roundToInt()
|
|
61
|
-
val height = ValueInterpolation.number(geometry.from.height(), toRect.height(), f, time).roundToInt()
|
|
62
|
-
layer.place(to, toRect.left.toInt(), toRect.top.toInt(), width, height)
|
|
63
|
-
to.translationX = left - toRect.left
|
|
64
|
-
to.translationY = top - toRect.top
|
|
65
|
-
outline.width = width
|
|
66
|
-
outline.height = height
|
|
67
|
-
outline.radius = ValueInterpolation.number(fromRadius, toRadius, f, time)
|
|
68
|
-
to.invalidateOutline()
|
|
69
|
-
if (image != null) {
|
|
70
|
-
val imageWidth = image.intrinsicWidth
|
|
71
|
-
val imageHeight = image.intrinsicHeight
|
|
72
|
-
fitMatrix(fromFit, imageWidth, imageHeight, width, height).getValues(start)
|
|
73
|
-
fitMatrix(toFit, imageWidth, imageHeight, width, height).getValues(end)
|
|
74
|
-
for (i in 0 until MATRIX) values[i] = ValueInterpolation.number(start[i], end[i], f, time)
|
|
75
|
-
matrix.setValues(values)
|
|
76
|
-
to.imageMatrix = matrix
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
onStart {
|
|
80
|
-
savedProvider = to.outlineProvider
|
|
81
|
-
savedClip = to.clipToOutline
|
|
82
|
-
to.outlineProvider = outline
|
|
83
|
-
to.clipToOutline = true
|
|
84
|
-
if (fits) to.scaleType = ImageView.ScaleType.MATRIX
|
|
85
|
-
frame(0f)
|
|
86
|
-
}
|
|
87
|
-
onFrame { frame(it) }
|
|
88
|
-
onEnd {
|
|
89
|
-
if (fits) {
|
|
90
|
-
to.scaleType = toFit
|
|
91
|
-
to.imageMatrix = savedMatrix
|
|
92
|
-
}
|
|
93
|
-
to.outlineProvider = savedProvider
|
|
94
|
-
to.clipToOutline = savedClip
|
|
95
|
-
to.translationX = 0f
|
|
96
|
-
to.translationY = 0f
|
|
97
|
-
layer.place(to, toRect.left.toInt(), toRect.top.toInt(), toRect.width().toInt(),
|
|
98
|
-
toRect.height().toInt())
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// The radius of a React parent that clips what is in it; 0 for another.
|
|
104
|
-
private fun clipRadius(parent: View?): Float =
|
|
105
|
-
(parent as? ReactViewGroup)?.takeIf { it.overflow == HIDDEN }?.borderRadius ?: 0f
|
|
106
|
-
|
|
107
|
-
private companion object {
|
|
108
|
-
const val MATRIX = 9
|
|
109
|
-
const val HIDDEN = "hidden"
|
|
110
|
-
val FITS = setOf(
|
|
111
|
-
ImageView.ScaleType.CENTER_CROP,
|
|
112
|
-
ImageView.ScaleType.FIT_XY,
|
|
113
|
-
ImageView.ScaleType.FIT_CENTER,
|
|
114
|
-
ImageView.ScaleType.CENTER_INSIDE,
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
// The matrix of a fit of an image of [imageWidth] × [imageHeight] into [width] × [height].
|
|
118
|
-
fun fitMatrix(fit: ImageView.ScaleType, imageWidth: Int, imageHeight: Int, width: Int, height: Int): Matrix {
|
|
119
|
-
val sx = width.toFloat() / imageWidth
|
|
120
|
-
val sy = height.toFloat() / imageHeight
|
|
121
|
-
val matrix = Matrix()
|
|
122
|
-
if (fit == ImageView.ScaleType.FIT_XY) {
|
|
123
|
-
matrix.setScale(sx, sy)
|
|
124
|
-
return matrix
|
|
125
|
-
}
|
|
126
|
-
val scale = when (fit) {
|
|
127
|
-
ImageView.ScaleType.CENTER_CROP -> max(sx, sy)
|
|
128
|
-
ImageView.ScaleType.CENTER_INSIDE -> min(1f, min(sx, sy))
|
|
129
|
-
else -> min(sx, sy)
|
|
130
|
-
}
|
|
131
|
-
matrix.setScale(scale, scale)
|
|
132
|
-
matrix.postTranslate((width - imageWidth * scale) / 2f, (height - imageHeight * scale) / 2f)
|
|
133
|
-
return matrix
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.views.element.animators
|
|
2
|
-
|
|
3
|
-
import android.animation.Animator
|
|
4
|
-
import android.view.View
|
|
5
|
-
import android.view.ViewOutlineProvider
|
|
6
|
-
import com.facebook.react.uimanager.BackgroundStyleApplicator
|
|
7
|
-
import com.facebook.react.uimanager.style.BorderRadiusProp
|
|
8
|
-
import dev.apexnative.navigation.utils.borderRadius
|
|
9
|
-
import dev.apexnative.navigation.views.animations.ValueInterpolation
|
|
10
|
-
import dev.apexnative.navigation.views.element.TransitionLayer
|
|
11
|
-
import kotlin.math.roundToInt
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* A shared React view without children moves itself: from `from`'s place on the screen to its own by a translation; its
|
|
15
|
-
* size and corner radius by an outline that grows from `from`'s (at the scale of its parents) to its own while it is
|
|
16
|
-
* laid out at the larger of the two sizes; its own radius taken off meanwhile and put back as it was; its background
|
|
17
|
-
* color from `from`'s to its own in Lab, ending exactly on its own (`BackgroundStyleApplicator`); its rotation from
|
|
18
|
-
* `from`'s to its own. Main thread only.
|
|
19
|
-
*/
|
|
20
|
-
internal class PlainViewAnimator(
|
|
21
|
-
private val from: View,
|
|
22
|
-
private val to: View,
|
|
23
|
-
private val layer: TransitionLayer,
|
|
24
|
-
) {
|
|
25
|
-
/** The animator; none when [to] has no place in the layer. */
|
|
26
|
-
fun create(): Animator? {
|
|
27
|
-
val geometry = FlightGeometry.of(from, to, layer) ?: return null
|
|
28
|
-
val fromRadius = from.borderRadius * geometry.fromScale
|
|
29
|
-
val toRadius = to.borderRadius
|
|
30
|
-
val fromColor = BackgroundStyleApplicator.getBackgroundColor(from)
|
|
31
|
-
val toColor = BackgroundStyleApplicator.getBackgroundColor(to)
|
|
32
|
-
val fromRotation = from.rotation
|
|
33
|
-
val toRotation = to.rotation
|
|
34
|
-
val ownRadius = BackgroundStyleApplicator.getBorderRadius(to, RADIUS)
|
|
35
|
-
val outline = FlightOutline()
|
|
36
|
-
var savedProvider: ViewOutlineProvider? = null
|
|
37
|
-
var savedClip = false
|
|
38
|
-
val (width, height) = geometry.largest
|
|
39
|
-
val toRect = geometry.to
|
|
40
|
-
return MoveAnimator().apply {
|
|
41
|
-
fun frame(time: Float) {
|
|
42
|
-
val f = curve.getInterpolation(time)
|
|
43
|
-
val left = ValueInterpolation.number(geometry.from.left, toRect.left, f, time)
|
|
44
|
-
val top = ValueInterpolation.number(geometry.from.top, toRect.top, f, time)
|
|
45
|
-
to.translationX = left - toRect.left
|
|
46
|
-
to.translationY = top - toRect.top
|
|
47
|
-
val from = geometry.from
|
|
48
|
-
outline.width = ValueInterpolation.number(from.width(), toRect.width(), f, time).roundToInt()
|
|
49
|
-
outline.height = ValueInterpolation.number(from.height(), toRect.height(), f, time).roundToInt()
|
|
50
|
-
outline.radius = ValueInterpolation.number(fromRadius, toRadius, f, time)
|
|
51
|
-
to.invalidateOutline()
|
|
52
|
-
if (fromColor != toColor) {
|
|
53
|
-
val color = ValueInterpolation.color(fromColor, toColor, f, time)
|
|
54
|
-
BackgroundStyleApplicator.setBackgroundColor(to, color)
|
|
55
|
-
}
|
|
56
|
-
to.rotation = ValueInterpolation.number(fromRotation, toRotation, f, time)
|
|
57
|
-
}
|
|
58
|
-
onStart {
|
|
59
|
-
savedProvider = to.outlineProvider
|
|
60
|
-
savedClip = to.clipToOutline
|
|
61
|
-
if (ownRadius != null) BackgroundStyleApplicator.setBorderRadius(to, RADIUS, null)
|
|
62
|
-
to.outlineProvider = outline
|
|
63
|
-
to.clipToOutline = true
|
|
64
|
-
layer.place(to, toRect.left.toInt(), toRect.top.toInt(), width, height)
|
|
65
|
-
frame(0f)
|
|
66
|
-
}
|
|
67
|
-
onFrame { frame(it) }
|
|
68
|
-
// A cancelled flight ends too: the view goes back whole.
|
|
69
|
-
onEnd {
|
|
70
|
-
to.translationX = 0f
|
|
71
|
-
to.translationY = 0f
|
|
72
|
-
to.rotation = toRotation
|
|
73
|
-
if (fromColor != toColor) BackgroundStyleApplicator.setBackgroundColor(to, toColor)
|
|
74
|
-
if (ownRadius != null) BackgroundStyleApplicator.setBorderRadius(to, RADIUS, ownRadius)
|
|
75
|
-
to.outlineProvider = savedProvider
|
|
76
|
-
to.clipToOutline = savedClip
|
|
77
|
-
layer.place(to, toRect.left.toInt(), toRect.top.toInt(), toRect.width().toInt(),
|
|
78
|
-
toRect.height().toInt())
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
private companion object {
|
|
84
|
-
val RADIUS = BorderRadiusProp.BORDER_RADIUS
|
|
85
|
-
}
|
|
86
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.views.element.animators
|
|
2
|
-
|
|
3
|
-
import android.animation.Animator
|
|
4
|
-
import android.view.View
|
|
5
|
-
import dev.apexnative.navigation.options.SharedElementTransitionOptions
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* One animator of a shared element: how [from], on the screen that goes, becomes [to], on the screen that comes, when
|
|
9
|
-
* both are of [type]. The core picks one by the views' classes (`SharedAnimatorFactory`) and runs it in the
|
|
10
|
-
* transition's layer.
|
|
11
|
-
*/
|
|
12
|
-
abstract class PropertyAnimatorCreator<T : View>(
|
|
13
|
-
protected val from: View,
|
|
14
|
-
protected val to: View,
|
|
15
|
-
private val type: Class<T>,
|
|
16
|
-
) {
|
|
17
|
-
/** Whether this animator takes part: both views are of its type and differ in what it animates. */
|
|
18
|
-
fun shouldAnimate(): Boolean {
|
|
19
|
-
if (!type.isInstance(from) || !type.isInstance(to)) return false
|
|
20
|
-
val fromChild = type.cast(from) ?: return false
|
|
21
|
-
val toChild = type.cast(to) ?: return false
|
|
22
|
-
return shouldAnimateProperty(fromChild, toChild)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** Whether [fromChild] and [toChild] differ in what this animator animates. */
|
|
26
|
-
abstract fun shouldAnimateProperty(fromChild: T, toChild: T): Boolean
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* The animator of the pair for [options]; the core gives it the pair's duration, delay and curve (each animator
|
|
30
|
-
* its own, never through a set around it).
|
|
31
|
-
*/
|
|
32
|
-
abstract fun create(options: SharedElementTransitionOptions): Animator
|
|
33
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.views.element.animators
|
|
2
|
-
|
|
3
|
-
import android.animation.Animator
|
|
4
|
-
import com.facebook.drawee.drawable.ScalingUtils
|
|
5
|
-
import com.facebook.react.views.image.ReactImageView
|
|
6
|
-
import dev.apexnative.navigation.views.animations.ValueInterpolation
|
|
7
|
-
import dev.apexnative.navigation.views.element.TransitionLayer
|
|
8
|
-
import kotlin.math.roundToInt
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* A shared React image: its place by a translation from `from`'s on the screen; its content by Fresco's scale type
|
|
12
|
-
* going from `from`'s fit to its own (`ScalingUtils.InterpolatingScaleType`); the part seen from `from`'s size to its
|
|
13
|
-
* own (it is laid out at the size of each frame); its rotation from `from`'s to its own; Fresco's own fade off
|
|
14
|
-
* meanwhile. Everything goes back as it was at the end. Main thread only.
|
|
15
|
-
*/
|
|
16
|
-
internal class ReactImageAnimator(
|
|
17
|
-
private val from: ReactImageView,
|
|
18
|
-
private val to: ReactImageView,
|
|
19
|
-
private val layer: TransitionLayer,
|
|
20
|
-
) {
|
|
21
|
-
/** The animator; none when [to] has no place in the layer or no hierarchy. */
|
|
22
|
-
fun create(): Animator? {
|
|
23
|
-
if (!from.hasHierarchy() || !to.hasHierarchy()) return null
|
|
24
|
-
val geometry = FlightGeometry.of(from, to, layer) ?: return null
|
|
25
|
-
val toRect = geometry.to
|
|
26
|
-
val toType = to.hierarchy.actualImageScaleType ?: ScalingUtils.ScaleType.CENTER_CROP
|
|
27
|
-
val fromType = from.hierarchy.actualImageScaleType ?: ScalingUtils.ScaleType.CENTER_CROP
|
|
28
|
-
val scale = ScalingUtils.InterpolatingScaleType(fromType, toType)
|
|
29
|
-
val fromRotation = from.rotation
|
|
30
|
-
val toRotation = to.rotation
|
|
31
|
-
var savedFade = 0
|
|
32
|
-
return MoveAnimator().apply {
|
|
33
|
-
fun frame(time: Float) {
|
|
34
|
-
val f = curve.getInterpolation(time)
|
|
35
|
-
val left = ValueInterpolation.number(geometry.from.left, toRect.left, f, time)
|
|
36
|
-
val top = ValueInterpolation.number(geometry.from.top, toRect.top, f, time)
|
|
37
|
-
val width = ValueInterpolation.number(geometry.from.width(), toRect.width(), f, time).roundToInt()
|
|
38
|
-
val height = ValueInterpolation.number(geometry.from.height(), toRect.height(), f, time).roundToInt()
|
|
39
|
-
layer.place(to, toRect.left.toInt(), toRect.top.toInt(), width, height)
|
|
40
|
-
to.translationX = left - toRect.left
|
|
41
|
-
to.translationY = top - toRect.top
|
|
42
|
-
scale.setValue(if (time >= 1f) 1f else f)
|
|
43
|
-
to.rotation = ValueInterpolation.number(fromRotation, toRotation, f, time)
|
|
44
|
-
to.invalidate()
|
|
45
|
-
}
|
|
46
|
-
onStart {
|
|
47
|
-
savedFade = to.hierarchy.fadeDuration
|
|
48
|
-
to.hierarchy.fadeDuration = 0
|
|
49
|
-
to.hierarchy.setActualImageScaleType(scale)
|
|
50
|
-
frame(0f)
|
|
51
|
-
}
|
|
52
|
-
onFrame { frame(it) }
|
|
53
|
-
onEnd {
|
|
54
|
-
to.hierarchy.setActualImageScaleType(toType)
|
|
55
|
-
to.hierarchy.fadeDuration = savedFade
|
|
56
|
-
to.translationX = 0f
|
|
57
|
-
to.translationY = 0f
|
|
58
|
-
to.rotation = toRotation
|
|
59
|
-
layer.place(to, toRect.left.toInt(), toRect.top.toInt(), toRect.width().toInt(),
|
|
60
|
-
toRect.height().toInt())
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.views.element.animators
|
|
2
|
-
|
|
3
|
-
import android.animation.Animator
|
|
4
|
-
import android.graphics.Canvas
|
|
5
|
-
import android.graphics.ColorFilter
|
|
6
|
-
import android.graphics.Picture
|
|
7
|
-
import android.graphics.PixelFormat
|
|
8
|
-
import android.graphics.PointF
|
|
9
|
-
import android.graphics.drawable.Drawable
|
|
10
|
-
import android.text.Layout
|
|
11
|
-
import android.view.View
|
|
12
|
-
import android.view.ViewGroup
|
|
13
|
-
import android.widget.TextView
|
|
14
|
-
import com.facebook.react.views.text.ReactTextView
|
|
15
|
-
import dev.apexnative.navigation.options.SharedElementTransitionOptions
|
|
16
|
-
import dev.apexnative.navigation.utils.TextViewUtils
|
|
17
|
-
import dev.apexnative.navigation.utils.ViewUtils
|
|
18
|
-
import kotlin.math.roundToInt
|
|
19
|
-
|
|
20
|
-
// The text moves as two pictures of itself, of the text that goes away and of the text that comes, the same text or
|
|
21
|
-
// another. Both keep their proportions, scaled by the font size from a point of the first line, and one turns into the
|
|
22
|
-
// other in a quarter of the move: at its start when the text grows, at its end when it shrinks, so the larger picture
|
|
23
|
-
// shows most of the way (as on iOS). The pictures are drawing commands, not pixels: they stay sharp at any scale and
|
|
24
|
-
// keep the colors, emoji and background of the text. They are drawn in the overlay of the transition layer while `to`
|
|
25
|
-
// is hidden.
|
|
26
|
-
class TextChangeAnimator(from: View, to: View) : PropertyAnimatorCreator<ReactTextView>(from, to, ReactTextView::class.java) {
|
|
27
|
-
private val pictures by lazy { pictures() }
|
|
28
|
-
|
|
29
|
-
override fun shouldAnimateProperty(fromChild: ReactTextView, toChild: ReactTextView): Boolean {
|
|
30
|
-
val fromPlace = ViewUtils.getLocationOnScreen(from)
|
|
31
|
-
val toPlace = ViewUtils.getLocationOnScreen(to)
|
|
32
|
-
return (fromChild.text.toString() != toChild.text.toString() ||
|
|
33
|
-
TextViewUtils.getTextSize(fromChild) != TextViewUtils.getTextSize(toChild) || fromPlace != toPlace
|
|
34
|
-
) && pictures != null
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
override fun create(options: SharedElementTransitionOptions): Animator {
|
|
38
|
-
val (start, end) = checkNotNull(pictures)
|
|
39
|
-
val layer = to.parent as ViewGroup
|
|
40
|
-
val drawable = TextMorphDrawable(start, end)
|
|
41
|
-
// Everything changes between the start and the end of the animation: a cancelled one ends too.
|
|
42
|
-
return MoveAnimator().apply {
|
|
43
|
-
onStart {
|
|
44
|
-
drawable.setBounds(0, 0, layer.width, layer.height)
|
|
45
|
-
layer.overlay.add(drawable)
|
|
46
|
-
to.alpha = 0f
|
|
47
|
-
}
|
|
48
|
-
onFrame {
|
|
49
|
-
drawable.update(it, curve.getInterpolation(it))
|
|
50
|
-
layer.invalidate()
|
|
51
|
-
}
|
|
52
|
-
onEnd {
|
|
53
|
-
layer.overlay.remove(drawable)
|
|
54
|
-
layer.invalidate()
|
|
55
|
-
to.alpha = end.alpha
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// `to` is in the transition layer already, at its margins (the coordinates of the other animators); `from` is where
|
|
61
|
-
// it is on the screen. Texts that line up the same way go from that point of their first lines (the same text lies
|
|
62
|
-
// over itself); others from the start of the line, as on iOS: a centered text no longer sticks out of a text at the
|
|
63
|
-
// start.
|
|
64
|
-
private fun pictures(): Pair<TextPicture, TextPicture>? {
|
|
65
|
-
if (to.parent !is ViewGroup) return null
|
|
66
|
-
val toPlace = to.layoutParams as? ViewGroup.MarginLayoutParams ?: return null
|
|
67
|
-
val fromLayout = (from as TextView).layout ?: return null
|
|
68
|
-
val toLayout = (to as TextView).layout ?: return null
|
|
69
|
-
val edge = lineEdge(fromLayout).takeIf { it == lineEdge(toLayout) } ?: LineEdge.START
|
|
70
|
-
val fromPlace = ViewUtils.getLocationOnScreen(from)
|
|
71
|
-
.apply { ViewUtils.getLocationOnScreen(to.parent as View).let { offset(-it.x, -it.y) } }
|
|
72
|
-
val start = TextPicture.of(from, fromPlace.x, fromPlace.y, edge) ?: return null
|
|
73
|
-
val end = TextPicture.of(to, toPlace.leftMargin, toPlace.topMargin, edge) ?: return null
|
|
74
|
-
return start to end
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// A text's picture, the point of its first line it is scaled from (in the view) and where that point is in the
|
|
79
|
-
// transition layer, its font size and opacity.
|
|
80
|
-
private class TextPicture(
|
|
81
|
-
val picture: Picture,
|
|
82
|
-
val anchor: PointF,
|
|
83
|
-
val position: PointF,
|
|
84
|
-
val fontSize: Float,
|
|
85
|
-
val alpha: Float
|
|
86
|
-
) {
|
|
87
|
-
companion object {
|
|
88
|
-
fun of(view: TextView, left: Int, top: Int, edge: LineEdge): TextPicture? {
|
|
89
|
-
val layout = view.layout ?: return null
|
|
90
|
-
val fontSize = TextViewUtils.getTextSize(view).takeIf { it > 0 } ?: view.textSize
|
|
91
|
-
if (view.width <= 0 || view.height <= 0 || layout.lineCount == 0 || fontSize <= 0) return null
|
|
92
|
-
// Without a picture (recording failed) the text goes to its place at once, as a different text does.
|
|
93
|
-
val picture = recordPicture(view) ?: return null
|
|
94
|
-
val anchor = PointF(
|
|
95
|
-
view.totalPaddingLeft + edgeX(layout, edge),
|
|
96
|
-
view.totalPaddingTop + layout.getLineBaseline(0).toFloat()
|
|
97
|
-
)
|
|
98
|
-
return TextPicture(picture, anchor, PointF(left + anchor.x, top + anchor.y), fontSize, view.alpha)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// That point of the first line, in the direction of the text.
|
|
102
|
-
private fun edgeX(layout: Layout, edge: LineEdge): Float {
|
|
103
|
-
val left = layout.getLineLeft(0)
|
|
104
|
-
val right = layout.getLineRight(0)
|
|
105
|
-
val rightToLeft = layout.getParagraphDirection(0) == Layout.DIR_RIGHT_TO_LEFT
|
|
106
|
-
return when (edge) {
|
|
107
|
-
LineEdge.CENTER -> (left + right) / 2
|
|
108
|
-
LineEdge.START -> if (rightToLeft) right else left
|
|
109
|
-
LineEdge.END -> if (rightToLeft) left else right
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Where the lines of a text line up: their start, center or end, in the direction of the text.
|
|
116
|
-
private enum class LineEdge { START, CENTER, END }
|
|
117
|
-
|
|
118
|
-
// ALIGN_LEFT and ALIGN_RIGHT are hidden constants, for Gravity.LEFT and RIGHT.
|
|
119
|
-
private fun lineEdge(layout: Layout): LineEdge {
|
|
120
|
-
val rightToLeft = layout.getParagraphDirection(0) == Layout.DIR_RIGHT_TO_LEFT
|
|
121
|
-
return when (layout.getParagraphAlignment(0).name) {
|
|
122
|
-
"ALIGN_CENTER" -> LineEdge.CENTER
|
|
123
|
-
"ALIGN_OPPOSITE" -> LineEdge.END
|
|
124
|
-
"ALIGN_LEFT" -> if (rightToLeft) LineEdge.END else LineEdge.START
|
|
125
|
-
"ALIGN_RIGHT" -> if (rightToLeft) LineEdge.START else LineEdge.END
|
|
126
|
-
else -> LineEdge.START
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Both pictures where the move has brought the text: the font size and the point of the first line go from the start
|
|
131
|
-
// to the end along the transition's curve, the pictures change over by the clock.
|
|
132
|
-
private class TextMorphDrawable(private val start: TextPicture, private val end: TextPicture) : Drawable() {
|
|
133
|
-
private val grows = end.fontSize >= start.fontSize
|
|
134
|
-
private var progress = 0f
|
|
135
|
-
private var changeOver = 0f
|
|
136
|
-
|
|
137
|
-
fun update(time: Float, progress: Float) {
|
|
138
|
-
this.progress = progress
|
|
139
|
-
val changeOverStart = if (grows) 0f else 1f - CHANGE_OVER
|
|
140
|
-
changeOver = ((time - changeOverStart) / CHANGE_OVER).coerceIn(0f, 1f)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
override fun draw(canvas: Canvas) {
|
|
144
|
-
val x = start.position.x + (end.position.x - start.position.x) * progress
|
|
145
|
-
val y = start.position.y + (end.position.y - start.position.y) * progress
|
|
146
|
-
val fontSize = start.fontSize + (end.fontSize - start.fontSize) * progress
|
|
147
|
-
draw(canvas, start, x, y, fontSize, 1f - changeOver)
|
|
148
|
-
draw(canvas, end, x, y, fontSize, changeOver)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private fun draw(canvas: Canvas, text: TextPicture, x: Float, y: Float, fontSize: Float, shown: Float) {
|
|
152
|
-
val alpha = (shown * text.alpha * 255).roundToInt().coerceIn(0, 255)
|
|
153
|
-
if (alpha == 0) return
|
|
154
|
-
val scale = fontSize / text.fontSize
|
|
155
|
-
val count = canvas.save()
|
|
156
|
-
canvas.translate(x, y)
|
|
157
|
-
canvas.scale(scale, scale)
|
|
158
|
-
canvas.translate(-text.anchor.x, -text.anchor.y)
|
|
159
|
-
// The picture fades as a whole: its letters and background don't show through each other.
|
|
160
|
-
if (alpha < 255) {
|
|
161
|
-
canvas.saveLayerAlpha(0f, 0f, text.picture.width.toFloat(), text.picture.height.toFloat(), alpha)
|
|
162
|
-
}
|
|
163
|
-
canvas.drawPicture(text.picture)
|
|
164
|
-
canvas.restoreToCount(count)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
override fun setAlpha(alpha: Int) = Unit
|
|
168
|
-
|
|
169
|
-
override fun setColorFilter(colorFilter: ColorFilter?) = Unit
|
|
170
|
-
|
|
171
|
-
@Deprecated("Deprecated in Java")
|
|
172
|
-
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
|
|
173
|
-
|
|
174
|
-
private companion object {
|
|
175
|
-
const val CHANGE_OVER = 0.25f
|
|
176
|
-
}
|
|
177
|
-
}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.views.element.animators
|
|
2
|
-
|
|
3
|
-
import android.animation.Animator
|
|
4
|
-
import android.graphics.Canvas
|
|
5
|
-
import android.graphics.ColorFilter
|
|
6
|
-
import android.graphics.Paint
|
|
7
|
-
import android.graphics.Picture
|
|
8
|
-
import android.graphics.PixelFormat
|
|
9
|
-
import android.graphics.PorterDuff
|
|
10
|
-
import android.graphics.PorterDuffXfermode
|
|
11
|
-
import android.graphics.RectF
|
|
12
|
-
import android.graphics.drawable.Drawable
|
|
13
|
-
import android.view.View
|
|
14
|
-
import android.view.ViewGroup
|
|
15
|
-
import com.facebook.react.views.view.ReactViewGroup
|
|
16
|
-
import dev.apexnative.navigation.options.SharedElementTransitionOptions
|
|
17
|
-
import dev.apexnative.navigation.utils.ViewUtils
|
|
18
|
-
import dev.apexnative.navigation.utils.borderRadius
|
|
19
|
-
import dev.apexnative.navigation.utils.computeInheritedScale
|
|
20
|
-
import kotlin.math.roundToInt
|
|
21
|
-
|
|
22
|
-
// A view with children moves as two pictures of itself, as on iOS: of the view that goes away and of the one that
|
|
23
|
-
// comes, each with its children. The copy goes from the place, size and corner radius of the one to those of the other,
|
|
24
|
-
// both pictures fill it, and the picture of the destination shows over the other on the way. The pictures are drawing
|
|
25
|
-
// commands: an avatar's letter grows sharp. They are drawn in the overlay of the transition layer while `to` is hidden,
|
|
26
|
-
// and nothing else moves the pair. A view without children moves itself, its outline growing, as before.
|
|
27
|
-
class ViewChangeAnimator(from: View, to: View) : PropertyAnimatorCreator<ReactViewGroup>(from, to, ReactViewGroup::class.java) {
|
|
28
|
-
private val pictures by lazy { pictures() }
|
|
29
|
-
|
|
30
|
-
override fun shouldAnimateProperty(fromChild: ReactViewGroup, toChild: ReactViewGroup): Boolean =
|
|
31
|
-
(fromChild.childCount > 0 || toChild.childCount > 0) && pictures != null
|
|
32
|
-
|
|
33
|
-
override fun create(options: SharedElementTransitionOptions): Animator {
|
|
34
|
-
val (start, end) = checkNotNull(pictures)
|
|
35
|
-
val layer = to.parent as ViewGroup
|
|
36
|
-
val drawable = ViewMorphDrawable(start, end)
|
|
37
|
-
// Everything changes between the start and the end of the animation: a cancelled one ends too.
|
|
38
|
-
return MoveAnimator().apply {
|
|
39
|
-
onStart {
|
|
40
|
-
drawable.setBounds(0, 0, layer.width, layer.height)
|
|
41
|
-
layer.overlay.add(drawable)
|
|
42
|
-
to.alpha = 0f
|
|
43
|
-
}
|
|
44
|
-
onFrame {
|
|
45
|
-
drawable.progress = curve.getInterpolation(it)
|
|
46
|
-
layer.invalidate()
|
|
47
|
-
}
|
|
48
|
-
onEnd {
|
|
49
|
-
layer.overlay.remove(drawable)
|
|
50
|
-
layer.invalidate()
|
|
51
|
-
to.alpha = end.alpha
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// `to` is in the transition layer already, at its margins (the coordinates of the other animators); `from` is where
|
|
57
|
-
// it is on the screen, at the scale of its parents.
|
|
58
|
-
private fun pictures(): Pair<ViewPicture, ViewPicture>? {
|
|
59
|
-
if (to.parent !is ViewGroup) return null
|
|
60
|
-
val toPlace = to.layoutParams as? ViewGroup.MarginLayoutParams ?: return null
|
|
61
|
-
val fromPlace = ViewUtils.getLocationOnScreen(from)
|
|
62
|
-
.apply { ViewUtils.getLocationOnScreen(to.parent as View).let { offset(-it.x, -it.y) } }
|
|
63
|
-
val (scaleX, scaleY) = computeInheritedScale(from)
|
|
64
|
-
val fromRect = RectF(0f, 0f, from.width * scaleX, from.height * scaleY).apply {
|
|
65
|
-
offset(fromPlace.x.toFloat(), fromPlace.y.toFloat())
|
|
66
|
-
}
|
|
67
|
-
val toRect = RectF(0f, 0f, to.width.toFloat(), to.height.toFloat()).apply {
|
|
68
|
-
offset(toPlace.leftMargin.toFloat(), toPlace.topMargin.toFloat())
|
|
69
|
-
}
|
|
70
|
-
val start = ViewPicture.of(from as ReactViewGroup, fromRect, scaleX) ?: return null
|
|
71
|
-
val end = ViewPicture.of(to as ReactViewGroup, toRect, 1f) ?: return null
|
|
72
|
-
return start to end
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// A view's picture, its place in the transition layer, its corner radius there and its opacity.
|
|
77
|
-
private class ViewPicture(val picture: Picture, val rect: RectF, val radius: Float, val alpha: Float) {
|
|
78
|
-
companion object {
|
|
79
|
-
fun of(view: ReactViewGroup, rect: RectF, scale: Float): ViewPicture? {
|
|
80
|
-
if (view.width <= 0 || view.height <= 0) return null
|
|
81
|
-
val picture = recordPicture(view) ?: return null
|
|
82
|
-
return ViewPicture(picture, rect, view.borderRadius * scale, view.alpha)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// The copy where the move has brought it: its place, size and corner radius go from the start to the end along the
|
|
88
|
-
// transition's curve, and so does the picture of the end over the picture of the start.
|
|
89
|
-
private class ViewMorphDrawable(private val start: ViewPicture, private val end: ViewPicture) : Drawable() {
|
|
90
|
-
var progress = 0f
|
|
91
|
-
private val rect = RectF()
|
|
92
|
-
private val maskPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
|
93
|
-
// What is drawn over the mask keeps only the mask's pixels: the corners stay smooth (a clip path on the hardware
|
|
94
|
-
// canvas is not anti-aliased).
|
|
95
|
-
private val contentPaint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) }
|
|
96
|
-
|
|
97
|
-
override fun draw(canvas: Canvas) {
|
|
98
|
-
rect.set(
|
|
99
|
-
lerp(start.rect.left, end.rect.left),
|
|
100
|
-
lerp(start.rect.top, end.rect.top),
|
|
101
|
-
lerp(start.rect.right, end.rect.right),
|
|
102
|
-
lerp(start.rect.bottom, end.rect.bottom)
|
|
103
|
-
)
|
|
104
|
-
if (rect.isEmpty) return
|
|
105
|
-
val radius = lerp(start.radius, end.radius)
|
|
106
|
-
val count = canvas.saveLayer(rect, null)
|
|
107
|
-
canvas.drawRoundRect(rect, radius, radius, maskPaint)
|
|
108
|
-
canvas.saveLayer(rect, contentPaint)
|
|
109
|
-
draw(canvas, start, start.alpha)
|
|
110
|
-
draw(canvas, end, end.alpha * progress)
|
|
111
|
-
canvas.restoreToCount(count)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// A picture fills the copy, as on iOS.
|
|
115
|
-
private fun draw(canvas: Canvas, view: ViewPicture, shown: Float) {
|
|
116
|
-
val alpha = (shown * 255).roundToInt().coerceIn(0, 255)
|
|
117
|
-
if (alpha == 0) return
|
|
118
|
-
val width = view.picture.width.toFloat()
|
|
119
|
-
val height = view.picture.height.toFloat()
|
|
120
|
-
val count = canvas.save()
|
|
121
|
-
canvas.translate(rect.left, rect.top)
|
|
122
|
-
canvas.scale(rect.width() / width, rect.height() / height)
|
|
123
|
-
// The picture fades as a whole: its children and background don't show through each other.
|
|
124
|
-
if (alpha < 255) canvas.saveLayerAlpha(0f, 0f, width, height, alpha)
|
|
125
|
-
canvas.drawPicture(view.picture)
|
|
126
|
-
canvas.restoreToCount(count)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
private fun lerp(from: Float, to: Float) = from + (to - from) * progress
|
|
130
|
-
|
|
131
|
-
override fun setAlpha(alpha: Int) = Unit
|
|
132
|
-
|
|
133
|
-
override fun setColorFilter(colorFilter: ColorFilter?) = Unit
|
|
134
|
-
|
|
135
|
-
@Deprecated("Deprecated in Java")
|
|
136
|
-
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
|
|
137
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
#import "ANNEventEmitter.h"
|
|
2
|
-
#import <UIKit/UIKit.h>
|
|
3
|
-
|
|
4
|
-
NS_ASSUME_NONNULL_BEGIN
|
|
5
|
-
|
|
6
|
-
/// Posted on the main queue when the padding of a screen's safe area view changed; the object is the screen id.
|
|
7
|
-
extern NSNotificationName const ANNScreenSafeAreaPaddingDidChangeNotification;
|
|
8
|
-
|
|
9
|
-
/// The safe area of each screen: how much of its content the bars and the system cover on each side. The padding is
|
|
10
|
-
/// the part of it the screen's safe area view keeps its content out of: the insets on the edges the screen's options
|
|
11
|
-
/// give. JavaScript gets the rest, what still covers the content (0 on a padded edge): it reads it from its own thread
|
|
12
|
-
/// for a screen's first render, and gets every change as `ANN.ScreenInsetsChanged`. Main queue, but the reads.
|
|
13
|
-
@interface ANNScreenInsets : NSObject
|
|
14
|
-
|
|
15
|
-
/// Keeps the screen's insets and padding, and tells when they changed.
|
|
16
|
-
+ (void)setInsets:(UIEdgeInsets)insets
|
|
17
|
-
padding:(UIEdgeInsets)padding
|
|
18
|
-
forScreenId:(NSString *)screenId
|
|
19
|
-
eventEmitter:(ANNEventEmitter *)eventEmitter;
|
|
20
|
-
/// The padding of the screen's safe area view; none before the screen was laid out. Main queue.
|
|
21
|
-
+ (UIEdgeInsets)paddingForScreenId:(NSString *)screenId;
|
|
22
|
-
/// `{ top, right, bottom, left }`, or nil before the screen was laid out. Any thread.
|
|
23
|
-
+ (nullable NSDictionary<NSString *, NSNumber *> *)insetsForScreenId:(NSString *)screenId;
|
|
24
|
-
+ (void)removeScreenId:(NSString *)screenId;
|
|
25
|
-
/// Forgets every screen: after a reload the new JavaScript counts its ids anew. Main queue.
|
|
26
|
-
+ (void)removeAll;
|
|
27
|
-
|
|
28
|
-
@end
|
|
29
|
-
|
|
30
|
-
NS_ASSUME_NONNULL_END
|