Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-18 18:13:29 +03:00
parent 6f047b8607
commit 7fe2a4d823
6 changed files with 89 additions and 28 deletions

View file

@ -2,6 +2,7 @@ package com.tangem.core.ui.components.fields
import androidx.compose.animation.*
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
@ -36,9 +37,9 @@ fun PinTextField(
value: String,
length: Int,
isPasswordVisual: Boolean,
pinTextColor: PinTextColor,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
wrongCode: Boolean = false,
) {
val focusRequester = remember { FocusRequester() }
val textFieldValue = remember(value) {
@ -72,7 +73,7 @@ fun PinTextField(
CellDecoration(
length = length,
isPasswordVisual = isPasswordVisual,
wrongCode = wrongCode,
pinTextColor = pinTextColor,
value = value,
)
},
@ -84,17 +85,25 @@ fun PinTextField(
}
}
@Suppress("MagicNumber")
enum class PinTextColor {
Primary,
WrongCode,
Success,
}
@Suppress("MagicNumber", "LongMethod")
@Composable
private fun CellDecoration(
length: Int,
wrongCode: Boolean,
pinTextColor: PinTextColor,
value: String,
modifier: Modifier = Modifier,
isPasswordVisual: Boolean = false,
) {
val textMeasurer = rememberTextMeasurer()
val width = textMeasurer.measure("0")
val minSize = textMeasurer.measure("0")
val minWidth = maxOf(minSize.size.width.dp + 8.dp, 24.dp + 3.dp) // 24.dp is the minimum width of a pin cell
val minHeight = maxOf(minSize.size.height.dp, 48.dp) // 48.dp is the minimum height of a pin cell
Row(
modifier = modifier,
@ -107,6 +116,18 @@ private fun CellDecoration(
""
}
val color = when (pinTextColor) {
PinTextColor.Primary -> {
if (isPasswordVisual) {
TangemTheme.colors.icon.informative
} else {
TangemTheme.colors.text.primary1
}
}
PinTextColor.WrongCode -> TangemTheme.colors.icon.warning
PinTextColor.Success -> TangemTheme.colors.icon.accent
}
Box(
modifier = Modifier
.background(
@ -119,26 +140,34 @@ private fun CellDecoration(
targetState = char,
transitionSpec = {
(
fadeIn(animationSpec = tween(220, delayMillis = 90)) +
slideInVertically(animationSpec = tween(330, delayMillis = 0))
fadeIn(animationSpec = tween(90, delayMillis = 90)) +
slideInVertically(animationSpec = tween(220, delayMillis = 0))
)
.togetherWith(
fadeOut(animationSpec = tween(90)) + slideOutVertically(tween(220)),
)
},
) { text ->
Text(
modifier = Modifier.sizeIn(minWidth = width.size.width.dp + 8.dp, minHeight = 48.dp),
text = text,
style = TangemTheme.typography.h3,
color = if (wrongCode) {
TangemTheme.colors.text.warning
} else {
TangemTheme.colors.text.primary1
},
textAlign = TextAlign.Center,
lineHeight = 48.sp,
)
if (isPasswordVisual && text.isNotEmpty()) {
Canvas(
Modifier.sizeIn(minWidth = minWidth, minHeight = minHeight),
) {
drawCircle(
color = color,
radius = 4.dp.toPx(),
center = center,
)
}
} else {
Text(
modifier = Modifier.sizeIn(minWidth = minWidth, minHeight = minHeight),
text = text,
style = TangemTheme.typography.h3,
color = color,
textAlign = TextAlign.Center,
lineHeight = 48.sp,
)
}
}
}
}
@ -152,10 +181,18 @@ private fun Preview() {
var text by remember { mutableStateOf("123") }
Column {
PinTextField(
value = text,
onValueChange = { text = it },
isPasswordVisual = true,
pinTextColor = PinTextColor.Success,
length = 6,
)
PinTextField(
value = text,
onValueChange = { text = it },
isPasswordVisual = false,
pinTextColor = PinTextColor.Primary,
length = 6,
)