From 2afd250c0533bea207bb8deb1a1df20be3c2d2f9 Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Fri, 8 May 2026 17:50:36 +0500 Subject: [PATCH] perf(animation): drop bouncy springs on high-frequency selection animations --- .../app/navigation/BottomNavigation.kt | 21 +++++++++---------- .../components/HomeFilterChips.kt | 13 ++++++------ .../components/sections/Appearance.kt | 4 ++-- .../components/sections/Installation.kt | 4 ++-- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/BottomNavigation.kt b/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/BottomNavigation.kt index 7fc05516c..c543898a8 100644 --- a/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/BottomNavigation.kt +++ b/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/BottomNavigation.kt @@ -86,13 +86,12 @@ fun BottomNavigation( val targetX = raw.first + rowHorizontalPaddingPx - indicatorHorizontalInsetPx val targetW = raw.second + indicatorHorizontalInsetPx * 2f launch { + // E4.2: tab indicator animated via tween — bouncy spring on a + // high-frequency tap target overshoots on every tab change and + // reads as jittery (survey #16). Tween stays predictable. indicatorX.animateTo( targetValue = targetX, - animationSpec = - spring( - dampingRatio = Spring.DampingRatioLowBouncy, - stiffness = Spring.StiffnessLow, - ), + animationSpec = tween(durationMillis = 250, easing = FastOutSlowInEasing), ) } launch { @@ -289,8 +288,8 @@ private fun LiquidGlassTabItem( targetValue = if (isSelected) 1.15f else 1f, animationSpec = spring( - dampingRatio = Spring.DampingRatioMediumBouncy, - stiffness = Spring.StiffnessLow, + dampingRatio = Spring.DampingRatioNoBouncy, + stiffness = Spring.StiffnessMedium, ), label = "iconScale", ) @@ -299,8 +298,8 @@ private fun LiquidGlassTabItem( targetValue = if (isSelected) (-1).dp else 1.dp, animationSpec = spring( - dampingRatio = Spring.DampingRatioMediumBouncy, - stiffness = Spring.StiffnessLow, + dampingRatio = Spring.DampingRatioNoBouncy, + stiffness = Spring.StiffnessMedium, ), label = "iconOffsetY", ) @@ -326,8 +325,8 @@ private fun LiquidGlassTabItem( targetValue = if (isSelected) 1f else 0.6f, animationSpec = spring( - dampingRatio = Spring.DampingRatioMediumBouncy, - stiffness = Spring.StiffnessLow, + dampingRatio = Spring.DampingRatioNoBouncy, + stiffness = Spring.StiffnessMedium, ), label = "labelScale", ) diff --git a/feature/home/presentation/src/commonMain/kotlin/zed/rainxch/home/presentation/components/HomeFilterChips.kt b/feature/home/presentation/src/commonMain/kotlin/zed/rainxch/home/presentation/components/HomeFilterChips.kt index 6256cddd8..4452539e0 100644 --- a/feature/home/presentation/src/commonMain/kotlin/zed/rainxch/home/presentation/components/HomeFilterChips.kt +++ b/feature/home/presentation/src/commonMain/kotlin/zed/rainxch/home/presentation/components/HomeFilterChips.kt @@ -83,13 +83,12 @@ fun LiquidGlassCategoryChips( val targetW = raw.second + insetPx * 2f launch { + // E4.2: tween over spring for the chip-row indicator — same + // jitter rationale as BottomNavigation. Selecting a category + // hundreds of times per session shouldn't overshoot. indicatorX.animateTo( targetValue = targetX, - animationSpec = - spring( - dampingRatio = Spring.DampingRatioLowBouncy, - stiffness = Spring.StiffnessLow, - ), + animationSpec = tween(durationMillis = 220), ) } launch { @@ -290,8 +289,8 @@ private fun LiquidGlassCategoryChip( targetValue = if (isPressed) 0.90f else 1f, animationSpec = spring( - dampingRatio = Spring.DampingRatioMediumBouncy, - stiffness = Spring.StiffnessMedium, + dampingRatio = Spring.DampingRatioNoBouncy, + stiffness = Spring.StiffnessMediumLow, ), label = "chipPressScale", ) diff --git a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Appearance.kt b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Appearance.kt index fe6bdc924..bb95ae55f 100644 --- a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Appearance.kt +++ b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Appearance.kt @@ -186,8 +186,8 @@ private fun ThemeModeOption( targetValue = if (isSelected) 1.05f else 1f, animationSpec = spring( - dampingRatio = Spring.DampingRatioMediumBouncy, - stiffness = Spring.StiffnessLow, + dampingRatio = Spring.DampingRatioNoBouncy, + stiffness = Spring.StiffnessMedium, ), ) diff --git a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Installation.kt b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Installation.kt index 895e729ec..8ff52c51c 100644 --- a/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Installation.kt +++ b/feature/tweaks/presentation/src/commonMain/kotlin/zed/rainxch/tweaks/presentation/components/sections/Installation.kt @@ -512,8 +512,8 @@ private fun InstallerOption( val scale by animateFloatAsState( targetValue = if (isSelected) 1.02f else 1f, animationSpec = spring( - dampingRatio = Spring.DampingRatioMediumBouncy, - stiffness = Spring.StiffnessLow + dampingRatio = Spring.DampingRatioNoBouncy, + stiffness = Spring.StiffnessMedium ) )