Autofocus race condition with UI

This commit is contained in:
2026-09-09 09:20:47 +02:00
parent d7a51a797f
commit d2d713c616
@@ -63,10 +63,16 @@ fun EditBillScreen(
val context = LocalContext.current val context = LocalContext.current
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) { // The activity reads the project off the main thread and only then reports whether this is a
if (viewModel.isNewBill) { // new bill, so the flag arrives after the first composition. Keying on it rather than on Unit
focusRequester.requestFocus() // is what makes the effect run at all.
} LaunchedEffect(viewModel.isNewBill) {
if (!viewModel.isNewBill) return@LaunchedEffect
// The field has to be laid out before it can take focus, which is not yet true on the
// pass that composed it. Waiting for the next frame makes this hold whether the flag was
// already set or arrived later.
withFrameNanos { }
focusRequester.requestFocus()
} }
StatefulAlertDialog( StatefulAlertDialog(
@@ -198,7 +204,7 @@ fun BillBasicInfoSection(
OutlinedTextField( OutlinedTextField(
value = viewModel.amount, value = viewModel.amount,
onValueChange = { nv-> onValueChange = { nv ->
val filteredValue = nv.filter { it in "0123456789.+-*/" } val filteredValue = nv.filter { it in "0123456789.+-*/" }
viewModel.amount = filteredValue viewModel.amount = filteredValue
viewModel.updateSplits() viewModel.updateSplits()
@@ -252,8 +258,8 @@ fun BillBasicInfoSection(
placeholder = { Text(stringResource(R.string.label_what)) }, placeholder = { Text(stringResource(R.string.label_what)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
leadingIcon = { Icon(Icons.Default.Title, contentDescription = null) }, leadingIcon = { Icon(Icons.Default.Title, contentDescription = null) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) }) keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() })
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
@@ -528,7 +534,10 @@ fun BillAdditionalDetailsSection(
val context = LocalContext.current val context = LocalContext.current
var categoryExpanded by remember { mutableStateOf(false) } var categoryExpanded by remember { mutableStateOf(false) }
val selectedCategory = val selectedCategory =
categories.find { it.id == viewModel.categoryId } ?: CategoryUtils.getCategoryById(context, viewModel.categoryId) categories.find { it.id == viewModel.categoryId } ?: CategoryUtils.getCategoryById(
context,
viewModel.categoryId
)
EditableExposedDropdownMenu( EditableExposedDropdownMenu(
value = selectedCategory?.name ?: "", value = selectedCategory?.name ?: "",
@@ -582,7 +591,10 @@ fun BillAdditionalDetailsSection(
var pmExpanded by remember { mutableStateOf(false) } var pmExpanded by remember { mutableStateOf(false) }
val selectedPm = val selectedPm =
paymentModes.find { it.id == viewModel.paymentModeId } ?: CategoryUtils.getPaymentModeById(context, viewModel.paymentModeId) paymentModes.find { it.id == viewModel.paymentModeId } ?: CategoryUtils.getPaymentModeById(
context,
viewModel.paymentModeId
)
EditableExposedDropdownMenu( EditableExposedDropdownMenu(
value = selectedPm?.name ?: "", value = selectedPm?.name ?: "",