@apexnative/navigation 1.0.0-alpha.1 → 1.0.0-alpha.11
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 +132 -0
- package/README.md +147 -51
- package/android/CLAUDE.md +78 -25
- package/android/CORE.md +49 -25
- package/android/RECIPES.md +13 -6
- package/android/consumer-rules.pro +6 -0
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +85 -10
- package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
- package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonMenuOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -1
- package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
- package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
- package/android/src/main/java/dev/apexnative/navigation/options/OptionsCache.kt +8 -4
- package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
- package/android/src/main/java/dev/apexnative/navigation/options/SideMenuOptions.kt +6 -1
- package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
- package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
- package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
- package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
- package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +29 -36
- package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ErrorTexts.kt +75 -60
- package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +35 -23
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +12 -7
- package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +42 -4
- package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +54 -20
- package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +7 -6
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +19 -50
- package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
- package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +50 -81
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +135 -94
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
- package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
- package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +12 -10
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +39 -19
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +16 -4
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
- package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
- package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +10 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementDefinition.kt +9 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementPlanner.kt +20 -15
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +108 -34
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +12 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +109 -21
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +476 -73
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +57 -25
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +83 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +49 -14
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +71 -12
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +37 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +42 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +19 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +43 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +77 -17
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +315 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +30 -20
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +216 -18
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +149 -41
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +115 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +222 -48
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +30 -34
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +219 -54
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
- package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
- package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
- package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +9 -7
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +143 -135
- package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +112 -4
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +56 -41
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
- package/android/src/main/java/dev/apexnative/navigation/views/sidemenu/SideMenuView.kt +12 -3
- package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +45 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +140 -1
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -17
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +73 -34
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +125 -178
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
- package/android/src/main/jni/ANNContentHeights.cpp +82 -0
- package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
- package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
- package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
- package/android/src/main/res/values/styles.xml +1 -1
- package/android/src/main/res/values-night/styles.xml +1 -1
- package/cli/app.js +1 -1
- package/cli/doctor/checks/app.js +77 -14
- package/cli/doctor/checks/splash.js +4 -22
- package/cli/migrate/native.js +18 -0
- package/cli/project.js +10 -2
- package/cli/setup/index.js +18 -0
- package/cli/setup/source.js +2 -1
- package/cli/setup/steps/appDelegate.js +66 -11
- package/cli/setup/steps/mainApplication.js +134 -19
- package/cli/setup/steps/metro.js +46 -0
- package/cli/setup/steps/sceneDelegate.js +108 -0
- package/cli/splash/index.js +3 -1
- package/docs-md/architecture/native-screens.md +4 -0
- package/docs-md/architecture/theme-and-context.md +131 -12
- package/docs-md/architecture/transitions.md +58 -12
- package/docs-md/containers/arrangement.md +17 -1
- package/docs-md/containers/modals.md +8 -4
- package/docs-md/containers/overlays.md +3 -1
- package/docs-md/containers/side-menu.md +19 -2
- package/docs-md/containers/tabs.md +5 -1
- package/docs-md/flows/bottom-sheets.md +4 -2
- package/docs-md/flows/forms-in-a-modal.md +1 -1
- package/docs-md/fundamentals/screens-and-props.md +9 -1
- package/docs-md/fundamentals/starting-the-app.md +1 -1
- package/docs-md/guides/cli.md +4 -3
- package/docs-md/guides/deep-links.md +15 -33
- package/docs-md/help/glossary.md +4 -4
- package/docs-md/help/troubleshooting.md +44 -6
- package/docs-md/index.json +61 -1
- package/docs-md/migration/from-expo-router.md +1 -1
- package/docs-md/migration/from-react-native-navigation.md +9 -3
- package/docs-md/migration/from-react-navigation.md +2 -2
- package/docs-md/screen-ui/back-and-gestures.md +46 -2
- package/docs-md/screen-ui/bar-buttons.md +5 -5
- package/docs-md/screen-ui/search.md +1 -1
- package/docs-md/screen-ui/system-ui.md +17 -12
- package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
- package/docs-md/screen-ui/top-bar.md +8 -4
- package/docs-md/start/installation.md +21 -3
- package/ios/Animations/ANNFrameDriver.h +55 -15
- package/ios/Animations/ANNFrameDriver.mm +216 -60
- package/ios/Animations/ANNTransitionAnimator.h +26 -5
- package/ios/Animations/ANNTransitionAnimator.mm +61 -13
- package/ios/Animations/ANNTransitionPlan.h +2 -2
- package/ios/Animations/ANNTransitionPlan.mm +10 -0
- package/ios/Animations/ANNTransitionWait.mm +6 -7
- package/ios/Animations/Elements/ANNElementFinder.h +57 -0
- package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
- package/ios/Animations/Elements/ANNElementTransition.h +10 -8
- package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
- package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
- package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
- package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
- package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
- package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
- package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
- package/ios/CLAUDE.md +60 -24
- package/ios/CORE.md +44 -34
- package/ios/Contract/ANNCommandAnswer.h +13 -5
- package/ios/Contract/ANNCommandAnswer.mm +40 -32
- package/ios/Contract/ANNCommandContract.h +15 -0
- package/ios/Contract/ANNCommandContract.mm +78 -0
- package/ios/Contract/ANNCommandRunner.h +10 -9
- package/ios/Contract/ANNCommandRunner.mm +22 -28
- package/ios/Contract/ANNErrorTexts.h +6 -2
- package/ios/Contract/ANNErrorTexts.mm +18 -10
- package/ios/Contract/ANNLayoutNode.h +3 -3
- package/ios/Contract/ANNLayoutReader.h +3 -3
- package/ios/Core/ANNAppDelegate.mm +0 -2
- package/ios/Core/ANNAppearanceDispatcher.h +5 -4
- package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
- package/ios/Core/ANNDeepLinkQueue.h +22 -2
- package/ios/Core/ANNDeepLinkQueue.mm +121 -14
- package/ios/Core/ANNErrorHandler.h +9 -4
- package/ios/Core/ANNErrorHandler.mm +20 -2
- package/ios/Core/ANNEventContract.h +246 -0
- package/ios/Core/ANNEventContract.mm +225 -0
- package/ios/Core/ANNEventEmitter.h +6 -2
- package/ios/Core/ANNEventEmitter.mm +117 -80
- package/ios/Core/ANNHinge.h +6 -0
- package/ios/Core/ANNHinge.mm +15 -4
- package/ios/Core/ANNJavaScriptCalls.h +33 -0
- package/ios/Core/ANNJavaScriptCalls.mm +52 -0
- package/ios/Core/ANNLayoutProtocol.h +5 -5
- package/ios/Core/ANNNavigationState.h +7 -5
- package/ios/Core/ANNNavigationState.mm +8 -7
- package/ios/Core/ANNNodeHelper.h +32 -12
- package/ios/Core/ANNNodeHelper.mm +100 -3
- package/ios/Core/ANNParking.h +5 -4
- package/ios/Core/ANNReloadCoordinator.mm +5 -12
- package/ios/Core/ANNRenderWait.h +20 -6
- package/ios/Core/ANNRenderWait.mm +143 -56
- package/ios/Core/ANNSceneDelegate.mm +25 -15
- package/ios/Core/ANNSystemUI.h +3 -2
- package/ios/Core/ANNSystemUI.mm +7 -0
- package/ios/Core/ANNUtils.h +7 -0
- package/ios/Core/ANNUtils.mm +10 -0
- package/ios/Core/ApexNavigation+Internal.h +1 -1
- package/ios/Core/ApexNavigation.mm +7 -6
- package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
- package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
- package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
- package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
- package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +195 -21
- package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
- package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
- package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
- package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
- package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
- package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
- package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
- package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
- package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
- package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
- package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
- package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
- package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
- package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
- package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
- package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
- package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
- package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
- package/ios/Layouts/Screen/ANNScreenPlace.h +53 -0
- package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
- package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
- package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
- package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
- package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
- package/ios/Layouts/Screen/ANNScreenSettling.h +34 -0
- package/ios/Layouts/Screen/ANNScreenSettling.mm +171 -0
- package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
- package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
- package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
- package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
- package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
- package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
- package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
- package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
- package/ios/Layouts/Stack/ANNStackController.h +8 -0
- package/ios/Layouts/Stack/ANNStackController.mm +184 -16
- package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
- package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
- package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
- package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
- package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
- package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
- package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
- package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
- package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
- package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
- package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
- package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
- package/ios/Options/ANNAnimationOptions.h +2 -1
- package/ios/Options/ANNAnimationOptions.mm +1 -1
- package/ios/Options/ANNBottomTabsOptions.h +2 -0
- package/ios/Options/ANNBottomTabsOptions.mm +1 -0
- package/ios/Options/ANNOptions.h +25 -0
- package/ios/Options/ANNOptions.mm +157 -1
- package/ios/Options/ANNOptionsCache.h +7 -6
- package/ios/Options/ANNOptionsReader.mm +108 -0
- package/ios/Options/ANNSearchBarOptions.h +4 -3
- package/ios/Options/ANNSheetOptions.h +4 -1
- package/ios/Options/ANNSideMenuOptions.h +2 -0
- package/ios/Options/ANNSideMenuOptions.mm +2 -0
- package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
- package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
- package/ios/Options/ANNUserChoice.h +57 -0
- package/ios/Options/ANNUserChoice.mm +44 -0
- package/ios/Options/Params/ANNImageSource.h +61 -0
- package/ios/Options/Params/ANNImageSource.mm +101 -0
- package/ios/Options/Params/ANNOptionImages.h +37 -0
- package/ios/Options/Params/ANNOptionImages.mm +284 -0
- package/ios/Options/Params/ANNParam.h +15 -0
- package/ios/Options/Params/ANNParam.mm +61 -0
- package/ios/Options/Params/Color.h +3 -0
- package/ios/Options/Params/Color.mm +21 -0
- package/ios/Options/Params/ColorParser.h +4 -3
- package/ios/Options/Params/ColorParser.mm +22 -4
- package/ios/Options/Params/Image.h +15 -2
- package/ios/Options/Params/Image.mm +35 -2
- package/ios/Options/Params/ImageParser.h +5 -5
- package/ios/Options/Params/ImageParser.mm +28 -46
- package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
- package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
- package/ios/RECIPES.md +13 -6
- package/ios/React/ANNReactView.mm +6 -25
- package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
- package/ios/React/ANNSurfaceHostingView.h +14 -0
- package/ios/React/ANNSurfaceHostingView.mm +144 -1
- package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
- package/ios/React/Slots/ANNSlotContainers.h +14 -6
- package/ios/React/Slots/ANNSlotContainers.mm +75 -2
- package/ios/React/Slots/ANNSlotHost.mm +1 -3
- package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
- package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
- package/ios/TopBar/ANNBarAppearance.h +2 -1
- package/ios/TopBar/ANNBarAppearance.mm +111 -30
- package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
- package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
- package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
- package/ios/TopBar/ANNBarButtons.h +14 -8
- package/ios/TopBar/ANNBarButtons.mm +397 -80
- package/ios/TopBar/ANNIconButtonImage.h +1 -0
- package/ios/TopBar/ANNIconButtonImage.mm +34 -1
- package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
- package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
- package/ios/TopBar/ANNMainList.h +3 -0
- package/ios/TopBar/ANNMainList.mm +4 -0
- package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
- package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
- package/ios/TopBar/ANNSearchPresenter.mm +172 -21
- package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
- package/ios/TopBar/ANNTopBarPresenter.h +8 -2
- package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
- package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
- package/ios/TurboModules/ANNTurboModule.mm +104 -33
- package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
- package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
- package/lib/module/ARCHITECTURE.md +40 -27
- package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
- package/lib/module/api/app/AppRegistry.js +14 -2
- package/lib/module/api/app/AppRegistry.js.map +1 -1
- package/lib/module/api/app/createNavigation.js +190 -66
- package/lib/module/api/app/createNavigation.js.map +1 -1
- package/lib/module/api/commands/commands.js +54 -6
- package/lib/module/api/commands/commands.js.map +1 -1
- package/lib/module/api/events/navigationEvents.js +6 -2
- package/lib/module/api/events/navigationEvents.js.map +1 -1
- package/lib/module/api/hooks/useNavigation.js +8 -3
- package/lib/module/api/hooks/useNavigation.js.map +1 -1
- package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
- package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
- package/lib/module/api/linking/dispatchedLinks.js +23 -0
- package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
- package/lib/module/api/linking/linking.js +11 -0
- package/lib/module/api/linking/linking.js.map +1 -1
- package/lib/module/api/navigation.js.map +1 -1
- package/lib/module/api/options/OptionsChain.js +2 -2
- package/lib/module/api/screens/arrangement.js +5 -2
- package/lib/module/api/screens/arrangement.js.map +1 -1
- package/lib/module/api/screens/defineScreen.js +45 -3
- package/lib/module/api/screens/defineScreen.js.map +1 -1
- package/lib/module/api/screens/nativeScreens.js +31 -6
- package/lib/module/api/screens/nativeScreens.js.map +1 -1
- package/lib/module/api/screens/registerScreens.js +193 -35
- package/lib/module/api/screens/registerScreens.js.map +1 -1
- package/lib/module/api/theme/theme.js +5 -0
- package/lib/module/api/theme/theme.js.map +1 -1
- package/lib/module/engine/commands.js +51 -9
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/layout.js +20 -11
- package/lib/module/engine/layout.js.map +1 -1
- package/lib/module/engine/nativeScreens.js +9 -0
- package/lib/module/engine/nativeScreens.js.map +1 -1
- package/lib/module/engine/options.js +49 -15
- package/lib/module/engine/options.js.map +1 -1
- package/lib/module/engine/optionsChange.js +102 -0
- package/lib/module/engine/optionsChange.js.map +1 -0
- package/lib/module/engine/places.js +52 -7
- package/lib/module/engine/places.js.map +1 -1
- package/lib/module/engine/props.js +30 -1
- package/lib/module/engine/props.js.map +1 -1
- package/lib/module/engine/refresh.js +85 -0
- package/lib/module/engine/refresh.js.map +1 -0
- package/lib/module/engine/rememberedOptions.js +61 -1
- package/lib/module/engine/rememberedOptions.js.map +1 -1
- package/lib/module/engine/screens.js +77 -16
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/module/interfaces/contract/commands.json +101 -0
- package/lib/module/interfaces/contract/errors.json +275 -0
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
- package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
- package/lib/typescript/api/app/createNavigation.d.ts +8 -3
- package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
- package/lib/typescript/api/commands/commands.d.ts.map +1 -1
- package/lib/typescript/api/commands/presentation.d.ts +4 -3
- package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
- package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
- package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
- package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
- package/lib/typescript/api/index.d.ts +1 -1
- package/lib/typescript/api/index.d.ts.map +1 -1
- package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
- package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
- package/lib/typescript/api/linking/linking.d.ts +8 -0
- package/lib/typescript/api/linking/linking.d.ts.map +1 -1
- package/lib/typescript/api/navigation.d.ts +4 -1
- package/lib/typescript/api/navigation.d.ts.map +1 -1
- package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
- package/lib/typescript/api/screens/arrangement.d.ts +12 -2
- package/lib/typescript/api/screens/arrangement.d.ts.map +1 -1
- package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
- package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
- package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
- package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
- package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
- package/lib/typescript/api/theme/theme.d.ts +2 -0
- package/lib/typescript/api/theme/theme.d.ts.map +1 -1
- package/lib/typescript/engine/commands.d.ts +5 -0
- package/lib/typescript/engine/commands.d.ts.map +1 -1
- package/lib/typescript/engine/layout.d.ts.map +1 -1
- package/lib/typescript/engine/nativeScreens.d.ts +5 -0
- package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
- package/lib/typescript/engine/options.d.ts +5 -2
- package/lib/typescript/engine/options.d.ts.map +1 -1
- package/lib/typescript/engine/optionsChange.d.ts +28 -0
- package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
- package/lib/typescript/engine/places.d.ts +7 -2
- package/lib/typescript/engine/places.d.ts.map +1 -1
- package/lib/typescript/engine/props.d.ts +8 -1
- package/lib/typescript/engine/props.d.ts.map +1 -1
- package/lib/typescript/engine/refresh.d.ts +35 -0
- package/lib/typescript/engine/refresh.d.ts.map +1 -0
- package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
- package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
- package/lib/typescript/engine/screens.d.ts +27 -6
- package/lib/typescript/engine/screens.d.ts.map +1 -1
- package/lib/typescript/interfaces/ComponentEvents.d.ts +4 -4
- package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
- package/lib/typescript/interfaces/Events.d.ts +28 -10
- package/lib/typescript/interfaces/Events.d.ts.map +1 -1
- package/lib/typescript/interfaces/Options.d.ts +1 -1
- package/lib/typescript/interfaces/Options.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/animations.d.ts +80 -22
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
- package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
- package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/modals.d.ts +34 -26
- package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
- package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/stack.d.ts +17 -3
- package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/system.d.ts +18 -11
- package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
- package/lib/typescript/interfaces/options/topBar.d.ts +68 -38
- package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
- package/metro/acceptPlugin.js +57 -0
- package/metro/babelTransformer.js +45 -0
- package/metro/index.js +36 -0
- package/package.json +3 -1
- package/src/ARCHITECTURE.md +40 -27
- package/src/adapters/NativeANNTurboModule.ts +12 -2
- package/src/api/app/AppRegistry.ts +16 -2
- package/src/api/app/createNavigation.ts +203 -69
- package/src/api/commands/commands.ts +48 -7
- package/src/api/commands/presentation.ts +4 -3
- package/src/api/events/navigationEvents.ts +10 -4
- package/src/api/hooks/useNavigation.ts +9 -4
- package/src/api/hooks/useSafeAreaInsets.ts +4 -3
- package/src/api/index.ts +1 -0
- package/src/api/linking/dispatchedLinks.ts +18 -0
- package/src/api/linking/linking.ts +22 -1
- package/src/api/navigation.ts +4 -1
- package/src/api/options/OptionsChain.ts +2 -2
- package/src/api/screens/arrangement.ts +17 -4
- package/src/api/screens/defineScreen.ts +49 -5
- package/src/api/screens/nativeScreens.ts +40 -4
- package/src/api/screens/registerScreens.tsx +185 -42
- package/src/api/theme/theme.ts +5 -0
- package/src/engine/commands.ts +70 -13
- package/src/engine/layout.ts +27 -11
- package/src/engine/nativeScreens.ts +10 -1
- package/src/engine/options.ts +45 -19
- package/src/engine/optionsChange.ts +107 -0
- package/src/engine/places.ts +65 -7
- package/src/engine/props.ts +30 -1
- package/src/engine/refresh.ts +97 -0
- package/src/engine/rememberedOptions.ts +74 -1
- package/src/engine/screens.tsx +76 -21
- package/src/interfaces/ComponentEvents.ts +4 -4
- package/src/interfaces/Events.ts +29 -10
- package/src/interfaces/Options.ts +1 -0
- package/src/interfaces/contract/commands.json +101 -0
- package/src/interfaces/contract/errors.json +275 -0
- package/src/interfaces/options/animations.ts +81 -22
- package/src/interfaces/options/bottomTabs.ts +21 -7
- package/src/interfaces/options/buttons.ts +23 -15
- package/src/interfaces/options/modals.ts +34 -26
- package/src/interfaces/options/sideMenu.ts +24 -6
- package/src/interfaces/options/stack.ts +17 -3
- package/src/interfaces/options/system.ts +18 -11
- package/src/interfaces/options/toolbar.ts +2 -2
- package/src/interfaces/options/topBar.ts +68 -38
- package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
- package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -138
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -66
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
- package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
- package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
- package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
- package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt
CHANGED
|
@@ -1,53 +1,363 @@
|
|
|
1
1
|
package dev.apexnative.navigation.views.element.animators
|
|
2
2
|
|
|
3
|
-
import android.graphics.RectF
|
|
4
3
|
import android.view.View
|
|
5
4
|
import android.view.ViewGroup
|
|
6
|
-
import
|
|
7
|
-
import dev.apexnative.navigation.utils.
|
|
8
|
-
import dev.apexnative.navigation.views.
|
|
5
|
+
import com.facebook.react.uimanager.ReactOverflowView
|
|
6
|
+
import dev.apexnative.navigation.utils.borderRadius
|
|
7
|
+
import dev.apexnative.navigation.views.animations.ValueInterpolation
|
|
8
|
+
import kotlin.math.abs
|
|
9
|
+
import kotlin.math.cos
|
|
10
|
+
import kotlin.math.max
|
|
11
|
+
import kotlin.math.min
|
|
12
|
+
import kotlin.math.sin
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
15
|
+
* How a view lies in its parent and is drawn there: its frame's corner, its translation, scale and rotation about its
|
|
16
|
+
* pivot, and its parent's scroll. What `View.getMatrix` does, the scale first, without the tilts (`rotationX`,
|
|
17
|
+
* `rotationY`) but for a half turn about x or y: React Native draws a mirror that way ([of]). Pixels and degrees,
|
|
18
|
+
* clockwise.
|
|
13
19
|
*/
|
|
14
|
-
internal class
|
|
15
|
-
|
|
16
|
-
val
|
|
17
|
-
|
|
18
|
-
val
|
|
19
|
-
|
|
20
|
-
val
|
|
20
|
+
internal class ViewPlacement(
|
|
21
|
+
val left: Float,
|
|
22
|
+
val top: Float,
|
|
23
|
+
val translationX: Float = 0f,
|
|
24
|
+
val translationY: Float = 0f,
|
|
25
|
+
val scaleX: Float = 1f,
|
|
26
|
+
val scaleY: Float = 1f,
|
|
27
|
+
val rotation: Float = 0f,
|
|
28
|
+
val pivotX: Float = 0f,
|
|
29
|
+
val pivotY: Float = 0f,
|
|
30
|
+
val parentScrollX: Float = 0f,
|
|
31
|
+
val parentScrollY: Float = 0f,
|
|
21
32
|
) {
|
|
22
|
-
/** The
|
|
23
|
-
|
|
24
|
-
|
|
33
|
+
/** The point [x], [y] of the view in its parent's coordinates. */
|
|
34
|
+
fun toParent(x: Float, y: Float): FloatArray {
|
|
35
|
+
val dx = (x - pivotX) * scaleX
|
|
36
|
+
val dy = (y - pivotY) * scaleY
|
|
37
|
+
val radians = Math.toRadians(rotation.toDouble())
|
|
38
|
+
val cos = cos(radians).toFloat()
|
|
39
|
+
val sin = sin(radians).toFloat()
|
|
40
|
+
return floatArrayOf(
|
|
41
|
+
dx * cos - dy * sin + pivotX + translationX + left - parentScrollX,
|
|
42
|
+
dx * sin + dy * cos + pivotY + translationY + top - parentScrollY,
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The point [x], [y] of the parent in the view's coordinates: [toParent] undone. None when a scale of 0 flattens
|
|
48
|
+
* the view.
|
|
49
|
+
*/
|
|
50
|
+
fun toChild(x: Float, y: Float): FloatArray? {
|
|
51
|
+
if (scaleX == 0f || scaleY == 0f) return null
|
|
52
|
+
val dx = x - (pivotX + translationX + left - parentScrollX)
|
|
53
|
+
val dy = y - (pivotY + translationY + top - parentScrollY)
|
|
54
|
+
val radians = Math.toRadians(rotation.toDouble())
|
|
55
|
+
val cos = cos(radians).toFloat()
|
|
56
|
+
val sin = sin(radians).toFloat()
|
|
57
|
+
return floatArrayOf(
|
|
58
|
+
(dx * cos + dy * sin) / scaleX + pivotX,
|
|
59
|
+
(-dx * sin + dy * cos) / scaleY + pivotY,
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Whether the view shows mirrored: one of its scales is negative. */
|
|
64
|
+
val mirrors: Boolean get() = scaleX * scaleY < 0
|
|
25
65
|
|
|
26
66
|
companion object {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
val
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
67
|
+
// How close to half a turn a tilt counts as a flip, in degrees.
|
|
68
|
+
private const val FLIP_TOLERANCE = 0.5f
|
|
69
|
+
private const val HALF_TURN = 180f
|
|
70
|
+
|
|
71
|
+
/** [view] as it lies now. */
|
|
72
|
+
fun of(view: View): ViewPlacement {
|
|
73
|
+
val parent = view.parent as? View
|
|
74
|
+
return withTilts(
|
|
75
|
+
left = view.left.toFloat(),
|
|
76
|
+
top = view.top.toFloat(),
|
|
77
|
+
translationX = view.translationX,
|
|
78
|
+
translationY = view.translationY,
|
|
79
|
+
scaleX = view.scaleX,
|
|
80
|
+
scaleY = view.scaleY,
|
|
81
|
+
rotation = view.rotation,
|
|
82
|
+
rotationX = view.rotationX,
|
|
83
|
+
rotationY = view.rotationY,
|
|
84
|
+
pivotX = view.pivotX,
|
|
85
|
+
pivotY = view.pivotY,
|
|
86
|
+
parentScrollX = parent?.scrollX?.toFloat() ?: 0f,
|
|
87
|
+
parentScrollY = parent?.scrollY?.toFloat() ?: 0f,
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The placement of a view with these properties. React Native splits a mirror (`scaleX: -1`) into both scales
|
|
93
|
+
* negated and half a turn about x: a view turns about z after its scale and tilts about y, then x, last, and
|
|
94
|
+
* half a turn about x flips y after the turn, which is the same as flipping y first and turning the other way.
|
|
95
|
+
* Other tilts are left out.
|
|
96
|
+
*/
|
|
97
|
+
fun withTilts(
|
|
98
|
+
left: Float,
|
|
99
|
+
top: Float,
|
|
100
|
+
translationX: Float,
|
|
101
|
+
translationY: Float,
|
|
102
|
+
scaleX: Float,
|
|
103
|
+
scaleY: Float,
|
|
104
|
+
rotation: Float,
|
|
105
|
+
rotationX: Float,
|
|
106
|
+
rotationY: Float,
|
|
107
|
+
pivotX: Float,
|
|
108
|
+
pivotY: Float,
|
|
109
|
+
parentScrollX: Float,
|
|
110
|
+
parentScrollY: Float,
|
|
111
|
+
): ViewPlacement {
|
|
112
|
+
val flipsY = abs(abs(rotationX) - HALF_TURN) < FLIP_TOLERANCE
|
|
113
|
+
val flipsX = abs(abs(rotationY) - HALF_TURN) < FLIP_TOLERANCE
|
|
114
|
+
return ViewPlacement(
|
|
115
|
+
left = left,
|
|
116
|
+
top = top,
|
|
117
|
+
translationX = translationX,
|
|
118
|
+
translationY = translationY,
|
|
119
|
+
scaleX = if (flipsX) -scaleX else scaleX,
|
|
120
|
+
scaleY = if (flipsY) -scaleY else scaleY,
|
|
121
|
+
rotation = if (flipsX != flipsY) -rotation else rotation,
|
|
122
|
+
pivotX = pivotX,
|
|
123
|
+
pivotY = pivotY,
|
|
124
|
+
parentScrollX = parentScrollX,
|
|
125
|
+
parentScrollY = parentScrollY,
|
|
126
|
+
)
|
|
40
127
|
}
|
|
41
128
|
}
|
|
42
129
|
}
|
|
43
130
|
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Where the points of a view are drawn in a transition's layer: through its own placement and each parent's ([chain],
|
|
133
|
+
* the view first, up to the top view of the window but not it), then moved by [offsetX], [offsetY] (where the top view
|
|
134
|
+
* is from the layer's corner). The angle and the scale are those of the whole chain: a turned or scaled parent turns
|
|
135
|
+
* or scales what is in it. [clips] are the parents that cut what the view draws, the innermost first.
|
|
136
|
+
*/
|
|
137
|
+
internal class LayerPlace(
|
|
138
|
+
private val chain: List<ViewPlacement>,
|
|
139
|
+
private val offsetX: Float,
|
|
140
|
+
private val offsetY: Float,
|
|
141
|
+
private val clips: List<Clip> = emptyList(),
|
|
142
|
+
) {
|
|
143
|
+
/** The angle the view is drawn at, degrees, clockwise: a mirrored parent turns what is in it the other way. */
|
|
144
|
+
val rotation: Float = chain.fold(0f) { inner, placement ->
|
|
145
|
+
placement.rotation + if (placement.mirrors) -inner else inner
|
|
146
|
+
}
|
|
49
147
|
|
|
50
|
-
|
|
51
|
-
|
|
148
|
+
/** The scale it is drawn at along its own x (a mirror is negative). */
|
|
149
|
+
val scaleX: Float = chain.fold(1f) { product, placement -> product * placement.scaleX }
|
|
150
|
+
|
|
151
|
+
/** The scale it is drawn at along its own y. */
|
|
152
|
+
val scaleY: Float = chain.fold(1f) { product, placement -> product * placement.scaleY }
|
|
153
|
+
|
|
154
|
+
/** The point [x], [y] of the view in the layer. */
|
|
155
|
+
fun point(x: Float, y: Float): FloatArray {
|
|
156
|
+
var point = floatArrayOf(x, y)
|
|
157
|
+
for (placement in chain) point = placement.toParent(point[0], point[1])
|
|
158
|
+
return floatArrayOf(point[0] + offsetX, point[1] + offsetY)
|
|
52
159
|
}
|
|
160
|
+
|
|
161
|
+
/** The flight's end of a view of [width] × [height] drawn here. */
|
|
162
|
+
fun end(width: Int, height: Int): FlightEnd {
|
|
163
|
+
val center = point(width / 2f, height / 2f)
|
|
164
|
+
return FlightEnd(
|
|
165
|
+
centerX = center[0],
|
|
166
|
+
centerY = center[1],
|
|
167
|
+
width = width * abs(scaleX),
|
|
168
|
+
height = height * abs(scaleY),
|
|
169
|
+
rotation = rotation,
|
|
170
|
+
mirrorX = if (scaleX < 0) -1f else 1f,
|
|
171
|
+
mirrorY = if (scaleY < 0) -1f else 1f,
|
|
172
|
+
scale = min(abs(scaleX), abs(scaleY)),
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* The part of a view of [width] × [height] drawn here that its [clips] leave visible, as iOS works it out: the
|
|
178
|
+
* view's bounds cut by the bounds of each clip, brought into the view's coordinates (the box around them where a
|
|
179
|
+
* turn tilts them), with the corners of the last clip that cut something. Uncut, it is the whole view with its own
|
|
180
|
+
* [cornerRadius] (in its pixels).
|
|
181
|
+
*/
|
|
182
|
+
fun visible(width: Int, height: Int, cornerRadius: Float): VisiblePart {
|
|
183
|
+
val w = width.toFloat()
|
|
184
|
+
val h = height.toFloat()
|
|
185
|
+
val visible = floatArrayOf(0f, 0f, w, h)
|
|
186
|
+
var radius = 0f
|
|
187
|
+
for (clip in clips) {
|
|
188
|
+
val cut = intersection(visible, boundsInView(clip))
|
|
189
|
+
if (!cut.contentEquals(visible)) radius = clip.radius
|
|
190
|
+
cut.copyInto(visible)
|
|
191
|
+
}
|
|
192
|
+
val clipped = abs(visible[0]) > SAME_RECT || abs(visible[1]) > SAME_RECT ||
|
|
193
|
+
abs(visible[2] - w) > SAME_RECT || abs(visible[3] - h) > SAME_RECT
|
|
194
|
+
val shown = if (clipped) visible else floatArrayOf(0f, 0f, w, h)
|
|
195
|
+
val scaleX = abs(scaleX)
|
|
196
|
+
val scaleY = abs(scaleY)
|
|
197
|
+
return VisiblePart(
|
|
198
|
+
left = (shown[0] - w / 2) * scaleX,
|
|
199
|
+
top = (shown[1] - h / 2) * scaleY,
|
|
200
|
+
right = (shown[2] - w / 2) * scaleX,
|
|
201
|
+
bottom = (shown[3] - h / 2) * scaleY,
|
|
202
|
+
radius = (if (clipped) radius else cornerRadius) * min(scaleX, scaleY),
|
|
203
|
+
clipped = clipped,
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// The bounds of [clip] in the view's coordinates: the box around its corners brought down the chain. Empty when a
|
|
208
|
+
// placement on the way flattens the view.
|
|
209
|
+
private fun boundsInView(clip: Clip): FloatArray {
|
|
210
|
+
val box = floatArrayOf(Float.MAX_VALUE, Float.MAX_VALUE, -Float.MAX_VALUE, -Float.MAX_VALUE)
|
|
211
|
+
for (corner in 0 until CORNERS) {
|
|
212
|
+
var point: FloatArray? = floatArrayOf(
|
|
213
|
+
if (corner % 2 == 0) 0f else clip.width,
|
|
214
|
+
if (corner < 2) 0f else clip.height,
|
|
215
|
+
)
|
|
216
|
+
for (level in clip.level - 1 downTo 0) point = point?.let { chain[level].toChild(it[0], it[1]) }
|
|
217
|
+
point ?: return FloatArray(RECT)
|
|
218
|
+
box[0] = min(box[0], point[0])
|
|
219
|
+
box[1] = min(box[1], point[1])
|
|
220
|
+
box[2] = max(box[2], point[0])
|
|
221
|
+
box[3] = max(box[3], point[1])
|
|
222
|
+
}
|
|
223
|
+
return box
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
companion object {
|
|
227
|
+
private const val CORNERS = 4
|
|
228
|
+
private const val RECT = 4
|
|
229
|
+
|
|
230
|
+
// How close two rects count as the same, in pixels: a visible part that is the whole view needs no mask.
|
|
231
|
+
private const val SAME_RECT = 0.5f
|
|
232
|
+
private const val VISIBLE = "visible"
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Where [view] is drawn in [layer]. With [clipRoot] (the view of its screen), the parents up to it that cut
|
|
236
|
+
* what they draw are its clips: as on iOS, the parents above the screen don't count.
|
|
237
|
+
*/
|
|
238
|
+
fun of(view: View, layer: View, clipRoot: View? = null): LayerPlace {
|
|
239
|
+
val chain = arrayListOf(ViewPlacement.of(view))
|
|
240
|
+
val clips = ArrayList<Clip>()
|
|
241
|
+
var clipping = clipRoot != null
|
|
242
|
+
var parent = view.parent as? View
|
|
243
|
+
while (parent != null) {
|
|
244
|
+
if (clipping) {
|
|
245
|
+
clipOf(parent, chain.size)?.let(clips::add)
|
|
246
|
+
clipping = parent !== clipRoot
|
|
247
|
+
}
|
|
248
|
+
val above = parent.parent as? View ?: break
|
|
249
|
+
chain += ViewPlacement.of(parent)
|
|
250
|
+
parent = above
|
|
251
|
+
}
|
|
252
|
+
// The window's top view (no parent view) lies where it is on the screen, with no properties of its own.
|
|
253
|
+
val base = parent ?: view
|
|
254
|
+
val screen = IntArray(2)
|
|
255
|
+
base.getLocationOnScreen(screen)
|
|
256
|
+
val origin = IntArray(2)
|
|
257
|
+
layer.getLocationOnScreen(origin)
|
|
258
|
+
return LayerPlace(chain, (screen[0] - origin[0]).toFloat(), (screen[1] - origin[1]).toFloat(), clips)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** The rect [a] cut by [b] (left, top, right, bottom); an empty one at 0, 0 when they don't meet, as on iOS. */
|
|
262
|
+
internal fun intersection(a: FloatArray, b: FloatArray): FloatArray {
|
|
263
|
+
val left = max(a[0], b[0])
|
|
264
|
+
val top = max(a[1], b[1])
|
|
265
|
+
val right = min(a[2], b[2])
|
|
266
|
+
val bottom = min(a[3], b[3])
|
|
267
|
+
return if (left < right && top < bottom) floatArrayOf(left, top, right, bottom) else FloatArray(RECT)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// The clip of [parent], at [level] of the chain, when it cuts what it draws to its bounds: a React Native view
|
|
271
|
+
// whose `overflow` isn't visible (a scroll view's is `scroll` unless set) with its corners, and any view whose
|
|
272
|
+
// own parent keeps its children in (`clipChildren`: Android cuts each child to its bounds, square), as the
|
|
273
|
+
// screen's own views do. React Native's views let their children out, so their `overflow` alone counts.
|
|
274
|
+
private fun clipOf(parent: View, level: Int): Clip? {
|
|
275
|
+
val overflows = parent is ReactOverflowView && parent.overflow.let { it != null && it != VISIBLE }
|
|
276
|
+
val keptIn = (parent.parent as? ViewGroup)?.clipChildren == true
|
|
277
|
+
if (!overflows && !keptIn) return null
|
|
278
|
+
val radius = if (overflows) parent.borderRadius else 0f
|
|
279
|
+
return Clip(level, parent.width.toFloat(), parent.height.toFloat(), radius)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* A parent that cuts what a view draws to its bounds: its [level] in the view's chain (1 the view's parent: its
|
|
286
|
+
* coordinates come down to the view's through the placements before it), its size and its corner radius. Pixels.
|
|
287
|
+
*/
|
|
288
|
+
internal class Clip(val level: Int, val width: Float, val height: Float, val radius: Float = 0f)
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* The part of a shared element's copy that shows at one end of its flight: left, top, right, bottom from the copy's
|
|
292
|
+
* center at the size it is drawn at, and its corner radius there. [clipped]: a parent cuts the view; else it is the
|
|
293
|
+
* whole copy with its own corners.
|
|
294
|
+
*/
|
|
295
|
+
internal class VisiblePart(
|
|
296
|
+
val left: Float,
|
|
297
|
+
val top: Float,
|
|
298
|
+
val right: Float,
|
|
299
|
+
val bottom: Float,
|
|
300
|
+
val radius: Float,
|
|
301
|
+
val clipped: Boolean,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* The mask of a copy cut by its views' parents, as on iOS: a rounded rect that goes from the part of the copy that
|
|
306
|
+
* shows at one end to the part that shows at the other, evenly.
|
|
307
|
+
*/
|
|
308
|
+
internal class FlightMask private constructor(private val from: VisiblePart, private val to: VisiblePart) {
|
|
309
|
+
/**
|
|
310
|
+
* Fills [out] with the mask at [fraction] of the way (the curve's value), [time] the part of the time: left, top,
|
|
311
|
+
* right, bottom from the copy's center, then the corner radius.
|
|
312
|
+
*/
|
|
313
|
+
fun at(fraction: Float, time: Float, out: FloatArray) {
|
|
314
|
+
out[0] = ValueInterpolation.number(from.left, to.left, fraction, time)
|
|
315
|
+
out[1] = ValueInterpolation.number(from.top, to.top, fraction, time)
|
|
316
|
+
out[2] = ValueInterpolation.number(from.right, to.right, fraction, time)
|
|
317
|
+
out[3] = ValueInterpolation.number(from.bottom, to.bottom, fraction, time)
|
|
318
|
+
out[4] = ValueInterpolation.number(from.radius, to.radius, fraction, time)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
companion object {
|
|
322
|
+
/** The values [at] fills. */
|
|
323
|
+
const val SIZE = 5
|
|
324
|
+
|
|
325
|
+
/** The mask between [from] and [to]; none when neither is cut, and the copy shows whole. */
|
|
326
|
+
fun of(from: VisiblePart, to: VisiblePart): FlightMask? =
|
|
327
|
+
if (from.clipped || to.clipped) FlightMask(from, to) else null
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* One end of a shared element's flight in its layer: where its center is drawn, the size it shows (its own at the
|
|
333
|
+
* scale of its chain), its angle, whether it shows mirrored, and its scale (what its corners shrink by). Pixels.
|
|
334
|
+
*/
|
|
335
|
+
internal class FlightEnd(
|
|
336
|
+
val centerX: Float,
|
|
337
|
+
val centerY: Float,
|
|
338
|
+
val width: Float,
|
|
339
|
+
val height: Float,
|
|
340
|
+
val rotation: Float,
|
|
341
|
+
val mirrorX: Float = 1f,
|
|
342
|
+
val mirrorY: Float = 1f,
|
|
343
|
+
val scale: Float = 1f,
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Where a shared element flies in its transition's layer: from where `from` is drawn to where `to` is drawn in its
|
|
348
|
+
* screen, both through their own and their parents' translation, scale and rotation. The center, the size and the
|
|
349
|
+
* mirror go evenly, the angle along the shorter arc (as on iOS).
|
|
350
|
+
*/
|
|
351
|
+
internal class FlightGeometry(val from: FlightEnd, val to: FlightEnd) {
|
|
352
|
+
/** The flight at [fraction] of the way (the curve's value), [time] the part of the time. */
|
|
353
|
+
fun at(fraction: Float, time: Float): FlightEnd = FlightEnd(
|
|
354
|
+
centerX = ValueInterpolation.number(from.centerX, to.centerX, fraction, time),
|
|
355
|
+
centerY = ValueInterpolation.number(from.centerY, to.centerY, fraction, time),
|
|
356
|
+
width = ValueInterpolation.number(from.width, to.width, fraction, time),
|
|
357
|
+
height = ValueInterpolation.number(from.height, to.height, fraction, time),
|
|
358
|
+
rotation = ValueInterpolation.angle(from.rotation, to.rotation, fraction, time),
|
|
359
|
+
mirrorX = ValueInterpolation.number(from.mirrorX, to.mirrorX, fraction, time),
|
|
360
|
+
mirrorY = ValueInterpolation.number(from.mirrorY, to.mirrorY, fraction, time),
|
|
361
|
+
scale = ValueInterpolation.number(from.scale, to.scale, fraction, time),
|
|
362
|
+
)
|
|
53
363
|
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
package dev.apexnative.navigation.views.element.animators
|
|
2
|
+
|
|
3
|
+
import android.graphics.Canvas
|
|
4
|
+
import android.graphics.Color
|
|
5
|
+
import android.graphics.Paint
|
|
6
|
+
import android.graphics.PorterDuff
|
|
7
|
+
import android.graphics.PorterDuffXfermode
|
|
8
|
+
import android.graphics.RectF
|
|
9
|
+
import android.graphics.drawable.Drawable
|
|
10
|
+
import android.view.View
|
|
11
|
+
import android.widget.ImageView
|
|
12
|
+
import com.facebook.react.uimanager.BackgroundStyleApplicator
|
|
13
|
+
import com.facebook.react.uimanager.style.LogicalEdge
|
|
14
|
+
import com.facebook.react.views.image.ReactImageView
|
|
15
|
+
import com.facebook.react.views.view.ReactViewGroup
|
|
16
|
+
import dev.apexnative.navigation.utils.borderRadius
|
|
17
|
+
import kotlin.math.abs
|
|
18
|
+
import kotlin.math.roundToInt
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A shared image flies as its image, fitted all the way: the copy goes from where `from` is drawn to where `to` is
|
|
22
|
+
* drawn in its screen ([FlightGeometry]), clipped to its corners, and the image of `to` in it goes from the part and
|
|
23
|
+
* place `from` shows its image at (its fit, `resizeMode`) to those of `to`, keeping its proportions where both fits
|
|
24
|
+
* do. The image is `to`'s own drawable, drawn on the layer's canvas and only read: an animated image plays on. The
|
|
25
|
+
* corners are the image's own radius, else that of a parent that clips it (`overflow: hidden`) and that it fills.
|
|
26
|
+
* Where a parent cuts the view, only the part that shows flies, as with a view ([ViewMorph]). A pair whose views draw
|
|
27
|
+
* more than their images (a background, a border) or whose images differ in proportions flies as pictures of the views
|
|
28
|
+
* ([ViewMorph]).
|
|
29
|
+
*/
|
|
30
|
+
internal class ImageMorph private constructor(
|
|
31
|
+
private val start: ImageEnd,
|
|
32
|
+
private val end: ImageEnd,
|
|
33
|
+
private val image: Drawable,
|
|
34
|
+
// Where the image's drawable draws the image, in the coordinates it draws in.
|
|
35
|
+
private val drawn: RectF,
|
|
36
|
+
) : FlightPicture() {
|
|
37
|
+
private val flight = FlightGeometry(start.end, end.end)
|
|
38
|
+
private val cut = FlightMask.of(start.visible, end.visible)?.let(::MaskCut)
|
|
39
|
+
private var at = start.end
|
|
40
|
+
private var progress = 0f
|
|
41
|
+
private val rect = RectF()
|
|
42
|
+
private val imageRect = FloatArray(RECT)
|
|
43
|
+
private val maskPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
|
44
|
+
// What is drawn over the mask keeps only the mask's pixels: the corners stay smooth.
|
|
45
|
+
private val contentPaint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) }
|
|
46
|
+
|
|
47
|
+
override val live: Boolean get() = true
|
|
48
|
+
|
|
49
|
+
override fun update(time: Float, progress: Float) {
|
|
50
|
+
this.progress = progress
|
|
51
|
+
at = flight.at(progress, time)
|
|
52
|
+
for (i in 0 until RECT) imageRect[i] = lerp(start.image[i], end.image[i])
|
|
53
|
+
cut?.update(time, progress)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
override fun draw(canvas: Canvas) {
|
|
57
|
+
rect.set(-at.width / 2, -at.height / 2, at.width / 2, at.height / 2)
|
|
58
|
+
val imageWidth = imageRect[2] - imageRect[0]
|
|
59
|
+
val imageHeight = imageRect[3] - imageRect[1]
|
|
60
|
+
if (rect.isEmpty || imageWidth <= 0 || imageHeight <= 0 || drawn.isEmpty) return
|
|
61
|
+
val alpha = (lerp(start.alpha, end.alpha) * 255).roundToInt().coerceIn(0, 255)
|
|
62
|
+
if (alpha == 0) return
|
|
63
|
+
val radius = lerp(start.radius, end.radius)
|
|
64
|
+
// The copy turns about its center, mirrored where a view is.
|
|
65
|
+
canvas.translate(at.centerX, at.centerY)
|
|
66
|
+
canvas.rotate(at.rotation)
|
|
67
|
+
canvas.scale(at.mirrorX, at.mirrorY)
|
|
68
|
+
canvas.saveLayer(rect, null)
|
|
69
|
+
canvas.drawRoundRect(rect, radius, radius, maskPaint)
|
|
70
|
+
cut?.draw(canvas, rect)
|
|
71
|
+
contentPaint.alpha = alpha
|
|
72
|
+
canvas.saveLayer(rect, contentPaint)
|
|
73
|
+
canvas.translate(imageRect[0], imageRect[1])
|
|
74
|
+
canvas.scale(imageWidth / drawn.width(), imageHeight / drawn.height())
|
|
75
|
+
canvas.translate(-drawn.left, -drawn.top)
|
|
76
|
+
image.draw(canvas)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private fun lerp(from: Float, to: Float) = from + (to - from) * progress
|
|
80
|
+
|
|
81
|
+
// One end of the flight: where the view is drawn, where its image shows in it (left, top, right, bottom from the
|
|
82
|
+
// view's center, at the size it is drawn at), its corner radius there, its opacity and the part of it that shows.
|
|
83
|
+
private class ImageEnd(
|
|
84
|
+
val end: FlightEnd,
|
|
85
|
+
val image: FloatArray,
|
|
86
|
+
val radius: Float,
|
|
87
|
+
val alpha: Float,
|
|
88
|
+
val visible: VisiblePart,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
companion object {
|
|
92
|
+
private const val RECT = 4
|
|
93
|
+
|
|
94
|
+
// How far from its parent's size an image still fills it, in pixels.
|
|
95
|
+
private const val FILLS = 1
|
|
96
|
+
private const val HIDDEN = "hidden"
|
|
97
|
+
|
|
98
|
+
// How far the proportions of two images may differ for one to stand for the other, in parts of one.
|
|
99
|
+
private const val SAME_ASPECT = 0.02f
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The morph of [from] into [to] in [layer], each cut by its parents up to the view of its screen ([fromRoot],
|
|
103
|
+
* [toRoot]); none when an image isn't there to fit, the images differ in proportions, or a view draws more
|
|
104
|
+
* than its image.
|
|
105
|
+
*/
|
|
106
|
+
fun of(from: ImageView, to: ImageView, fromRoot: View?, toRoot: View?, layer: View): ImageMorph? {
|
|
107
|
+
if (!onlyImage(from) || !onlyImage(to)) return null
|
|
108
|
+
val image = to.drawable ?: return null
|
|
109
|
+
val drawn = drawnRect(to) ?: return null
|
|
110
|
+
val fromDrawn = drawnRect(from) ?: return null
|
|
111
|
+
if (!sameAspect(fromDrawn.width(), fromDrawn.height(), drawn.width(), drawn.height())) return null
|
|
112
|
+
val start = endOf(from, layer, fromRoot) ?: return null
|
|
113
|
+
val end = endOf(to, layer, toRoot) ?: return null
|
|
114
|
+
return ImageMorph(start, end, image, drawn)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Whether an image of [width] × [height] has the proportions of one of [otherWidth] × [otherHeight]. */
|
|
118
|
+
internal fun sameAspect(width: Float, height: Float, otherWidth: Float, otherHeight: Float): Boolean {
|
|
119
|
+
if (width <= 0f || height <= 0f || otherWidth <= 0f || otherHeight <= 0f) return false
|
|
120
|
+
val aspect = width / height
|
|
121
|
+
val other = otherWidth / otherHeight
|
|
122
|
+
return abs(aspect - other) <= SAME_ASPECT * other
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// The view draws nothing but its image: no background color, no border (React Native draws them as the
|
|
126
|
+
// view's background, around the image).
|
|
127
|
+
private fun onlyImage(view: View): Boolean = try {
|
|
128
|
+
val background = BackgroundStyleApplicator.getBackgroundColor(view)
|
|
129
|
+
(background == null || Color.alpha(background) == 0) && LogicalEdge.entries.none {
|
|
130
|
+
(BackgroundStyleApplicator.getBorderWidth(view, it) ?: 0f) > 0f
|
|
131
|
+
}
|
|
132
|
+
} catch (e: RuntimeException) {
|
|
133
|
+
false
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private fun endOf(view: ImageView, layer: View, root: View?): ImageEnd? {
|
|
137
|
+
if (view.width <= 0 || view.height <= 0) return null
|
|
138
|
+
val shown = shownRect(view) ?: return null
|
|
139
|
+
val place = LayerPlace.of(view, layer, root)
|
|
140
|
+
val end = place.end(view.width, view.height)
|
|
141
|
+
val image = imageFromCenter(
|
|
142
|
+
floatArrayOf(shown.left, shown.top, shown.right, shown.bottom),
|
|
143
|
+
view.width, view.height, end.width, end.height,
|
|
144
|
+
)
|
|
145
|
+
val radius = cornerRadius(view)
|
|
146
|
+
return ImageEnd(
|
|
147
|
+
end, image, radius * end.scale, view.alpha, place.visible(view.width, view.height, radius),
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Where the drawable draws the image when the view draws it: Fresco's image where its fit puts it in the
|
|
152
|
+
// drawable, another image at its drawable's bounds (the view's matrix comes on top).
|
|
153
|
+
private fun drawnRect(view: ImageView): RectF? {
|
|
154
|
+
val rect = if (view is ReactImageView) {
|
|
155
|
+
if (!view.hasHierarchy()) return null
|
|
156
|
+
RectF().also { view.hierarchy.getActualImageBounds(it) }
|
|
157
|
+
} else {
|
|
158
|
+
RectF(view.drawable?.bounds ?: return null)
|
|
159
|
+
}
|
|
160
|
+
return rect.takeUnless { it.isEmpty }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Where the image shows in the view, in its pixels.
|
|
164
|
+
private fun shownRect(view: ImageView): RectF? {
|
|
165
|
+
val rect = drawnRect(view) ?: return null
|
|
166
|
+
if (view !is ReactImageView) view.imageMatrix.mapRect(rect)
|
|
167
|
+
rect.offset(view.paddingLeft.toFloat(), view.paddingTop.toFloat())
|
|
168
|
+
return rect
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private fun cornerRadius(view: ImageView): Float {
|
|
172
|
+
view.borderRadius.takeIf { it > 0f }?.let { return it }
|
|
173
|
+
val parent = view.parent as? ReactViewGroup ?: return 0f
|
|
174
|
+
val fills = abs(parent.width - view.width) <= FILLS && abs(parent.height - view.height) <= FILLS
|
|
175
|
+
return if (fills && parent.overflow == HIDDEN) parent.borderRadius else 0f
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The rect [shown] (left, top, right, bottom) of a view of [width] × [height], from the view's center, at the
|
|
180
|
+
* size [shownWidth] × [shownHeight] the view is drawn at.
|
|
181
|
+
*/
|
|
182
|
+
internal fun imageFromCenter(
|
|
183
|
+
shown: FloatArray,
|
|
184
|
+
width: Int,
|
|
185
|
+
height: Int,
|
|
186
|
+
shownWidth: Float,
|
|
187
|
+
shownHeight: Float,
|
|
188
|
+
): FloatArray {
|
|
189
|
+
val scaleX = shownWidth / width
|
|
190
|
+
val scaleY = shownHeight / height
|
|
191
|
+
return floatArrayOf(
|
|
192
|
+
(shown[0] - width / 2f) * scaleX,
|
|
193
|
+
(shown[1] - height / 2f) * scaleY,
|
|
194
|
+
(shown[2] - width / 2f) * scaleX,
|
|
195
|
+
(shown[3] - height / 2f) * scaleY,
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|