Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 183e7f3c authored by Jordan Demeulenaere's avatar Jordan Demeulenaere Committed by Android (Google) Code Review
Browse files

Merge "Replace transitions to avoid unnecessary interruption handling" into main

parents 998ccda0 b6315634
Loading
Loading
Loading
Loading
+17 −3
Original line number Diff line number Diff line
@@ -48,8 +48,15 @@ internal fun CoroutineScope.animateToScene(
    }

    return when (transitionState) {
        is TransitionState.Idle ->
            animate(layoutState, target, transitionKey, isInitiatedByUserInput = false)
        is TransitionState.Idle -> {
            animate(
                layoutState,
                target,
                transitionKey,
                isInitiatedByUserInput = false,
                replacedTransition = null,
            )
        }
        is TransitionState.Transition -> {
            val isInitiatedByUserInput = transitionState.isInitiatedByUserInput

@@ -79,6 +86,7 @@ internal fun CoroutineScope.animateToScene(
                        isInitiatedByUserInput,
                        initialProgress = progress,
                        initialVelocity = transitionState.progressVelocity,
                        replacedTransition = transitionState,
                    )
                }
            } else if (transitionState.fromScene == target) {
@@ -101,6 +109,7 @@ internal fun CoroutineScope.animateToScene(
                        initialProgress = progress,
                        initialVelocity = transitionState.progressVelocity,
                        reversed = true,
                        replacedTransition = transitionState,
                    )
                }
            } else {
@@ -137,6 +146,7 @@ internal fun CoroutineScope.animateToScene(
                    isInitiatedByUserInput,
                    fromScene = animateFrom,
                    chain = chain,
                    replacedTransition = null,
                )
            }
        }
@@ -148,6 +158,7 @@ private fun CoroutineScope.animate(
    targetScene: SceneKey,
    transitionKey: TransitionKey?,
    isInitiatedByUserInput: Boolean,
    replacedTransition: TransitionState.Transition?,
    initialProgress: Float = 0f,
    initialVelocity: Float = 0f,
    reversed: Boolean = false,
@@ -164,6 +175,7 @@ private fun CoroutineScope.animate(
                currentScene = targetScene,
                isInitiatedByUserInput = isInitiatedByUserInput,
                isUserInputOngoing = false,
                replacedTransition = replacedTransition,
            )
        } else {
            OneOffTransition(
@@ -173,6 +185,7 @@ private fun CoroutineScope.animate(
                currentScene = targetScene,
                isInitiatedByUserInput = isInitiatedByUserInput,
                isUserInputOngoing = false,
                replacedTransition = replacedTransition,
            )
        }

@@ -214,7 +227,8 @@ private class OneOffTransition(
    override val currentScene: SceneKey,
    override val isInitiatedByUserInput: Boolean,
    override val isUserInputOngoing: Boolean,
) : TransitionState.Transition(fromScene, toScene) {
    replacedTransition: TransitionState.Transition?,
) : TransitionState.Transition(fromScene, toScene, replacedTransition) {
    /**
     * The animatable used to animate this transition.
     *
+6 −3
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch

interface DraggableHandler {
internal interface DraggableHandler {
    /**
     * Start a drag in the given [startedPosition], with the given [overSlop] and number of
     * [pointersDown].
@@ -51,7 +51,7 @@ interface DraggableHandler {
 * The [DragController] provides control over the transition between two scenes through the [onDrag]
 * and [onStop] methods.
 */
interface DragController {
internal interface DragController {
    /** Drag the current scene by [delta] pixels. */
    fun onDrag(delta: Float)

@@ -537,6 +537,7 @@ private fun SwipeTransition(
        orientation = orientation,
        isUpOrLeft = isUpOrLeft,
        requiresFullDistanceSwipe = result.requiresFullDistanceSwipe,
        replacedTransition = null,
    )
}

@@ -553,6 +554,7 @@ private fun SwipeTransition(old: SwipeTransition): SwipeTransition {
            isUpOrLeft = old.isUpOrLeft,
            lastDistance = old.lastDistance,
            requiresFullDistanceSwipe = old.requiresFullDistanceSwipe,
            replacedTransition = old,
        )
        .apply {
            _currentScene = old._currentScene
@@ -571,9 +573,10 @@ private class SwipeTransition(
    override val orientation: Orientation,
    override val isUpOrLeft: Boolean,
    val requiresFullDistanceSwipe: Boolean,
    replacedTransition: SwipeTransition?,
    var lastDistance: Float = DistanceUnspecified,
) :
    TransitionState.Transition(_fromScene.key, _toScene.key),
    TransitionState.Transition(_fromScene.key, _toScene.key, replacedTransition),
    TransitionState.HasOverscrollProperties {
    var _currentScene by mutableStateOf(_fromScene)
    override val currentScene: SceneKey
+4 −0
Original line number Diff line number Diff line
@@ -495,6 +495,10 @@ private fun prepareInterruption(
    transition: TransitionState.Transition,
    previousTransition: TransitionState.Transition,
) {
    if (transition.replacedTransition == previousTransition) {
        return
    }

    val sceneStates = element.sceneStates
    fun updatedSceneState(key: SceneKey): Element.SceneState? {
        return sceneStates[key]?.also { it.selfUpdateValuesBeforeInterruption() }
+16 −0
Original line number Diff line number Diff line
@@ -224,6 +224,9 @@ sealed interface TransitionState {

        /** The scene this transition is going to. Can't be the same as fromScene */
        val toScene: SceneKey,

        /** The transition that `this` transition is replacing, if any. */
        internal val replacedTransition: Transition? = null,
    ) : TransitionState {
        /**
         * The key of this transition. This should usually be null, but it can be specified to use a
@@ -279,6 +282,11 @@ sealed interface TransitionState {

        init {
            check(fromScene != toScene)
            check(
                replacedTransition == null ||
                    (replacedTransition.fromScene == fromScene &&
                        replacedTransition.toScene == toScene)
            )
        }

        /**
@@ -321,6 +329,10 @@ sealed interface TransitionState {
                return 0f
            }

            if (replacedTransition != null) {
                return replacedTransition.interruptionProgress(layoutImpl)
            }

            fun create(): Animatable<Float, AnimationVector1D> {
                val animatable = Animatable(1f, visibilityThreshold = ProgressVisibilityThreshold)
                layoutImpl.coroutineScope.launch {
@@ -521,6 +533,10 @@ internal abstract class BaseSceneTransitionLayoutState(
                    check(transitionStates.size == 1)
                    check(transitionStates[0] is TransitionState.Idle)
                    transitionStates = listOf(transition)
                } else if (currentState == transition.replacedTransition) {
                    // Replace the transition.
                    transitionStates =
                        transitionStates.subList(0, transitionStates.lastIndex) + transition
                } else {
                    // Append the new transition.
                    transitionStates = transitionStates + transition
+13 −0
Original line number Diff line number Diff line
@@ -1233,4 +1233,17 @@ class DraggableHandlerTest {
        advanceUntilIdle()
        assertIdle(SceneB)
    }

    @Test
    fun interceptingTransitionReplacesCurrentTransition() = runGestureTest {
        val controller = onDragStarted(overSlop = up(fractionOfScreen = 0.5f))
        val transition = assertThat(layoutState.transitionState).isTransition()
        controller.onDragStopped(velocity = 0f)

        // Intercept the transition.
        onDragStartedImmediately()
        val newTransition = assertThat(layoutState.transitionState).isTransition()
        assertThat(newTransition).isNotSameInstanceAs(transition)
        assertThat(newTransition.replacedTransition).isSameInstanceAs(transition)
    }
}
Loading