Audit: form-error TalkBack + focus management + navigateUp polish
(a) liveRegion + error semantics on form error surfaces so TalkBack
announces them when they appear:
- Shared ErrorCard (used by LoginScreen, RegisterScreen,
VerifyEmail/ResetCode, ForgotPassword, ResetPassword)
- OnboardingCreateAccountContent inline error row
- JoinResidenceScreen inline error row
(b) focusRequester + ImeAction.Next on multi-field forms:
- LoginScreen: auto-focus username, Next→password, Done→submit
- RegisterScreen: auto-focus username, Next chain through
email/password/confirm, Done on last
(c) navigateUp() replaces navController.popBackStack() for simple back
actions in App.kt (6 screens) and MainScreen.kt (3 screens), where
the back behavior is purely navigation-controlled.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -511,7 +511,7 @@ fun App(
|
|||||||
|
|
||||||
composable<JoinResidenceRoute> {
|
composable<JoinResidenceRoute> {
|
||||||
com.tt.honeyDue.ui.screens.residence.JoinResidenceScreen(
|
com.tt.honeyDue.ui.screens.residence.JoinResidenceScreen(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.navigateUp() },
|
||||||
onJoined = { residenceId ->
|
onJoined = { residenceId ->
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
navController.navigate(ResidenceDetailRoute(residenceId))
|
navController.navigate(ResidenceDetailRoute(residenceId))
|
||||||
@@ -674,7 +674,7 @@ fun App(
|
|||||||
composable<FeatureComparisonRoute> {
|
composable<FeatureComparisonRoute> {
|
||||||
// P2 Stream E — full-screen Free vs. Pro comparison.
|
// P2 Stream E — full-screen Free vs. Pro comparison.
|
||||||
FeatureComparisonScreen(
|
FeatureComparisonScreen(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.navigateUp() },
|
||||||
onNavigateToUpgrade = {
|
onNavigateToUpgrade = {
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
navController.navigate(UpgradeRoute)
|
navController.navigate(UpgradeRoute)
|
||||||
@@ -687,7 +687,7 @@ fun App(
|
|||||||
val route = backStackEntry.toRoute<TaskSuggestionsRoute>()
|
val route = backStackEntry.toRoute<TaskSuggestionsRoute>()
|
||||||
TaskSuggestionsScreen(
|
TaskSuggestionsScreen(
|
||||||
residenceId = route.residenceId,
|
residenceId = route.residenceId,
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.navigateUp() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,7 +696,7 @@ fun App(
|
|||||||
val route = backStackEntry.toRoute<AddTaskWithResidenceRoute>()
|
val route = backStackEntry.toRoute<AddTaskWithResidenceRoute>()
|
||||||
AddTaskWithResidenceScreen(
|
AddTaskWithResidenceScreen(
|
||||||
residenceId = route.residenceId,
|
residenceId = route.residenceId,
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.navigateUp() },
|
||||||
onCreated = { navController.popBackStack() },
|
onCreated = { navController.popBackStack() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -707,7 +707,7 @@ fun App(
|
|||||||
TaskTemplatesBrowserScreen(
|
TaskTemplatesBrowserScreen(
|
||||||
residenceId = route.residenceId,
|
residenceId = route.residenceId,
|
||||||
fromOnboarding = route.fromOnboarding,
|
fromOnboarding = route.fromOnboarding,
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.navigateUp() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,7 +734,7 @@ fun App(
|
|||||||
updatedAt = route.updatedAt,
|
updatedAt = route.updatedAt,
|
||||||
completions = emptyList()
|
completions = emptyList()
|
||||||
),
|
),
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.navigateUp() },
|
||||||
onTaskUpdated = { navController.popBackStack() }
|
onTaskUpdated = { navController.popBackStack() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ import androidx.compose.material3.*
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.semantics.LiveRegionMode
|
||||||
|
import androidx.compose.ui.semantics.error
|
||||||
|
import androidx.compose.ui.semantics.liveRegion
|
||||||
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.tt.honeyDue.ui.haptics.Haptics
|
import com.tt.honeyDue.ui.haptics.Haptics
|
||||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
@@ -22,7 +26,12 @@ fun ErrorCard(
|
|||||||
colors = CardDefaults.cardColors(
|
colors = CardDefaults.cardColors(
|
||||||
containerColor = MaterialTheme.colorScheme.errorContainer
|
containerColor = MaterialTheme.colorScheme.errorContainer
|
||||||
),
|
),
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.semantics {
|
||||||
|
liveRegion = LiveRegionMode.Polite
|
||||||
|
error(message)
|
||||||
|
},
|
||||||
shape = RoundedCornerShape(12.dp)
|
shape = RoundedCornerShape(12.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -8,12 +8,17 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.*
|
import androidx.compose.material.icons.filled.*
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.focus.FocusDirection
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.semantics.testTagsAsResourceId
|
import androidx.compose.ui.semantics.testTagsAsResourceId
|
||||||
@@ -51,6 +56,12 @@ fun LoginScreen(
|
|||||||
var googleSignInError by remember { mutableStateOf<String?>(null) }
|
var googleSignInError by remember { mutableStateOf<String?>(null) }
|
||||||
val loginState by viewModel.loginState.collectAsStateWithLifecycle()
|
val loginState by viewModel.loginState.collectAsStateWithLifecycle()
|
||||||
val googleSignInState by viewModel.googleSignInState.collectAsStateWithLifecycle()
|
val googleSignInState by viewModel.googleSignInState.collectAsStateWithLifecycle()
|
||||||
|
val focusManager = LocalFocusManager.current
|
||||||
|
val usernameFocusRequester = remember { FocusRequester() }
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
usernameFocusRequester.requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
// Handle errors for login
|
// Handle errors for login
|
||||||
loginState.HandleErrors(
|
loginState.HandleErrors(
|
||||||
@@ -139,12 +150,16 @@ fun LoginScreen(
|
|||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
.focusRequester(usernameFocusRequester)
|
||||||
.testTag(AccessibilityIds.Authentication.usernameField),
|
.testTag(AccessibilityIds.Authentication.usernameField),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
shape = RoundedCornerShape(OrganicRadius.md),
|
shape = RoundedCornerShape(OrganicRadius.md),
|
||||||
keyboardOptions = KeyboardOptions(
|
keyboardOptions = KeyboardOptions(
|
||||||
keyboardType = KeyboardType.Email,
|
keyboardType = KeyboardType.Email,
|
||||||
imeAction = ImeAction.Next
|
imeAction = ImeAction.Next
|
||||||
|
),
|
||||||
|
keyboardActions = KeyboardActions(
|
||||||
|
onNext = { focusManager.moveFocus(FocusDirection.Down) }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -171,7 +186,19 @@ fun LoginScreen(
|
|||||||
.testTag(AccessibilityIds.Authentication.passwordField),
|
.testTag(AccessibilityIds.Authentication.passwordField),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||||
shape = RoundedCornerShape(OrganicRadius.md)
|
shape = RoundedCornerShape(OrganicRadius.md),
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Password,
|
||||||
|
imeAction = ImeAction.Done
|
||||||
|
),
|
||||||
|
keyboardActions = KeyboardActions(
|
||||||
|
onDone = {
|
||||||
|
focusManager.clearFocus()
|
||||||
|
if (username.isNotEmpty() && password.isNotEmpty()) {
|
||||||
|
viewModel.login(username, password)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
ErrorCard(message = errorMessage)
|
ErrorCard(message = errorMessage)
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ fun MainScreen(
|
|||||||
composable<JoinResidenceRoute> {
|
composable<JoinResidenceRoute> {
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
com.tt.honeyDue.ui.screens.residence.JoinResidenceScreen(
|
com.tt.honeyDue.ui.screens.residence.JoinResidenceScreen(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.navigateUp() },
|
||||||
onJoined = { residenceId ->
|
onJoined = { residenceId ->
|
||||||
// Pop the join screen and hand off to the
|
// Pop the join screen and hand off to the
|
||||||
// parent nav graph (ResidenceDetailRoute lives
|
// parent nav graph (ResidenceDetailRoute lives
|
||||||
@@ -242,7 +242,7 @@ fun MainScreen(
|
|||||||
AddDocumentScreen(
|
AddDocumentScreen(
|
||||||
residenceId = route.residenceId,
|
residenceId = route.residenceId,
|
||||||
initialDocumentType = route.initialDocumentType,
|
initialDocumentType = route.initialDocumentType,
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.navigateUp() },
|
||||||
onDocumentCreated = {
|
onDocumentCreated = {
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,7 @@ fun MainScreen(
|
|||||||
val route = backStackEntry.toRoute<DocumentDetailRoute>()
|
val route = backStackEntry.toRoute<DocumentDetailRoute>()
|
||||||
DocumentDetailScreen(
|
DocumentDetailScreen(
|
||||||
documentId = route.documentId,
|
documentId = route.documentId,
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.navigateUp() },
|
||||||
onNavigateToEdit = { documentId ->
|
onNavigateToEdit = { documentId ->
|
||||||
navController.navigate(EditDocumentRoute(documentId))
|
navController.navigate(EditDocumentRoute(documentId))
|
||||||
}
|
}
|
||||||
@@ -264,7 +264,7 @@ fun MainScreen(
|
|||||||
val route = backStackEntry.toRoute<EditDocumentRoute>()
|
val route = backStackEntry.toRoute<EditDocumentRoute>()
|
||||||
EditDocumentScreen(
|
EditDocumentScreen(
|
||||||
documentId = route.documentId,
|
documentId = route.documentId,
|
||||||
onNavigateBack = { navController.popBackStack() }
|
onNavigateBack = { navController.navigateUp() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package com.tt.honeyDue.ui.screens
|
|||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.*
|
import androidx.compose.material.icons.filled.*
|
||||||
@@ -11,10 +13,16 @@ import androidx.compose.material3.*
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusDirection
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.semantics.testTagsAsResourceId
|
import androidx.compose.ui.semantics.testTagsAsResourceId
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
@@ -47,6 +55,12 @@ fun RegisterScreen(
|
|||||||
var isLoading by remember { mutableStateOf(false) }
|
var isLoading by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val createState by viewModel.registerState.collectAsStateWithLifecycle()
|
val createState by viewModel.registerState.collectAsStateWithLifecycle()
|
||||||
|
val focusManager = LocalFocusManager.current
|
||||||
|
val usernameFocusRequester = remember { FocusRequester() }
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
usernameFocusRequester.requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
// Handle errors for registration
|
// Handle errors for registration
|
||||||
createState.HandleErrors(
|
createState.HandleErrors(
|
||||||
@@ -130,9 +144,14 @@ fun RegisterScreen(
|
|||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
.focusRequester(usernameFocusRequester)
|
||||||
.testTag(AccessibilityIds.Authentication.registerUsernameField),
|
.testTag(AccessibilityIds.Authentication.registerUsernameField),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
shape = RoundedCornerShape(AppRadius.md)
|
shape = RoundedCornerShape(AppRadius.md),
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
|
||||||
|
keyboardActions = KeyboardActions(
|
||||||
|
onNext = { focusManager.moveFocus(FocusDirection.Down) }
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
@@ -146,7 +165,14 @@ fun RegisterScreen(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag(AccessibilityIds.Authentication.registerEmailField),
|
.testTag(AccessibilityIds.Authentication.registerEmailField),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
shape = RoundedCornerShape(AppRadius.md)
|
shape = RoundedCornerShape(AppRadius.md),
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Email,
|
||||||
|
imeAction = ImeAction.Next
|
||||||
|
),
|
||||||
|
keyboardActions = KeyboardActions(
|
||||||
|
onNext = { focusManager.moveFocus(FocusDirection.Down) }
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
OrganicDivider()
|
OrganicDivider()
|
||||||
@@ -163,7 +189,14 @@ fun RegisterScreen(
|
|||||||
.testTag(AccessibilityIds.Authentication.registerPasswordField),
|
.testTag(AccessibilityIds.Authentication.registerPasswordField),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
visualTransformation = PasswordVisualTransformation(),
|
visualTransformation = PasswordVisualTransformation(),
|
||||||
shape = RoundedCornerShape(AppRadius.md)
|
shape = RoundedCornerShape(AppRadius.md),
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Password,
|
||||||
|
imeAction = ImeAction.Next
|
||||||
|
),
|
||||||
|
keyboardActions = KeyboardActions(
|
||||||
|
onNext = { focusManager.moveFocus(FocusDirection.Down) }
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
@@ -178,7 +211,14 @@ fun RegisterScreen(
|
|||||||
.testTag(AccessibilityIds.Authentication.registerConfirmPasswordField),
|
.testTag(AccessibilityIds.Authentication.registerConfirmPasswordField),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
visualTransformation = PasswordVisualTransformation(),
|
visualTransformation = PasswordVisualTransformation(),
|
||||||
shape = RoundedCornerShape(AppRadius.md)
|
shape = RoundedCornerShape(AppRadius.md),
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Password,
|
||||||
|
imeAction = ImeAction.Done
|
||||||
|
),
|
||||||
|
keyboardActions = KeyboardActions(
|
||||||
|
onDone = { focusManager.clearFocus() }
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ import androidx.compose.material3.*
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.semantics.LiveRegionMode
|
||||||
|
import androidx.compose.ui.semantics.error
|
||||||
|
import androidx.compose.ui.semantics.liveRegion
|
||||||
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
@@ -240,7 +244,12 @@ fun OnboardingCreateAccountContent(
|
|||||||
// Error message
|
// Error message
|
||||||
if (localErrorMessage != null) {
|
if (localErrorMessage != null) {
|
||||||
OrganicCard(
|
OrganicCard(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.semantics {
|
||||||
|
liveRegion = LiveRegionMode.Polite
|
||||||
|
error(localErrorMessage ?: "")
|
||||||
|
},
|
||||||
accentColor = MaterialTheme.colorScheme.error,
|
accentColor = MaterialTheme.colorScheme.error,
|
||||||
showBlob = false
|
showBlob = false
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
|
import androidx.compose.ui.semantics.LiveRegionMode
|
||||||
|
import androidx.compose.ui.semantics.error
|
||||||
|
import androidx.compose.ui.semantics.liveRegion
|
||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.semantics.testTagsAsResourceId
|
import androidx.compose.ui.semantics.testTagsAsResourceId
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@@ -160,7 +163,11 @@ fun JoinResidenceScreen(
|
|||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(AppSpacing.sm),
|
.padding(AppSpacing.sm)
|
||||||
|
.semantics {
|
||||||
|
liveRegion = LiveRegionMode.Polite
|
||||||
|
error(error ?: "")
|
||||||
|
},
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.spacedBy(AppSpacing.sm),
|
horizontalArrangement = Arrangement.spacedBy(AppSpacing.sm),
|
||||||
) {
|
) {
|
||||||
|
|||||||
Reference in New Issue
Block a user