mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 21:32:34 +00:00
A11y: Add programmatic label and keyboard focus indicator to PIN entry field
Fixes: https://github.com/element-hq/element-x-android/issues/6391 Fixes: https://github.com/element-hq/element-x-android/issues/6401 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+26
-2
@@ -22,8 +22,18 @@ import androidx.compose.foundation.text.BasicTextField
|
|||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
|
import androidx.compose.ui.res.pluralStringResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.compound.theme.ElementTheme
|
import io.element.android.compound.theme.ElementTheme
|
||||||
@@ -32,6 +42,8 @@ import io.element.android.features.lockscreen.impl.pin.model.PinEntry
|
|||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.pinDigitBg
|
import io.element.android.libraries.designsystem.theme.pinDigitBg
|
||||||
|
import io.element.android.libraries.ui.strings.CommonPlurals
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PinEntryTextField(
|
fun PinEntryTextField(
|
||||||
@@ -40,15 +52,21 @@ fun PinEntryTextField(
|
|||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
var isFocused by remember { mutableStateOf(false) }
|
||||||
|
val filledCount = pinEntry.digits.count { it is PinDigit.Filled }
|
||||||
|
val pinFieldLabel = stringResource(CommonStrings.a11y_pin_field)
|
||||||
|
val digitsEnteredLabel = pluralStringResource(CommonPlurals.a11y_digits_entered, filledCount, filledCount)
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
modifier = modifier,
|
modifier = modifier
|
||||||
|
.onFocusChanged { isFocused = it.isFocused }
|
||||||
|
.semantics { contentDescription = "$pinFieldLabel, $digitsEnteredLabel" },
|
||||||
value = pinEntry.toText(),
|
value = pinEntry.toText(),
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
onValueChange(it)
|
onValueChange(it)
|
||||||
},
|
},
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword),
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword),
|
||||||
decorationBox = {
|
decorationBox = {
|
||||||
PinEntryRow(pinEntry = pinEntry, isSecured = isSecured)
|
PinEntryRow(pinEntry = pinEntry, isSecured = isSecured, isFocused = isFocused)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -58,8 +76,14 @@ fun PinEntryTextField(
|
|||||||
private fun PinEntryRow(
|
private fun PinEntryRow(
|
||||||
pinEntry: PinEntry,
|
pinEntry: PinEntry,
|
||||||
isSecured: Boolean,
|
isSecured: Boolean,
|
||||||
|
isFocused: Boolean = false,
|
||||||
) {
|
) {
|
||||||
FlowRow(
|
FlowRow(
|
||||||
|
modifier = Modifier.border(
|
||||||
|
width = 2.dp,
|
||||||
|
color = if (isFocused) ElementTheme.colors.borderInteractiveHovered else Color.Transparent,
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
),
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp, alignment = Alignment.CenterHorizontally),
|
horizontalArrangement = Arrangement.spacedBy(8.dp, alignment = Alignment.CenterHorizontally),
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
) {
|
) {
|
||||||
|
|||||||
Reference in New Issue
Block a user