@apexnative/navigation 1.0.0-alpha.6 → 1.0.0-alpha.8
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 +15 -0
- package/android/CLAUDE.md +19 -10
- package/android/CORE.md +3 -2
- package/android/consumer-rules.pro +6 -0
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
- 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 +4 -0
- 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/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/viewcontrollers/modal/ModalSheet.kt +329 -55
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +26 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +60 -2
- 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/StackController.kt +46 -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 +7 -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 +86 -39
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +124 -181
- 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 +56 -3
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +170 -153
- 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 -45
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/{TextChangeAnimator.kt → TextMorph.kt} +79 -129
- 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 +43 -4
- package/docs-md/flows/bottom-sheets.md +4 -2
- package/docs-md/fundamentals/screens-and-props.md +9 -1
- package/docs-md/guides/cli.md +3 -1
- package/docs-md/help/troubleshooting.md +1 -1
- package/docs-md/index.json +29 -1
- package/docs-md/screen-ui/back-and-gestures.md +3 -1
- package/docs-md/screen-ui/bar-buttons.md +1 -1
- package/docs-md/screen-ui/toolbar-and-fab.md +2 -0
- package/docs-md/start/installation.md +16 -1
- package/ios/Animations/ANNFrameDriver.h +55 -15
- package/ios/Animations/ANNFrameDriver.mm +214 -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 +181 -43
- package/ios/Animations/Interpolators/ANNViewTracks.h +6 -5
- package/ios/Animations/Interpolators/ANNViewTracks.mm +51 -21
- package/ios/CLAUDE.md +19 -8
- package/ios/CORE.md +1 -1
- package/ios/Core/ANNAppDelegate.mm +0 -2
- package/ios/Core/ANNDeepLinkQueue.h +6 -5
- package/ios/Core/ANNDeepLinkQueue.mm +22 -10
- package/ios/Core/ANNSceneDelegate.mm +2 -2
- package/ios/Core/ANNUtils.h +7 -0
- package/ios/Core/ANNUtils.mm +10 -0
- package/ios/Core/ApexNavigation.mm +6 -2
- package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +1 -7
- package/ios/Layouts/Root/ANNRootCoordinator.mm +45 -15
- package/ios/Layouts/Screen/ANNComponentViewController.mm +4 -1
- 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/ANNTabsPreloadWindow.mm +2 -4
- package/ios/Options/ANNAnimationOptions.h +2 -1
- package/ios/Options/ANNAnimationOptions.mm +1 -1
- package/ios/Options/ANNOptions.h +7 -0
- package/ios/Options/ANNOptions.mm +45 -0
- package/ios/Options/ANNOptionsReader.mm +2 -4
- package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
- package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
- package/ios/Options/Params/ColorParser.h +4 -3
- package/ios/Options/Params/ColorParser.mm +22 -4
- package/ios/React/ANNSurfaceHostingView.h +8 -0
- package/ios/React/ANNSurfaceHostingView.mm +28 -1
- package/ios/React/Slots/ANNSlotHost.mm +1 -3
- package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
- package/ios/TurboModules/ANNTurboModule.mm +46 -0
- 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 +9 -3
- 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/linking/linking.js +11 -0
- package/lib/module/api/linking/linking.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 +21 -1
- 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 +26 -0
- 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 +5 -0
- 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/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/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 +7 -0
- 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 +40 -15
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +2 -2
- package/lib/typescript/interfaces/options/buttons.d.ts +2 -2
- 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/topBar.d.ts +14 -0
- 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 +9 -3
- package/src/adapters/NativeANNTurboModule.ts +7 -0
- package/src/api/app/AppRegistry.ts +16 -2
- package/src/api/app/createNavigation.ts +198 -66
- package/src/api/events/navigationEvents.ts +9 -3
- package/src/api/index.ts +1 -0
- package/src/api/linking/linking.ts +22 -1
- 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 +21 -0
- 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 +24 -0
- package/src/interfaces/ComponentEvents.ts +2 -2
- package/src/interfaces/options/animations.ts +40 -15
- package/src/interfaces/options/bottomTabs.ts +2 -2
- package/src/interfaces/options/buttons.ts +2 -2
- package/src/interfaces/options/modals.ts +6 -7
- package/src/interfaces/options/stack.ts +8 -3
- package/src/interfaces/options/topBar.ts +14 -0
- 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 -134
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -78
- 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 -57
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -146
package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt
DELETED
|
@@ -1,78 +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 where `from` is drawn to where it is drawn in its screen
|
|
15
|
-
* ([FlightGeometry]); its size and corner radius by an outline that grows from `from`'s (at the scale it is drawn at)
|
|
16
|
-
* to its own while it is laid out at the larger of the two sizes, unscaled and turned about the outline's middle; its
|
|
17
|
-
* own radius taken off meanwhile and put back as it was; its background color from `from`'s to its own in Lab, ending
|
|
18
|
-
* exactly on its own (`BackgroundStyleApplicator`). Main thread only.
|
|
19
|
-
*/
|
|
20
|
-
internal class PlainViewAnimator(
|
|
21
|
-
private val from: View,
|
|
22
|
-
private val to: View,
|
|
23
|
-
/** Where [to] was in its screen: what it flies to. */
|
|
24
|
-
private val toStandIn: View?,
|
|
25
|
-
private val layer: TransitionLayer,
|
|
26
|
-
) {
|
|
27
|
-
/** The animator; none when [to] has no place in the layer. */
|
|
28
|
-
fun create(): Animator? {
|
|
29
|
-
val geometry = FlightGeometry.of(from, to, toStandIn, layer) ?: return null
|
|
30
|
-
val fromRadius = from.borderRadius * geometry.from.scale
|
|
31
|
-
val toRadius = to.borderRadius * geometry.to.scale
|
|
32
|
-
val fromColor = BackgroundStyleApplicator.getBackgroundColor(from)
|
|
33
|
-
val toColor = BackgroundStyleApplicator.getBackgroundColor(to)
|
|
34
|
-
val ownRadius = BackgroundStyleApplicator.getBorderRadius(to, RADIUS)
|
|
35
|
-
val outline = FlightOutline()
|
|
36
|
-
val moved = MovedProperties(to)
|
|
37
|
-
var savedProvider: ViewOutlineProvider? = null
|
|
38
|
-
var savedClip = false
|
|
39
|
-
val (width, height) = geometry.largest
|
|
40
|
-
return MoveAnimator().apply {
|
|
41
|
-
fun frame(time: Float) {
|
|
42
|
-
val f = curve.getInterpolation(time)
|
|
43
|
-
val at = geometry.at(f, time)
|
|
44
|
-
outline.width = at.width.roundToInt()
|
|
45
|
-
outline.height = at.height.roundToInt()
|
|
46
|
-
outline.radius = ValueInterpolation.number(fromRadius, toRadius, f, time)
|
|
47
|
-
moved.show(geometry, at, outline.width, outline.height)
|
|
48
|
-
to.invalidateOutline()
|
|
49
|
-
if (fromColor != toColor) {
|
|
50
|
-
val color = ValueInterpolation.color(fromColor, toColor, f, time)
|
|
51
|
-
BackgroundStyleApplicator.setBackgroundColor(to, color)
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
onStart {
|
|
55
|
-
savedProvider = to.outlineProvider
|
|
56
|
-
savedClip = to.clipToOutline
|
|
57
|
-
if (ownRadius != null) BackgroundStyleApplicator.setBorderRadius(to, RADIUS, null)
|
|
58
|
-
to.outlineProvider = outline
|
|
59
|
-
to.clipToOutline = true
|
|
60
|
-
layer.place(to, geometry.toLeft, geometry.toTop, width, height)
|
|
61
|
-
frame(0f)
|
|
62
|
-
}
|
|
63
|
-
onFrame { frame(it) }
|
|
64
|
-
// A cancelled flight ends too: the view goes back whole.
|
|
65
|
-
onEnd {
|
|
66
|
-
if (fromColor != toColor) BackgroundStyleApplicator.setBackgroundColor(to, toColor)
|
|
67
|
-
if (ownRadius != null) BackgroundStyleApplicator.setBorderRadius(to, RADIUS, ownRadius)
|
|
68
|
-
to.outlineProvider = savedProvider
|
|
69
|
-
to.clipToOutline = savedClip
|
|
70
|
-
moved.end(geometry, landed) { w, h -> layer.place(to, geometry.toLeft, geometry.toTop, w, h) }
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
private companion object {
|
|
76
|
-
val RADIUS = BorderRadiusProp.BORDER_RADIUS
|
|
77
|
-
}
|
|
78
|
-
}
|
|
@@ -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,57 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.views.element.animators
|
|
2
|
-
|
|
3
|
-
import android.animation.Animator
|
|
4
|
-
import android.view.View
|
|
5
|
-
import com.facebook.drawee.drawable.ScalingUtils
|
|
6
|
-
import com.facebook.react.views.image.ReactImageView
|
|
7
|
-
import dev.apexnative.navigation.views.element.TransitionLayer
|
|
8
|
-
import kotlin.math.roundToInt
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* A shared React image: from where `from` is drawn to where it is drawn in its screen ([FlightGeometry]), laid out at
|
|
12
|
-
* the size of each frame, unscaled and turned about its middle; its content by Fresco's scale type going from `from`'s
|
|
13
|
-
* fit to its own (`ScalingUtils.InterpolatingScaleType`); Fresco's own fade off meanwhile. Everything goes back as it
|
|
14
|
-
* was at the end. Main thread only.
|
|
15
|
-
*/
|
|
16
|
-
internal class ReactImageAnimator(
|
|
17
|
-
private val from: ReactImageView,
|
|
18
|
-
private val to: ReactImageView,
|
|
19
|
-
/** Where [to] was in its screen: what it flies to. */
|
|
20
|
-
private val toStandIn: View?,
|
|
21
|
-
private val layer: TransitionLayer,
|
|
22
|
-
) {
|
|
23
|
-
/** The animator; none when [to] has no place in the layer or no hierarchy. */
|
|
24
|
-
fun create(): Animator? {
|
|
25
|
-
if (!from.hasHierarchy() || !to.hasHierarchy()) return null
|
|
26
|
-
val geometry = FlightGeometry.of(from, to, toStandIn, layer) ?: return null
|
|
27
|
-
val toType = to.hierarchy.actualImageScaleType ?: ScalingUtils.ScaleType.CENTER_CROP
|
|
28
|
-
val fromType = from.hierarchy.actualImageScaleType ?: ScalingUtils.ScaleType.CENTER_CROP
|
|
29
|
-
val scale = ScalingUtils.InterpolatingScaleType(fromType, toType)
|
|
30
|
-
val moved = MovedProperties(to)
|
|
31
|
-
var savedFade = 0
|
|
32
|
-
return MoveAnimator().apply {
|
|
33
|
-
fun frame(time: Float) {
|
|
34
|
-
val f = curve.getInterpolation(time)
|
|
35
|
-
val at = geometry.at(f, time)
|
|
36
|
-
val width = at.width.roundToInt()
|
|
37
|
-
val height = at.height.roundToInt()
|
|
38
|
-
layer.place(to, geometry.toLeft, geometry.toTop, width, height)
|
|
39
|
-
moved.show(geometry, at, width, height)
|
|
40
|
-
scale.setValue(if (time >= 1f) 1f else f)
|
|
41
|
-
to.invalidate()
|
|
42
|
-
}
|
|
43
|
-
onStart {
|
|
44
|
-
savedFade = to.hierarchy.fadeDuration
|
|
45
|
-
to.hierarchy.fadeDuration = 0
|
|
46
|
-
to.hierarchy.setActualImageScaleType(scale)
|
|
47
|
-
frame(0f)
|
|
48
|
-
}
|
|
49
|
-
onFrame { frame(it) }
|
|
50
|
-
onEnd {
|
|
51
|
-
to.hierarchy.setActualImageScaleType(toType)
|
|
52
|
-
to.hierarchy.fadeDuration = savedFade
|
|
53
|
-
moved.end(geometry, landed) { w, h -> layer.place(to, geometry.toLeft, geometry.toTop, w, h) }
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
@@ -1,146 +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.borderRadius
|
|
18
|
-
import kotlin.math.roundToInt
|
|
19
|
-
|
|
20
|
-
// A view with children moves as two pictures of itself, as on iOS: of the view that goes away and of the one that
|
|
21
|
-
// comes, each with its children. The copy goes from where the one is drawn — its center, its size at the scale it is
|
|
22
|
-
// drawn at, its angle and corner radius — to where the other is drawn in its screen (FlightGeometry), the angle along
|
|
23
|
-
// the shorter arc; both pictures fill it, and the picture of the destination shows over the other on the way. The
|
|
24
|
-
// pictures are drawing commands: an avatar's letter grows sharp. They are drawn in the overlay of the transition layer
|
|
25
|
-
// while `to` is hidden, and nothing else moves the pair. A view without children moves itself, its outline growing, as
|
|
26
|
-
// before.
|
|
27
|
-
class ViewChangeAnimator internal constructor(
|
|
28
|
-
from: View,
|
|
29
|
-
to: View,
|
|
30
|
-
// Where `to` was in its screen: what the copy flies to.
|
|
31
|
-
private val toStandIn: View?,
|
|
32
|
-
) : PropertyAnimatorCreator<ReactViewGroup>(from, to, ReactViewGroup::class.java) {
|
|
33
|
-
private val pictures by lazy { pictures() }
|
|
34
|
-
|
|
35
|
-
override fun shouldAnimateProperty(fromChild: ReactViewGroup, toChild: ReactViewGroup): Boolean =
|
|
36
|
-
(fromChild.childCount > 0 || toChild.childCount > 0) && pictures != null
|
|
37
|
-
|
|
38
|
-
override fun create(options: SharedElementTransitionOptions): Animator {
|
|
39
|
-
val (start, end) = checkNotNull(pictures)
|
|
40
|
-
val layer = to.parent as ViewGroup
|
|
41
|
-
val drawable = ViewMorphDrawable(start, end)
|
|
42
|
-
// Everything changes between the start and the end of the animation: a cancelled one ends too.
|
|
43
|
-
return MoveAnimator().apply {
|
|
44
|
-
onStart {
|
|
45
|
-
drawable.setBounds(0, 0, layer.width, layer.height)
|
|
46
|
-
layer.overlay.add(drawable)
|
|
47
|
-
to.alpha = 0f
|
|
48
|
-
}
|
|
49
|
-
onFrame {
|
|
50
|
-
drawable.update(it, curve.getInterpolation(it))
|
|
51
|
-
layer.invalidate()
|
|
52
|
-
}
|
|
53
|
-
// A flight that landed where `to` shows only in its screen keeps its last picture: the transition takes the
|
|
54
|
-
// layer away with it and shows `to` in its place.
|
|
55
|
-
val holds = FlightEnd.holdsAtEnd(to, toStandIn, layer)
|
|
56
|
-
onEnd {
|
|
57
|
-
if (!holds || !landed) {
|
|
58
|
-
layer.overlay.remove(drawable)
|
|
59
|
-
layer.invalidate()
|
|
60
|
-
to.alpha = end.alpha
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// `to` is in the transition layer already: the pictures are drawn in its coordinates. `from` is where it is drawn
|
|
67
|
-
// on the screen, `to` where it is drawn once back in its screen.
|
|
68
|
-
private fun pictures(): Pair<ViewPicture, ViewPicture>? {
|
|
69
|
-
val layer = to.parent as? ViewGroup ?: return null
|
|
70
|
-
val start = ViewPicture.of(from as ReactViewGroup, LayerPlace.of(from, layer)) ?: return null
|
|
71
|
-
val end = ViewPicture.of(to as ReactViewGroup, LayerPlace.of(to, layer, toStandIn)) ?: return null
|
|
72
|
-
return start to end
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// A view's picture, where it is drawn in the transition layer, its corner radius there and its opacity.
|
|
77
|
-
private class ViewPicture(val picture: Picture, val end: FlightEnd, val radius: Float, val alpha: Float) {
|
|
78
|
-
companion object {
|
|
79
|
-
fun of(view: ReactViewGroup, place: LayerPlace): ViewPicture? {
|
|
80
|
-
if (view.width <= 0 || view.height <= 0) return null
|
|
81
|
-
val picture = recordPicture(view) ?: return null
|
|
82
|
-
val end = place.end(view.width, view.height)
|
|
83
|
-
return ViewPicture(picture, end, view.borderRadius * end.scale, view.alpha)
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// The copy where the move has brought it: its center, size, angle and corner radius go from the start to the end along
|
|
89
|
-
// the transition's curve, and so does the picture of the end over the picture of the start.
|
|
90
|
-
private class ViewMorphDrawable(private val start: ViewPicture, private val end: ViewPicture) : Drawable() {
|
|
91
|
-
private val flight = FlightGeometry(start.end, end.end, 0, 0)
|
|
92
|
-
private var at = start.end
|
|
93
|
-
private var progress = 0f
|
|
94
|
-
private val rect = RectF()
|
|
95
|
-
private val maskPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
|
96
|
-
// What is drawn over the mask keeps only the mask's pixels: the corners stay smooth (a clip path on the hardware
|
|
97
|
-
// canvas is not anti-aliased).
|
|
98
|
-
private val contentPaint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) }
|
|
99
|
-
|
|
100
|
-
/** The copy at [time] (the part of the time), [progress] the curve's value. */
|
|
101
|
-
fun update(time: Float, progress: Float) {
|
|
102
|
-
this.progress = progress
|
|
103
|
-
at = flight.at(progress, time)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
override fun draw(canvas: Canvas) {
|
|
107
|
-
rect.set(-at.width / 2, -at.height / 2, at.width / 2, at.height / 2)
|
|
108
|
-
if (rect.isEmpty) return
|
|
109
|
-
val radius = lerp(start.radius, end.radius)
|
|
110
|
-
// The copy turns about its center, mirrored where a view is.
|
|
111
|
-
val count = canvas.save()
|
|
112
|
-
canvas.translate(at.centerX, at.centerY)
|
|
113
|
-
canvas.rotate(at.rotation)
|
|
114
|
-
canvas.scale(at.mirrorX, at.mirrorY)
|
|
115
|
-
canvas.saveLayer(rect, null)
|
|
116
|
-
canvas.drawRoundRect(rect, radius, radius, maskPaint)
|
|
117
|
-
canvas.saveLayer(rect, contentPaint)
|
|
118
|
-
draw(canvas, start, start.alpha)
|
|
119
|
-
draw(canvas, end, end.alpha * progress)
|
|
120
|
-
canvas.restoreToCount(count)
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// A picture fills the copy, as on iOS.
|
|
124
|
-
private fun draw(canvas: Canvas, view: ViewPicture, shown: Float) {
|
|
125
|
-
val alpha = (shown * 255).roundToInt().coerceIn(0, 255)
|
|
126
|
-
if (alpha == 0) return
|
|
127
|
-
val width = view.picture.width.toFloat()
|
|
128
|
-
val height = view.picture.height.toFloat()
|
|
129
|
-
val count = canvas.save()
|
|
130
|
-
canvas.translate(rect.left, rect.top)
|
|
131
|
-
canvas.scale(rect.width() / width, rect.height() / height)
|
|
132
|
-
// The picture fades as a whole: its children and background don't show through each other.
|
|
133
|
-
if (alpha < 255) canvas.saveLayerAlpha(0f, 0f, width, height, alpha)
|
|
134
|
-
canvas.drawPicture(view.picture)
|
|
135
|
-
canvas.restoreToCount(count)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
private fun lerp(from: Float, to: Float) = from + (to - from) * progress
|
|
139
|
-
|
|
140
|
-
override fun setAlpha(alpha: Int) = Unit
|
|
141
|
-
|
|
142
|
-
override fun setColorFilter(colorFilter: ColorFilter?) = Unit
|
|
143
|
-
|
|
144
|
-
@Deprecated("Deprecated in Java")
|
|
145
|
-
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
|
|
146
|
-
}
|