PeachExpandableCard.kt

2.7 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.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        // Gate 1: colorScheme.onSurface is PeachTheme's exact mapping of T0.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}