fix(android): split LoginScreen into LoginForm + SubmitButton (detekt LongMethod)

LoginScreen body was 76 lines vs the 60 cap. Pulled the centered
Column into LoginForm() and the spin-aware Button into SubmitButton().
LoginScreen is back to ~20 lines (LaunchedEffect + Box around LoginForm).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-25 11:15:51 -04:00
parent d6b8c20a17
commit df026d8e74
@@ -46,68 +46,88 @@ fun LoginScreen(
}
Box(modifier = Modifier.fillMaxSize()) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
verticalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterVertically),
horizontalAlignment = Alignment.CenterHorizontally,
) {
LoginForm(
state = state,
onUsernameChange = viewModel::setUsername,
onPasswordChange = viewModel::setPassword,
onSubmit = viewModel::submit,
)
}
}
@Composable
private fun LoginForm(
state: LoginFormState,
onUsernameChange: (String) -> Unit,
onPasswordChange: (String) -> Unit,
onSubmit: () -> Unit,
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
verticalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterVertically),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "Sign in",
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onBackground,
)
OutlinedTextField(
value = state.username,
onValueChange = onUsernameChange,
modifier = Modifier.fillMaxWidth(),
label = { Text("Username") },
singleLine = true,
enabled = !state.isSubmitting,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Email,
imeAction = ImeAction.Next,
),
)
OutlinedTextField(
value = state.password,
onValueChange = onPasswordChange,
modifier = Modifier.fillMaxWidth(),
label = { Text("Password") },
singleLine = true,
enabled = !state.isSubmitting,
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password,
imeAction = ImeAction.Done,
),
keyboardActions = KeyboardActions(onDone = { onSubmit() }),
)
if (state.errorMessage != null) {
Text(
text = "Sign in",
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onBackground,
text = state.errorMessage,
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodySmall,
)
OutlinedTextField(
value = state.username,
onValueChange = viewModel::setUsername,
modifier = Modifier.fillMaxWidth(),
label = { Text("Username") },
singleLine = true,
enabled = !state.isSubmitting,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Email,
imeAction = ImeAction.Next,
),
}
SubmitButton(state = state, onSubmit = onSubmit)
}
}
@Composable
private fun SubmitButton(state: LoginFormState, onSubmit: () -> Unit) {
Button(
onClick = onSubmit,
enabled = !state.isSubmitting &&
state.username.isNotBlank() &&
state.password.isNotBlank(),
modifier = Modifier.fillMaxWidth(),
) {
if (state.isSubmitting) {
CircularProgressIndicator(
modifier = Modifier.size(20.dp),
color = MaterialTheme.colorScheme.onPrimary,
strokeWidth = 2.dp,
)
OutlinedTextField(
value = state.password,
onValueChange = viewModel::setPassword,
modifier = Modifier.fillMaxWidth(),
label = { Text("Password") },
singleLine = true,
enabled = !state.isSubmitting,
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password,
imeAction = ImeAction.Done,
),
keyboardActions = KeyboardActions(onDone = { viewModel.submit() }),
)
if (state.errorMessage != null) {
Text(
text = state.errorMessage.orEmpty(),
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodySmall,
)
}
Button(
onClick = viewModel::submit,
enabled = !state.isSubmitting &&
state.username.isNotBlank() &&
state.password.isNotBlank(),
modifier = Modifier.fillMaxWidth(),
) {
if (state.isSubmitting) {
CircularProgressIndicator(
modifier = Modifier.size(20.dp),
color = MaterialTheme.colorScheme.onPrimary,
strokeWidth = 2.dp,
)
} else {
Text("Sign in")
}
}
} else {
Text("Sign in")
}
}
}