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

Commit 396d9caf authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Make UserActionResult a class instead of interface (1/2)

In ag/25970777, we introduced a new UserActionResult interface to allow
the user to specify the distance of a user action, as well as changing
the transition key of a user action. This CL made the UserActionResult
an interface that was implemented by SceneKey, so that the old and most
common syntax userActions=mapOf(Swipe.Up to Scenes.Foo) still compiles.

After some discussions with other peers, it came out the the
UserActionResult being an interface implemented by SceneKey was
confusing. This CL makes the UserActionResult a class and instead
overloads the infix `to` function in UserAction so that
`UserAction to SceneKey` returns a Pair<UserAction, UserActionResult>
instead of a Pair<UserAction, SceneKey>, still allowing the shorter and
most common syntax to define user actions.

Bug: 321932826
Test: PlatformComposeSceneTransitionLayoutTests
Flag: N/A
Change-Id: I99566aee81bdd14022e0eda2af9144525d77da49
parent fa838838
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.UserAction as SceneTransitionUserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.updateSceneTransitionLayoutState
import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon
@@ -168,7 +169,7 @@ private fun SceneTransitionObservableTransitionState.toModel(): ObservableTransi
private fun toTransitionModels(
    userAction: UserAction,
    sceneModel: SceneModel,
): Pair<SceneTransitionUserAction, SceneTransitionSceneKey> {
): Pair<SceneTransitionUserAction, UserActionResult> {
    return userAction.toTransitionUserAction() to sceneModel.key.toTransitionSceneKey()
}

+1 −6
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ sealed class Key(val debugName: String, val identity: Any) {
class SceneKey(
    debugName: String,
    identity: Any = Object(),
) : Key(debugName, identity), UserActionResult {
) : Key(debugName, identity) {
    @VisibleForTesting
    // TODO(b/240432457): Make internal once PlatformComposeSceneTransitionLayoutTestsUtils can
    // access internal members.
@@ -53,11 +53,6 @@ class SceneKey(
    /** The unique [ElementKey] identifying this scene's root element. */
    val rootElementKey = ElementKey(debugName, identity)

    // Implementation of [UserActionResult].
    override val toScene: SceneKey = this
    override val transitionKey: TransitionKey? = null
    override val distance: UserActionDistance? = null

    override fun toString(): String {
        return "SceneKey(debugName=$debugName)"
    }
+17 −52
Original line number Diff line number Diff line
@@ -332,7 +332,11 @@ interface ElementBoxScope {
@Stable @ElementDsl interface MovableElementContentScope : BaseSceneScope, ElementBoxScope

/** An action performed by the user. */
sealed interface UserAction
sealed interface UserAction {
    infix fun to(scene: SceneKey): Pair<UserAction, UserActionResult> {
        return this to UserActionResult(toScene = scene)
    }
}

/** The user navigated back, either using a gesture or by triggering a KEYCODE_BACK event. */
data object Back : UserAction
@@ -385,65 +389,26 @@ interface SwipeSourceDetector {
    ): SwipeSource?
}

/**
 * The result of performing a [UserAction].
 *
 * Note: [UserActionResult] is implemented by [SceneKey], so you can also use scene keys directly
 * when defining your [UserActionResult]s.
 *
 * ```
 * SceneTransitionLayout(...) {
 *     scene(
 *         Scenes.Foo,
 *         userActions =
 *             mapOf(
 *                 Swipe.Right to Scene.Bar,
 *                 Swipe.Down to Scene.Doe,
 *             )
 *         )
 *     ) { ... }
 * }
 * ```
 */
interface UserActionResult {
/** The result of performing a [UserAction]. */
class UserActionResult(
    /** The scene we should be transitioning to during the [UserAction]. */
    val toScene: SceneKey

    /** The key of the transition that should be used. */
    val transitionKey: TransitionKey?
    val toScene: SceneKey,

    /**
     * The distance the action takes to animate from 0% to 100%.
     *
     * If `null`, a default distance will be used that depends on the [UserAction] performed.
     */
    val distance: UserActionDistance?
}
    val distance: UserActionDistance? = null,

/** Create a [UserActionResult] to [toScene] with the given [distance] and [transitionKey]. */
fun UserActionResult(
    toScene: SceneKey,
    distance: UserActionDistance? = null,
    transitionKey: TransitionKey? = null,
): UserActionResult {
    return object : UserActionResult {
        override val toScene: SceneKey = toScene
        override val transitionKey: TransitionKey? = transitionKey
        override val distance: UserActionDistance? = distance
    }
}

/** Create a [UserActionResult] to [toScene] with the given fixed [distance] and [transitionKey]. */
fun UserActionResult(
    /** The key of the transition that should be used. */
    val transitionKey: TransitionKey? = null,
) {
    constructor(
        toScene: SceneKey,
        distance: Dp,
        transitionKey: TransitionKey? = null,
): UserActionResult {
    return UserActionResult(
        toScene = toScene,
        distance = FixedDistance(distance),
        transitionKey = transitionKey,
    )
    ) : this(toScene, FixedDistance(distance), transitionKey)
}

interface UserActionDistance {
+4 −8
Original line number Diff line number Diff line
@@ -54,12 +54,8 @@ class SceneGestureHandlerTest {
        private val layoutState =
            MutableSceneTransitionLayoutStateImpl(SceneA, EmptyTestTransitions)

        val mutableUserActionsA: MutableMap<UserAction, SceneKey> =
            mutableMapOf(Swipe.Up to SceneB, Swipe.Down to SceneC)

        val mutableUserActionsB: MutableMap<UserAction, SceneKey> =
            mutableMapOf(Swipe.Up to SceneC, Swipe.Down to SceneA)

        val mutableUserActionsA = mutableMapOf(Swipe.Up to SceneB, Swipe.Down to SceneC)
        val mutableUserActionsB = mutableMapOf(Swipe.Up to SceneC, Swipe.Down to SceneA)
        private val scenesBuilder: SceneTransitionLayoutScope.() -> Unit = {
            scene(
                key = SceneA,
@@ -507,7 +503,7 @@ class SceneGestureHandlerTest {
        onDragStarted(overSlop = up(fractionOfScreen = 0.1f))
        assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.1f)

        mutableUserActionsA[Swipe.Up] = SceneC
        mutableUserActionsA[Swipe.Up] = UserActionResult(SceneC)
        onDelta(pixels = up(fractionOfScreen = 0.1f))
        // target stays B even though UserActions changed
        assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.2f)
@@ -524,7 +520,7 @@ class SceneGestureHandlerTest {
        onDragStarted(overSlop = up(fractionOfScreen = 0.1f))
        assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.1f)

        mutableUserActionsA[Swipe.Up] = SceneC
        mutableUserActionsA[Swipe.Up] = UserActionResult(SceneC)
        onDelta(pixels = up(fractionOfScreen = 0.1f))
        onDragStopped(velocity = down(fractionOfScreen = 0.1f))