improvement: Align Expiry date's field styling with the common text fields
This commit is contained in:
parent
7c9d9c1022
commit
2e68f469a7
@ -32,7 +32,6 @@ import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Add
|
||||
import androidx.compose.material.icons.outlined.ArrowDropDown
|
||||
import androidx.compose.material.icons.outlined.Clear
|
||||
import androidx.compose.material.icons.outlined.CloudDone
|
||||
import androidx.compose.material.icons.outlined.FileUpload
|
||||
import androidx.compose.material.icons.outlined.Folder
|
||||
@ -41,7 +40,6 @@ import androidx.compose.material.icons.outlined.Password
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@ -64,9 +62,7 @@ import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusDirection
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
@ -77,15 +73,11 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.artemchep.keyguard.common.model.Loadable
|
||||
import com.artemchep.keyguard.common.model.UsernameVariationIcon
|
||||
import com.artemchep.keyguard.common.model.fold
|
||||
import com.artemchep.keyguard.common.model.titleH
|
||||
import com.artemchep.keyguard.common.service.logging.LogRepository
|
||||
import com.artemchep.keyguard.feature.auth.common.TextFieldModel2
|
||||
import com.artemchep.keyguard.feature.auth.common.VisibilityState
|
||||
import com.artemchep.keyguard.feature.auth.common.VisibilityToggle
|
||||
import com.artemchep.keyguard.feature.home.vault.add.AddState
|
||||
import com.artemchep.keyguard.feature.home.vault.component.FlatItemTextContent2
|
||||
import com.artemchep.keyguard.feature.home.vault.component.Section
|
||||
import com.artemchep.keyguard.feature.home.vault.component.VaultViewTotpBadge2
|
||||
@ -107,12 +99,12 @@ import com.artemchep.keyguard.ui.DropdownScopeImpl
|
||||
import com.artemchep.keyguard.ui.EmailFlatTextField
|
||||
import com.artemchep.keyguard.ui.ExpandedIfNotEmpty
|
||||
import com.artemchep.keyguard.ui.ExpandedIfNotEmptyForRow
|
||||
import com.artemchep.keyguard.ui.FakeFlatTextField
|
||||
import com.artemchep.keyguard.ui.FlatDropdown
|
||||
import com.artemchep.keyguard.ui.FlatItem
|
||||
import com.artemchep.keyguard.ui.FlatItemAction
|
||||
import com.artemchep.keyguard.ui.FlatItemLayout
|
||||
import com.artemchep.keyguard.ui.FlatItemTextContent
|
||||
import com.artemchep.keyguard.ui.FlatSimpleNote
|
||||
import com.artemchep.keyguard.ui.FlatTextField
|
||||
import com.artemchep.keyguard.ui.FlatTextFieldBadge
|
||||
import com.artemchep.keyguard.ui.LeMOdelBottomSheet
|
||||
@ -142,7 +134,6 @@ import com.artemchep.keyguard.ui.theme.isDark
|
||||
import com.artemchep.keyguard.ui.theme.monoFontFamily
|
||||
import com.artemchep.keyguard.ui.util.DividerColor
|
||||
import com.artemchep.keyguard.ui.util.HorizontalDivider
|
||||
import com.artemchep.keyguard.ui.util.VerticalDivider
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@ -1086,104 +1077,44 @@ private fun DateMonthYearField(
|
||||
item: AddStateItem.DateMonthYear<*>,
|
||||
) {
|
||||
val state by item.state.flow.collectAsState()
|
||||
BiFlatContainer(
|
||||
val isEmpty by derivedStateOf {
|
||||
val isEmpty = state.month.state.value.isEmpty() &&
|
||||
state.year.state.value.isEmpty()
|
||||
isEmpty
|
||||
}
|
||||
val onClear = remember {
|
||||
// lambda
|
||||
{
|
||||
state.month.state.value = ""
|
||||
state.year.state.value = ""
|
||||
}
|
||||
}
|
||||
FakeFlatTextField(
|
||||
modifier = modifier
|
||||
.padding(horizontal = Dimens.horizontalPadding),
|
||||
contentModifier = Modifier
|
||||
.clickable(
|
||||
indication = LocalIndication.current,
|
||||
interactionSource = remember {
|
||||
MutableInteractionSource()
|
||||
},
|
||||
role = Role.Button,
|
||||
) {
|
||||
state.onClick.invoke()
|
||||
},
|
||||
isError = rememberUpdatedState(newValue = false),
|
||||
isFocused = rememberUpdatedState(newValue = false),
|
||||
isEmpty = rememberUpdatedState(newValue = false),
|
||||
label = {
|
||||
Text(
|
||||
text = item.label,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
},
|
||||
content = {
|
||||
val density = LocalDensity.current
|
||||
label = item.label,
|
||||
value = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.graphicsLayer {
|
||||
translationY = 12f + density.density
|
||||
},
|
||||
modifier = Modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.heightIn(min = BiFlatValueHeightMin)
|
||||
.weight(1f, fill = false),
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
val month = state.month.text.ifBlank { "--" }
|
||||
val year = state.year.text.ifBlank { "----" }
|
||||
Text(
|
||||
text = month,
|
||||
)
|
||||
Text(
|
||||
text = "/",
|
||||
color = LocalContentColor.current
|
||||
.combineAlpha(DisabledEmphasisAlpha),
|
||||
)
|
||||
Text(
|
||||
text = year,
|
||||
)
|
||||
}
|
||||
// Spacer(
|
||||
// modifier = Modifier
|
||||
// .width(4.dp),
|
||||
// )
|
||||
// Icon(
|
||||
// modifier = Modifier
|
||||
// .alpha(MediumEmphasisAlpha),
|
||||
// imageVector = Icons.Outlined.ArrowDropDown,
|
||||
// contentDescription = null,
|
||||
// )
|
||||
}
|
||||
},
|
||||
trailing = {
|
||||
val isEmpty = state.month.state.value.isEmpty() &&
|
||||
state.year.state.value.isEmpty()
|
||||
ExpandedIfNotEmptyForRow(
|
||||
valueOrNull = Unit.takeUnless { isEmpty },
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.width(8.dp),
|
||||
)
|
||||
VerticalDivider(
|
||||
modifier = Modifier
|
||||
.height(24.dp),
|
||||
)
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.width(8.dp),
|
||||
)
|
||||
IconButton(
|
||||
enabled = true,
|
||||
onClick = {
|
||||
state.month.state.value = ""
|
||||
state.year.state.value = ""
|
||||
},
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Clear,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
val month = state.month.text.ifBlank { "--" }
|
||||
val year = state.year.text.ifBlank { "----" }
|
||||
Text(
|
||||
text = month,
|
||||
)
|
||||
Text(
|
||||
text = "/",
|
||||
color = LocalContentColor.current
|
||||
.combineAlpha(DisabledEmphasisAlpha),
|
||||
)
|
||||
Text(
|
||||
text = year,
|
||||
)
|
||||
}
|
||||
},
|
||||
onClick = state.onClick,
|
||||
onClear = onClear.takeIf { !isEmpty },
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,9 @@ import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.core.updateTransition
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.LocalIndication
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
@ -72,6 +75,7 @@ import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
@ -296,6 +300,189 @@ fun ConcealedFlatTextField(
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FakeFlatTextField(
|
||||
modifier: Modifier = Modifier,
|
||||
label: String? = null,
|
||||
error: String? = null,
|
||||
value: @Composable () -> Unit,
|
||||
onClick: (() -> Unit)?,
|
||||
onClear: (() -> Unit)?,
|
||||
textStyle: TextStyle = LocalTextStyle.current,
|
||||
leading: (@Composable RowScope.() -> Unit)? = null,
|
||||
trailing: (@Composable RowScope.() -> Unit)? = null,
|
||||
content: (@Composable ColumnScope.() -> Unit)? = null,
|
||||
) {
|
||||
val isError = error != null
|
||||
var hasFocus by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
val updatedOnClick by rememberUpdatedState(onClick)
|
||||
FlatTextFieldSurface(
|
||||
modifier = modifier
|
||||
.onFocusChanged { state ->
|
||||
hasFocus = state.hasFocus
|
||||
},
|
||||
isError = isError,
|
||||
isFocused = hasFocus,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
indication = LocalIndication.current,
|
||||
enabled = onClick != null,
|
||||
interactionSource = remember {
|
||||
MutableInteractionSource()
|
||||
},
|
||||
role = Role.Button,
|
||||
) {
|
||||
updatedOnClick?.invoke()
|
||||
},
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = 16.dp,
|
||||
end = 8.dp,
|
||||
top = 8.dp,
|
||||
bottom = 8.dp,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val disabledAlphaTarget = if (onClick != null) 1f else DisabledEmphasisAlpha
|
||||
val disabledAlphaState = animateFloatAsState(disabledAlphaTarget)
|
||||
|
||||
if (leading != null) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.graphicsLayer {
|
||||
alpha = disabledAlphaState.value
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
leading()
|
||||
}
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.width(16.dp),
|
||||
)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
) {
|
||||
val expanded = onClear != null
|
||||
TextFieldLabelLayout(
|
||||
modifier = Modifier
|
||||
.heightIn(min = 50.dp),
|
||||
expanded = onClear != null,
|
||||
) {
|
||||
if (label != null) {
|
||||
TextFieldLabel(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.animateContentSize()
|
||||
.graphicsLayer {
|
||||
alpha = disabledAlphaState.value
|
||||
},
|
||||
text = label,
|
||||
expanded = expanded,
|
||||
hasFocus = hasFocus,
|
||||
hasError = isError,
|
||||
)
|
||||
}
|
||||
|
||||
Box {
|
||||
androidx.compose.animation.AnimatedVisibility(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
visible = expanded,
|
||||
) {
|
||||
// If color is not provided via the text style, use content color as a default
|
||||
val textColor = run {
|
||||
val color =
|
||||
contentColorFor(backgroundColor = MaterialTheme.colorScheme.background)
|
||||
val alpha =
|
||||
if (onClick != null) DefaultEmphasisAlpha else DisabledEmphasisAlpha
|
||||
color.copy(alpha = alpha)
|
||||
}
|
||||
val mergedTextStyle = textStyle.merge(TextStyle(color = textColor))
|
||||
ProvideTextStyle(mergedTextStyle) {
|
||||
value()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
end = 8.dp,
|
||||
),
|
||||
) {
|
||||
ExpandedIfNotEmpty(
|
||||
valueOrNull = error,
|
||||
) { text ->
|
||||
FlatTextFieldBadgeLegacy(
|
||||
error = text,
|
||||
badge = null,
|
||||
)
|
||||
}
|
||||
if (content != null) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trailing != null) {
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.width(8.dp),
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.graphicsLayer {
|
||||
alpha = disabledAlphaState.value
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
trailing()
|
||||
}
|
||||
}
|
||||
ExpandedIfNotEmptyForRow(
|
||||
valueOrNull = onClear,
|
||||
) { lambda ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.width(8.dp),
|
||||
)
|
||||
VerticalDivider(
|
||||
modifier = Modifier
|
||||
.height(24.dp),
|
||||
)
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.width(8.dp),
|
||||
)
|
||||
IconButton(
|
||||
onClick = lambda,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Clear,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FlatTextField(
|
||||
modifier: Modifier = Modifier,
|
||||
@ -376,24 +563,7 @@ fun FlatTextField(
|
||||
expanded = focused,
|
||||
) {
|
||||
if (label != null) {
|
||||
val focusedTextSize = MaterialTheme.typography.bodySmall.fontSize.value
|
||||
val normalTextSize = LocalTextStyle.current.fontSize.value
|
||||
val textSize by animateFloatAsState(
|
||||
targetValue = if (focused) focusedTextSize else normalTextSize,
|
||||
)
|
||||
|
||||
val focusedTextColor = when {
|
||||
isError -> MaterialTheme.colorScheme.error
|
||||
hasFocus -> MaterialTheme.colorScheme.primary
|
||||
else -> LocalContentColor.current
|
||||
}
|
||||
val normalTextColor = LocalContentColor.current
|
||||
.combineAlpha(HighEmphasisAlpha)
|
||||
val textColor by animateColorAsState(
|
||||
targetValue = if (focused) focusedTextColor else normalTextColor,
|
||||
)
|
||||
|
||||
Text(
|
||||
TextFieldLabel(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.animateContentSize()
|
||||
@ -401,9 +571,9 @@ fun FlatTextField(
|
||||
alpha = disabledAlphaState.value
|
||||
},
|
||||
text = label,
|
||||
fontSize = textSize.sp,
|
||||
maxLines = 1,
|
||||
color = textColor,
|
||||
expanded = focused,
|
||||
hasFocus = hasFocus,
|
||||
hasError = isError,
|
||||
)
|
||||
}
|
||||
|
||||
@ -627,6 +797,40 @@ private data class Afh(
|
||||
val createdAt: Instant,
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun TextFieldLabel(
|
||||
modifier: Modifier = Modifier,
|
||||
text: String,
|
||||
expanded: Boolean,
|
||||
hasFocus: Boolean,
|
||||
hasError: Boolean,
|
||||
) {
|
||||
val expandedTextSize = MaterialTheme.typography.bodySmall.fontSize.value
|
||||
val normalTextSize = LocalTextStyle.current.fontSize.value
|
||||
val textSize by animateFloatAsState(
|
||||
targetValue = if (expanded) expandedTextSize else normalTextSize,
|
||||
)
|
||||
|
||||
val expandedTextColor = when {
|
||||
hasError -> MaterialTheme.colorScheme.error
|
||||
hasFocus -> MaterialTheme.colorScheme.primary
|
||||
else -> LocalContentColor.current
|
||||
}
|
||||
val normalTextColor = LocalContentColor.current
|
||||
.combineAlpha(HighEmphasisAlpha)
|
||||
val textColor by animateColorAsState(
|
||||
targetValue = if (expanded) expandedTextColor else normalTextColor,
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = text,
|
||||
fontSize = textSize.sp,
|
||||
maxLines = 1,
|
||||
color = textColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextFieldLabelLayout(
|
||||
modifier: Modifier = Modifier,
|
||||
|
Loading…
x
Reference in New Issue
Block a user