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

Commit c54d612c authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Move more swipe animation logic into SwipeAnimation

This CL moves more code from DraggableHandler.kt to SwipeAnimation.kt,
so that this logic is shared with other usages of SwipeAnimation.

Bug: 353679003
Test: Existing tests
Flag: com.android.systemui.scene_container
Change-Id: I149a338290760d052e6d45d85a634bce86532d7d
parent 5fb380ec
Loading
Loading
Loading
Loading
+17 −66
Original line number Diff line number Diff line
@@ -405,20 +405,10 @@ private class DragControllerImpl(
            return 0f
        }

        fun animateTo(targetContent: T, targetOffset: Float) {
            // If the effective current content changed, it should be reflected right now in the
            // current state, even before the settle animation is ongoing. That way all the
            // swipeables and back handlers will be refreshed and the user can for instance quickly
            // swipe vertically from A => B then horizontally from B => C, or swipe from A => B then
            // immediately go back B => A.
            if (targetContent != swipeAnimation.currentContent) {
                swipeAnimation.currentContent = targetContent
            }

        fun animateTo(targetContent: T) {
            swipeAnimation.animateOffset(
                coroutineScope = draggableHandler.coroutineScope,
                initialVelocity = velocity,
                targetOffset = targetOffset,
                targetContent = targetContent,
            )
        }
@@ -433,8 +423,7 @@ private class DragControllerImpl(
            // Compute the destination content (and therefore offset) to settle in.
            val offset = swipeAnimation.dragOffset
            val distance = swipeAnimation.distance()
            var targetContent: Content
            var targetOffset: Float
            val targetContent =
                if (
                    distance != DistanceUnspecified &&
                        shouldCommitSwipe(
@@ -445,56 +434,18 @@ private class DragControllerImpl(
                            requiresFullDistanceSwipe = swipeAnimation.requiresFullDistanceSwipe,
                        )
                ) {
                targetContent = toContent
                targetOffset = distance
            } else {
                targetContent = fromContent
                targetOffset = 0f
            }

            fun shouldChangeContent(): Boolean {
                return when (val transition = swipeAnimation.contentTransition) {
                    is TransitionState.Transition.ChangeCurrentScene ->
                        layoutState.canChangeScene(targetContent.key as SceneKey)
                    is TransitionState.Transition.ShowOrHideOverlay -> {
                        if (targetContent.key == transition.overlay) {
                            layoutState.canShowOverlay(transition.overlay)
                        } else {
                            layoutState.canHideOverlay(transition.overlay)
                        }
                    }
                    is TransitionState.Transition.ReplaceOverlay -> {
                        val to = targetContent.key as OverlayKey
                        val from =
                            if (to == transition.toOverlay) transition.fromOverlay
                            else transition.toOverlay
                        layoutState.canReplaceOverlay(from, to)
                    }
                }
            }

            if (targetContent != swipeAnimation.currentContent && !shouldChangeContent()) {
                // We wanted to change to a new scene but we are not allowed to, so we animate back
                // to the current scene.
                targetContent = swipeAnimation.currentContent
                targetOffset =
                    if (targetContent == fromContent) {
                        0f
                    toContent
                } else {
                        check(distance != DistanceUnspecified) {
                            "distance is equal to $DistanceUnspecified"
                        }
                        distance
                    }
                    fromContent
                }

            animateTo(targetContent = targetContent, targetOffset = targetOffset)
            animateTo(targetContent = targetContent)
        } else {
            // We are doing an overscroll preview animation between scenes.
            check(fromContent == swipeAnimation.currentContent) {
                "canChangeContent is false but currentContent != fromContent"
            }
            animateTo(targetContent = fromContent, targetOffset = 0f)
            animateTo(targetContent = fromContent)
        }

        // The onStop animation consumes any remaining velocity.
+50 −16
Original line number Diff line number Diff line
@@ -265,7 +265,6 @@ internal class SwipeAnimation<T : Content>(
        // TODO(b/317063114) The CoroutineScope should be removed.
        coroutineScope: CoroutineScope,
        initialVelocity: Float,
        targetOffset: Float,
        targetContent: T,
    ): OffsetAnimation {
        val initialProgress = progress
@@ -277,6 +276,33 @@ internal class SwipeAnimation<T : Content>(
        val skipAnimation =
            hasReachedTargetContent && !contentTransition.isWithinProgressRange(initialProgress)

        val targetContent =
            if (targetContent != currentContent && !canChangeContent(targetContent)) {
                currentContent
            } else {
                targetContent
            }

        val targetOffset =
            if (targetContent == fromContent) {
                0f
            } else {
                val distance = distance()
                check(distance != DistanceUnspecified) {
                    "distance is equal to $DistanceUnspecified"
                }
                distance
            }

        // If the effective current content changed, it should be reflected right now in the
        // current state, even before the settle animation is ongoing. That way all the
        // swipeables and back handlers will be refreshed and the user can for instance quickly
        // swipe vertically from A => B then horizontally from B => C, or swipe from A => B then
        // immediately go back B => A.
        if (targetContent != currentContent) {
            currentContent = targetContent
        }

        return startOffsetAnimation {
            val animatable = Animatable(dragOffset, OffsetVisibilityThreshold)
            val isTargetGreater = targetOffset > animatable.value
@@ -342,7 +368,28 @@ internal class SwipeAnimation<T : Content>(
        }
    }

    fun snapToContent(content: T) {
    private fun canChangeContent(targetContent: Content): Boolean {
        val layoutState = layoutImpl.state
        return when (val transition = contentTransition) {
            is TransitionState.Transition.ChangeCurrentScene ->
                layoutState.canChangeScene(targetContent.key as SceneKey)
            is TransitionState.Transition.ShowOrHideOverlay -> {
                if (targetContent.key == transition.overlay) {
                    layoutState.canShowOverlay(transition.overlay)
                } else {
                    layoutState.canHideOverlay(transition.overlay)
                }
            }
            is TransitionState.Transition.ReplaceOverlay -> {
                val to = targetContent.key as OverlayKey
                val from =
                    if (to == transition.toOverlay) transition.fromOverlay else transition.toOverlay
                layoutState.canReplaceOverlay(from, to)
            }
        }
    }

    private fun snapToContent(content: T) {
        cancelOffsetAnimation()
        check(currentContent == content)
        layoutImpl.state.finishTransition(contentTransition)
@@ -358,24 +405,11 @@ internal class SwipeAnimation<T : Content>(
        }

        // Animate to the current content.
        val targetContent = currentContent
        val targetOffset =
            if (targetContent == fromContent) {
                0f
            } else {
                val distance = distance()
                check(distance != DistanceUnspecified) {
                    "targetContent != fromContent but distance is unspecified"
                }
                distance
            }

        val animation =
            animateOffset(
                coroutineScope = layoutImpl.coroutineScope,
                initialVelocity = 0f,
                targetOffset = targetOffset,
                targetContent = targetContent,
                targetContent = currentContent,
            )
        check(offsetAnimation == animation)
        return animation.job