For #12554: Helper class for password reveal on logins

releases/v80.0.0
Hakkı Kaan Çalışkan 4 years ago committed by Emily Kager
parent 66d8591334
commit 3f25a28cf7

@ -0,0 +1,39 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.settings.logins
import android.text.InputType
import android.widget.ImageButton
import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
fun togglePasswordReveal(passwordText: TextView, revealPasswordButton: ImageButton) {
val context = passwordText.context
if (passwordText.inputType == InputType.TYPE_TEXT_VARIATION_PASSWORD
or InputType.TYPE_CLASS_TEXT
) {
context.components.analytics.metrics.track(Event.ViewLoginPassword)
passwordText.inputType = InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
revealPasswordButton.setImageDrawable(
AppCompatResources.getDrawable(context, R.drawable.mozac_ic_password_hide)
)
revealPasswordButton.contentDescription =
context.getString(R.string.saved_login_hide_password)
} else {
passwordText.inputType =
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
revealPasswordButton.setImageDrawable(
AppCompatResources.getDrawable(context, R.drawable.mozac_ic_password_reveal)
)
revealPasswordButton.contentDescription =
context.getString(R.string.saved_login_reveal_password)
}
// We need to reset to take effect
passwordText.text = passwordText.text
}

@ -18,7 +18,6 @@ import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import kotlinx.android.synthetic.main.fragment_edit_login.* import kotlinx.android.synthetic.main.fragment_edit_login.*
import kotlinx.android.synthetic.main.fragment_edit_login.view.*
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.lib.state.ext.consumeFrom
import mozilla.components.support.ktx.android.view.hideKeyboard import mozilla.components.support.ktx.android.view.hideKeyboard
@ -32,9 +31,9 @@ import org.mozilla.fenix.settings.logins.LoginsAction
import org.mozilla.fenix.settings.logins.LoginsFragmentStore import org.mozilla.fenix.settings.logins.LoginsFragmentStore
import org.mozilla.fenix.settings.logins.LoginsListState import org.mozilla.fenix.settings.logins.LoginsListState
import org.mozilla.fenix.settings.logins.SavedLogin import org.mozilla.fenix.settings.logins.SavedLogin
import org.mozilla.fenix.settings.logins.togglePasswordReveal
import org.mozilla.fenix.settings.logins.controller.SavedLoginsStorageController import org.mozilla.fenix.settings.logins.controller.SavedLoginsStorageController
import org.mozilla.fenix.settings.logins.interactor.EditLoginInteractor import org.mozilla.fenix.settings.logins.interactor.EditLoginInteractor
import org.mozilla.fenix.settings.logins.view.EditLoginView
/** /**
* Displays the editable saved login information for a single website * Displays the editable saved login information for a single website
@ -43,12 +42,11 @@ import org.mozilla.fenix.settings.logins.view.EditLoginView
@Suppress("TooManyFunctions", "NestedBlockDepth", "ForbiddenComment") @Suppress("TooManyFunctions", "NestedBlockDepth", "ForbiddenComment")
class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { class EditLoginFragment : Fragment(R.layout.fragment_edit_login) {
fun String.toEditable(): Editable = Editable.Factory.getInstance().newEditable(this) private fun String.toEditable(): Editable = Editable.Factory.getInstance().newEditable(this)
private val args by navArgs<EditLoginFragmentArgs>() private val args by navArgs<EditLoginFragmentArgs>()
private lateinit var loginsFragmentStore: LoginsFragmentStore private lateinit var loginsFragmentStore: LoginsFragmentStore
private lateinit var interactor: EditLoginInteractor private lateinit var interactor: EditLoginInteractor
private lateinit var editLoginView: EditLoginView
private lateinit var oldLogin: SavedLogin private lateinit var oldLogin: SavedLogin
private var listOfPossibleDupes: List<SavedLogin>? = null private var listOfPossibleDupes: List<SavedLogin>? = null
@ -56,7 +54,6 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) {
private var usernameChanged = false private var usernameChanged = false
private var passwordChanged = false private var passwordChanged = false
private var saveEnabled = false private var saveEnabled = false
private var showPassword = true
private var validPassword = true private var validPassword = true
private var validUsername = true private var validUsername = true
@ -65,7 +62,6 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true) setHasOptionsMenu(true)
oldLogin = args.savedLoginItem oldLogin = args.savedLoginItem
editLoginView = EditLoginView(view.editLoginLayout)
loginsFragmentStore = StoreProvider.get(this) { loginsFragmentStore = StoreProvider.get(this) {
LoginsFragmentStore( LoginsFragmentStore(
@ -102,7 +98,7 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) {
initSaveState() initSaveState()
setUpClickListeners() setUpClickListeners()
setUpTextListeners() setUpTextListeners()
editLoginView.showPassword() togglePasswordReveal(passwordText, revealPasswordButton)
consumeFrom(loginsFragmentStore) { consumeFrom(loginsFragmentStore) {
listOfPossibleDupes = loginsFragmentStore.state.duplicateLogins listOfPossibleDupes = loginsFragmentStore.state.duplicateLogins
@ -146,12 +142,7 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) {
it.isEnabled = false it.isEnabled = false
} }
revealPasswordButton.setOnClickListener { revealPasswordButton.setOnClickListener {
showPassword = !showPassword togglePasswordReveal(passwordText, revealPasswordButton)
if (showPassword) {
editLoginView.showPassword()
} else {
editLoginView.hidePassword()
}
} }
} }
@ -170,8 +161,8 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) {
usernameText.addTextChangedListener(object : TextWatcher { usernameText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(u: Editable?) { override fun afterTextChanged(u: Editable?) {
when { when (oldLogin.username) {
u.toString() == oldLogin.username -> { u.toString() -> {
usernameChanged = false usernameChanged = false
validUsername = true validUsername = true
inputLayoutUsername.error = null inputLayoutUsername.error = null

@ -43,6 +43,7 @@ import org.mozilla.fenix.settings.logins.LoginsListState
import org.mozilla.fenix.settings.logins.SavedLogin import org.mozilla.fenix.settings.logins.SavedLogin
import org.mozilla.fenix.settings.logins.controller.SavedLoginsStorageController import org.mozilla.fenix.settings.logins.controller.SavedLoginsStorageController
import org.mozilla.fenix.settings.logins.interactor.LoginDetailInteractor import org.mozilla.fenix.settings.logins.interactor.LoginDetailInteractor
import org.mozilla.fenix.settings.logins.togglePasswordReveal
import org.mozilla.fenix.settings.logins.view.LoginDetailView import org.mozilla.fenix.settings.logins.view.LoginDetailView
/** /**
@ -59,7 +60,6 @@ class LoginDetailFragment : Fragment(R.layout.fragment_login_detail) {
private lateinit var interactor: LoginDetailInteractor private lateinit var interactor: LoginDetailInteractor
private lateinit var menu: Menu private lateinit var menu: Menu
private var deleteDialog: AlertDialog? = null private var deleteDialog: AlertDialog? = null
private var showPassword = true
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -112,7 +112,7 @@ class LoginDetailFragment : Fragment(R.layout.fragment_login_detail) {
) )
setUpPasswordReveal() setUpPasswordReveal()
} }
loginDetailView.togglePasswordReveal(showPassword) togglePasswordReveal(passwordText, revealPasswordButton)
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -140,11 +140,10 @@ class LoginDetailFragment : Fragment(R.layout.fragment_login_detail) {
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
revealPasswordButton.increaseTapArea(BUTTON_INCREASE_DPS) revealPasswordButton.increaseTapArea(BUTTON_INCREASE_DPS)
revealPasswordButton.setOnClickListener { revealPasswordButton.setOnClickListener {
showPassword = !showPassword togglePasswordReveal(passwordText, revealPasswordButton)
loginDetailView.togglePasswordReveal(!showPassword)
} }
passwordText.setOnClickListener { passwordText.setOnClickListener {
loginDetailView.togglePasswordReveal(!showPassword) togglePasswordReveal(passwordText, revealPasswordButton)
} }
} }

@ -171,6 +171,8 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver {
accountExists -> updateSyncPreferenceStatus() accountExists -> updateSyncPreferenceStatus()
!accountExists -> updateSyncPreferenceNeedsLogin() !accountExists -> updateSyncPreferenceNeedsLogin()
} }
togglePrefsEnabledWhileAuthenticating(enabled = true)
} }
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) = override fun onAuthenticated(account: OAuthAccount, authType: AuthType) =

@ -1,54 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.settings.logins.view
import android.text.InputType
import android.view.ViewGroup
import androidx.appcompat.content.res.AppCompatResources
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.fragment_edit_login.view.*
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
/**
* View that contains and configures the Edit Login screen
*/
@Suppress("ForbiddenComment")
class EditLoginView(
override val containerView: ViewGroup
) : LayoutContainer {
private val context = containerView.context
// TODO: create helper class for toggling passwords. https://github.com/mozilla-mobile/fenix/issues/12554
fun showPassword() {
val currText = containerView.passwordText?.text
context.components.analytics.metrics.track(Event.ViewLoginPassword)
containerView.passwordText?.inputType =
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
containerView.revealPasswordButton?.setImageDrawable(
AppCompatResources.getDrawable(context, R.drawable.mozac_ic_password_hide)
)
containerView.revealPasswordButton?.contentDescription =
context.resources.getString(R.string.saved_login_hide_password)
// For the new type to take effect you need to reset the text to it's current edited version
containerView.passwordText?.text = currText
}
fun hidePassword() {
val currText = containerView.passwordText?.text
containerView.passwordText?.inputType =
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
containerView.revealPasswordButton?.setImageDrawable(
AppCompatResources.getDrawable(context, R.drawable.mozac_ic_password_reveal)
)
containerView.revealPasswordButton?.contentDescription =
context.getString(R.string.saved_login_reveal_password)
// For the new type to take effect you need to reset the text to it's current edited version
containerView.passwordText?.text = currText
}
}

