Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt +17 −41 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.round import com.android.compose.nestedscroll.PriorityNestedScrollConnection Loading Loading @@ -536,24 +535,6 @@ internal class SceneNestedScrollHandler( ) : NestedScrollHandler { override val connection: PriorityNestedScrollConnection = nestedScrollConnection() private fun Offset.toAmount() = when (gestureHandler.orientation) { Orientation.Horizontal -> x Orientation.Vertical -> y } private fun Velocity.toAmount() = when (gestureHandler.orientation) { Orientation.Horizontal -> x Orientation.Vertical -> y } private fun Float.toOffset() = when (gestureHandler.orientation) { Orientation.Horizontal -> Offset(x = this, y = 0f) Orientation.Vertical -> Offset(x = 0f, y = this) } private fun nestedScrollConnection(): PriorityNestedScrollConnection { // If we performed a long gesture before entering priority mode, we would have to avoid // moving on to the next scene. Loading Loading @@ -591,13 +572,12 @@ internal class SceneNestedScrollHandler( } return PriorityNestedScrollConnection( orientation = gestureHandler.orientation, canStartPreScroll = { offsetAvailable, offsetBeforeStart -> canChangeScene = offsetBeforeStart == Offset.Zero canChangeScene = offsetBeforeStart == 0f val canInterceptSwipeTransition = canChangeScene && gestureHandler.isDrivingTransition && offsetAvailable.toAmount() != 0f canChangeScene && gestureHandler.isDrivingTransition && offsetAvailable != 0f if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false val progress = gestureHandler.swipeTransition.progress Loading @@ -618,15 +598,14 @@ internal class SceneNestedScrollHandler( !shouldSnapToIdle }, canStartPostScroll = { offsetAvailable, offsetBeforeStart -> val amount = offsetAvailable.toAmount() val behavior: NestedScrollBehavior = when { amount > 0 -> startBehavior amount < 0 -> endBehavior offsetAvailable > 0f -> startBehavior offsetAvailable < 0f -> endBehavior else -> return@PriorityNestedScrollConnection false } val isZeroOffset = offsetBeforeStart == Offset.Zero val isZeroOffset = offsetBeforeStart == 0f when (behavior) { NestedScrollBehavior.DuringTransitionBetweenScenes -> { Loading @@ -635,30 +614,29 @@ internal class SceneNestedScrollHandler( } NestedScrollBehavior.EdgeNoOverscroll -> { canChangeScene = isZeroOffset isZeroOffset && hasNextScene(amount) isZeroOffset && hasNextScene(offsetAvailable) } NestedScrollBehavior.EdgeWithOverscroll -> { canChangeScene = isZeroOffset hasNextScene(amount) hasNextScene(offsetAvailable) } NestedScrollBehavior.Always -> { canChangeScene = true hasNextScene(amount) hasNextScene(offsetAvailable) } } }, canStartPostFling = { velocityAvailable -> val amount = velocityAvailable.toAmount() val behavior: NestedScrollBehavior = when { amount > 0 -> startBehavior amount < 0 -> endBehavior velocityAvailable > 0f -> startBehavior velocityAvailable < 0f -> endBehavior else -> return@PriorityNestedScrollConnection false } // We could start an overscroll animation canChangeScene = false behavior.canStartOnPostFling && hasNextScene(amount) behavior.canStartOnPostFling && hasNextScene(velocityAvailable) }, canContinueScroll = { true }, onStart = { Loading @@ -671,24 +649,22 @@ internal class SceneNestedScrollHandler( }, onScroll = { offsetAvailable -> if (gestureHandler.gestureWithPriority != this) { return@PriorityNestedScrollConnection Offset.Zero return@PriorityNestedScrollConnection 0f } val amount = offsetAvailable.toAmount() // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is // initiated in a nested child. gestureHandler.onDrag(amount) gestureHandler.onDrag(offsetAvailable) amount.toOffset() offsetAvailable }, onStop = { velocityAvailable -> if (gestureHandler.gestureWithPriority != this) { return@PriorityNestedScrollConnection Velocity.Zero return@PriorityNestedScrollConnection 0f } gestureHandler.onDragStopped( velocity = velocityAvailable.toAmount(), velocity = velocityAvailable, canChangeScene = canChangeScene ) Loading packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt +34 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package com.android.compose.nestedscroll import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.unit.Velocity import com.android.compose.ui.util.SpaceVectorConverter /** * This [NestedScrollConnection] waits for a child to scroll ([onPreScroll] or [onPostScroll]), and Loading Loading @@ -147,3 +149,35 @@ 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: () -> Boolean, onStart: () -> Unit, onScroll: (offsetAvailable: Float) -> Float, onStop: (velocityAvailable: Float) -> 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, onStart = onStart, onScroll = { offsetAvailable: Offset -> onScroll(offsetAvailable.toFloat()).toOffset() }, onStop = { velocityAvailable: Velocity -> onStop(velocityAvailable.toFloat()).toVelocity() }, ) } packages/SystemUI/compose/scene/src/com/android/compose/ui/util/SpaceVectorConverter.kt 0 → 100644 +50 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.compose.ui.util import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Velocity interface SpaceVectorConverter { fun Offset.toFloat(): Float fun Velocity.toFloat(): Float fun Float.toOffset(): Offset fun Float.toVelocity(): Velocity } fun SpaceVectorConverter(orientation: Orientation) = when (orientation) { Orientation.Horizontal -> HorizontalConverter Orientation.Vertical -> VerticalConverter } private val HorizontalConverter = object : SpaceVectorConverter { override fun Offset.toFloat() = x override fun Velocity.toFloat() = x override fun Float.toOffset() = Offset(this, 0f) override fun Float.toVelocity() = Velocity(this, 0f) } private val VerticalConverter = object : SpaceVectorConverter { override fun Offset.toFloat() = y override fun Velocity.toFloat() = y override fun Float.toOffset() = Offset(0f, this) override fun Float.toVelocity() = Velocity(0f, this) } Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt +17 −41 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.round import com.android.compose.nestedscroll.PriorityNestedScrollConnection Loading Loading @@ -536,24 +535,6 @@ internal class SceneNestedScrollHandler( ) : NestedScrollHandler { override val connection: PriorityNestedScrollConnection = nestedScrollConnection() private fun Offset.toAmount() = when (gestureHandler.orientation) { Orientation.Horizontal -> x Orientation.Vertical -> y } private fun Velocity.toAmount() = when (gestureHandler.orientation) { Orientation.Horizontal -> x Orientation.Vertical -> y } private fun Float.toOffset() = when (gestureHandler.orientation) { Orientation.Horizontal -> Offset(x = this, y = 0f) Orientation.Vertical -> Offset(x = 0f, y = this) } private fun nestedScrollConnection(): PriorityNestedScrollConnection { // If we performed a long gesture before entering priority mode, we would have to avoid // moving on to the next scene. Loading Loading @@ -591,13 +572,12 @@ internal class SceneNestedScrollHandler( } return PriorityNestedScrollConnection( orientation = gestureHandler.orientation, canStartPreScroll = { offsetAvailable, offsetBeforeStart -> canChangeScene = offsetBeforeStart == Offset.Zero canChangeScene = offsetBeforeStart == 0f val canInterceptSwipeTransition = canChangeScene && gestureHandler.isDrivingTransition && offsetAvailable.toAmount() != 0f canChangeScene && gestureHandler.isDrivingTransition && offsetAvailable != 0f if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false val progress = gestureHandler.swipeTransition.progress Loading @@ -618,15 +598,14 @@ internal class SceneNestedScrollHandler( !shouldSnapToIdle }, canStartPostScroll = { offsetAvailable, offsetBeforeStart -> val amount = offsetAvailable.toAmount() val behavior: NestedScrollBehavior = when { amount > 0 -> startBehavior amount < 0 -> endBehavior offsetAvailable > 0f -> startBehavior offsetAvailable < 0f -> endBehavior else -> return@PriorityNestedScrollConnection false } val isZeroOffset = offsetBeforeStart == Offset.Zero val isZeroOffset = offsetBeforeStart == 0f when (behavior) { NestedScrollBehavior.DuringTransitionBetweenScenes -> { Loading @@ -635,30 +614,29 @@ internal class SceneNestedScrollHandler( } NestedScrollBehavior.EdgeNoOverscroll -> { canChangeScene = isZeroOffset isZeroOffset && hasNextScene(amount) isZeroOffset && hasNextScene(offsetAvailable) } NestedScrollBehavior.EdgeWithOverscroll -> { canChangeScene = isZeroOffset hasNextScene(amount) hasNextScene(offsetAvailable) } NestedScrollBehavior.Always -> { canChangeScene = true hasNextScene(amount) hasNextScene(offsetAvailable) } } }, canStartPostFling = { velocityAvailable -> val amount = velocityAvailable.toAmount() val behavior: NestedScrollBehavior = when { amount > 0 -> startBehavior amount < 0 -> endBehavior velocityAvailable > 0f -> startBehavior velocityAvailable < 0f -> endBehavior else -> return@PriorityNestedScrollConnection false } // We could start an overscroll animation canChangeScene = false behavior.canStartOnPostFling && hasNextScene(amount) behavior.canStartOnPostFling && hasNextScene(velocityAvailable) }, canContinueScroll = { true }, onStart = { Loading @@ -671,24 +649,22 @@ internal class SceneNestedScrollHandler( }, onScroll = { offsetAvailable -> if (gestureHandler.gestureWithPriority != this) { return@PriorityNestedScrollConnection Offset.Zero return@PriorityNestedScrollConnection 0f } val amount = offsetAvailable.toAmount() // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is // initiated in a nested child. gestureHandler.onDrag(amount) gestureHandler.onDrag(offsetAvailable) amount.toOffset() offsetAvailable }, onStop = { velocityAvailable -> if (gestureHandler.gestureWithPriority != this) { return@PriorityNestedScrollConnection Velocity.Zero return@PriorityNestedScrollConnection 0f } gestureHandler.onDragStopped( velocity = velocityAvailable.toAmount(), velocity = velocityAvailable, canChangeScene = canChangeScene ) Loading
packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt +34 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package com.android.compose.nestedscroll import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.unit.Velocity import com.android.compose.ui.util.SpaceVectorConverter /** * This [NestedScrollConnection] waits for a child to scroll ([onPreScroll] or [onPostScroll]), and Loading Loading @@ -147,3 +149,35 @@ 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: () -> Boolean, onStart: () -> Unit, onScroll: (offsetAvailable: Float) -> Float, onStop: (velocityAvailable: Float) -> 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, onStart = onStart, onScroll = { offsetAvailable: Offset -> onScroll(offsetAvailable.toFloat()).toOffset() }, onStop = { velocityAvailable: Velocity -> onStop(velocityAvailable.toFloat()).toVelocity() }, ) }
packages/SystemUI/compose/scene/src/com/android/compose/ui/util/SpaceVectorConverter.kt 0 → 100644 +50 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.compose.ui.util import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Velocity interface SpaceVectorConverter { fun Offset.toFloat(): Float fun Velocity.toFloat(): Float fun Float.toOffset(): Offset fun Float.toVelocity(): Velocity } fun SpaceVectorConverter(orientation: Orientation) = when (orientation) { Orientation.Horizontal -> HorizontalConverter Orientation.Vertical -> VerticalConverter } private val HorizontalConverter = object : SpaceVectorConverter { override fun Offset.toFloat() = x override fun Velocity.toFloat() = x override fun Float.toOffset() = Offset(this, 0f) override fun Float.toVelocity() = Velocity(this, 0f) } private val VerticalConverter = object : SpaceVectorConverter { override fun Offset.toFloat() = y override fun Velocity.toFloat() = y override fun Float.toOffset() = Offset(0f, this) override fun Float.toVelocity() = Velocity(0f, this) }