PeachExpandableCard.kt

2.5 KB · raw

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}