From bd7cfc59813eb9628f71d81f3daa634fd78b79b0 Mon Sep 17 00:00:00 2001 From: OmkarTenkale Date: Tue, 9 Jul 2024 22:26:37 +0530 Subject: [PATCH] add transitions --- .../dev.omkartenkale.nodal/compose/UI.kt | 2 +- .../transitions/BackstackTransition.kt | 53 +++++++++++++++++++ .../nodes/root/loggedin/ride/RideNode.kt | 7 ++- .../loggedin/ride/request/RequestRideNode.kt | 3 +- .../paymentmode/PaymentModeSelectionNode.kt | 3 +- .../select/route/RouteSelectionNode.kt | 3 +- .../nodes/root/loggedout/ConfirmOtpNode.kt | 2 +- 7 files changed, 64 insertions(+), 9 deletions(-) diff --git a/nodal/src/commonMain/kotlin/dev.omkartenkale.nodal/compose/UI.kt b/nodal/src/commonMain/kotlin/dev.omkartenkale.nodal/compose/UI.kt index ef6b75f..3c492b6 100644 --- a/nodal/src/commonMain/kotlin/dev.omkartenkale.nodal/compose/UI.kt +++ b/nodal/src/commonMain/kotlin/dev.omkartenkale.nodal/compose/UI.kt @@ -22,7 +22,7 @@ public class UI { Backstack(backstack = layers) } - public fun draw(transitionSpec: TransitionSpec = TransitionSpec.Slide, content: @Composable (Modifier) -> Unit): Layer { + public fun draw(transitionSpec: TransitionSpec = TransitionSpec.None, content: @Composable (Modifier) -> Unit): Layer { return Layer(transitionSpec = transitionSpec, content = content) { layers -= it }.also { diff --git a/nodal/src/commonMain/kotlin/dev.omkartenkale.nodal/compose/transitions/BackstackTransition.kt b/nodal/src/commonMain/kotlin/dev.omkartenkale.nodal/compose/transitions/BackstackTransition.kt index 8c3cdd8..8eb09b2 100644 --- a/nodal/src/commonMain/kotlin/dev.omkartenkale.nodal/compose/transitions/BackstackTransition.kt +++ b/nodal/src/commonMain/kotlin/dev.omkartenkale.nodal/compose/transitions/BackstackTransition.kt @@ -4,10 +4,15 @@ import androidx.compose.animation.core.AnimationSpec import androidx.compose.animation.core.CubicBezierEasing import androidx.compose.animation.core.TweenSpec import androidx.compose.foundation.background +import androidx.compose.foundation.shape.CutCornerShape +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.scale +import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.LayoutModifier import androidx.compose.ui.layout.Measurable @@ -16,6 +21,7 @@ import androidx.compose.ui.layout.MeasureScope import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp import androidx.compose.ui.util.lerp // https://easings.net/#easeOutExpo @@ -35,10 +41,22 @@ public class TransitionSpec( ) public val BottomSheet: TransitionSpec = TransitionSpec( topTransition = BackstackTransition.Top.VerticalSlide, + bottomTransition = BackstackTransition.Bottom.VerticalSlide, + bottomOnTop = false, + animationSpec = TweenSpec(durationMillis = 500, easing = EaseOutExpoEasing), + ) + public val Fade: TransitionSpec = TransitionSpec( + topTransition = BackstackTransition.Crossfade, bottomTransition = BackstackTransition.None, bottomOnTop = false, animationSpec = TweenSpec(durationMillis = 500, easing = EaseOutExpoEasing), ) + public val None: TransitionSpec = TransitionSpec( + topTransition = BackstackTransition.None, + bottomTransition = BackstackTransition.None, + bottomOnTop = false, + animationSpec = TweenSpec(durationMillis = 0), + ) } } @@ -177,6 +195,41 @@ public fun interface BackstackTransition { override fun toString(): String = "${this::class.simpleName}(offset=$offset)" } } + + + public object VerticalSlide : BackstackTransition { + override fun Modifier.modifierForScreen( + visibility: State, + isTop: Boolean //isTop is always false + ): Modifier = background(Color.Black).scale(lerp(0.95f, 1f, visibility.value) ) +// .then(PercentageLayoutOffset( +// rawOffset = derivedStateOf { if (isTop) 1f - visibility.value else lerp(0.05f, 0f, visibility.value) } +// )) + .clip(RoundedCornerShape(10.dp)) + + internal class PercentageLayoutOffset(private val rawOffset: State) : + LayoutModifier { + private val offset = { rawOffset.value.coerceIn(-1f..1f) } + + override fun MeasureScope.measure( + measurable: Measurable, + constraints: Constraints + ): MeasureResult { + val placeable = measurable.measure(constraints) + return layout(placeable.width, placeable.height) { + placeable.place(offsetPosition(IntSize(placeable.width, placeable.height))) + } + } + + internal fun offsetPosition(containerSize: IntSize) = IntOffset( + x = 0, + y = (containerSize.height * offset()).toInt() + ) + + override fun toString(): String = "${this::class.simpleName}(offset=$offset)" + } + } + } /** diff --git a/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/RideNode.kt b/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/RideNode.kt index 3cd61f9..ebda6d5 100644 --- a/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/RideNode.kt +++ b/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/RideNode.kt @@ -21,6 +21,7 @@ import dev.omkartenkale.nodal.sample.ride.nodes.root.loggedin.ride.active.addAct import dev.omkartenkale.nodal.sample.ride.nodes.root.loggedin.ride.completed.addDriverRatingNode import dev.omkartenkale.nodal.sample.ride.nodes.root.loggedin.ride.request.RideRequest import dev.omkartenkale.nodal.sample.ride.nodes.root.loggedin.ride.request.addRequestRideNode +import dev.omkartenkale.nodal.util.isAdded import kotlinx.coroutines.delay import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -40,7 +41,7 @@ class RideNode: Node() { // removeSelf() // } // }.launchIn(coroutineScope) - layer = ui.draw(TransitionSpec.Slide) { + layer = ui.draw(TransitionSpec.Fade) { Image( modifier = it.clickable { removeSelf() @@ -50,11 +51,9 @@ class RideNode: Node() { contentDescription = null ) LaunchedEffect(Unit){ - delay(2.seconds) - val rideActive = false // Random.nextBoolean() - if(rideActive){ + if(rideActive && isAdded){ addActiveRideNode(::onRideCompleted) }else{ addRequestRideNode(::onRideRequested) diff --git a/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/RequestRideNode.kt b/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/RequestRideNode.kt index 8f9741c..d89f24a 100644 --- a/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/RequestRideNode.kt +++ b/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/RequestRideNode.kt @@ -28,6 +28,7 @@ import com.skydoves.flexible.core.rememberFlexibleBottomSheetState import dev.omkartenkale.nodal.Node import dev.omkartenkale.nodal.compose.UI import dev.omkartenkale.nodal.compose.draw +import dev.omkartenkale.nodal.compose.transitions.TransitionSpec import dev.omkartenkale.nodal.misc.Callback import dev.omkartenkale.nodal.sample.ride.nodes.root.loggedin.ride.request.select.paymentmode.SelectedPaymentModeNode import dev.omkartenkale.nodal.sample.ride.nodes.root.loggedin.ride.request.select.paymentmode.addSelectedPaymentModeNode @@ -65,7 +66,7 @@ class RequestRideNode : Node() { @OptIn(ExperimentalResourceApi::class) override fun onAdded() { - layer = ui.draw { + layer = ui.draw(TransitionSpec.Fade) { var selectedRoute by remember { mutableStateOf(null) } LaunchedEffect(Unit) { addRouteSelectionNode { diff --git a/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/select/paymentmode/PaymentModeSelectionNode.kt b/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/select/paymentmode/PaymentModeSelectionNode.kt index f342fc5..1d73f5e 100644 --- a/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/select/paymentmode/PaymentModeSelectionNode.kt +++ b/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/select/paymentmode/PaymentModeSelectionNode.kt @@ -12,6 +12,7 @@ import com.skydoves.flexible.core.rememberFlexibleBottomSheetState import dev.omkartenkale.nodal.Node import dev.omkartenkale.nodal.compose.UI import dev.omkartenkale.nodal.compose.draw +import dev.omkartenkale.nodal.compose.transitions.TransitionSpec import dev.omkartenkale.nodal.misc.Callback import dev.omkartenkale.nodal.sample.ride.util.ui.bottomsheet.nonExpandingSheetState import dev.omkartenkale.nodal.util.addChild @@ -30,7 +31,7 @@ class PaymentModeSelectionNode : Node() { private lateinit var layer: UI.Layer override fun onAdded() { - layer = ui.draw { + layer = ui.draw(TransitionSpec.None) { FlexibleBottomSheet( onDismissRequest = { removeSelf() diff --git a/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/select/route/RouteSelectionNode.kt b/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/select/route/RouteSelectionNode.kt index c2c1147..4037445 100644 --- a/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/select/route/RouteSelectionNode.kt +++ b/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedin/ride/request/select/route/RouteSelectionNode.kt @@ -11,6 +11,7 @@ import com.skydoves.flexible.core.rememberFlexibleBottomSheetState import dev.omkartenkale.nodal.Node import dev.omkartenkale.nodal.compose.UI import dev.omkartenkale.nodal.compose.draw +import dev.omkartenkale.nodal.compose.transitions.TransitionSpec import dev.omkartenkale.nodal.misc.Callback import dev.omkartenkale.nodal.sample.ride.util.ui.bottomsheet.alwaysIntermediatelyExpandedSheetState import dev.omkartenkale.nodal.sample.ride.util.ui.bottomsheet.nonExpandingSheetState @@ -36,7 +37,7 @@ class RouteSelectionNode : Node() { @OptIn(ExperimentalResourceApi::class) override fun onAdded() { - layer = ui.draw { + layer = ui.draw(TransitionSpec.None) { FlexibleBottomSheet( onDismissRequest = { removeSelf() diff --git a/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedout/ConfirmOtpNode.kt b/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedout/ConfirmOtpNode.kt index aa64723..dc66a1a 100644 --- a/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedout/ConfirmOtpNode.kt +++ b/samples/ride/src/commonMain/kotlin/dev.omkartenkale.nodal.sample.ride/nodes/root/loggedout/ConfirmOtpNode.kt @@ -37,7 +37,7 @@ class ConfirmOtpNode : Node() { private val onOtpConfirmed: OTPConfirmedCallback by dependencies() override fun onAdded() { - layer = ui.draw(TransitionSpec.BottomSheet) { + layer = ui.draw(TransitionSpec.None) { // Box(Modifier.background(Color.Red).fillMaxSize()) { val scope = rememberCoroutineScope() val state = nonExpandingSheetState()