@apexnative/navigation 1.0.0-alpha.6 → 1.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ApexNavigation.podspec +2 -1
- package/CHANGELOG.md +7 -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 +36 -38
- 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 +15 -7
- 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/ApexNavigation.mm +6 -2
- 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/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/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 +172 -35
- package/lib/module/api/screens/registerScreens.js.map +1 -1
- package/lib/module/api/theme/theme.js +5 -0
- package/lib/module/api/theme/theme.js.map +1 -1
- package/lib/module/engine/commands.js +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 +170 -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
|
@@ -7,17 +7,13 @@ import android.app.Activity
|
|
|
7
7
|
import android.content.Context
|
|
8
8
|
import android.content.pm.ApplicationInfo
|
|
9
9
|
import android.graphics.Color
|
|
10
|
-
import android.graphics.drawable.BitmapDrawable
|
|
11
10
|
import android.graphics.drawable.Drawable
|
|
12
|
-
import android.view.Menu
|
|
13
|
-
import android.view.MenuItem
|
|
14
11
|
import android.view.MotionEvent
|
|
15
12
|
import android.view.View
|
|
16
13
|
import android.view.ViewGroup
|
|
17
14
|
import android.view.animation.LinearInterpolator
|
|
18
15
|
import android.view.animation.PathInterpolator
|
|
19
16
|
import android.widget.FrameLayout
|
|
20
|
-
import android.widget.ImageView
|
|
21
17
|
import androidx.appcompat.content.res.AppCompatResources
|
|
22
18
|
import androidx.core.graphics.drawable.DrawableCompat
|
|
23
19
|
import androidx.core.view.WindowInsetsCompat
|
|
@@ -59,6 +55,7 @@ import dev.apexnative.navigation.views.stack.topbar.TitleBar
|
|
|
59
55
|
import dev.apexnative.navigation.views.stack.topbar.TopBar
|
|
60
56
|
import dev.apexnative.navigation.views.stack.topbar.TopBarDefaults
|
|
61
57
|
import dev.apexnative.navigation.views.stack.topbar.titlebar.BarButtonComponentCell
|
|
58
|
+
import dev.apexnative.navigation.views.stack.topbar.titlebar.BarMenu
|
|
62
59
|
import dev.apexnative.navigation.views.stack.topbar.titlebar.ButtonBar
|
|
63
60
|
import dev.apexnative.navigation.views.stack.topbar.titlebar.IconBackgroundDrawable
|
|
64
61
|
import kotlin.math.roundToInt
|
|
@@ -142,8 +139,8 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
142
139
|
this.layout = layout
|
|
143
140
|
val bar = layout.topBar
|
|
144
141
|
this.bar = bar
|
|
145
|
-
leftButtons = ButtonBar(bar.leftButtonBar,
|
|
146
|
-
rightButtons = ButtonBar(bar.rightButtonBar,
|
|
142
|
+
leftButtons = ButtonBar(bar.leftButtonBar, ::loadIcon, Buttons())
|
|
143
|
+
rightButtons = ButtonBar(bar.rightButtonBar, ::loadIcon, Buttons())
|
|
147
144
|
visibility = TopBarVisibility(VisibilityTarget(bar) { collapse?.reset() })
|
|
148
145
|
rowTransition = BarRowTransition(RowTarget(bar).also { rowTarget = it })
|
|
149
146
|
collapse = TopBarCollapseBehavior(bar)
|
|
@@ -212,8 +209,8 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
212
209
|
* bar as it is goes with [leaving], and the bar, which takes [incoming]'s options next, is drawn flat as [incoming]
|
|
213
210
|
* moves — under [leaving] on a pop ([StackDisplay.BarTravel.Back]) (`StackLayout.barTravels`). No picture when the
|
|
214
211
|
* bar doesn't show. Nothing travels when the new top hides the bar by a side of its own
|
|
215
|
-
* (`animations.*.topBar.exit`), which plays instead, or when the bar can't be
|
|
216
|
-
*
|
|
212
|
+
* (`animations.*.topBar.exit`), which plays instead, or when the bar can't be recorded (a `HARDWARE` bitmap in it
|
|
213
|
+
* on Android 8): the bar takes the options in its place.
|
|
217
214
|
*/
|
|
218
215
|
private fun beginTravel(
|
|
219
216
|
bar: TopBar,
|
|
@@ -238,10 +235,10 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
238
235
|
|
|
239
236
|
// The bar's picture where the bar is in the stack, its moves counted.
|
|
240
237
|
private fun pictureOfBar(bar: TopBar): Drawable? {
|
|
241
|
-
val
|
|
238
|
+
val picture = bar.picture() ?: return null
|
|
242
239
|
val left = (bar.left + bar.translationX).roundToInt()
|
|
243
240
|
val top = (bar.top + bar.translationY).roundToInt()
|
|
244
|
-
return
|
|
241
|
+
return picture.apply { setBounds(left, top, left + intrinsicWidth, top + intrinsicHeight) }
|
|
245
242
|
}
|
|
246
243
|
|
|
247
244
|
// The bar's travel ends: the picture goes, the bar is drawn in its place again with its shadow.
|
|
@@ -284,6 +281,8 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
284
281
|
val bar = bar ?: return
|
|
285
282
|
val screen = host.optionsScreen(entry)
|
|
286
283
|
if (screen !== shownScreen) return apply(entry)
|
|
284
|
+
// An open menu has the colors of before.
|
|
285
|
+
if (delta.topBar.menuBackgroundColor.hasValue() || delta.topBar.menuTextColor.hasValue()) closeMenus()
|
|
287
286
|
val options = host.resolvedOf(entry)
|
|
288
287
|
applyAll(bar, entry, screen, options, merge = true, delta = delta)
|
|
289
288
|
}
|
|
@@ -293,6 +292,8 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
293
292
|
* now.
|
|
294
293
|
*/
|
|
295
294
|
fun repaint(entry: ViewController<*>?) {
|
|
295
|
+
// An open menu has the old colors: it closes.
|
|
296
|
+
closeMenus()
|
|
296
297
|
keys.clear()
|
|
297
298
|
apply(entry)
|
|
298
299
|
val options = entry?.let(host::resolvedOf) ?: return
|
|
@@ -582,16 +583,15 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
582
583
|
keys[Part.Left] = leftKey
|
|
583
584
|
reportWithoutId(topBar.buttons.left, "leftButtons")
|
|
584
585
|
leftButtons?.set(
|
|
585
|
-
left.map { button(screen, it, roots) },
|
|
586
|
+
ButtonPlaces.line(left, left = true).map { button(screen, it, roots) },
|
|
586
587
|
emptyList(),
|
|
587
588
|
null,
|
|
588
589
|
merge && topBar.animateLeftButtons.isTrue,
|
|
589
590
|
)
|
|
590
591
|
}
|
|
591
592
|
val overflow = topBar.overflowMenu?.takeIf { it.items.isNotEmpty() }
|
|
592
|
-
val menu = bar.rightButtonBar.menu
|
|
593
593
|
search.applyMagnifier()
|
|
594
|
-
val taken =
|
|
594
|
+
val taken = if (bar.rightButtonBar.trailingView != null) 1 else 0
|
|
595
595
|
val configuration = context.resources.configuration
|
|
596
596
|
val plan = ButtonPlaces.plan(
|
|
597
597
|
right.map { ButtonPlaces.Button(ButtonPlaces.priorityOf(it.priority.get(null)), it.pinned.isTrue) },
|
|
@@ -612,12 +612,11 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
612
612
|
keys[Part.Right] = rightKey
|
|
613
613
|
reportWithoutId(topBar.buttons.right, "rightButtons")
|
|
614
614
|
rightButtons?.set(
|
|
615
|
-
plan.inBar.map { button(screen, right[it], roots) },
|
|
615
|
+
ButtonPlaces.line(plan.inBar, left = false).map { button(screen, right[it], roots) },
|
|
616
616
|
plan.inOverflow.map { button(screen, right[it], roots) },
|
|
617
617
|
overflow,
|
|
618
618
|
merge && topBar.animateRightButtons.isTrue,
|
|
619
619
|
)
|
|
620
|
-
search.applyMagnifier()
|
|
621
620
|
rightButtons?.setOverflowColor(overflowColor)
|
|
622
621
|
}
|
|
623
622
|
}
|
|
@@ -639,9 +638,9 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
639
638
|
).joinToString()
|
|
640
639
|
if (keys[Part.Back] == key) return
|
|
641
640
|
keys[Part.Back] = key
|
|
642
|
-
val
|
|
641
|
+
val row = bar.leftButtonBar
|
|
643
642
|
if (!shown) {
|
|
644
|
-
|
|
643
|
+
row.navigationIcon = null
|
|
645
644
|
return
|
|
646
645
|
}
|
|
647
646
|
val own = back.icon.get(null)?.let(::loadIcon)?.mutate()
|
|
@@ -668,19 +667,13 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
668
667
|
dp(background.height.get(0.0)),
|
|
669
668
|
)
|
|
670
669
|
} ?: icon
|
|
671
|
-
|
|
672
|
-
// Taking the icon, the
|
|
673
|
-
//
|
|
674
|
-
// gets the bar's direction at once
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
toolbar.navigationContentDescription = label
|
|
679
|
-
// The toolbar uses its navigation button again from screen to screen: its id is set every time.
|
|
680
|
-
for (index in 0 until toolbar.childCount) {
|
|
681
|
-
val child = toolbar.getChildAt(index)
|
|
682
|
-
if ((child as? ImageView)?.drawable === held) TestIds.apply(child, testId)
|
|
683
|
-
}
|
|
670
|
+
row.navigationIcon = drawable
|
|
671
|
+
// Taking the icon, the back button gives it its own direction, which is stale while the button is new or the
|
|
672
|
+
// bar's direction has just changed; the button corrects it only once its direction is resolved again. So the
|
|
673
|
+
// arrow gets the bar's direction at once; a background passes it to the arrow.
|
|
674
|
+
DrawableCompat.setLayoutDirection(drawable, arrowDirection)
|
|
675
|
+
row.navigationContentDescription = label
|
|
676
|
+
row.navigationButton?.let { TestIds.apply(it, testId) }
|
|
684
677
|
}
|
|
685
678
|
|
|
686
679
|
// The background (`topBar.background.component`).
|
|
@@ -719,15 +712,14 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
719
712
|
|
|
720
713
|
private fun pictureUnderRow(bar: TopBar, leaving: ViewController<*>) {
|
|
721
714
|
val view = leaving.peekView() ?: return
|
|
722
|
-
val (
|
|
715
|
+
val (picture, top) = bar.pictureUnderRow() ?: return
|
|
723
716
|
val barPlace = IntArray(2)
|
|
724
717
|
val viewPlace = IntArray(2)
|
|
725
718
|
bar.getLocationInWindow(barPlace)
|
|
726
719
|
view.getLocationInWindow(viewPlace)
|
|
727
|
-
val picture = BitmapDrawable(bar.resources, bitmap)
|
|
728
720
|
val left = barPlace[0] - viewPlace[0]
|
|
729
721
|
val y = barPlace[1] + top - viewPlace[1]
|
|
730
|
-
picture.setBounds(left, y, left +
|
|
722
|
+
picture.setBounds(left, y, left + picture.intrinsicWidth, y + picture.intrinsicHeight)
|
|
731
723
|
view.overlay.add(picture)
|
|
732
724
|
underRow = leaving to picture
|
|
733
725
|
}
|
|
@@ -1037,11 +1029,16 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
1037
1029
|
return (buttons.left.orEmpty() + buttons.right.orEmpty()).firstOrNull { it.id.get(null) == buttonId }?.menu
|
|
1038
1030
|
}
|
|
1039
1031
|
|
|
1040
|
-
//
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1032
|
+
// Read as a menu opens, so they follow light and dark mode: `menuBackgroundColor`, else the bar's color as it
|
|
1033
|
+
// shows (none when it lets something through), and then `menuTextColor` or else the title's color, the pair
|
|
1034
|
+
// the bar shows; with neither, the theme's.
|
|
1035
|
+
override fun menuColors(): BarMenu.Colors {
|
|
1036
|
+
val topBar = shownEntry?.let(host::resolvedOf)?.topBar ?: return BarMenu.Colors(null, null)
|
|
1037
|
+
val context = bar?.context ?: activity
|
|
1038
|
+
val text = topBar.menuTextColor.get(context, null)
|
|
1039
|
+
topBar.menuBackgroundColor.get(context, null)?.let { return BarMenu.Colors(it, text) }
|
|
1040
|
+
val barColor = bar?.barColor?.takeIf { Color.alpha(it) == OPAQUE } ?: return BarMenu.Colors(null, text)
|
|
1041
|
+
return BarMenu.Colors(barColor, text ?: topBar.title.color.get(context, null))
|
|
1045
1042
|
}
|
|
1046
1043
|
}
|
|
1047
1044
|
|
|
@@ -1183,6 +1180,7 @@ internal class TopBarPresenter(private val activity: Activity, private val host:
|
|
|
1183
1180
|
|
|
1184
1181
|
private companion object {
|
|
1185
1182
|
const val DEFAULT_HEIGHT_DP = 64.0
|
|
1183
|
+
const val OPAQUE = 255
|
|
1186
1184
|
const val DEFAULT_TITLE_SP = 22.0
|
|
1187
1185
|
const val DEFAULT_SUBTITLE_SP = 14.0
|
|
1188
1186
|
const val CENTER = "center"
|
|
@@ -2,150 +2,78 @@ package dev.apexnative.navigation.views.element
|
|
|
2
2
|
|
|
3
3
|
import android.animation.Animator
|
|
4
4
|
import android.animation.AnimatorListenerAdapter
|
|
5
|
-
import android.graphics.Rect
|
|
6
5
|
import android.os.Build
|
|
7
6
|
import android.util.Log
|
|
8
7
|
import android.view.View
|
|
9
8
|
import android.view.ViewGroup
|
|
10
|
-
import com.facebook.react.views.view.ReactViewGroup
|
|
11
9
|
import dev.apexnative.navigation.options.ElementTransitionOptions
|
|
12
10
|
import dev.apexnative.navigation.options.LayoutAnimation
|
|
13
11
|
import dev.apexnative.navigation.options.SharedElementTransitionOptions
|
|
14
12
|
import dev.apexnative.navigation.react.events.AppearanceDispatcher
|
|
15
13
|
import dev.apexnative.navigation.utils.DevelopmentLog
|
|
16
14
|
import dev.apexnative.navigation.utils.NavigationLog
|
|
15
|
+
import dev.apexnative.navigation.utils.SystemAnimations
|
|
17
16
|
import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
|
|
18
17
|
import dev.apexnative.navigation.views.animations.AnimationLayer
|
|
19
18
|
import dev.apexnative.navigation.views.animations.SideAnimator
|
|
20
19
|
import dev.apexnative.navigation.views.element.animators.SharedAnimatorFactory
|
|
20
|
+
import java.util.Collections
|
|
21
|
+
import java.util.WeakHashMap
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
|
-
* The elements of one transition: the element transitions and the
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
24
|
+
* The elements of one transition: the element transitions and the shared pairs found by their `nativeID` (depth first,
|
|
25
|
+
* the first match) in the whole view of the screen each side shows — an element in the screen that goes first, then in
|
|
26
|
+
* the one that comes; a pair's `fromId` in the screen that goes, its `toId` in the one that comes; each screen is
|
|
27
|
+
* walked once for all of them ([TransitionViews]). What isn't found, what another transition plays now and an image
|
|
28
|
+
* that isn't loaded is skipped; so is an element whose start fails ([elementStep]): it gets its values back at once and
|
|
29
|
+
* the rest plays. No view leaves its parent, as on iOS. An element plays where it is, in its screen: its properties
|
|
30
|
+
* animate about its center and it moves with its screen. A pair flies as a copy drawn in a [TransitionLayer] over the
|
|
31
|
+
* screens, the copies in the order their targets are drawn; its `to` is hidden from the start, its `from` from the
|
|
32
|
+
* start of its flight. [finish] gives every element the values of its properties read before, shows the pairs' views
|
|
33
|
+
* again and takes the layer away. Main thread only.
|
|
33
34
|
*/
|
|
34
|
-
internal class ElementTransition private constructor(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
val pivotSet: Boolean,
|
|
43
|
-
// Where its parent's origin is in the layer: what `x` and `y` are counted from.
|
|
44
|
-
val originX: Int,
|
|
45
|
-
val originY: Int,
|
|
46
|
-
)
|
|
35
|
+
internal class ElementTransition private constructor(
|
|
36
|
+
private val layer: TransitionLayer?,
|
|
37
|
+
// The views of the screens, as far as the parents that cut a pair's views count.
|
|
38
|
+
private val fromRoot: View?,
|
|
39
|
+
private val toRoot: View?,
|
|
40
|
+
) {
|
|
41
|
+
// An element playing where it is: what it was.
|
|
42
|
+
private class InPlace(val view: View, val values: FloatArray, val pivotSet: Boolean)
|
|
47
43
|
|
|
48
|
-
private val
|
|
49
|
-
private val
|
|
44
|
+
private val inPlace = ArrayList<InPlace>()
|
|
45
|
+
private val taken = ArrayList<View>()
|
|
46
|
+
// The views of the pairs hidden while their copies fly, with the alpha each had.
|
|
47
|
+
private val hidden = LinkedHashMap<View, Float>()
|
|
50
48
|
private var finished = false
|
|
51
49
|
|
|
52
50
|
/** The animators of the elements and of the shared elements, each with its own time. */
|
|
53
51
|
val animators = ArrayList<Animator>()
|
|
54
52
|
|
|
55
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Every element's values back, the pairs' views seen, the layer gone; at the end of the transition and at any stop.
|
|
55
|
+
* Once.
|
|
56
|
+
*/
|
|
56
57
|
fun finish() {
|
|
57
58
|
if (finished) return
|
|
58
59
|
finished = true
|
|
59
|
-
for ((view, alpha) in hidden) view
|
|
60
|
+
for ((view, alpha) in hidden) show(view, alpha)
|
|
60
61
|
hidden.clear()
|
|
61
|
-
// Each
|
|
62
|
-
for (item in
|
|
62
|
+
// Each element on its own: one that can't get its values back doesn't keep the others from theirs.
|
|
63
|
+
for (item in inPlace.asReversed()) {
|
|
63
64
|
try {
|
|
64
|
-
|
|
65
|
+
restore(item.view, item.values, item.pivotSet)
|
|
65
66
|
} catch (e: RuntimeException) {
|
|
66
|
-
Log.w(NavigationLog.TAG, "[ApexNavigation] An element of a transition couldn't
|
|
67
|
+
Log.w(NavigationLog.TAG, "[ApexNavigation] An element of a transition couldn't get its values back", e)
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
inPlace.clear()
|
|
71
|
+
playing -= taken.toSet()
|
|
72
|
+
taken.clear()
|
|
73
|
+
layer?.detach()
|
|
71
74
|
}
|
|
72
75
|
|
|
73
|
-
private fun
|
|
74
|
-
val parent = view.parent as? ViewGroup ?: return null
|
|
75
|
-
// A parent that clips its subviews keeps its own list of children, which a stub swapped in would leave
|
|
76
|
-
// behind: its element stays where it is.
|
|
77
|
-
if ((parent as? ReactViewGroup)?.removeClippedSubviews == true) return null
|
|
78
|
-
val index = parent.indexOfChild(view)
|
|
79
|
-
if (index < 0) return null
|
|
80
|
-
val onScreen = IntArray(2)
|
|
81
|
-
parent.getLocationOnScreen(onScreen)
|
|
82
|
-
val origin = layer.originOnScreen
|
|
83
|
-
val originX = onScreen[0] - parent.scrollX - origin.x
|
|
84
|
-
val originY = onScreen[1] - parent.scrollY - origin.y
|
|
85
|
-
val frame = Rect(view.left, view.top, view.right, view.bottom)
|
|
86
|
-
val params = view.layoutParams ?: ViewGroup.LayoutParams(view.width, view.height)
|
|
87
|
-
val pivotSet = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && view.isPivotSet
|
|
88
|
-
val values = floatArrayOf(
|
|
89
|
-
view.alpha, view.translationX, view.translationY, view.scaleX, view.scaleY, view.rotation,
|
|
90
|
-
view.rotationX, view.rotationY, view.pivotX, view.pivotY,
|
|
91
|
-
)
|
|
92
|
-
val stub = ElementStub(view.context, view)
|
|
93
|
-
try {
|
|
94
|
-
parent.removeViewAt(index)
|
|
95
|
-
parent.addView(stub, index, params)
|
|
96
|
-
stub.layout(frame.left, frame.top, frame.right, frame.bottom)
|
|
97
|
-
val left = originX + frame.left
|
|
98
|
-
val top = originY + frame.top
|
|
99
|
-
layer.put(view, left, top, frame.width(), frame.height())
|
|
100
|
-
} catch (e: RuntimeException) {
|
|
101
|
-
putBack(view, stub, parent, index, params, frame)
|
|
102
|
-
throw e
|
|
103
|
-
}
|
|
104
|
-
// Scale and rotations turn about the center.
|
|
105
|
-
view.pivotX = frame.width() / 2f
|
|
106
|
-
view.pivotY = frame.height() / 2f
|
|
107
|
-
return Moved(view, stub, params, frame, values, pivotSet, originX, originY).also { moved += it }
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// A move that failed half way undone: the view back at its index in its parent, the stub gone.
|
|
111
|
-
private fun putBack(
|
|
112
|
-
view: View,
|
|
113
|
-
stub: ElementStub,
|
|
114
|
-
parent: ViewGroup,
|
|
115
|
-
index: Int,
|
|
116
|
-
params: ViewGroup.LayoutParams,
|
|
117
|
-
frame: Rect,
|
|
118
|
-
) {
|
|
119
|
-
if (view.parent === layer) layer.removeView(view)
|
|
120
|
-
val stubIndex = parent.indexOfChild(stub)
|
|
121
|
-
if (stubIndex >= 0) parent.removeViewAt(stubIndex)
|
|
122
|
-
if (view.parent == null) {
|
|
123
|
-
parent.addView(view, index.coerceAtMost(parent.childCount), params)
|
|
124
|
-
view.layout(frame.left, frame.top, frame.right, frame.bottom)
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
private fun giveBack(item: Moved) {
|
|
129
|
-
val view = item.view
|
|
130
|
-
// A commit of Fabric meanwhile laid it out in its parent's coordinates: the newest such frame holds.
|
|
131
|
-
val reactFrame = if (view.parent === layer) layer.frameFromReact(view) else null
|
|
132
|
-
if (view.parent === layer) layer.removeView(view)
|
|
133
|
-
restore(view, item)
|
|
134
|
-
val parent = item.stub.parent as? ViewGroup ?: return
|
|
135
|
-
val index = parent.indexOfChild(item.stub)
|
|
136
|
-
if (index < 0) return
|
|
137
|
-
parent.removeViewAt(index)
|
|
138
|
-
parent.addView(view, index, item.params)
|
|
139
|
-
val frame = reactFrame ?: item.frame
|
|
140
|
-
view.measure(
|
|
141
|
-
View.MeasureSpec.makeMeasureSpec(frame.width(), View.MeasureSpec.EXACTLY),
|
|
142
|
-
View.MeasureSpec.makeMeasureSpec(frame.height(), View.MeasureSpec.EXACTLY),
|
|
143
|
-
)
|
|
144
|
-
view.layout(frame.left, frame.top, frame.right, frame.bottom)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
private fun restore(view: View, item: Moved) {
|
|
148
|
-
val values = item.values
|
|
76
|
+
private fun restore(view: View, values: FloatArray, pivotSet: Boolean) {
|
|
149
77
|
view.alpha = values[ALPHA]
|
|
150
78
|
view.translationX = values[TRANSLATION_X]
|
|
151
79
|
view.translationY = values[TRANSLATION_Y]
|
|
@@ -154,7 +82,7 @@ internal class ElementTransition private constructor(private val layer: Transiti
|
|
|
154
82
|
view.rotation = values[ROTATION]
|
|
155
83
|
view.rotationX = values[ROTATION_X]
|
|
156
84
|
view.rotationY = values[ROTATION_Y]
|
|
157
|
-
if (!
|
|
85
|
+
if (!pivotSet && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
158
86
|
view.resetPivot()
|
|
159
87
|
} else {
|
|
160
88
|
view.pivotX = values[PIVOT_X]
|
|
@@ -165,50 +93,71 @@ internal class ElementTransition private constructor(private val layer: Transiti
|
|
|
165
93
|
// An element with views in it fades through a hardware layer only where its alpha would draw it into an offscreen
|
|
166
94
|
// buffer at every frame (AnimationLayer: its rendering overlaps). React's views overlap only with
|
|
167
95
|
// `needsOffscreenAlphaCompositing`, so most elements fade without one and nothing they draw outside their bounds (a
|
|
168
|
-
// box shadow) is clipped. A view without children fades its own drawing at no extra cost.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
96
|
+
// box shadow) is clipped. A view without children fades its own drawing at no extra cost. Scale and rotations turn
|
|
97
|
+
// about the element's center; `x` and `y` are its place in its own parent.
|
|
98
|
+
private fun addElement(options: ElementTransitionOptions, view: View) {
|
|
99
|
+
inPlace += InPlace(view, valuesOf(view), pivotSetOf(view))
|
|
100
|
+
view.pivotX = view.width / 2f
|
|
101
|
+
view.pivotY = view.height / 2f
|
|
102
|
+
val animator = SideAnimator.build(view, options, SideAnimator.Base()) ?: return
|
|
103
|
+
if (view is ViewGroup) AnimationLayer.during(view, animator)
|
|
173
104
|
animators += animator
|
|
174
105
|
}
|
|
175
106
|
|
|
176
|
-
//
|
|
107
|
+
// An element whose start failed gets its values back now.
|
|
108
|
+
private fun giveValuesBack(view: View) {
|
|
109
|
+
val item = inPlace.lastOrNull { it.view === view } ?: return
|
|
110
|
+
inPlace -= item
|
|
111
|
+
try {
|
|
112
|
+
restore(view, item.values, item.pivotSet)
|
|
113
|
+
} catch (e: RuntimeException) {
|
|
114
|
+
Log.w(NavigationLog.TAG, "[ApexNavigation] An element of a transition couldn't get its values back", e)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// The pair's flight: `to` hidden from now, `from` from its start, both seen again when it stops or its copy can't
|
|
119
|
+
// be drawn. Nothing changes when it doesn't fly.
|
|
177
120
|
private fun addPair(
|
|
178
121
|
options: SharedElementTransitionOptions,
|
|
179
122
|
from: View,
|
|
180
|
-
|
|
181
|
-
|
|
123
|
+
to: View,
|
|
124
|
+
name: String,
|
|
182
125
|
fallbackDuration: Long,
|
|
183
|
-
)
|
|
184
|
-
val
|
|
126
|
+
) {
|
|
127
|
+
val layer = layer ?: return
|
|
185
128
|
val flight = SharedAnimatorFactory.create(
|
|
186
|
-
from, to,
|
|
187
|
-
) ?: return
|
|
188
|
-
val alpha = item.values[ALPHA]
|
|
129
|
+
from, to, fromRoot, toRoot, layer, options, fallbackDuration, DevelopmentLog::warn,
|
|
130
|
+
) ?: return
|
|
189
131
|
val fromAlpha = from.alpha
|
|
190
|
-
|
|
191
|
-
|
|
132
|
+
val seenAgain = {
|
|
133
|
+
flight.picture.shown = false
|
|
134
|
+
hidden.remove(from)?.let { show(from, it) }
|
|
135
|
+
hidden.remove(to)?.let { show(to, it) }
|
|
136
|
+
layer.invalidate()
|
|
137
|
+
}
|
|
138
|
+
flight.picture.onFailed = { e ->
|
|
139
|
+
elementSkipped(name, e.toString())
|
|
140
|
+
seenAgain()
|
|
141
|
+
}
|
|
192
142
|
flight.animator.addListener(object : AnimatorListenerAdapter() {
|
|
193
143
|
private var stopped = false
|
|
194
144
|
|
|
195
145
|
override fun onAnimationStart(animation: Animator) {
|
|
196
|
-
if (stopped) return
|
|
146
|
+
if (stopped || finished) return
|
|
147
|
+
hidden[from] = fromAlpha
|
|
197
148
|
from.alpha = 0f
|
|
198
|
-
if (!flight.drawsPictures) to.alpha = alpha
|
|
199
149
|
}
|
|
200
150
|
|
|
201
|
-
// A flight whose start or frame failed stops (`MoveAnimator`), maybe inside its own start
|
|
202
|
-
// again in its screen, and a `to` that moves itself in its place, as at any stop (a flight of pictures
|
|
203
|
-
// shows its `to` at its end).
|
|
151
|
+
// A flight whose start or frame failed stops (`MoveAnimator`), maybe inside its own start.
|
|
204
152
|
override fun onAnimationCancel(animation: Animator) {
|
|
205
153
|
stopped = true
|
|
206
|
-
|
|
207
|
-
if (!flight.drawsPictures) to.alpha = alpha
|
|
154
|
+
seenAgain()
|
|
208
155
|
}
|
|
209
156
|
})
|
|
157
|
+
layer.add(flight.picture)
|
|
158
|
+
hidden[to] = to.alpha
|
|
159
|
+
to.alpha = 0f
|
|
210
160
|
animators += flight.animator
|
|
211
|
-
return true
|
|
212
161
|
}
|
|
213
162
|
|
|
214
163
|
companion object {
|
|
@@ -223,10 +172,26 @@ internal class ElementTransition private constructor(private val layer: Transiti
|
|
|
223
172
|
private const val PIVOT_X = 8
|
|
224
173
|
private const val PIVOT_Y = 9
|
|
225
174
|
|
|
175
|
+
// The views the transitions that run now play: another transition leaves them alone.
|
|
176
|
+
private val playing: MutableSet<View> = Collections.newSetFromMap(WeakHashMap())
|
|
177
|
+
|
|
178
|
+
private fun valuesOf(view: View) = floatArrayOf(
|
|
179
|
+
view.alpha, view.translationX, view.translationY, view.scaleX, view.scaleY, view.rotation,
|
|
180
|
+
view.rotationX, view.rotationY, view.pivotX, view.pivotY,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
private fun pivotSetOf(view: View) = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && view.isPivotSet
|
|
184
|
+
|
|
185
|
+
// A view hidden for a flight shows again with its alpha, unless React gave it another one meanwhile. React
|
|
186
|
+
// writes the same alpha: an opacity it commits during the flight shows the view beside its copy until the end.
|
|
187
|
+
private fun show(view: View, alpha: Float) {
|
|
188
|
+
if (view.alpha == 0f) view.alpha = alpha
|
|
189
|
+
}
|
|
190
|
+
|
|
226
191
|
/**
|
|
227
|
-
* The elements of [animation] from [from] to [to]
|
|
228
|
-
* top without one)
|
|
229
|
-
* [fallbackDuration], the screen's fade.
|
|
192
|
+
* The elements of [animation] from [from] to [to]; the copies of the pairs in a layer that joins [host] at
|
|
193
|
+
* [layerIndex] (its top without one). None when none of them is found or the system's animations are off. A
|
|
194
|
+
* shared element without a duration takes [fallbackDuration], the screen's fade.
|
|
230
195
|
*/
|
|
231
196
|
fun start(
|
|
232
197
|
animation: LayoutAnimation,
|
|
@@ -236,6 +201,7 @@ internal class ElementTransition private constructor(private val layer: Transiti
|
|
|
236
201
|
layerIndex: Int?,
|
|
237
202
|
fallbackDuration: Long,
|
|
238
203
|
): ElementTransition? {
|
|
204
|
+
if (SystemAnimations.areOff(host.context)) return null
|
|
239
205
|
val fromView = from?.let { AppearanceDispatcher.visibleNode(it).peekView() }
|
|
240
206
|
val toView = AppearanceDispatcher.visibleNode(to).peekView()
|
|
241
207
|
val transitions = animation.elementTransitions.transitions
|
|
@@ -245,27 +211,28 @@ internal class ElementTransition private constructor(private val layer: Transiti
|
|
|
245
211
|
val elements = ArrayList<Pair<ElementTransitionOptions, View>>()
|
|
246
212
|
for (element in transitions) {
|
|
247
213
|
if (element.id.isEmpty()) continue
|
|
248
|
-
val view =
|
|
249
|
-
if (
|
|
214
|
+
val view = views.leaving(element.id) ?: views.arriving(element.id) ?: continue
|
|
215
|
+
if (view in playing || !taken.add(view)) continue
|
|
250
216
|
elements += element to view
|
|
251
217
|
}
|
|
252
218
|
val pairs = ArrayList<Triple<SharedElementTransitionOptions, View, View>>()
|
|
253
219
|
for (pair in shared) {
|
|
254
220
|
val fromId = pair.fromId.get(null) ?: continue
|
|
255
221
|
val toId = pair.toId.get(null) ?: continue
|
|
256
|
-
val source =
|
|
257
|
-
val target =
|
|
258
|
-
if (source === target ||
|
|
222
|
+
val source = views.leaving(fromId) ?: continue
|
|
223
|
+
val target = views.arriving(toId) ?: continue
|
|
224
|
+
if (source === target || source in playing || target in playing) continue
|
|
259
225
|
if (target in taken || source in taken) continue
|
|
260
226
|
if (!loaded(source, fromId) || !loaded(target, toId)) continue
|
|
227
|
+
taken += source
|
|
261
228
|
taken += target
|
|
262
229
|
pairs += Triple(pair, source, target)
|
|
263
230
|
}
|
|
264
231
|
if (elements.isEmpty() && pairs.isEmpty()) return null
|
|
265
|
-
val layer = TransitionLayer(host.context)
|
|
266
|
-
val transition = ElementTransition(layer)
|
|
232
|
+
val layer = if (pairs.isEmpty()) null else TransitionLayer(host.context)
|
|
233
|
+
val transition = ElementTransition(layer, fromView, toView)
|
|
267
234
|
try {
|
|
268
|
-
layer
|
|
235
|
+
layer?.attachTo(host, layerIndex ?: host.childCount)
|
|
269
236
|
transition.fill(host, elements, pairs, fallbackDuration)
|
|
270
237
|
} catch (e: RuntimeException) {
|
|
271
238
|
transition.finish()
|
|
@@ -275,8 +242,8 @@ internal class ElementTransition private constructor(private val layer: Transiti
|
|
|
275
242
|
}
|
|
276
243
|
|
|
277
244
|
/**
|
|
278
|
-
* [start], and when that fails, a line in the log and none: the screens play without their elements; every
|
|
279
|
-
*
|
|
245
|
+
* [start], and when that fails, a line in the log and none: the screens play without their elements; every
|
|
246
|
+
* element has its values back already.
|
|
280
247
|
*/
|
|
281
248
|
fun startOrLog(
|
|
282
249
|
animation: LayoutAnimation,
|
|
@@ -292,8 +259,6 @@ internal class ElementTransition private constructor(private val layer: Transiti
|
|
|
292
259
|
null
|
|
293
260
|
}
|
|
294
261
|
|
|
295
|
-
private fun found(view: View?): View? = view?.takeUnless { it is ElementStub }
|
|
296
|
-
|
|
297
262
|
// An image not loaded drops out of the transition; its wait logged it already, else it is logged now.
|
|
298
263
|
private fun loaded(view: View, id: String): Boolean {
|
|
299
264
|
if (ImageLoads.isLoaded(view)) return true
|
|
@@ -302,45 +267,23 @@ internal class ElementTransition private constructor(private val layer: Transiti
|
|
|
302
267
|
}
|
|
303
268
|
}
|
|
304
269
|
|
|
305
|
-
// The
|
|
306
|
-
//
|
|
270
|
+
// The elements' animators where they are, then the pairs' flights, their copies in the order their targets are
|
|
271
|
+
// drawn. Each element's steps run on their own ([elementStep]): one that fails is left as it was, the others play.
|
|
307
272
|
private fun fill(
|
|
308
273
|
host: ViewGroup,
|
|
309
274
|
elements: List<Pair<ElementTransitionOptions, View>>,
|
|
310
275
|
pairs: List<Triple<SharedElementTransitionOptions, View, View>>,
|
|
311
276
|
fallbackDuration: Long,
|
|
312
277
|
) {
|
|
313
|
-
|
|
314
|
-
for ((
|
|
315
|
-
|
|
316
|
-
val views = elements.map { it.second } + pairs.map { it.third }
|
|
317
|
-
val parents = views.associateWith { it.parent as? View }
|
|
318
|
-
val placed = HashMap<View, Moved>()
|
|
319
|
-
for (view in DrawOrder.sorted(views, host) { it }) {
|
|
320
|
-
var item: Moved? = null
|
|
321
|
-
if (elementStep(names.getValue(view)) { item = moveIntoLayer(view) }) item?.let { placed[view] = it }
|
|
322
|
-
}
|
|
278
|
+
for ((_, view) in elements) taken += view
|
|
279
|
+
for ((_, source, target) in pairs) taken += listOf(source, target)
|
|
280
|
+
playing += taken
|
|
323
281
|
for ((options, view) in elements) {
|
|
324
|
-
|
|
325
|
-
if (!elementStep(names.getValue(view)) { addElement(options, item) }) goBack(item)
|
|
326
|
-
}
|
|
327
|
-
for ((options, source, target) in pairs) {
|
|
328
|
-
val item = placed[target] ?: continue
|
|
329
|
-
var flies = false
|
|
330
|
-
elementStep(names.getValue(target)) {
|
|
331
|
-
flies = addPair(options, source, item, parents[target], fallbackDuration)
|
|
332
|
-
}
|
|
333
|
-
if (!flies) goBack(item)
|
|
282
|
+
if (!elementStep(elementName(options.id)) { addElement(options, view) }) giveValuesBack(view)
|
|
334
283
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
private fun goBack(item: Moved) {
|
|
339
|
-
moved -= item
|
|
340
|
-
try {
|
|
341
|
-
giveBack(item)
|
|
342
|
-
} catch (e: RuntimeException) {
|
|
343
|
-
Log.w(NavigationLog.TAG, "[ApexNavigation] An element of a transition couldn't go back", e)
|
|
284
|
+
for ((options, source, target) in DrawOrder.sorted(pairs, host) { it.third }) {
|
|
285
|
+
val name = pairName(options.fromId.get(""), options.toId.get(""))
|
|
286
|
+
elementStep(name) { addPair(options, source, target, name, fallbackDuration) }
|
|
344
287
|
}
|
|
345
288
|
}
|
|
346
289
|
}
|