CardEditFields.kt

3.2 KB · raw

1package com.peachpasswords.ui.vault23import androidx.compose.foundation.clickable4import androidx.compose.foundation.layout.padding5import androidx.compose.foundation.shape.RoundedCornerShape6import androidx.compose.material3.Text7import androidx.compose.runtime.Composable8import androidx.compose.ui.Modifier9import androidx.compose.ui.draw.clip10import androidx.compose.ui.text.input.KeyboardType11import androidx.compose.ui.text.input.PasswordVisualTransformation12import androidx.compose.ui.text.input.VisualTransformation13import androidx.compose.ui.unit.dp14import androidx.compose.ui.unit.sp15import com.peachpasswords.ui.theme.LocalPeachAccent16import com.peachpasswords.ui.theme.peachColors17import com.peachpasswords.ui.theme.PeachType1819/**20 * D2 — EntryEdit CARD field block. Self-contained: drop a single call to21 * [CardEditFields] in place of the login fields when `f.type == "card"`.22 *23 * Mirrors the existing private `Field` underline style in EntryEditScreen.kt24 * (1.dp T3 border, mono 13sp, accent cursor). Includes its own label+box25 * primitive (`CardField`) so it does not depend on that file's private members.26 *27 * Network is detected live from the card number; CVC maxLength + PAN grouping28 * follow the detected network (Amex 15/4, others 16/3).29 */30@Composable31fun CardEditFields(32    cardNumber: String,33    cardholderName: String,34    expiry: String,35    cvc: String,36    showCvc: Boolean,37    network: String,38    onCardNumber: (String) -> Unit,39    onCardholder: (String) -> Unit,40    onExpiry: (String) -> Unit,41    onCvc: (String) -> Unit,42    onToggleShowCvc: () -> Unit,43) {44    // CARD NUMBER — auto-formatted, network label beside the label.45    PeachField(46        label = "card number",47        value = cardNumber,48        onChange = { raw -> onCardNumber(CardFieldUtils.formatPan(raw)) },49        keyboardType = KeyboardType.Number,50        labelTrailing = {51            val net = CardFieldUtils.networkLabel(network)52            if (net.isNotEmpty()) {53                Text(net, color = peachColors.T2, fontFamily = PeachType.Mono, fontSize = 9.sp)54            }55        },56    )5758    // CARDHOLDER — Inter body, not mono.59    PeachField(60        label = "cardholder",61        value = cardholderName,62        onChange = onCardholder,63        mono = false,64    )6566    // EXPIRY — auto "MM/YY".67    PeachField(68        label = "expiry",69        value = expiry,70        onChange = { raw -> onExpiry(CardFieldUtils.formatExpiry(raw)) },71        keyboardType = KeyboardType.Number,72    )7374    // CVC — masked by default, eye toggle, maxLength by network.75    val cvcMax = CardFieldUtils.cvcMaxDigits(network)76    PeachField(77        label = "cvc",78        value = cvc,79        onChange = { raw -> onCvc(raw.filter { it.isDigit() }.take(cvcMax)) },80        keyboardType = KeyboardType.NumberPassword,81        visualTransformation = if (showCvc) VisualTransformation.None else PasswordVisualTransformation(),82        trailing = {83            Text(84                if (showCvc) "hide" else "show",85                color = LocalPeachAccent.current, fontFamily = PeachType.Mono, fontSize = 9.sp,86                modifier = Modifier.clip(RoundedCornerShape(6.dp)).clickable(onClick = onToggleShowCvc).padding(6.dp),87            )88        },89    )90}