From 29ade1e5b7426fc8db75cd359b85a4e3898a7935 Mon Sep 17 00:00:00 2001 From: VoidRaven Date: Thu, 17 Jul 2025 06:11:28 +0530 Subject: [PATCH] Fix email verification input (#6367) * Set imeOptions to actionDone and enforce singleLine for xlarge * Set imeOptions to actionDone and enforce singleLine for landscape * Set imeOptions to actionDone and enforce singleLine * Update askUserForTwoFactorAuth for IME_ACTION_DONE to trigger performLogin * Fix email verification: Set imeOptions to actionDone and replace singleLine with maxLines=1 * Fix email verification: Set imeOptions to actionDone and replace singleLine with maxLines=1 * Fix email verification: Set imeOptions to actionDone and replace singleLine with maxLines=1 * feat: Set imeOptions to actionNext for login_password to improve focus transition * feat: Enhance keyboard visibility for email verification code input --- .../fr/free/nrw/commons/auth/LoginActivity.kt | 84 ++++++++++++++++--- .../main/res/layout-land/activity_login.xml | 6 +- .../main/res/layout-xlarge/activity_login.xml | 6 +- app/src/main/res/layout/activity_login.xml | 6 +- 4 files changed, 84 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.kt b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.kt index a606d639f..7a665197b 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.kt @@ -92,7 +92,19 @@ class LoginActivity : AccountAuthenticatorActivity() { aboutPrivacyPolicy.setOnClickListener { onPrivacyPolicyClicked() } signUpButton.setOnClickListener { signUp() } loginButton.setOnClickListener { performLogin() } - loginPassword.setOnEditorActionListener(::onEditorAction) + loginPassword.setOnEditorActionListener { textView, actionId, keyEvent -> + if (binding!!.loginButton.isEnabled && isTriggerAction(actionId, keyEvent)) { + if (actionId == EditorInfo.IME_ACTION_NEXT && lastLoginResult != null) { + askUserForTwoFactorAuthWithKeyboard() + true + } else { + performLogin() + true + } + } else { + false + } + } loginPassword.onFocusChangeListener = View.OnFocusChangeListener(::onPasswordFocusChanged) @@ -113,6 +125,39 @@ class LoginActivity : AccountAuthenticatorActivity() { } } + @VisibleForTesting + fun askUserForTwoFactorAuthWithKeyboard() { + if (binding == null) { + Timber.w("Binding is null, reinitializing in askUserForTwoFactorAuthWithKeyboard") + binding = ActivityLoginBinding.inflate(layoutInflater) + setContentView(binding!!.root) + } + progressDialog!!.dismiss() + if (binding != null) { + with(binding!!) { + twoFactorContainer.visibility = View.VISIBLE + twoFactorContainer.hint = getString(if (lastLoginResult is LoginResult.EmailAuthResult) R.string.email_auth_code else R.string._2fa_code) + loginTwoFactor.visibility = View.VISIBLE + loginTwoFactor.requestFocus() + + val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager + imm.showSoftInput(loginTwoFactor, InputMethodManager.SHOW_IMPLICIT) + + loginTwoFactor.setOnEditorActionListener { _, actionId, event -> + if (actionId == EditorInfo.IME_ACTION_DONE || + (event != null && event.keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN)) { + performLogin() + true + } else { + false + } + } + } + } else { + Timber.e("Binding is null in askUserForTwoFactorAuthWithKeyboard after reinitialization attempt") + } + showMessageAndCancelDialog(getString(if (lastLoginResult is LoginResult.EmailAuthResult) R.string.login_failed_email_auth_needed else R.string.login_failed_2fa_needed)) + } override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) delegate.onPostCreate(savedInstanceState) @@ -236,7 +281,7 @@ class LoginActivity : AccountAuthenticatorActivity() { } else false private fun isTriggerAction(actionId: Int, keyEvent: KeyEvent?) = - actionId == EditorInfo.IME_ACTION_DONE || keyEvent?.keyCode == KeyEvent.KEYCODE_ENTER + actionId == EditorInfo.IME_ACTION_NEXT || actionId == EditorInfo.IME_ACTION_DONE || keyEvent?.keyCode == KeyEvent.KEYCODE_ENTER private fun skipLogin() { AlertDialog.Builder(this) @@ -286,14 +331,14 @@ class LoginActivity : AccountAuthenticatorActivity() { Timber.d("Requesting 2FA prompt") progressDialog!!.dismiss() lastLoginResult = loginResult - askUserForTwoFactorAuth() + askUserForTwoFactorAuthWithKeyboard() } - override fun emailAuthPrompt(loginResult: LoginResult, caught: Throwable, token: String?) { + override fun emailAuthPrompt(loginResult: LoginResult, caught: Throwable, token: String?) = runOnUiThread { Timber.d("Requesting email auth prompt") progressDialog!!.dismiss() lastLoginResult = loginResult - askUserForTwoFactorAuth() + askUserForTwoFactorAuthWithKeyboard() } override fun passwordResetPrompt(token: String?) = runOnUiThread { @@ -348,12 +393,31 @@ class LoginActivity : AccountAuthenticatorActivity() { @VisibleForTesting fun askUserForTwoFactorAuth() { + if (binding == null) { + Timber.w("Binding is null, reinitializing in askUserForTwoFactorAuth") + binding = ActivityLoginBinding.inflate(layoutInflater) + setContentView(binding!!.root) + } progressDialog!!.dismiss() - with(binding!!) { - twoFactorContainer.visibility = View.VISIBLE - twoFactorContainer.hint = getString(if (lastLoginResult is LoginResult.EmailAuthResult) R.string.email_auth_code else R.string._2fa_code) - loginTwoFactor.visibility = View.VISIBLE - loginTwoFactor.requestFocus() + if (binding != null) { + with(binding!!) { + twoFactorContainer.visibility = View.VISIBLE + twoFactorContainer.hint = getString(if (lastLoginResult is LoginResult.EmailAuthResult) R.string.email_auth_code else R.string._2fa_code) + loginTwoFactor.visibility = View.VISIBLE + loginTwoFactor.requestFocus() + + loginTwoFactor.setOnEditorActionListener { _, actionId, event -> + if (actionId == EditorInfo.IME_ACTION_DONE || + (event != null && event.keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN)) { + performLogin() + true + } else { + false + } + } + } + } else { + Timber.e("Binding is null in askUserForTwoFactorAuth after reinitialization attempt") } val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY) diff --git a/app/src/main/res/layout-land/activity_login.xml b/app/src/main/res/layout-land/activity_login.xml index b9adfd033..fa36b56ff 100644 --- a/app/src/main/res/layout-land/activity_login.xml +++ b/app/src/main/res/layout-land/activity_login.xml @@ -125,7 +125,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/password" - android:imeOptions="flagNoExtractUi" + android:imeOptions="actionNext" android:inputType="textPassword" /> @@ -148,9 +148,9 @@ android:id="@+id/login_two_factor" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/_2fa_code" - android:imeOptions="flagNoExtractUi" + android:imeOptions="actionDone" android:inputType="number" + android:maxLines="1" android:visibility="gone" tools:visibility="visible" /> diff --git a/app/src/main/res/layout-xlarge/activity_login.xml b/app/src/main/res/layout-xlarge/activity_login.xml index c255aa45f..74f89228e 100644 --- a/app/src/main/res/layout-xlarge/activity_login.xml +++ b/app/src/main/res/layout-xlarge/activity_login.xml @@ -128,7 +128,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/password" - android:imeOptions="flagNoExtractUi" + android:imeOptions="actionNext" android:inputType="textPassword" /> @@ -151,9 +151,9 @@ android:id="@+id/login_two_factor" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/_2fa_code" - android:imeOptions="flagNoExtractUi" + android:imeOptions="actionDone" android:inputType="number" + android:maxLines="1" android:visibility="gone" tools:visibility="visible" /> diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 0da9f5d9f..1cdfce8ae 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -131,7 +131,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/password" - android:imeOptions="flagNoExtractUi" + android:imeOptions="actionNext" android:inputType="textPassword" /> @@ -155,7 +155,9 @@ android:id="@+id/login_two_factor" android:layout_width="match_parent" android:layout_height="wrap_content" - android:imeOptions="flagNoExtractUi" + android:imeOptions="actionDone" + android:inputType="number" + android:maxLines="1" android:visibility="gone" tools:visibility="visible" />