61 lines
2.2 KiB
Kotlin
Raw Normal View History

package eu.kanade.presentation.util
import androidx.compose.animation.core.AnimationState
import androidx.compose.animation.core.DecayAnimationSpec
import androidx.compose.animation.core.animateDecay
import androidx.compose.animation.rememberSplineBasedDecay
import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.ScrollScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.MotionDurationScale
import kotlinx.coroutines.withContext
import kotlin.math.abs
/**
* FlingBehavior that always uses the default motion scale.
*
* This makes the scrolling animation works like View's lists
* when "Remove animation" settings is on.
*/
@Composable
fun flingBehaviorIgnoringMotionScale(): FlingBehavior {
val flingSpec = rememberSplineBasedDecay<Float>()
return remember(flingSpec) {
DefaultFlingBehavior(flingSpec)
}
}
private val DefaultMotionDurationScale = object : MotionDurationScale {
// Use default motion scale factor
override val scaleFactor: Float = 1f
}
private class DefaultFlingBehavior(
private val flingDecay: DecayAnimationSpec<Float>,
) : FlingBehavior {
override suspend fun ScrollScope.performFling(initialVelocity: Float): Float {
// come up with the better threshold, but we need it since spline curve gives us NaNs
return if (abs(initialVelocity) > 1f) {
var velocityLeft = initialVelocity
var lastValue = 0f
withContext(DefaultMotionDurationScale) {
AnimationState(
initialValue = 0f,
initialVelocity = initialVelocity,
).animateDecay(flingDecay) {
val delta = value - lastValue
val consumed = scrollBy(delta)
lastValue = value
velocityLeft = this.velocity
// avoid rounding errors and stop if anything is unconsumed
if (abs(delta - consumed) > 0.5f) this.cancelAnimation()
}
}
velocityLeft
} else {
initialVelocity
}
}
}