diff --git a/you-have-mail-android/app/src/main/java/dev/lbeernaert/youhavemail/components/PasswordField.kt b/you-have-mail-android/app/src/main/java/dev/lbeernaert/youhavemail/components/PasswordField.kt index 40330a9..0a24ae2 100644 --- a/you-have-mail-android/app/src/main/java/dev/lbeernaert/youhavemail/components/PasswordField.kt +++ b/you-have-mail-android/app/src/main/java/dev/lbeernaert/youhavemail/components/PasswordField.kt @@ -14,14 +14,19 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.autofill.AutofillType 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.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation +import dev.lbeernaert.youhavemail.ui.AutoFillRequestHandler +import dev.lbeernaert.youhavemail.ui.autofill +@OptIn(ExperimentalComposeUiApi::class) @Composable fun PasswordField( placeHolder: String, @@ -31,8 +36,15 @@ fun PasswordField( val showPassword = remember { mutableStateOf(false) } + val autoFillHandler = AutoFillRequestHandler( + autofillTypes = listOf(AutofillType.Password), + onFill = { state.value = TextFieldValue(it) } + ) + TextField( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .autofill(handler = autoFillHandler), label = { Text(text = placeHolder) }, value = state.value, singleLine = true, diff --git a/you-have-mail-android/app/src/main/java/dev/lbeernaert/youhavemail/screens/Login.kt b/you-have-mail-android/app/src/main/java/dev/lbeernaert/youhavemail/screens/Login.kt index 7e4a028..17db598 100644 --- a/you-have-mail-android/app/src/main/java/dev/lbeernaert/youhavemail/screens/Login.kt +++ b/you-have-mail-android/app/src/main/java/dev/lbeernaert/youhavemail/screens/Login.kt @@ -15,7 +15,9 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember 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.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType @@ -25,8 +27,11 @@ import dev.lbeernaert.youhavemail.R import dev.lbeernaert.youhavemail.components.ActionButton import dev.lbeernaert.youhavemail.components.AsyncScreen import dev.lbeernaert.youhavemail.components.PasswordField +import dev.lbeernaert.youhavemail.ui.AutoFillRequestHandler +import dev.lbeernaert.youhavemail.ui.autofill +@OptIn(ExperimentalComposeUiApi::class) @Composable fun Login( backendName: String, @@ -34,7 +39,7 @@ fun Login( onBackClicked: () -> Unit, onLoginClicked: suspend (email: String, password: String) -> Unit ) { - var email = rememberSaveable(stateSaver = TextFieldValue.Saver) { + val email = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(accountEmail) ) @@ -53,6 +58,10 @@ fun Login( onLoginClicked(email.value.text, password.value.text) } } + val autoFillHandler = AutoFillRequestHandler( + autofillTypes = listOf(AutofillType.EmailAddress), + onFill = { email.value = TextFieldValue(it) } + ) Column( modifier = Modifier @@ -68,7 +77,8 @@ fun Login( Spacer(modifier = Modifier.height(20.dp)) TextField( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth() + .autofill(handler = autoFillHandler), label = { Text(text = "Email") }, singleLine = true, value = email.value, diff --git a/you-have-mail-android/app/src/main/java/dev/lbeernaert/youhavemail/ui/Autofill.kt b/you-have-mail-android/app/src/main/java/dev/lbeernaert/youhavemail/ui/Autofill.kt new file mode 100644 index 0000000..863a111 --- /dev/null +++ b/you-have-mail-android/app/src/main/java/dev/lbeernaert/youhavemail/ui/Autofill.kt @@ -0,0 +1,71 @@ +package dev.lbeernaert.youhavemail.ui + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +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.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 + +// This file is adapted from https://medium.com/@bagadeshrp/compose-ui-textfield-autofill-6e2ac434e380 + +// The autofill modifier internally adds two modifiers: +// one to setup the layout, and one to listen for focus events. +@OptIn(ExperimentalComposeUiApi::class) +fun Modifier.autofill(handler: AutoFillHandler): Modifier { + return this.then( + onGloballyPositioned { + handler.autoFillNode.boundingBox = it.boundsInWindow() + } + ).then( + onFocusChanged { + if (it.isFocused) { + handler.request() + } else { + handler.cancel() + } + } + ) +} + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +fun AutoFillRequestHandler( + autofillTypes: List = listOf(), + onFill: (String) -> Unit, +): AutoFillHandler { + val autoFillNode = remember { + AutofillNode( + autofillTypes = autofillTypes, + onFill = { onFill(it) } + ) + } + val autofill = LocalAutofill.current + LocalAutofillTree.current += autoFillNode + return remember { + object : AutoFillHandler { + override val autoFillNode: AutofillNode + get() = autoFillNode + + override fun request() { + autofill?.requestAutofillForNode(autofillNode = autoFillNode) + } + + override fun cancel() { + autofill?.cancelAutofillForNode(autofillNode = autoFillNode) + } + } + } +} + +@OptIn(ExperimentalComposeUiApi::class) +interface AutoFillHandler { + val autoFillNode: AutofillNode + fun request() + fun cancel() +}