1package com.peachpasswords.ui.components23import androidx.compose.animation.core.Spring4import androidx.compose.animation.core.animateDpAsState5import androidx.compose.animation.core.spring6import androidx.compose.foundation.gestures.Orientation7import androidx.compose.foundation.gestures.scrollable8import androidx.compose.foundation.gestures.rememberScrollableState9import androidx.compose.foundation.layout.Column10import androidx.compose.foundation.layout.ColumnScope11import androidx.compose.foundation.layout.fillMaxWidth12import androidx.compose.foundation.layout.height13import androidx.compose.foundation.layout.padding14import androidx.compose.foundation.shape.RoundedCornerShape15import androidx.compose.material3.Surface16import androidx.compose.runtime.Composable17import androidx.compose.runtime.getValue18import androidx.compose.runtime.mutableFloatStateOf19import androidx.compose.runtime.remember20import androidx.compose.runtime.setValue21import androidx.compose.ui.Modifier22import androidx.compose.ui.unit.Dp23import androidx.compose.ui.unit.dp24import com.peachpasswords.ui.theme.LocalReduceMotion25import com.peachpasswords.ui.theme.PeachSpacing26import com.peachpasswords.ui.theme.peachColors2728@Composable29fun PeachExpandableCard(30 modifier: Modifier = Modifier,31 collapsedHeight: Dp = 168.dp,32 expandedHeight: Dp = 360.dp,33 content: @Composable ColumnScope.(progress: Float) -> Unit,34) {35 val reduceMotion = LocalReduceMotion.current36 var progress by remember { mutableFloatStateOf(0f) }37 val animatedHeight by animateDpAsState(38 targetValue = collapsedHeight + (expandedHeight - collapsedHeight) * progress,39 animationSpec = if (reduceMotion) {40 spring(stiffness = Spring.StiffnessHigh, dampingRatio = Spring.DampingRatioNoBouncy)41 } else {42 spring(stiffness = Spring.StiffnessLow, dampingRatio = Spring.DampingRatioMediumBouncy)43 },44 label = "peach_expandable_card_height",45 )46 val scrollState = rememberScrollableState { delta ->47 val old = progress48 progress = (progress + delta / 900f).coerceIn(0f, 1f)49 if (old == progress) 0f else delta50 }5152 Surface(53 modifier = modifier54 .fillMaxWidth()55 .height(animatedHeight)56 .scrollable(scrollState, orientation = Orientation.Vertical),57 color = peachColors.SurfaceElevated,58 contentColor = peachColors.T0,59 shape = RoundedCornerShape(18.dp),60 tonalElevation = 1.dp,61 ) {62 Column(Modifier.padding(PeachSpacing.lg)) {63 content(progress)64 }65 }66}