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

Commit a135731e authored by omarmt's avatar omarmt
Browse files

Remove unused PriorityNestedScrollConnection constructor

The version without Orientation had no practical applications, and it
would have made future updates harder to implement and less efficient.

Test: Just a refactor
Bug: 370949877
Flag: com.android.systemui.scene_container
Change-Id: I5fef1f9904a0628456de013da3ab0127eaad57d6
parent f87fc38d
Loading
Loading
Loading
Loading
+38 −67
Original line number Diff line number Diff line
@@ -34,71 +34,76 @@ internal typealias SuspendedValue<T> = suspend () -> T
 * Note: Call [reset] before destroying this object to make sure you always get a call to [onStop]
 * after [onStart].
 *
 * @sample com.android.compose.animation.scene.rememberSwipeToSceneNestedScrollConnection
 * @sample LargeTopAppBarNestedScrollConnection
 * @sample com.android.compose.animation.scene.NestedScrollHandlerImpl.nestedScrollConnection
 */
class PriorityNestedScrollConnection(
    private val canStartPreScroll: (offsetAvailable: Offset, offsetBeforeStart: Offset) -> Boolean,
    private val canStartPostScroll: (offsetAvailable: Offset, offsetBeforeStart: Offset) -> Boolean,
    private val canStartPostFling: (velocityAvailable: Velocity) -> Boolean,
    orientation: Orientation,
    private val canStartPreScroll: (offsetAvailable: Float, offsetBeforeStart: Float) -> Boolean,
    private val canStartPostScroll: (offsetAvailable: Float, offsetBeforeStart: Float) -> Boolean,
    private val canStartPostFling: (velocityAvailable: Float) -> Boolean,
    private val canContinueScroll: (source: NestedScrollSource) -> Boolean,
    private val canScrollOnFling: Boolean,
    private val onStart: (offsetAvailable: Offset) -> Unit,
    private val onScroll: (offsetAvailable: Offset) -> Offset,
    private val onStop: (velocityAvailable: Velocity) -> SuspendedValue<Velocity>,
) : NestedScrollConnection {
    private val onStart: (offsetAvailable: Float) -> Unit,
    private val onScroll: (offsetAvailable: Float) -> Float,
    private val onStop: (velocityAvailable: Float) -> SuspendedValue<Float>,
) : NestedScrollConnection, SpaceVectorConverter by SpaceVectorConverter(orientation) {

    /** In priority mode [onPreScroll] events are first consumed by the parent, via [onScroll]. */
    private var isPriorityMode = false

    private var offsetScrolledBeforePriorityMode = Offset.Zero
    private var offsetScrolledBeforePriorityMode = 0f

    override fun onPostScroll(
        consumed: Offset,
        available: Offset,
        source: NestedScrollSource,
    ): Offset {
        val availableFloat = available.toFloat()
        // The offset before the start takes into account the up and down movements, starting from
        // the beginning or from the last fling gesture.
        val offsetBeforeStart = offsetScrolledBeforePriorityMode - available
        val offsetBeforeStart = offsetScrolledBeforePriorityMode - availableFloat

        if (
            isPriorityMode ||
                (source == NestedScrollSource.SideEffect && !canScrollOnFling) ||
                !canStartPostScroll(available, offsetBeforeStart)
                !canStartPostScroll(availableFloat, offsetBeforeStart)
        ) {
            // The priority mode cannot start so we won't consume the available offset.
            return Offset.Zero
        }

        return onPriorityStart(available)
        return onPriorityStart(availableFloat).toOffset()
    }

    override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
        if (!isPriorityMode) {
            if (source == NestedScrollSource.UserInput || canScrollOnFling) {
                if (canStartPreScroll(available, offsetScrolledBeforePriorityMode)) {
                    return onPriorityStart(available)
                val availableFloat = available.toFloat()
                if (canStartPreScroll(availableFloat, offsetScrolledBeforePriorityMode)) {
                    return onPriorityStart(availableFloat).toOffset()
                }
                // We want to track the amount of offset consumed before entering priority mode
                offsetScrolledBeforePriorityMode += available
                offsetScrolledBeforePriorityMode += availableFloat
            }

            return Offset.Zero
        }

        val availableFloat = available.toFloat()
        if (!canContinueScroll(source)) {
            // Step 3a: We have lost priority and we no longer need to intercept scroll events.
            onPriorityStop(velocity = Velocity.Zero)
            onPriorityStop(velocity = 0f)

            // We've just reset offsetScrolledBeforePriorityMode to Offset.Zero
            // We've just reset offsetScrolledBeforePriorityMode to 0f
            // We want to track the amount of offset consumed before entering priority mode
            offsetScrolledBeforePriorityMode += available
            offsetScrolledBeforePriorityMode += availableFloat

            return Offset.Zero
        }

        // Step 2: We have the priority and can consume the scroll events.
        return onScroll(available)
        return onScroll(availableFloat).toOffset()
    }

    override suspend fun onPreFling(available: Velocity): Velocity {
@@ -108,15 +113,16 @@ class PriorityNestedScrollConnection(
        }
        // Step 3b: The finger is lifted, we can stop intercepting scroll events and use the speed
        // of the fling gesture.
        return onPriorityStop(velocity = available).invoke()
        return onPriorityStop(velocity = available.toFloat()).invoke().toVelocity()
    }

    override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
        val availableFloat = available.toFloat()
        if (isPriorityMode) {
            return onPriorityStop(velocity = available).invoke()
            return onPriorityStop(velocity = availableFloat).invoke().toVelocity()
        }

        if (!canStartPostFling(available)) {
        if (!canStartPostFling(availableFloat)) {
            return Velocity.Zero
        }

@@ -124,11 +130,11 @@ class PriorityNestedScrollConnection(
        // given the available velocity.
        // TODO(b/291053278): Remove canStartPostFling() and instead make it possible to define the
        // overscroll behavior on the Scene level.
        val smallOffset = Offset(available.x.sign, available.y.sign)
        onPriorityStart(available = smallOffset)
        val smallOffset = availableFloat.sign
        onPriorityStart(availableOffset = smallOffset)

        // This is the last event of a scroll gesture.
        return onPriorityStop(available).invoke()
        return onPriorityStop(availableFloat).invoke().toVelocity()
    }

    /**
@@ -138,10 +144,10 @@ class PriorityNestedScrollConnection(
     */
    fun reset() {
        // Step 3c: To ensure that an onStop is always called for every onStart.
        onPriorityStop(velocity = Velocity.Zero)
        onPriorityStop(velocity = 0f)
    }

    private fun onPriorityStart(available: Offset): Offset {
    private fun onPriorityStart(availableOffset: Float): Float {
        if (isPriorityMode) {
            error("This should never happen, onPriorityStart() was called when isPriorityMode")
        }
@@ -152,17 +158,17 @@ class PriorityNestedScrollConnection(

        // Note: onStop will be called if we cannot continue to scroll (step 3a), or the finger is
        // lifted (step 3b), or this object has been destroyed (step 3c).
        onStart(available)
        onStart(availableOffset)

        return onScroll(available)
        return onScroll(availableOffset)
    }

    private fun onPriorityStop(velocity: Velocity): SuspendedValue<Velocity> {
    private fun onPriorityStop(velocity: Float): SuspendedValue<Float> {
        // We can restart tracking the consumed offsets from scratch.
        offsetScrolledBeforePriorityMode = Offset.Zero
        offsetScrolledBeforePriorityMode = 0f

        if (!isPriorityMode) {
            return { Velocity.Zero }
            return { 0f }
        }

        isPriorityMode = false
@@ -170,38 +176,3 @@ class PriorityNestedScrollConnection(
        return onStop(velocity)
    }
}

fun PriorityNestedScrollConnection(
    orientation: Orientation,
    canStartPreScroll: (offsetAvailable: Float, offsetBeforeStart: Float) -> Boolean,
    canStartPostScroll: (offsetAvailable: Float, offsetBeforeStart: Float) -> Boolean,
    canStartPostFling: (velocityAvailable: Float) -> Boolean,
    canContinueScroll: (source: NestedScrollSource) -> Boolean,
    canScrollOnFling: Boolean,
    onStart: (offsetAvailable: Float) -> Unit,
    onScroll: (offsetAvailable: Float) -> Float,
    onStop: (velocityAvailable: Float) -> SuspendedValue<Float>,
) =
    with(SpaceVectorConverter(orientation)) {
        PriorityNestedScrollConnection(
            canStartPreScroll = { offsetAvailable: Offset, offsetBeforeStart: Offset ->
                canStartPreScroll(offsetAvailable.toFloat(), offsetBeforeStart.toFloat())
            },
            canStartPostScroll = { offsetAvailable: Offset, offsetBeforeStart: Offset ->
                canStartPostScroll(offsetAvailable.toFloat(), offsetBeforeStart.toFloat())
            },
            canStartPostFling = { velocityAvailable: Velocity ->
                canStartPostFling(velocityAvailable.toFloat())
            },
            canContinueScroll = canContinueScroll,
            canScrollOnFling = canScrollOnFling,
            onStart = { offsetAvailable -> onStart(offsetAvailable.toFloat()) },
            onScroll = { offsetAvailable: Offset ->
                onScroll(offsetAvailable.toFloat()).toOffset()
            },
            onStop = { velocityAvailable: Velocity ->
                val consumedVelocity = onStop(velocityAvailable.toFloat())
                suspend { consumedVelocity.invoke().toVelocity() }
            },
        )
    }
+26 −29
Original line number Diff line number Diff line
@@ -18,8 +18,9 @@

package com.android.compose.nestedscroll

import androidx.compose.foundation.gestures.Orientation
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion.UserInput
import androidx.compose.ui.unit.Velocity
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
@@ -35,13 +36,14 @@ class PriorityNestedScrollConnectionTest {
    private var canStartPostFling = false
    private var canContinueScroll = false
    private var isStarted = false
    private var lastScroll: Offset? = null
    private var returnOnScroll = Offset.Zero
    private var lastStop: Velocity? = null
    private var returnOnStop = Velocity.Zero
    private var lastScroll: Float? = null
    private var returnOnScroll = 0f
    private var lastStop: Float? = null
    private var returnOnStop = 0f

    private val scrollConnection =
        PriorityNestedScrollConnection(
            orientation = Orientation.Vertical,
            canStartPreScroll = { _, _ -> canStartPreScroll },
            canStartPostScroll = { _, _ -> canStartPostScroll },
            canStartPostFling = { canStartPostFling },
@@ -58,11 +60,6 @@ class PriorityNestedScrollConnectionTest {
            },
        )

    private val offset1 = Offset(1f, 1f)
    private val offset2 = Offset(2f, 2f)
    private val velocity1 = Velocity(1f, 1f)
    private val velocity2 = Velocity(2f, 2f)

    @Test
    fun step1_priorityModeShouldStartOnlyOnPreScroll() = runTest {
        canStartPreScroll = true
@@ -70,7 +67,7 @@ class PriorityNestedScrollConnectionTest {
        scrollConnection.onPostScroll(
            consumed = Offset.Zero,
            available = Offset.Zero,
            source = NestedScrollSource.Drag,
            source = UserInput,
        )
        assertThat(isStarted).isEqualTo(false)

@@ -80,7 +77,7 @@ class PriorityNestedScrollConnectionTest {
        scrollConnection.onPostFling(consumed = Velocity.Zero, available = Velocity.Zero)
        assertThat(isStarted).isEqualTo(false)

        scrollConnection.onPreScroll(available = Offset.Zero, source = NestedScrollSource.Drag)
        scrollConnection.onPreScroll(available = Offset.Zero, source = UserInput)
        assertThat(isStarted).isEqualTo(true)
    }

@@ -89,7 +86,7 @@ class PriorityNestedScrollConnectionTest {
        scrollConnection.onPostScroll(
            consumed = Offset.Zero,
            available = Offset.Zero,
            source = NestedScrollSource.Drag,
            source = UserInput,
        )
    }

@@ -97,7 +94,7 @@ class PriorityNestedScrollConnectionTest {
    fun step1_priorityModeShouldStartOnlyOnPostScroll() = runTest {
        canStartPostScroll = true

        scrollConnection.onPreScroll(available = Offset.Zero, source = NestedScrollSource.Drag)
        scrollConnection.onPreScroll(available = Offset.Zero, source = UserInput)
        assertThat(isStarted).isEqualTo(false)

        scrollConnection.onPreFling(available = Velocity.Zero)
@@ -115,7 +112,7 @@ class PriorityNestedScrollConnectionTest {
        scrollConnection.onPostScroll(
            consumed = Offset.Zero,
            available = Offset.Zero,
            source = NestedScrollSource.Drag,
            source = UserInput,
        )
        assertThat(isStarted).isEqualTo(false)

@@ -128,12 +125,12 @@ class PriorityNestedScrollConnectionTest {
        canStartPostScroll = true

        scrollConnection.onPostScroll(
            consumed = offset1,
            available = offset2,
            source = NestedScrollSource.Drag,
            consumed = Offset(1f, 1f),
            available = Offset(2f, 2f),
            source = UserInput,
        )

        assertThat(lastScroll).isEqualTo(offset2)
        assertThat(lastScroll).isEqualTo(2f)
    }

    @Test
@@ -141,13 +138,13 @@ class PriorityNestedScrollConnectionTest {
        startPriorityModePostScroll()
        canContinueScroll = true

        scrollConnection.onPreScroll(available = offset1, source = NestedScrollSource.Drag)
        assertThat(lastScroll).isEqualTo(offset1)
        scrollConnection.onPreScroll(available = Offset(1f, 1f), source = UserInput)
        assertThat(lastScroll).isEqualTo(1f)

        canContinueScroll = false
        scrollConnection.onPreScroll(available = offset2, source = NestedScrollSource.Drag)
        assertThat(lastScroll).isNotEqualTo(offset2)
        assertThat(lastScroll).isEqualTo(offset1)
        scrollConnection.onPreScroll(available = Offset(2f, 2f), source = UserInput)
        assertThat(lastScroll).isNotEqualTo(2f)
        assertThat(lastScroll).isEqualTo(1f)
    }

    @Test
@@ -155,7 +152,7 @@ class PriorityNestedScrollConnectionTest {
        startPriorityModePostScroll()
        canContinueScroll = false

        scrollConnection.onPreScroll(available = Offset.Zero, source = NestedScrollSource.Drag)
        scrollConnection.onPreScroll(available = Offset.Zero, source = UserInput)

        assertThat(lastStop).isNotNull()
    }
@@ -184,22 +181,22 @@ class PriorityNestedScrollConnectionTest {
    fun receive_onPostFling() = runTest {
        canStartPostFling = true

        scrollConnection.onPostFling(consumed = velocity1, available = velocity2)
        scrollConnection.onPostFling(consumed = Velocity(1f, 1f), available = Velocity(2f, 2f))

        assertThat(lastStop).isEqualTo(velocity2)
        assertThat(lastStop).isEqualTo(2f)
    }

    @Test
    fun step1_priorityModeShouldStartOnlyOnPostFling() = runTest {
        canStartPostFling = true

        scrollConnection.onPreScroll(available = Offset.Zero, source = NestedScrollSource.Drag)
        scrollConnection.onPreScroll(available = Offset.Zero, source = UserInput)
        assertThat(isStarted).isEqualTo(false)

        scrollConnection.onPostScroll(
            consumed = Offset.Zero,
            available = Offset.Zero,
            source = NestedScrollSource.Drag,
            source = UserInput,
        )
        assertThat(isStarted).isEqualTo(false)