mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-28 22:18:46 +03:00
Improve prompt password dialog
Reveal password, inline error when empty
This commit is contained in:
parent
ce13e824b6
commit
783a514496
5 changed files with 143 additions and 77 deletions
|
@ -29,7 +29,7 @@ import im.vector.riotx.core.platform.SimpleTextWatcher
|
||||||
|
|
||||||
class ExportKeysDialog {
|
class ExportKeysDialog {
|
||||||
|
|
||||||
var passwordVisible = false
|
private var passwordVisible = false
|
||||||
|
|
||||||
fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) {
|
fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) {
|
||||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null)
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null)
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.riotx.core.dialogs
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.text.Editable
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.extensions.hideKeyboard
|
||||||
|
import im.vector.riotx.core.extensions.showPassword
|
||||||
|
import im.vector.riotx.core.platform.SimpleTextWatcher
|
||||||
|
|
||||||
|
class PromptPasswordDialog {
|
||||||
|
|
||||||
|
private var passwordVisible = false
|
||||||
|
|
||||||
|
fun show(activity: Activity, listener: (String) -> Unit) {
|
||||||
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_prompt_password, null)
|
||||||
|
|
||||||
|
val passwordTil = dialogLayout.findViewById<TextInputLayout>(R.id.promptPasswordTil)
|
||||||
|
val passwordEditText = dialogLayout.findViewById<TextInputEditText>(R.id.promptPassword)
|
||||||
|
val textWatcher = object : SimpleTextWatcher() {
|
||||||
|
override fun afterTextChanged(s: Editable) {
|
||||||
|
passwordTil.error = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
passwordEditText.addTextChangedListener(textWatcher)
|
||||||
|
|
||||||
|
val showPassword = dialogLayout.findViewById<ImageView>(R.id.promptPasswordPasswordReveal)
|
||||||
|
showPassword.setOnClickListener {
|
||||||
|
passwordVisible = !passwordVisible
|
||||||
|
passwordEditText.showPassword(passwordVisible)
|
||||||
|
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black)
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialog.Builder(activity)
|
||||||
|
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||||
|
.setTitle(R.string.devices_delete_dialog_title)
|
||||||
|
.setView(dialogLayout)
|
||||||
|
.setPositiveButton(R.string.auth_submit, null)
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.setOnKeyListener(DialogInterface.OnKeyListener { dialog, keyCode, event ->
|
||||||
|
if (event.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
|
dialog.cancel()
|
||||||
|
return@OnKeyListener true
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
.setOnDismissListener {
|
||||||
|
dialogLayout.hideKeyboard()
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
.apply {
|
||||||
|
setOnShowListener {
|
||||||
|
getButton(AlertDialog.BUTTON_POSITIVE)
|
||||||
|
.setOnClickListener {
|
||||||
|
if (passwordEditText.text.toString().isEmpty()) {
|
||||||
|
passwordTil.error = activity.getString(R.string.error_empty_field_your_password)
|
||||||
|
} else {
|
||||||
|
listener.invoke(passwordEditText.text.toString())
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,11 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package im.vector.riotx.features.settings.crosssigning
|
package im.vector.riotx.features.settings.crosssigning
|
||||||
|
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.KeyEvent
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.EditText
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
|
@ -27,12 +24,12 @@ import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
|
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.dialogs.PromptPasswordDialog
|
||||||
import im.vector.riotx.core.extensions.cleanup
|
import im.vector.riotx.core.extensions.cleanup
|
||||||
import im.vector.riotx.core.extensions.configureWith
|
import im.vector.riotx.core.extensions.configureWith
|
||||||
import im.vector.riotx.core.extensions.observeEvent
|
import im.vector.riotx.core.extensions.observeEvent
|
||||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||||
import im.vector.riotx.core.utils.toast
|
|
||||||
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -93,36 +90,13 @@ class CrossSigningSettingsFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requestPassword(sessionId: String) {
|
private fun requestPassword(sessionId: String) {
|
||||||
val inflater = requireActivity().layoutInflater
|
PromptPasswordDialog().show(requireActivity()) { password ->
|
||||||
val layout = inflater.inflate(R.layout.dialog_prompt_password, null)
|
// TODO sessionId should never get out the ViewModel
|
||||||
val passwordEditText = layout.findViewById<EditText>(R.id.prompt_password)
|
viewModel.handle(CrossSigningAction.InitializeCrossSigning(UserPasswordAuth(
|
||||||
|
session = sessionId,
|
||||||
AlertDialog.Builder(requireActivity())
|
password = password
|
||||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
)))
|
||||||
.setTitle(R.string.devices_delete_dialog_title)
|
}
|
||||||
.setView(layout)
|
|
||||||
.setPositiveButton(R.string.auth_submit, DialogInterface.OnClickListener { _, _ ->
|
|
||||||
if (passwordEditText.toString().isEmpty()) {
|
|
||||||
requireActivity().toast(R.string.error_empty_field_your_password)
|
|
||||||
return@OnClickListener
|
|
||||||
}
|
|
||||||
val pass = passwordEditText.text.toString()
|
|
||||||
|
|
||||||
// TODO sessionId should never get out the ViewModel
|
|
||||||
viewModel.handle(CrossSigningAction.InitializeCrossSigning(UserPasswordAuth(
|
|
||||||
session = sessionId,
|
|
||||||
password = pass
|
|
||||||
)))
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.setOnKeyListener(DialogInterface.OnKeyListener { dialog, keyCode, event ->
|
|
||||||
if (event.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
|
||||||
dialog.cancel()
|
|
||||||
return@OnKeyListener true
|
|
||||||
}
|
|
||||||
false
|
|
||||||
})
|
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onInitializeCrossSigningKeys() {
|
override fun onInitializeCrossSigningKeys() {
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
|
|
||||||
package im.vector.riotx.features.settings.devices
|
package im.vector.riotx.features.settings.devices
|
||||||
|
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.KeyEvent
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
@ -30,13 +28,13 @@ import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.dialogs.PromptPasswordDialog
|
||||||
import im.vector.riotx.core.extensions.cleanup
|
import im.vector.riotx.core.extensions.cleanup
|
||||||
import im.vector.riotx.core.extensions.configureWith
|
import im.vector.riotx.core.extensions.configureWith
|
||||||
import im.vector.riotx.core.extensions.exhaustive
|
import im.vector.riotx.core.extensions.exhaustive
|
||||||
import im.vector.riotx.core.extensions.observeEvent
|
import im.vector.riotx.core.extensions.observeEvent
|
||||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||||
import im.vector.riotx.core.utils.toast
|
|
||||||
import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
|
import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
|
||||||
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
||||||
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
||||||
|
@ -167,31 +165,10 @@ class VectorSettingsDevicesFragment @Inject constructor(
|
||||||
if (mAccountPassword.isNotEmpty()) {
|
if (mAccountPassword.isNotEmpty()) {
|
||||||
viewModel.handle(DevicesAction.Password(mAccountPassword))
|
viewModel.handle(DevicesAction.Password(mAccountPassword))
|
||||||
} else {
|
} else {
|
||||||
val inflater = requireActivity().layoutInflater
|
PromptPasswordDialog().show(requireActivity()) { password ->
|
||||||
val layout = inflater.inflate(R.layout.dialog_prompt_password, null)
|
mAccountPassword = password
|
||||||
val passwordEditText = layout.findViewById<EditText>(R.id.prompt_password)
|
viewModel.handle(DevicesAction.Password(mAccountPassword))
|
||||||
|
}
|
||||||
AlertDialog.Builder(requireActivity())
|
|
||||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
|
||||||
.setTitle(R.string.devices_delete_dialog_title)
|
|
||||||
.setView(layout)
|
|
||||||
.setPositiveButton(R.string.devices_delete_submit_button_label, DialogInterface.OnClickListener { _, _ ->
|
|
||||||
if (passwordEditText.toString().isEmpty()) {
|
|
||||||
requireActivity().toast(R.string.error_empty_field_your_password)
|
|
||||||
return@OnClickListener
|
|
||||||
}
|
|
||||||
mAccountPassword = passwordEditText.text.toString()
|
|
||||||
viewModel.handle(DevicesAction.Password(mAccountPassword))
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.setOnKeyListener(DialogInterface.OnKeyListener { dialog, keyCode, event ->
|
|
||||||
if (event.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
|
||||||
dialog.cancel()
|
|
||||||
return@OnKeyListener true
|
|
||||||
}
|
|
||||||
false
|
|
||||||
})
|
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView 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_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
@ -14,28 +16,54 @@
|
||||||
android:paddingRight="?dialogPreferredPadding">
|
android:paddingRight="?dialogPreferredPadding">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/delete_dialog_info_label"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="6dp"
|
||||||
android:text="@string/devices_delete_dialog_text"
|
android:text="@string/devices_delete_dialog_text"
|
||||||
android:textSize="12sp" />
|
android:textSize="12sp" />
|
||||||
|
|
||||||
<TextView
|
<FrameLayout
|
||||||
android:id="@+id/password_label"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="8dp">
|
||||||
android:text="@string/devices_delete_pswd"
|
|
||||||
android:textSize="12sp"
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:textStyle="bold" />
|
android:id="@+id/promptPasswordTil"
|
||||||
|
style="@style/VectorTextInputLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/soft_logout_signin_password_hint"
|
||||||
|
app:errorEnabled="true"
|
||||||
|
app:errorIconDrawable="@null">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/promptPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ems="10"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:paddingEnd="48dp"
|
||||||
|
android:paddingRight="48dp"
|
||||||
|
tools:ignore="RtlSymmetry"
|
||||||
|
tools:text="abc" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/promptPasswordPasswordReveal"
|
||||||
|
android:layout_width="@dimen/layout_touch_size"
|
||||||
|
android:layout_height="@dimen/layout_touch_size"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="@drawable/ic_eye_black"
|
||||||
|
android:tint="?attr/colorAccent"
|
||||||
|
tools:contentDescription="@string/a11y_show_password" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/prompt_password"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ems="10"
|
|
||||||
android:inputType="textPassword"
|
|
||||||
android:maxLines="1" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
Loading…
Reference in a new issue