@ -4,62 +4,18 @@
package org.mozilla.fenix.settings.logins.view package org.mozilla.fenix.settings.logins.view
import android.text.InputType
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import kotlinx.android.extensions.LayoutContainer import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.fragment_login_detail.* import kotlinx.android.synthetic.main.fragment_login_detail.*
import kotlinx.android.synthetic.main.fragment_login_detail.view.*
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.settings.logins.LoginsListState import org.mozilla.fenix.settings.logins.LoginsListState
/** /**
* View that contains and configures the Login Details * View that contains and configures the Login Details
*/ */
@Suppress("ForbiddenComment")
class LoginDetailView(override val containerView: ViewGroup) : LayoutContainer { class LoginDetailView(override val containerView: ViewGroup) : LayoutContainer {
private val context = containerView.context
fun update(login: LoginsListState) { fun update(login: LoginsListState) {
webAddressText.text = login.currentItem?.origin webAddressText.text = login.currentItem?.origin
usernameText.text = login.currentItem?.username usernameText.text = login.currentItem?.username
passwordText.text = login.currentItem?.password passwordText.text = login.currentItem?.password
} }
fun togglePasswordReveal(show: Boolean) {
if (show) showPassword() else { hidePassword() }
}
// TODO: create helper class for toggling passwords. https://github.com/mozilla-mobile/fenix/issues/12554
fun showPassword() {
if (passwordText.inputType == InputType.TYPE_TEXT_VARIATION_PASSWORD or InputType.TYPE_CLASS_TEXT) {
context?.components?.analytics?.metrics?.track(Event.ViewLoginPassword)
passwordText.inputType = InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
revealPasswordButton.setImageDrawable(
ResourcesCompat.getDrawable(
context.resources,
R.drawable.mozac_ic_password_hide, null
)
)
revealPasswordButton.contentDescription =
context.resources.getString(R.string.saved_login_hide_password)
}
// For the new type to take effect you need to reset the text
passwordText.text = containerView.passwordText.editableText
}
fun hidePassword() {
passwordText.inputType =
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
revealPasswordButton.setImageDrawable(
ResourcesCompat.getDrawable(context.resources,
R.drawable.mozac_ic_password_reveal, null)
)
revealPasswordButton.contentDescription =
context.getString(R.string.saved_login_reveal_password)
// For the new type to take effect you need to reset the text
passwordText.text = containerView.passwordText.editableText
}
} }

Loading…
Cancel
Save