mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Fix scroll animation when system animation is disabled (#7509)
This commit is contained in:
		| @@ -3,7 +3,6 @@ package eu.kanade.presentation.browse | ||||
| import androidx.compose.foundation.layout.WindowInsets | ||||
| import androidx.compose.foundation.layout.asPaddingValues | ||||
| import androidx.compose.foundation.layout.navigationBars | ||||
| import androidx.compose.foundation.lazy.LazyColumn | ||||
| import androidx.compose.foundation.lazy.items | ||||
| import androidx.compose.material3.Switch | ||||
| import androidx.compose.material3.Text | ||||
| @@ -15,6 +14,7 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection | ||||
| import androidx.compose.ui.input.nestedscroll.nestedScroll | ||||
| import androidx.compose.ui.platform.LocalContext | ||||
| import eu.kanade.presentation.components.EmptyScreen | ||||
| import eu.kanade.presentation.components.LazyColumn | ||||
| import eu.kanade.presentation.components.LoadingScreen | ||||
| import eu.kanade.presentation.components.PreferenceRow | ||||
| import eu.kanade.tachiyomi.R | ||||
|   | ||||
| @@ -2,12 +2,12 @@ package eu.kanade.presentation.category.components | ||||
|  | ||||
| import androidx.compose.foundation.layout.Arrangement | ||||
| import androidx.compose.foundation.layout.PaddingValues | ||||
| import androidx.compose.foundation.lazy.LazyColumn | ||||
| import androidx.compose.foundation.lazy.LazyListState | ||||
| import androidx.compose.foundation.lazy.itemsIndexed | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.ui.unit.dp | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.presentation.components.LazyColumn | ||||
|  | ||||
| @Composable | ||||
| fun CategoryContent( | ||||
|   | ||||
| @@ -1,11 +1,9 @@ | ||||
| package eu.kanade.presentation.components | ||||
|  | ||||
| import androidx.compose.foundation.gestures.FlingBehavior | ||||
| import androidx.compose.foundation.gestures.ScrollableDefaults | ||||
| import androidx.compose.foundation.layout.Arrangement | ||||
| import androidx.compose.foundation.layout.PaddingValues | ||||
| import androidx.compose.foundation.layout.calculateEndPadding | ||||
| import androidx.compose.foundation.lazy.LazyColumn | ||||
| import androidx.compose.foundation.lazy.LazyListScope | ||||
| import androidx.compose.foundation.lazy.LazyListState | ||||
| import androidx.compose.foundation.lazy.rememberLazyListState | ||||
| @@ -17,6 +15,38 @@ import androidx.compose.ui.platform.LocalDensity | ||||
| import androidx.compose.ui.platform.LocalLayoutDirection | ||||
| import androidx.compose.ui.unit.dp | ||||
| import eu.kanade.presentation.util.drawVerticalScrollbar | ||||
| import eu.kanade.presentation.util.flingBehaviorIgnoringMotionScale | ||||
|  | ||||
| /** | ||||
|  * LazyColumn with fling animation fix | ||||
|  * | ||||
|  * @see flingBehaviorIgnoringMotionScale | ||||
|  */ | ||||
| @Composable | ||||
| fun LazyColumn( | ||||
|     modifier: Modifier = Modifier, | ||||
|     state: LazyListState = rememberLazyListState(), | ||||
|     contentPadding: PaddingValues = PaddingValues(0.dp), | ||||
|     reverseLayout: Boolean = false, | ||||
|     verticalArrangement: Arrangement.Vertical = | ||||
|         if (!reverseLayout) Arrangement.Top else Arrangement.Bottom, | ||||
|     horizontalAlignment: Alignment.Horizontal = Alignment.Start, | ||||
|     flingBehavior: FlingBehavior = flingBehaviorIgnoringMotionScale(), | ||||
|     userScrollEnabled: Boolean = true, | ||||
|     content: LazyListScope.() -> Unit, | ||||
| ) { | ||||
|     androidx.compose.foundation.lazy.LazyColumn( | ||||
|         modifier = modifier, | ||||
|         state = state, | ||||
|         contentPadding = contentPadding, | ||||
|         reverseLayout = reverseLayout, | ||||
|         verticalArrangement = verticalArrangement, | ||||
|         horizontalAlignment = horizontalAlignment, | ||||
|         flingBehavior = flingBehavior, | ||||
|         userScrollEnabled = userScrollEnabled, | ||||
|         content = content, | ||||
|     ) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * LazyColumn with scrollbar. | ||||
| @@ -30,7 +60,7 @@ fun ScrollbarLazyColumn( | ||||
|     verticalArrangement: Arrangement.Vertical = | ||||
|         if (!reverseLayout) Arrangement.Top else Arrangement.Bottom, | ||||
|     horizontalAlignment: Alignment.Horizontal = Alignment.Start, | ||||
|     flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), | ||||
|     flingBehavior: FlingBehavior = flingBehaviorIgnoringMotionScale(), | ||||
|     userScrollEnabled: Boolean = true, | ||||
|     content: LazyListScope.() -> Unit, | ||||
| ) { | ||||
| @@ -69,7 +99,7 @@ fun FastScrollLazyColumn( | ||||
|     verticalArrangement: Arrangement.Vertical = | ||||
|         if (!reverseLayout) Arrangement.Top else Arrangement.Bottom, | ||||
|     horizontalAlignment: Alignment.Horizontal = Alignment.Start, | ||||
|     flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), | ||||
|     flingBehavior: FlingBehavior = flingBehaviorIgnoringMotionScale(), | ||||
|     userScrollEnabled: Boolean = true, | ||||
|     content: LazyListScope.() -> Unit, | ||||
| ) { | ||||
|   | ||||
| @@ -20,7 +20,6 @@ import androidx.compose.foundation.layout.navigationBars | ||||
| import androidx.compose.foundation.layout.only | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.foundation.layout.systemBars | ||||
| import androidx.compose.foundation.lazy.LazyColumn | ||||
| import androidx.compose.foundation.lazy.LazyListScope | ||||
| import androidx.compose.foundation.lazy.items | ||||
| import androidx.compose.foundation.lazy.rememberLazyListState | ||||
| @@ -52,6 +51,7 @@ import com.google.accompanist.swiperefresh.SwipeRefresh | ||||
| import com.google.accompanist.swiperefresh.rememberSwipeRefreshState | ||||
| import eu.kanade.domain.chapter.model.Chapter | ||||
| import eu.kanade.presentation.components.ExtendedFloatingActionButton | ||||
| import eu.kanade.presentation.components.LazyColumn | ||||
| import eu.kanade.presentation.components.Scaffold | ||||
| import eu.kanade.presentation.components.SwipeRefreshIndicator | ||||
| import eu.kanade.presentation.components.VerticalFastScroller | ||||
|   | ||||
							
								
								
									
										60
									
								
								app/src/main/java/eu/kanade/presentation/util/Scrollable.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								app/src/main/java/eu/kanade/presentation/util/Scrollable.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| 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 | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user