From 481b953f4b7ad87accc4909581f8bdc865668620 Mon Sep 17 00:00:00 2001 From: Arkadii Ivanov Date: Tue, 21 Nov 2023 22:47:54 +0000 Subject: [PATCH] Added materialPredictiveBackAnimatable as default --- .../android/extensions-compose-jetbrains.api | 3 +- .../api/jvm/extensions-compose-jetbrains.api | 3 +- .../MaterialPredictiveBackAnimatable.kt | 92 +++++++++++++++++++ .../PredictiveBackAnimatable.kt | 49 ++++------ .../predictiveback/PredictiveBackAnimation.kt | 2 +- .../api/extensions-compose-jetpack.api | 3 +- .../MaterialPredictiveBackAnimatable.kt | 92 +++++++++++++++++++ .../PredictiveBackAnimatable.kt | 49 ++++------ .../predictiveback/PredictiveBackAnimation.kt | 2 +- 9 files changed, 232 insertions(+), 63 deletions(-) create mode 100644 extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/MaterialPredictiveBackAnimatable.kt create mode 100644 extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/MaterialPredictiveBackAnimatable.kt diff --git a/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api b/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api index 26ca4566c..7b15fd552 100644 --- a/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api +++ b/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api @@ -120,8 +120,9 @@ public abstract interface class com/arkivanov/decompose/extensions/compose/jetbr } public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatableKt { + public static final fun materialPredictiveBackAnimatable (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable; + public static synthetic fun materialPredictiveBackAnimatable$default (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable; public static final fun predictiveBackAnimatable (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable; - public static synthetic fun predictiveBackAnimatable$default (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable; } public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimationKt { diff --git a/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api b/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api index a519761cf..8242f7ee0 100644 --- a/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api +++ b/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api @@ -132,8 +132,9 @@ public abstract interface class com/arkivanov/decompose/extensions/compose/jetbr } public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatableKt { + public static final fun materialPredictiveBackAnimatable (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable; + public static synthetic fun materialPredictiveBackAnimatable$default (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable; public static final fun predictiveBackAnimatable (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable; - public static synthetic fun predictiveBackAnimatable$default (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable; } public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimationKt { diff --git a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/MaterialPredictiveBackAnimatable.kt b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/MaterialPredictiveBackAnimatable.kt new file mode 100644 index 000000000..2d69f3fce --- /dev/null +++ b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/MaterialPredictiveBackAnimatable.kt @@ -0,0 +1,92 @@ +package com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.predictiveback + +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.tween +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.GraphicsLayerScope +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.TransformOrigin +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.unit.dp +import com.arkivanov.decompose.ExperimentalDecomposeApi +import com.arkivanov.essenty.backhandler.BackEvent +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch + +@ExperimentalDecomposeApi +internal class MaterialPredictiveBackAnimatable( + private val initialEvent: BackEvent, + private val shape: (progress: Float, edge: BackEvent.SwipeEdge) -> Shape, +) : PredictiveBackAnimatable { + + private val finishProgressAnimatable = Animatable(initialValue = 1F) + private val finishProgress by derivedStateOf { finishProgressAnimatable.value } + private val progressAnimatable = Animatable(initialValue = initialEvent.progress) + private val progress by derivedStateOf { progressAnimatable.value } + private var edge by mutableStateOf(initialEvent.swipeEdge) + private var touchY by mutableFloatStateOf(initialEvent.touchY) + + override val exitModifier: Modifier + get() = Modifier.graphicsLayer { setupExitGraphicLayer() } + + override val enterModifier: Modifier + get() = + Modifier.drawWithContent { + drawContent() + drawRect(color = Color.Black.copy(alpha = finishProgress * 0.25F)) + } + + private fun GraphicsLayerScope.setupExitGraphicLayer() { + val pivotFractionX = + when (edge) { + BackEvent.SwipeEdge.LEFT -> 1F + BackEvent.SwipeEdge.RIGHT -> 0F + BackEvent.SwipeEdge.UNKNOWN -> 0.5F + } + + transformOrigin = TransformOrigin(pivotFractionX = pivotFractionX, pivotFractionY = 0.5F) + + val scale = 1F - progress / 10F + scaleX = scale + scaleY = scale + + val translationXLimit = + when (edge) { + BackEvent.SwipeEdge.LEFT -> -8.dp.toPx() + BackEvent.SwipeEdge.RIGHT -> 8.dp.toPx() + BackEvent.SwipeEdge.UNKNOWN -> 0F + } + + translationX = translationXLimit * progress + + val translationYLimit = size.height / 20F - 8.dp.toPx() + val translationYFactor = ((touchY - initialEvent.touchY) / size.height) * (progress * 3F).coerceAtMost(1f) + translationY = translationYLimit * translationYFactor + + alpha = finishProgress + shape = shape(progress, edge) + clip = true + } + + override suspend fun animate(event: BackEvent) { + edge = event.swipeEdge + touchY = event.touchY + progressAnimatable.animateTo(event.progress) + } + + override suspend fun finish() { + val velocityFactor = progressAnimatable.velocity.coerceAtMost(1F) / 1F + val progress = progressAnimatable.value + coroutineScope { + launch { progressAnimatable.animateTo(progress + (1F - progress) * velocityFactor) } + launch { finishProgressAnimatable.animateTo(targetValue = 0F, animationSpec = tween()) } + } + } +} diff --git a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable.kt b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable.kt index 95ca88b62..0c63478a9 100644 --- a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable.kt +++ b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable.kt @@ -1,13 +1,8 @@ package com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.predictiveback -import androidx.compose.foundation.layout.absoluteOffset import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.drawWithContent -import androidx.compose.ui.draw.scale -import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape import androidx.compose.ui.unit.dp import com.arkivanov.decompose.ExperimentalDecomposeApi import com.arkivanov.essenty.backhandler.BackEvent @@ -61,12 +56,8 @@ interface PredictiveBackAnimatable { @ExperimentalDecomposeApi fun predictiveBackAnimatable( initialBackEvent: BackEvent, - exitModifier: (progress: Float, edge: BackEvent.SwipeEdge) -> Modifier = { progress, edge -> - Modifier.exitModifier(progress = progress, edge = edge) - }, - enterModifier: (progress: Float, edge: BackEvent.SwipeEdge) -> Modifier = { progress, _ -> - Modifier.enterModifier(progress = progress) - }, + exitModifier: (progress: Float, edge: BackEvent.SwipeEdge) -> Modifier, + enterModifier: (progress: Float, edge: BackEvent.SwipeEdge) -> Modifier, ): PredictiveBackAnimatable = DefaultPredictiveBackAnimatable( initialBackEvent = initialBackEvent, @@ -74,20 +65,20 @@ fun predictiveBackAnimatable( getEnterModifier = enterModifier, ) -private fun Modifier.exitModifier(progress: Float, edge: BackEvent.SwipeEdge): Modifier = - scale(1F - progress * 0.25F) - .absoluteOffset( - x = when (edge) { - BackEvent.SwipeEdge.LEFT -> 32.dp * progress - BackEvent.SwipeEdge.RIGHT -> (-32).dp * progress - BackEvent.SwipeEdge.UNKNOWN -> 0.dp - }, - ) - .alpha(((1F - progress) * 2F).coerceAtMost(1F)) - .clip(RoundedCornerShape(size = 64.dp * progress)) - -private fun Modifier.enterModifier(progress: Float): Modifier = - drawWithContent { - drawContent() - drawRect(color = Color(red = 0F, green = 0F, blue = 0F, alpha = (1F - progress) / 4F)) - } +/** + * Creates an implementation of [PredictiveBackAnimatable] that resembles the + * [predictive back design for Android](https://developer.android.com/design/ui/mobile/guides/patterns/predictive-back). + * + * @param initialBackEvent an initial [BackEvent] of the predictive back gesture. + * @param shape a clipping shape of the child being removed (the currently active child), + * default is [RoundedCornerShape] that gradually increases following the gesture progress. + */ +@ExperimentalDecomposeApi +fun materialPredictiveBackAnimatable( + initialBackEvent: BackEvent, + shape: (progress: Float, edge: BackEvent.SwipeEdge) -> Shape = { progress, _ -> RoundedCornerShape(size = 16.dp * progress) }, +): PredictiveBackAnimatable = + MaterialPredictiveBackAnimatable( + initialEvent = initialBackEvent, + shape = shape, + ) diff --git a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimation.kt b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimation.kt index a14edfe99..b941d1e6f 100644 --- a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimation.kt +++ b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimation.kt @@ -42,7 +42,7 @@ fun predictiveBackAnimation( exitChild: Child.Created, enterChild: Child.Created, ) -> PredictiveBackAnimatable = { initialBackEvent, _, _ -> - predictiveBackAnimatable(initialBackEvent = initialBackEvent) + materialPredictiveBackAnimatable(initialBackEvent = initialBackEvent) }, onBack: () -> Unit, ): StackAnimation = diff --git a/extensions-compose-jetpack/api/extensions-compose-jetpack.api b/extensions-compose-jetpack/api/extensions-compose-jetpack.api index a4063a739..94b156793 100644 --- a/extensions-compose-jetpack/api/extensions-compose-jetpack.api +++ b/extensions-compose-jetpack/api/extensions-compose-jetpack.api @@ -120,8 +120,9 @@ public abstract interface class com/arkivanov/decompose/extensions/compose/jetpa } public final class com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimatableKt { + public static final fun materialPredictiveBackAnimatable (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimatable; + public static synthetic fun materialPredictiveBackAnimatable$default (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimatable; public static final fun predictiveBackAnimatable (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimatable; - public static synthetic fun predictiveBackAnimatable$default (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimatable; } public final class com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimationKt { diff --git a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/MaterialPredictiveBackAnimatable.kt b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/MaterialPredictiveBackAnimatable.kt new file mode 100644 index 000000000..3641a8d86 --- /dev/null +++ b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/MaterialPredictiveBackAnimatable.kt @@ -0,0 +1,92 @@ +package com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.predictiveback + +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.tween +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.GraphicsLayerScope +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.TransformOrigin +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.unit.dp +import com.arkivanov.decompose.ExperimentalDecomposeApi +import com.arkivanov.essenty.backhandler.BackEvent +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch + +@ExperimentalDecomposeApi +internal class MaterialPredictiveBackAnimatable( + private val initialEvent: BackEvent, + private val shape: (progress: Float, edge: BackEvent.SwipeEdge) -> Shape, +) : PredictiveBackAnimatable { + + private val finishProgressAnimatable = Animatable(initialValue = 1F) + private val finishProgress by derivedStateOf { finishProgressAnimatable.value } + private val progressAnimatable = Animatable(initialValue = initialEvent.progress) + private val progress by derivedStateOf { progressAnimatable.value } + private var edge by mutableStateOf(initialEvent.swipeEdge) + private var touchY by mutableFloatStateOf(initialEvent.touchY) + + override val exitModifier: Modifier + get() = Modifier.graphicsLayer { setupExitGraphicLayer() } + + override val enterModifier: Modifier + get() = + Modifier.drawWithContent { + drawContent() + drawRect(color = Color.Black.copy(alpha = finishProgress * 0.25F)) + } + + private fun GraphicsLayerScope.setupExitGraphicLayer() { + val pivotFractionX = + when (edge) { + BackEvent.SwipeEdge.LEFT -> 1F + BackEvent.SwipeEdge.RIGHT -> 0F + BackEvent.SwipeEdge.UNKNOWN -> 0.5F + } + + transformOrigin = TransformOrigin(pivotFractionX = pivotFractionX, pivotFractionY = 0.5F) + + val scale = 1F - progress / 10F + scaleX = scale + scaleY = scale + + val translationXLimit = + when (edge) { + BackEvent.SwipeEdge.LEFT -> -8.dp.toPx() + BackEvent.SwipeEdge.RIGHT -> 8.dp.toPx() + BackEvent.SwipeEdge.UNKNOWN -> 0F + } + + translationX = translationXLimit * progress + + val translationYLimit = size.height / 20F - 8.dp.toPx() + val translationYFactor = ((touchY - initialEvent.touchY) / size.height) * (progress * 3F).coerceAtMost(1f) + translationY = translationYLimit * translationYFactor + + alpha = finishProgress + shape = shape(progress, edge) + clip = true + } + + override suspend fun animate(event: BackEvent) { + edge = event.swipeEdge + touchY = event.touchY + progressAnimatable.animateTo(event.progress) + } + + override suspend fun finish() { + val velocityFactor = progressAnimatable.velocity.coerceAtMost(1F) / 1F + val progress = progressAnimatable.value + coroutineScope { + launch { progressAnimatable.animateTo(progress + (1F - progress) * velocityFactor) } + launch { finishProgressAnimatable.animateTo(targetValue = 0F, animationSpec = tween()) } + } + } +} diff --git a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimatable.kt b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimatable.kt index a6dc4e1be..5ab67a4e2 100644 --- a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimatable.kt +++ b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimatable.kt @@ -1,13 +1,8 @@ package com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.predictiveback -import androidx.compose.foundation.layout.absoluteOffset import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.drawWithContent -import androidx.compose.ui.draw.scale -import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape import androidx.compose.ui.unit.dp import com.arkivanov.decompose.ExperimentalDecomposeApi import com.arkivanov.essenty.backhandler.BackEvent @@ -61,12 +56,8 @@ interface PredictiveBackAnimatable { @ExperimentalDecomposeApi fun predictiveBackAnimatable( initialBackEvent: BackEvent, - exitModifier: (progress: Float, edge: BackEvent.SwipeEdge) -> Modifier = { progress, edge -> - Modifier.exitModifier(progress = progress, edge = edge) - }, - enterModifier: (progress: Float, edge: BackEvent.SwipeEdge) -> Modifier = { progress, _ -> - Modifier.enterModifier(progress = progress) - }, + exitModifier: (progress: Float, edge: BackEvent.SwipeEdge) -> Modifier, + enterModifier: (progress: Float, edge: BackEvent.SwipeEdge) -> Modifier, ): PredictiveBackAnimatable = DefaultPredictiveBackAnimatable( initialBackEvent = initialBackEvent, @@ -74,20 +65,20 @@ fun predictiveBackAnimatable( getEnterModifier = enterModifier, ) -private fun Modifier.exitModifier(progress: Float, edge: BackEvent.SwipeEdge): Modifier = - scale(1F - progress * 0.25F) - .absoluteOffset( - x = when (edge) { - BackEvent.SwipeEdge.LEFT -> 32.dp * progress - BackEvent.SwipeEdge.RIGHT -> (-32).dp * progress - BackEvent.SwipeEdge.UNKNOWN -> 0.dp - }, - ) - .alpha(((1F - progress) * 2F).coerceAtMost(1F)) - .clip(RoundedCornerShape(size = 64.dp * progress)) - -private fun Modifier.enterModifier(progress: Float): Modifier = - drawWithContent { - drawContent() - drawRect(color = Color(red = 0F, green = 0F, blue = 0F, alpha = (1F - progress) / 4F)) - } +/** + * Creates an implementation of [PredictiveBackAnimatable] that resembles the + * [predictive back design for Android](https://developer.android.com/design/ui/mobile/guides/patterns/predictive-back). + * + * @param initialBackEvent an initial [BackEvent] of the predictive back gesture. + * @param shape a clipping shape of the child being removed (the currently active child), + * default is [RoundedCornerShape] that gradually increases following the gesture progress. + */ +@ExperimentalDecomposeApi +fun materialPredictiveBackAnimatable( + initialBackEvent: BackEvent, + shape: (progress: Float, edge: BackEvent.SwipeEdge) -> Shape = { progress, _ -> RoundedCornerShape(size = 16.dp * progress) }, +): PredictiveBackAnimatable = + MaterialPredictiveBackAnimatable( + initialEvent = initialBackEvent, + shape = shape, + ) diff --git a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimation.kt b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimation.kt index d3cc6624a..c025a9ce9 100644 --- a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimation.kt +++ b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/predictiveback/PredictiveBackAnimation.kt @@ -42,7 +42,7 @@ fun predictiveBackAnimation( exitChild: Child.Created, enterChild: Child.Created, ) -> PredictiveBackAnimatable = { initialBackEvent, _, _ -> - predictiveBackAnimatable(initialBackEvent = initialBackEvent) + materialPredictiveBackAnimatable(initialBackEvent = initialBackEvent) }, onBack: () -> Unit, ): StackAnimation =