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.MaterialTheme16import androidx.compose.material3.Surface17import androidx.compose.runtime.Composable18import androidx.compose.runtime.getValue19import androidx.compose.runtime.mutableFloatStateOf20import androidx.compose.runtime.remember21import androidx.compose.runtime.setValue22import androidx.compose.ui.Modifier23import androidx.compose.ui.unit.Dp24import androidx.compose.ui.unit.dp25import com.peachpasswords.ui.theme.LocalReduceMotion26import com.peachpasswords.ui.theme.PeachSpacing27import com.peachpasswords.ui.theme.peachColors2829@Composable30fun PeachExpandableCard(31 modifier: Modifier = Modifier,32 collapsedHeight: Dp = 168.dp,33 expandedHeight: Dp = 360.dp,34 content: @Composable ColumnScope.(progress: Float) -> Unit,35) {36 val reduceMotion = LocalReduceMotion.current37 var progress by remember { mutableFloatStateOf(0f) }38 val animatedHeight by animateDpAsState(39 targetValue = collapsedHeight + (expandedHeight - collapsedHeight) * progress,40 animationSpec = if (reduceMotion) {41 spring(stiffness = Spring.StiffnessHigh, dampingRatio = Spring.DampingRatioNoBouncy)42 } else {43 spring(stiffness = Spring.StiffnessLow, dampingRatio = Spring.DampingRatioMediumBouncy)44 },45 label = "peach_expandable_card_height",46 )47 val scrollState = rememberScrollableState { delta ->48 val old = progress49 progress = (progress + delta / 900f).coerceIn(0f, 1f)50 if (old == progress) 0f else delta51 }5253 Surface(54 modifier = modifier55 .fillMaxWidth()56 .height(animatedHeight)57 .scrollable(scrollState, orientation = Orientation.Vertical),58 color = peachColors.SurfaceElevated,59 60 contentColor = MaterialTheme.colorScheme.onSurface,61 shape = RoundedCornerShape(18.dp),62 tonalElevation = 1.dp,63 ) {64 Column(Modifier.padding(PeachSpacing.lg)) {65 content(progress)66 }67 }68}