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

Commit 929eab03 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Remove STLState.snapToIdleIfClose()" into main

parents 11f742ec 4bce8a30
Loading
Loading
Loading
Loading
+0 −34
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import androidx.compose.ui.util.fastAny
import androidx.compose.ui.util.fastForEach
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.transformation.SharedElementTransformation
import kotlin.math.absoluteValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Job
@@ -528,39 +527,6 @@ internal class MutableSceneTransitionLayoutStateImpl(
        transitionStates = listOf(TransitionState.Idle(scene, currentOverlays))
    }

    /**
     * Check if a transition is in progress. If the progress value is near 0 or 1, immediately snap
     * to the closest scene.
     *
     * Important: Snapping to the closest scene will instantly finish *all* ongoing transitions,
     * only the progress of the last transition will be checked.
     *
     * @return true if snapped to the closest scene.
     */
    internal fun snapToIdleIfClose(threshold: Float): Boolean {
        val transition = currentTransition ?: return false
        val progress = transition.progress

        fun isProgressCloseTo(value: Float) = (progress - value).absoluteValue <= threshold

        fun finishAllTransitions() {
            // Force finish all transitions.
            while (currentTransitions.isNotEmpty()) {
                finishTransition(transitionStates[0] as TransitionState.Transition)
            }
        }

        val shouldSnap =
            (isProgressCloseTo(0f) && transition.isFromCurrentContent()) ||
                (isProgressCloseTo(1f) && transition.isToCurrentContent())
        return if (shouldSnap) {
            finishAllTransitions()
            true
        } else {
            false
        }
    }

    override fun showOverlay(
        overlay: OverlayKey,
        animationScope: CoroutineScope,
+0 −127
Original line number Diff line number Diff line
@@ -18,12 +18,9 @@ package com.android.compose.animation.scene

import android.util.Log
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compose.animation.scene.TestOverlays.OverlayA
import com.android.compose.animation.scene.TestScenes.SceneA
import com.android.compose.animation.scene.TestScenes.SceneB
import com.android.compose.animation.scene.TestScenes.SceneC
@@ -169,130 +166,6 @@ class SceneTransitionLayoutStateTest {
        assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(2)
    }

    @Test
    fun snapToIdleIfClose_snapToStart() = runMonotonicClockTest {
        val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
        state.startTransitionImmediately(
            animationScope = backgroundScope,
            transition(from = SceneA, to = SceneB, current = { SceneA }, progress = { 0.2f }),
        )
        assertThat(state.isTransitioning()).isTrue()

        // Ignore the request if the progress is not close to 0 or 1, using the threshold.
        assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
        assertThat(state.isTransitioning()).isTrue()

        // Go to the initial scene if it is close to 0.
        assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
        assertThat(state.isTransitioning()).isFalse()
        assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneA))
    }

    @Test
    fun snapToIdleIfClose_snapToStart_overlays() = runMonotonicClockTest {
        val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
        state.startTransitionImmediately(
            animationScope = backgroundScope,
            transition(SceneA, OverlayA, isEffectivelyShown = { false }, progress = { 0.2f }),
        )
        assertThat(state.isTransitioning()).isTrue()

        // Ignore the request if the progress is not close to 0 or 1, using the threshold.
        assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
        assertThat(state.isTransitioning()).isTrue()

        // Go to the initial scene if it is close to 0.
        assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
        assertThat(state.isTransitioning()).isFalse()
        assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneA))
    }

    @Test
    fun snapToIdleIfClose_snapToEnd() = runMonotonicClockTest {
        val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
        state.startTransitionImmediately(
            animationScope = backgroundScope,
            transition(from = SceneA, to = SceneB, progress = { 0.8f }),
        )
        assertThat(state.isTransitioning()).isTrue()

        // Ignore the request if the progress is not close to 0 or 1, using the threshold.
        assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
        assertThat(state.isTransitioning()).isTrue()

        // Go to the final scene if it is close to 1.
        assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
        assertThat(state.isTransitioning()).isFalse()
        assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneB))
    }

    @Test
    fun snapToIdleIfClose_snapToEnd_overlays() = runMonotonicClockTest {
        val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
        state.startTransitionImmediately(
            animationScope = backgroundScope,
            transition(SceneA, OverlayA, isEffectivelyShown = { true }, progress = { 0.8f }),
        )
        assertThat(state.isTransitioning()).isTrue()

        // Ignore the request if the progress is not close to 0 or 1, using the threshold.
        assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
        assertThat(state.isTransitioning()).isTrue()

        // Go to the final scene if it is close to 1.
        assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
        assertThat(state.isTransitioning()).isFalse()
        assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneA, setOf(OverlayA)))
    }

    @Test
    fun snapToIdleIfClose_multipleTransitions() = runMonotonicClockTest {
        val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)

        val aToB = transition(from = SceneA, to = SceneB, progress = { 0.5f })
        state.startTransitionImmediately(animationScope = backgroundScope, aToB)
        assertThat(state.currentTransitions).containsExactly(aToB).inOrder()

        val bToC = transition(from = SceneB, to = SceneC, progress = { 0.8f })
        state.startTransitionImmediately(animationScope = backgroundScope, bToC)
        assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder()

        // Ignore the request if the progress is not close to 0 or 1, using the threshold.
        assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
        assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder()

        // Go to the final scene if it is close to 1.
        assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
        assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneC))
        assertThat(state.currentTransitions).isEmpty()
    }

    @Test
    fun snapToIdleIfClose_closeButNotCurrentScene() = runMonotonicClockTest {
        val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
        var progress by mutableStateOf(0f)
        var currentScene by mutableStateOf(SceneB)
        state.startTransitionImmediately(
            animationScope = backgroundScope,
            transition(
                from = SceneA,
                to = SceneB,
                current = { currentScene },
                progress = { progress },
            ),
        )
        assertThat(state.isTransitioning()).isTrue()

        // Ignore the request if we are close to a scene that is not the current scene
        assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
        assertThat(state.isTransitioning()).isTrue()

        progress = 1f
        currentScene = SceneA
        assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
        assertThat(state.isTransitioning()).isTrue()
    }

    private fun MonotonicClockTestScope.startOverscrollableTransistionFromAtoB(
        progress: () -> Float,
        sceneTransitions: SceneTransitions,