diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/AuthUtils.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/AuthUtils.kt new file mode 100644 index 000000000..c51f93b50 --- /dev/null +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/AuthUtils.kt @@ -0,0 +1,39 @@ +package app.omnivore.omnivore.ui.auth + +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.autofill.AutofillNode +import androidx.compose.ui.autofill.AutofillType +import androidx.compose.ui.composed +import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.layout.boundsInWindow +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalAutofill +import androidx.compose.ui.platform.LocalAutofillTree + + +object AuthUtils { + @OptIn(ExperimentalComposeUiApi::class) + fun Modifier.autofill( + autofillTypes: List, + onFill: ((String) -> Unit), + ) = composed { + val autofill = LocalAutofill.current + val autofillNode = AutofillNode(onFill = onFill, autofillTypes = autofillTypes) + LocalAutofillTree.current += autofillNode + + this + .onGloballyPositioned { + autofillNode.boundingBox = it.boundsInWindow() + } + .onFocusChanged { focusState -> + autofill?.run { + if (focusState.isFocused) { + requestAutofillForNode(autofillNode) + } else { + cancelAutofillForNode(autofillNode) + } + } + } + } +} diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/EmailLogin.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/EmailLogin.kt index 5af3750e3..67ed205c2 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/EmailLogin.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/EmailLogin.kt @@ -10,7 +10,9 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.autofill.AutofillType import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager @@ -25,6 +27,7 @@ import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import app.omnivore.omnivore.BuildConfig import app.omnivore.omnivore.R +import app.omnivore.omnivore.ui.auth.AuthUtils.autofill @SuppressLint("CoroutineCreationDuringComposition") @Composable @@ -86,6 +89,7 @@ fun EmailLoginView(viewModel: LoginViewModel) { } } +@OptIn(ExperimentalComposeUiApi::class) @Composable fun LoginFields( email: String, @@ -105,6 +109,12 @@ fun LoginFields( horizontalAlignment = Alignment.CenterHorizontally ) { OutlinedTextField( + modifier = Modifier.autofill( + autofillTypes = listOf( + AutofillType.EmailAddress, + ), + onFill = { onEmailChange(it) } + ), value = email, placeholder = { Text(stringResource(R.string.email_login_field_placeholder_email)) }, label = { Text(stringResource(R.string.email_login_field_label_email)) }, @@ -112,11 +122,17 @@ fun LoginFields( keyboardOptions = KeyboardOptions( imeAction = ImeAction.Done, keyboardType = KeyboardType.Email, - ), + ), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }) ) OutlinedTextField( + modifier = Modifier.autofill( + autofillTypes = listOf( + AutofillType.Password, + ), + onFill = { onPasswordChange(it) } + ), value = password, placeholder = { Text(stringResource(R.string.email_login_field_placeholder_password)) }, label = { Text(stringResource(R.string.email_login_field_label_password)) }, @@ -129,21 +145,22 @@ fun LoginFields( keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }) ) - Button(onClick = { - if (email.isNotBlank() && password.isNotBlank()) { - onLoginClick() - focusManager.clearFocus() - } else { - Toast.makeText( - context, - context.getString(R.string.email_login_error_msg), - Toast.LENGTH_SHORT - ).show() - } - }, colors = ButtonDefaults.buttonColors( - contentColor = Color(0xFF3D3D3D), - containerColor = Color(0xffffd234) - ) + Button( + onClick = { + if (email.isNotBlank() && password.isNotBlank()) { + onLoginClick() + focusManager.clearFocus() + } else { + Toast.makeText( + context, + context.getString(R.string.email_login_error_msg), + Toast.LENGTH_SHORT + ).show() + } + }, colors = ButtonDefaults.buttonColors( + contentColor = Color(0xFF3D3D3D), + containerColor = Color(0xffffd234) + ) ) { Text( text = stringResource(R.string.email_login_action_login), diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/EmailSignUpView.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/EmailSignUpView.kt index e27023e0f..268aad3dc 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/EmailSignUpView.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/EmailSignUpView.kt @@ -14,7 +14,9 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.autofill.AutofillType import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager @@ -27,6 +29,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import app.omnivore.omnivore.R +import app.omnivore.omnivore.ui.auth.AuthUtils.autofill @Composable fun EmailSignUpView(viewModel: LoginViewModel) { @@ -140,6 +143,7 @@ fun EmailSignUpForm(viewModel: LoginViewModel) { } } +@OptIn(ExperimentalComposeUiApi::class) @Composable fun EmailSignUpFields( email: String, @@ -165,6 +169,12 @@ fun EmailSignUpFields( horizontalAlignment = Alignment.CenterHorizontally ) { OutlinedTextField( + modifier = Modifier.autofill( + autofillTypes = listOf( + AutofillType.EmailAddress, + ), + onFill = { onEmailChange(it) } + ), value = email, placeholder = { Text(stringResource(R.string.email_signup_field_placeholder_email)) }, label = { Text(stringResource(R.string.email_signup_field_label_email)) }, @@ -174,6 +184,12 @@ fun EmailSignUpFields( ) OutlinedTextField( + modifier = Modifier.autofill( + autofillTypes = listOf( + AutofillType.Password, + ), + onFill = { onPasswordChange(it) } + ), value = password, placeholder = { Text(stringResource(R.string.email_signup_field_placeholder_password)) }, label = { Text(stringResource(R.string.email_signup_field_label_password)) }, diff --git a/android/Omnivore/app/src/main/res/values/strings.xml b/android/Omnivore/app/src/main/res/values/strings.xml index a9eb61336..ad478efa8 100644 --- a/android/Omnivore/app/src/main/res/values/strings.xml +++ b/android/Omnivore/app/src/main/res/values/strings.xml @@ -54,8 +54,8 @@ Password Name Name - Name - Name + Username + Username Please complete all fields.