diff --git a/android/app/src/main/java/com/fabledsword/minstrel/auth/ui/LoginScreen.kt b/android/app/src/main/java/com/fabledsword/minstrel/auth/ui/LoginScreen.kt index 24fbb12c..20960d6f 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/auth/ui/LoginScreen.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/auth/ui/LoginScreen.kt @@ -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") } } }