PeachField.kt

5.4 KB · raw

1package com.peachpasswords.ui.vault23import androidx.compose.foundation.interaction.MutableInteractionSource4import androidx.compose.foundation.interaction.collectIsFocusedAsState5import androidx.compose.foundation.background6import androidx.compose.foundation.border7import androidx.compose.foundation.layout.Box8import androidx.compose.foundation.layout.Column9import androidx.compose.foundation.layout.Row10import androidx.compose.foundation.layout.Spacer11import androidx.compose.foundation.layout.fillMaxWidth12import androidx.compose.foundation.layout.height13import androidx.compose.foundation.layout.padding14import androidx.compose.foundation.layout.width15import androidx.compose.foundation.shape.RoundedCornerShape16import androidx.compose.foundation.text.BasicTextField17import androidx.compose.foundation.text.KeyboardOptions18import androidx.compose.material3.Text19import androidx.compose.runtime.Composable20import androidx.compose.runtime.getValue21import androidx.compose.runtime.remember22import androidx.compose.ui.Alignment23import androidx.compose.ui.Modifier24import androidx.compose.ui.draw.drawBehind25import androidx.compose.ui.geometry.Offset26import androidx.compose.ui.geometry.Size27import androidx.compose.ui.graphics.SolidColor28import androidx.compose.ui.text.TextStyle29import androidx.compose.ui.text.input.KeyboardType30import androidx.compose.ui.text.input.VisualTransformation31import androidx.compose.ui.unit.dp32import androidx.compose.ui.unit.em33import androidx.compose.ui.unit.sp34import com.peachpasswords.ui.theme.LocalPeachAccent35import com.peachpasswords.ui.theme.peachColors36import com.peachpasswords.ui.theme.PeachType37import com.peachpasswords.ui.theme.PeachRadius38import com.peachpasswords.ui.theme.PeachSpacing3940/**41 * The Peach text field used across the entry-edit screens: a bare underline (no42 * border box), drawn in t3 and lit to the accent while focused — matching the43 * lock screen's credential inputs. Label is IBM Plex Mono 9sp, uppercase, t2,44 * with 0.08em tracking.45 *46 * Replaces the old boxed `Field`/`CardField` primitives so every new-entry input47 * shares one underline style (brief Fix 6).48 */49@Composable50fun PeachField(51    label: String,52    value: String,53    onChange: (String) -> Unit,54    modifier: Modifier = Modifier,55    singleLine: Boolean = true,56    mono: Boolean = true,57    keyboardType: KeyboardType = KeyboardType.Text,58    visualTransformation: VisualTransformation = VisualTransformation.None,59    labelTrailing: (@Composable () -> Unit)? = null,60    trailing: (@Composable () -> Unit)? = null,61    joined: Boolean = false,62    divider: Boolean = false,63) {64    val accent = LocalPeachAccent.current65    val interaction = remember { MutableInteractionSource() }66    val focused by interaction.collectIsFocusedAsState()67    Column(68        modifier.fillMaxWidth()69            .then(if (joined) Modifier else Modifier.padding(bottom = PeachSpacing.sm))70            .then(71                if (joined) Modifier.padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.md)72                else Modifier73                    .background(peachColors.SurfaceCard, RoundedCornerShape(PeachRadius.StackCard))74                    .border(1.dp, peachColors.T3, RoundedCornerShape(PeachRadius.StackCard))75                    .padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.md),76            ),77    ) {78        Row(verticalAlignment = Alignment.CenterVertically) {79            Text(80                label.uppercase(),81                color = peachColors.T2,82                fontFamily = PeachType.Mono,83                fontSize = 9.sp,84                letterSpacing = 0.08.em,85            )86            if (labelTrailing != null) {87                Spacer(Modifier.width(8.dp))88                labelTrailing()89            }90        }91        Spacer(Modifier.height(6.dp))92        Row(verticalAlignment = Alignment.CenterVertically) {93            BasicTextField(94                value = value,95                onValueChange = onChange,96                singleLine = singleLine,97                textStyle = TextStyle(98                    color = peachColors.T0,99                    fontFamily = if (mono) PeachType.Mono else PeachType.Body,100                    fontSize = 13.sp,101                ),102                cursorBrush = SolidColor(accent),103                interactionSource = interaction,104                keyboardOptions = KeyboardOptions(keyboardType = keyboardType),105                visualTransformation = visualTransformation,106                modifier = Modifier107                    .weight(1f)108                    .drawBehind {109                        if (focused) drawRect(110                            color = accent,111                            topLeft = Offset(0f, size.height - 1.dp.toPx()),112                            size = Size(size.width, 1.dp.toPx()),113                        )114                    }115                    .padding(vertical = 8.dp),116            )117            if (trailing != null) {118                Spacer(Modifier.width(8.dp))119                trailing()120            }121        }122    }123    if (joined && divider) Box(Modifier.fillMaxWidth().height(1.dp).background(peachColors.T3))124}125126@Composable127fun PeachFieldStack(modifier: Modifier = Modifier, content: @Composable () -> Unit) {128    Column(129        modifier.fillMaxWidth()130            .padding(bottom = PeachSpacing.sm)131            .background(peachColors.SurfaceCard, RoundedCornerShape(PeachRadius.StackCard))132            .border(1.dp, peachColors.T3, RoundedCornerShape(PeachRadius.StackCard)),133    ) { content() }134}