diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index ea78faf50f..89540bbc62 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -636,7 +636,7 @@ class LoggedInFlowNode( ) { contentModifier -> Box(modifier = contentModifier) { val ftueState by ftueService.state.collectAsState() - BackstackView() + BackstackView(transitionHandler = rememberLoggedInFlowTransitionHandler(backstack)) if (ftueState is FtueState.Complete) { PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LoggedInPermanent) } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowTransitionHandler.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowTransitionHandler.kt new file mode 100644 index 0000000000..70945b8ab0 --- /dev/null +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowTransitionHandler.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.appnav + +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.Transition +import androidx.compose.animation.core.spring +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.navigation.transition.ModifierTransitionHandler +import com.bumble.appyx.core.navigation.transition.TransitionDescriptor +import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.transitionhandler.rememberBackstackFader +import com.bumble.appyx.navmodel.backstack.transitionhandler.rememberBackstackSlider + +/** + * A TransitionHandler that uses fade transition when Placeholder is being removed, + * and slide transition for all other cases. + */ +class LoggedInFlowTransitionHandler( + private val backstack: BackStack, + private val slider: ModifierTransitionHandler, + private val fader: ModifierTransitionHandler, +) : ModifierTransitionHandler() { + override fun createModifier( + modifier: Modifier, + transition: Transition, + descriptor: TransitionDescriptor + ): Modifier { + val isPlaceholderBeingRemoved = backstack.elements.value.any { element -> + element.key.navTarget == LoggedInFlowNode.NavTarget.Placeholder && + element.targetState != BackStack.State.ACTIVE + } + val handler = if (isPlaceholderBeingRemoved) fader else slider + return handler.createModifier(modifier, transition, descriptor) + } +} + +@Composable +fun rememberLoggedInFlowTransitionHandler( + backstack: BackStack, +): ModifierTransitionHandler { + val slider = rememberBackstackSlider( + transitionSpec = { spring(stiffness = Spring.StiffnessMediumLow) }, + ) + val fader = rememberBackstackFader( + transitionSpec = { spring(stiffness = Spring.StiffnessMediumLow) }, + ) + return remember(backstack, slider, fader) { + LoggedInFlowTransitionHandler(backstack, slider, fader) + } +}