Skip to content

Commit

Permalink
Reveal password: use facility from com.google.android.material.textfi…
Browse files Browse the repository at this point in the history
…eld.TextInputLayout instead of manaul handling

Also avoid repeating password on the change password dialog.
  • Loading branch information
bmarty committed Jun 22, 2021
1 parent 5db0d75 commit a964d79
Show file tree
Hide file tree
Showing 57 changed files with 259 additions and 900 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package im.vector.lib.ui.styles.debug

import android.os.Bundle
import android.text.InputType
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import im.vector.lib.ui.styles.databinding.ActivityDebugTextViewBinding

Expand All @@ -27,5 +29,20 @@ abstract class DebugVectorTextViewActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
val views = ActivityDebugTextViewBinding.inflate(layoutInflater)
setContentView(views.root)

views.debugShowPassword.setOnClickListener {
views.debugTextInputEditText.showPassword(true)
}
views.debugHidePassword.setOnClickListener {
views.debugTextInputEditText.showPassword(false)
}
}

private fun EditText.showPassword(visible: Boolean) {
if (visible) {
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
} else {
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
Expand Down Expand Up @@ -67,18 +68,33 @@
android:text="Default (TextAppearance.Vector.Body)\nline 2" />

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/debugTextInputLayout"
style="@style/Widget.Vector.TextInputLayout.Password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="Password">
android:hint="Password"
app:errorEnabled="true">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/debugTextInputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:maxLines="1" />

</com.google.android.material.textfield.TextInputLayout>

<Button
android:id="@+id/debugShowPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show password" />

<Button
android:id="@+id/debugHidePassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hide password" />

</LinearLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,11 @@ import android.app.Activity
import android.text.Editable
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import im.vector.app.R
import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.SimpleTextWatcher
import im.vector.app.databinding.DialogExportE2eKeysBinding

class ExportKeysDialog {

private var passwordVisible = false

fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) {
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null)
val views = DialogExportE2eKeysBinding.bind(dialogLayout)
Expand Down Expand Up @@ -57,13 +54,6 @@ class ExportKeysDialog {
views.exportDialogEt.addTextChangedListener(textWatcher)
views.exportDialogEtConfirm.addTextChangedListener(textWatcher)

views.exportDialogShowPassword.setOnClickListener {
passwordVisible = !passwordVisible
views.exportDialogEt.showPassword(passwordVisible)
views.exportDialogEtConfirm.showPassword(passwordVisible)
views.exportDialogShowPassword.render(passwordVisible)
}

val exportDialog = builder.show()

views.exportDialogSubmit.setOnClickListener {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,8 @@ fun SearchView.withoutLeftMargin() {
}
}

fun EditText.showPassword(visible: Boolean, updateCursor: Boolean = true) {
if (visible) {
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
} else {
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
}
if (updateCursor) setSelection(text?.length ?: 0)
fun EditText.hidePassword() {
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
}

fun View.getMeasurements(): Pair<Int, Int> {
Expand Down

This file was deleted.

15 changes: 2 additions & 13 deletions vector/src/main/java/im/vector/app/features/auth/PromptFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import androidx.core.view.isVisible
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentReauthConfirmBinding
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
Expand All @@ -41,13 +40,6 @@ class PromptFragment : VectorBaseFragment<FragmentReauthConfirmBinding>() {
views.reAuthConfirmButton.debouncedClicks {
onButtonClicked()
}
views.passwordReveal.debouncedClicks {
viewModel.handle(ReAuthActions.StartSSOFallback)
}

views.passwordReveal.debouncedClicks {
viewModel.handle(ReAuthActions.TogglePassVisibility)
}
}

private fun onButtonClicked() = withState(viewModel) { state ->
Expand All @@ -74,21 +66,18 @@ class PromptFragment : VectorBaseFragment<FragmentReauthConfirmBinding>() {
override fun invalidate() = withState(viewModel) {
when (it.flowType) {
LoginFlowTypes.SSO -> {
views.passwordContainer.isVisible = false
views.passwordFieldTil.isVisible = false
views.reAuthConfirmButton.text = getString(R.string.auth_login_sso)
}
LoginFlowTypes.PASSWORD -> {
views.passwordContainer.isVisible = true
views.passwordFieldTil.isVisible = true
views.reAuthConfirmButton.text = getString(R.string._continue)
}
else -> {
// This login flow is not supported, you should use web?
}
}

views.passwordField.showPassword(it.passwordVisible)
views.passwordReveal.render(it.passwordVisible)

if (it.lastErrorCode != null) {
when (it.flowType) {
LoginFlowTypes.SSO -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,5 @@ sealed class ReAuthActions : VectorViewModelAction {
object StartSSOFallback : ReAuthActions()
object FallBackPageLoaded : ReAuthActions()
object FallBackPageClosed : ReAuthActions()
object TogglePassVisibility : ReAuthActions()
data class ReAuthWithPass(val password: String) : ReAuthActions()
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ data class ReAuthState(
val session: String? = null,
val flowType: String? = null,
val ssoFallbackPageWasShown: Boolean = false,
val passwordVisible: Boolean = false,
val lastErrorCode: String? = null,
val resultKeyStoreAlias: String = ""
) : MvRxState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,6 @@ class ReAuthViewModel @AssistedInject constructor(
ReAuthActions.FallBackPageClosed -> {
// Should we do something here?
}
ReAuthActions.TogglePassVisibility -> {
setState {
copy(
passwordVisible = !state.passwordVisible
)
}
}
is ReAuthActions.ReAuthWithPass -> {
val safeForIntentCypher = ByteArrayOutputStream().also {
it.use {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import android.view.inputmethod.EditorInfo
import androidx.core.text.set
import androidx.core.widget.doOnTextChanged
import im.vector.app.R
import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentKeysBackupRestoreFromPassphraseBinding

Expand All @@ -40,10 +39,6 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
private lateinit var viewModel: KeysBackupRestoreFromPassphraseViewModel
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel

private fun toggleVisibilityMode() {
viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

Expand All @@ -56,12 +51,6 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase

views.helperTextWithLink.text = spannableStringForHelperText()

viewModel.showPasswordMode.observe(viewLifecycleOwner) {
val shouldBeVisible = it ?: false
views.keysBackupPassphraseEnterEdittext.showPassword(shouldBeVisible)
views.keysBackupViewShowPassword.render(shouldBeVisible)
}

views.keysBackupPassphraseEnterEdittext.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
onRestoreBackup()
Expand All @@ -70,7 +59,6 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
return@setOnEditorActionListener false
}

views.keysBackupViewShowPassword.setOnClickListener { toggleVisibilityMode() }
views.helperTextWithLink.setOnClickListener { onUseRecoveryKey() }
views.keysBackupRestoreWithPassphraseSubmit.setOnClickListener { onRestoreBackup() }
views.keysBackupPassphraseEnterEdittext.doOnTextChanged { text, _, _, _ -> onPassphraseTextEditChange(text) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ class KeysBackupRestoreFromPassphraseViewModel @Inject constructor(

var passphrase: MutableLiveData<String> = MutableLiveData()
var passphraseErrorText: MutableLiveData<String> = MutableLiveData()
var showPasswordMode: MutableLiveData<Boolean> = MutableLiveData()

init {
passphrase.value = null
passphraseErrorText.value = null
showPasswordMode.value = false
}

// ========= Actions =========
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() {
var confirmPassphraseError: MutableLiveData<String> = MutableLiveData()

var passwordStrength: MutableLiveData<Strength> = MutableLiveData()
var showPasswordMode: MutableLiveData<Boolean> = MutableLiveData()

// Step 3
// Var to ignore events from previous request(s) to generate a recovery key
Expand All @@ -80,7 +79,6 @@ class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() {
var loadingStatus: MutableLiveData<WaitingViewData> = MutableLiveData()

init {
showPasswordMode.value = false
recoveryKey.value = null
isCreatingBackupVersion.value = false
prepareRecoverFailError.value = null
Expand All @@ -97,9 +95,6 @@ class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() {
currentRequestId.value = System.currentTimeMillis()
isCreatingBackupVersion.value = true

// Ensure passphrase is hidden during the process
showPasswordMode.value = false

recoveryKey.value = null
prepareRecoverFailError.value = null
session.let { mxSession ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import androidx.lifecycle.viewModelScope
import androidx.transition.TransitionManager
import com.nulabinc.zxcvbn.Zxcvbn
import im.vector.app.R
import im.vector.app.core.extensions.showPassword
import im.vector.app.core.extensions.hidePassword
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentKeysBackupSetupStep2Binding
import im.vector.app.features.settings.VectorLocale
Expand Down Expand Up @@ -113,13 +113,6 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr

views.keysBackupSetupStep2PassphraseConfirmEditText.setText(viewModel.confirmPassphrase.value)

viewModel.showPasswordMode.observe(viewLifecycleOwner) {
val shouldBeVisible = it ?: false
views.keysBackupSetupStep2PassphraseEnterEdittext.showPassword(shouldBeVisible)
views.keysBackupSetupStep2PassphraseConfirmEditText.showPassword(shouldBeVisible)
views.keysBackupSetupStep2ShowPassword.render(shouldBeVisible)
}

viewModel.confirmPassphraseError.observe(viewLifecycleOwner) {
TransitionManager.beginDelayedTransition(views.keysBackupRoot)
views.keysBackupSetupStep2PassphraseConfirmTil.error = it
Expand All @@ -135,18 +128,13 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
}

private fun setupViews() {
views.keysBackupSetupStep2ShowPassword.setOnClickListener { toggleVisibilityMode() }
views.keysBackupSetupStep2Button.setOnClickListener { doNext() }
views.keysBackupSetupStep2SkipButton.setOnClickListener { skipPassphrase() }

views.keysBackupSetupStep2PassphraseEnterEdittext.doOnTextChanged { _, _, _, _ -> onPassphraseChanged() }
views.keysBackupSetupStep2PassphraseConfirmEditText.doOnTextChanged { _, _, _, _ -> onConfirmPassphraseChanged() }
}

private fun toggleVisibilityMode() {
viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false)
}

private fun doNext() {
when {
viewModel.passphrase.value.isNullOrEmpty() -> {
Expand All @@ -161,6 +149,9 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
else -> {
viewModel.megolmBackupCreationInfo = null

// Ensure passphrase is hidden during the process
views.keysBackupSetupStep2PassphraseEnterEdittext.hidePassword()
views.keysBackupSetupStep2PassphraseConfirmEditText.hidePassword()
viewModel.prepareRecoveryKey(requireActivity(), viewModel.passphrase.value)
}
}
Expand All @@ -172,6 +163,9 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
// Generate a recovery key for the user
viewModel.megolmBackupCreationInfo = null

// Ensure passphrase is hidden during the process
views.keysBackupSetupStep2PassphraseEnterEdittext.hidePassword()
views.keysBackupSetupStep2PassphraseConfirmEditText.hidePassword()
viewModel.prepareRecoveryKey(requireActivity(), null)
}
else -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ import im.vector.app.core.platform.VectorViewModelAction
import im.vector.app.core.platform.WaitingViewData

sealed class SharedSecureStorageAction : VectorViewModelAction {

object TogglePasswordVisibility : SharedSecureStorageAction()
object UseKey : SharedSecureStorageAction()
object Back : SharedSecureStorageAction()
object Cancel : SharedSecureStorageAction()
Expand Down
Loading

0 comments on commit a964d79

Please sign in to comment.