mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-02 20:26:47 +01:00
Add threePid: improve UX (remove dialog)
This commit is contained in:
parent
58938a239e
commit
e92cf38cde
@ -17,6 +17,8 @@
|
||||
package im.vector.app.features.form
|
||||
|
||||
import android.text.Editable
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
@ -35,9 +37,18 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
||||
@EpoxyAttribute
|
||||
var value: String? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var showBottomSeparator: Boolean = true
|
||||
|
||||
@EpoxyAttribute
|
||||
var errorMessage: String? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var enabled: Boolean = true
|
||||
|
||||
@EpoxyAttribute
|
||||
var inputType: Int? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var onTextChange: ((String) -> Unit)? = null
|
||||
|
||||
@ -51,14 +62,17 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
||||
super.bind(holder)
|
||||
holder.textInputLayout.isEnabled = enabled
|
||||
holder.textInputLayout.hint = hint
|
||||
holder.textInputLayout.error = errorMessage
|
||||
|
||||
// Update only if text is different
|
||||
if (holder.textInputEditText.text.toString() != value) {
|
||||
// Update only if text is different and value is not null
|
||||
if (value != null && holder.textInputEditText.text.toString() != value) {
|
||||
holder.textInputEditText.setText(value)
|
||||
}
|
||||
holder.textInputEditText.isEnabled = enabled
|
||||
inputType?.let { holder.textInputEditText.inputType = it }
|
||||
|
||||
holder.textInputEditText.addTextChangedListener(onTextChangeListener)
|
||||
holder.bottomSeparator.isVisible = showBottomSeparator
|
||||
}
|
||||
|
||||
override fun shouldSaveViewState(): Boolean {
|
||||
@ -73,5 +87,6 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val textInputLayout by bind<TextInputLayout>(R.id.formTextInputTextInputLayout)
|
||||
val textInputEditText by bind<TextInputEditText>(R.id.formTextInputTextInputEditText)
|
||||
val bottomSeparator by bind<View>(R.id.formTextInputDivider)
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import im.vector.app.core.platform.VectorViewModelAction
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
|
||||
sealed class ThreePidsSettingsAction : VectorViewModelAction {
|
||||
data class ChangeState(val newState: ThreePidsSettingsState) : ThreePidsSettingsAction()
|
||||
data class AddThreePid(val threePid: ThreePid) : ThreePidsSettingsAction()
|
||||
data class ContinueThreePid(val threePid: ThreePid) : ThreePidsSettingsAction()
|
||||
data class CancelThreePid(val threePid: ThreePid) : ThreePidsSettingsAction()
|
||||
|
@ -16,15 +16,15 @@
|
||||
|
||||
package im.vector.app.features.settings.threepids
|
||||
|
||||
import android.text.InputType
|
||||
import android.view.View
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.loadingItem
|
||||
import im.vector.app.core.epoxy.noResultItem
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.getFormattedValue
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
@ -33,6 +33,7 @@ import im.vector.app.core.ui.list.genericFooterItem
|
||||
import im.vector.app.features.discovery.settingsContinueCancelItem
|
||||
import im.vector.app.features.discovery.settingsInformationItem
|
||||
import im.vector.app.features.discovery.settingsSectionTitleItem
|
||||
import im.vector.app.features.form.formEditTextItem
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -44,6 +45,9 @@ class ThreePidsSettingsController @Inject constructor(
|
||||
interface InteractionListener {
|
||||
fun addEmail()
|
||||
fun addMsisdn()
|
||||
fun cancelAdding()
|
||||
fun doAddEmail(email: String)
|
||||
fun doAddMsisdn(msisdn: String)
|
||||
fun continueThreePid(threePid: ThreePid)
|
||||
fun cancelThreePid(threePid: ThreePid)
|
||||
fun deleteThreePid(threePid: ThreePid)
|
||||
@ -51,8 +55,15 @@ class ThreePidsSettingsController @Inject constructor(
|
||||
|
||||
var interactionListener: InteractionListener? = null
|
||||
|
||||
private var currentInputValue = ""
|
||||
|
||||
override fun buildModels(data: ThreePidsSettingsViewState?) {
|
||||
if (data == null) return
|
||||
|
||||
if (data.state is ThreePidsSettingsState.Idle) {
|
||||
currentInputValue = ""
|
||||
}
|
||||
|
||||
when (data.threePids) {
|
||||
is Loading -> {
|
||||
loadingItem {
|
||||
@ -68,12 +79,12 @@ class ThreePidsSettingsController @Inject constructor(
|
||||
}
|
||||
is Success -> {
|
||||
val dataList = data.threePids.invoke()
|
||||
buildThreePids(dataList, data.pendingThreePids)
|
||||
buildThreePids(dataList, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildThreePids(list: List<ThreePid>, pendingThreePids: Async<List<ThreePid>>) {
|
||||
private fun buildThreePids(list: List<ThreePid>, data: ThreePidsSettingsViewState) {
|
||||
val splited = list.groupBy { it is ThreePid.Email }
|
||||
val emails = splited[true].orEmpty()
|
||||
val msisdn = splited[false].orEmpty()
|
||||
@ -86,16 +97,35 @@ class ThreePidsSettingsController @Inject constructor(
|
||||
emails.forEach { buildThreePid("email ", it) }
|
||||
|
||||
// Pending threePids
|
||||
pendingThreePids.invoke()
|
||||
data.pendingThreePids.invoke()
|
||||
?.filterIsInstance(ThreePid.Email::class.java)
|
||||
?.forEach { buildPendingThreePid("p_email ", it) }
|
||||
|
||||
genericButtonItem {
|
||||
id("addEmail")
|
||||
text(stringProvider.getString(R.string.settings_add_email_address))
|
||||
textColor(colorProvider.getColor(R.color.riotx_accent))
|
||||
buttonClickAction(View.OnClickListener { interactionListener?.addEmail() })
|
||||
}
|
||||
when (data.state) {
|
||||
ThreePidsSettingsState.Idle ->
|
||||
genericButtonItem {
|
||||
id("addEmail")
|
||||
text(stringProvider.getString(R.string.settings_add_email_address))
|
||||
textColor(colorProvider.getColor(R.color.riotx_accent))
|
||||
buttonClickAction(View.OnClickListener { interactionListener?.addEmail() })
|
||||
}
|
||||
is ThreePidsSettingsState.AddingEmail -> {
|
||||
formEditTextItem {
|
||||
id("addingEmail")
|
||||
inputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS)
|
||||
hint(stringProvider.getString(R.string.medium_email))
|
||||
errorMessage(data.state.error)
|
||||
onTextChange { currentInputValue = it }
|
||||
showBottomSeparator(false)
|
||||
}
|
||||
settingsContinueCancelItem {
|
||||
id("contAddingEmail")
|
||||
continueOnClick { interactionListener?.doAddEmail(currentInputValue) }
|
||||
cancelOnClick { interactionListener?.cancelAdding() }
|
||||
}
|
||||
}
|
||||
is ThreePidsSettingsState.AddingPhoneNumber -> Unit
|
||||
}.exhaustive
|
||||
|
||||
settingsSectionTitleItem {
|
||||
id("msisdn")
|
||||
@ -105,26 +135,35 @@ class ThreePidsSettingsController @Inject constructor(
|
||||
msisdn.forEach { buildThreePid("msisdn ", it) }
|
||||
|
||||
// Pending threePids
|
||||
pendingThreePids.invoke()
|
||||
data.pendingThreePids.invoke()
|
||||
?.filterIsInstance(ThreePid.Msisdn::class.java)
|
||||
?.forEach { buildPendingThreePid("p_msisdn ", it) }
|
||||
|
||||
/*
|
||||
// TODO Support adding MSISDN
|
||||
genericButtonItem {
|
||||
id("addMsisdn")
|
||||
text(stringProvider.getString(R.string.settings_add_phone_number))
|
||||
textColor(colorProvider.getColor(R.color.riotx_accent))
|
||||
buttonClickAction(View.OnClickListener { interactionListener?.addMsisdn() })
|
||||
}
|
||||
*/
|
||||
// Avoid empty area
|
||||
if (msisdn.isEmpty()) {
|
||||
noResultItem {
|
||||
id("no_msisdn")
|
||||
text(stringProvider.getString(R.string.settings_phone_numbers_empty))
|
||||
when (data.state) {
|
||||
ThreePidsSettingsState.Idle ->
|
||||
genericButtonItem {
|
||||
id("addMsisdn")
|
||||
text(stringProvider.getString(R.string.settings_add_phone_number))
|
||||
textColor(colorProvider.getColor(R.color.riotx_accent))
|
||||
buttonClickAction(View.OnClickListener { interactionListener?.addMsisdn() })
|
||||
}
|
||||
is ThreePidsSettingsState.AddingEmail -> Unit
|
||||
is ThreePidsSettingsState.AddingPhoneNumber -> {
|
||||
formEditTextItem {
|
||||
id("addingMsisdn")
|
||||
inputType(InputType.TYPE_CLASS_PHONE)
|
||||
hint(stringProvider.getString(R.string.medium_phone_number))
|
||||
errorMessage(data.state.error)
|
||||
onTextChange { currentInputValue = it }
|
||||
showBottomSeparator(false)
|
||||
}
|
||||
settingsContinueCancelItem {
|
||||
id("contAddingMsisdn")
|
||||
continueOnClick { interactionListener?.doAddMsisdn(currentInputValue) }
|
||||
cancelOnClick { interactionListener?.cancelAdding() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun buildThreePid(idPrefix: String, threePid: ThreePid) {
|
||||
|
@ -18,9 +18,7 @@ package im.vector.app.features.settings.threepids
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
@ -30,10 +28,11 @@ import im.vector.app.core.dialogs.withColoredButton
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.hideKeyboard
|
||||
import im.vector.app.core.extensions.isEmail
|
||||
import im.vector.app.core.platform.OnBackPressed
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.toast
|
||||
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import javax.inject.Inject
|
||||
@ -43,6 +42,7 @@ class ThreePidsSettingsFragment @Inject constructor(
|
||||
private val epoxyController: ThreePidsSettingsController
|
||||
) :
|
||||
VectorBaseFragment(),
|
||||
OnBackPressed,
|
||||
ThreePidsSettingsViewModel.Factory by viewModelFactory,
|
||||
ThreePidsSettingsController.InteractionListener {
|
||||
|
||||
@ -90,27 +90,15 @@ class ThreePidsSettingsFragment @Inject constructor(
|
||||
}
|
||||
|
||||
override fun addEmail() {
|
||||
val inflater = requireActivity().layoutInflater
|
||||
val layout = inflater.inflate(R.layout.dialog_base_edit_text, null)
|
||||
|
||||
val input = layout.findViewById<EditText>(R.id.editText)
|
||||
input.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
||||
|
||||
AlertDialog.Builder(requireActivity())
|
||||
.setTitle(R.string.settings_add_email_address)
|
||||
.setView(layout)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
val email = input.text.toString()
|
||||
doAddEmail(email)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
viewModel.handle(ThreePidsSettingsAction.ChangeState(ThreePidsSettingsState.AddingEmail(null)))
|
||||
}
|
||||
|
||||
private fun doAddEmail(email: String) {
|
||||
override fun doAddEmail(email: String) {
|
||||
viewModel.handle(ThreePidsSettingsAction.ChangeState(ThreePidsSettingsState.AddingEmail(null)))
|
||||
|
||||
// Check that email is valid
|
||||
if (!email.isEmail()) {
|
||||
requireActivity().toast(R.string.auth_invalid_email)
|
||||
viewModel.handle(ThreePidsSettingsAction.ChangeState(ThreePidsSettingsState.AddingEmail(getString(R.string.auth_invalid_email))))
|
||||
return
|
||||
}
|
||||
|
||||
@ -118,9 +106,21 @@ class ThreePidsSettingsFragment @Inject constructor(
|
||||
}
|
||||
|
||||
override fun addMsisdn() {
|
||||
viewModel.handle(ThreePidsSettingsAction.ChangeState(ThreePidsSettingsState.AddingPhoneNumber(null)))
|
||||
}
|
||||
|
||||
override fun doAddMsisdn(msisdn: String) {
|
||||
viewModel.handle(ThreePidsSettingsAction.ChangeState(ThreePidsSettingsState.AddingPhoneNumber(null)))
|
||||
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun cancelAdding() {
|
||||
viewModel.handle(ThreePidsSettingsAction.ChangeState(ThreePidsSettingsState.Idle))
|
||||
// Hide the keyboard
|
||||
view?.hideKeyboard()
|
||||
}
|
||||
|
||||
override fun continueThreePid(threePid: ThreePid) {
|
||||
viewModel.handle(ThreePidsSettingsAction.ContinueThreePid(threePid))
|
||||
}
|
||||
@ -139,4 +139,15 @@ class ThreePidsSettingsFragment @Inject constructor(
|
||||
.show()
|
||||
.withColoredButton(DialogInterface.BUTTON_POSITIVE)
|
||||
}
|
||||
|
||||
override fun onBackPressed(toolbarButton: Boolean): Boolean {
|
||||
return withState(viewModel) {
|
||||
if (it.state is ThreePidsSettingsState.Idle) {
|
||||
false
|
||||
} else {
|
||||
cancelAdding()
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 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.app.features.settings.threepids
|
||||
|
||||
sealed class ThreePidsSettingsState {
|
||||
object Idle : ThreePidsSettingsState()
|
||||
data class AddingEmail(val error: String?) : ThreePidsSettingsState()
|
||||
data class AddingPhoneNumber(val error: String?) : ThreePidsSettingsState()
|
||||
}
|
@ -129,14 +129,23 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
|
||||
|
||||
override fun handle(action: ThreePidsSettingsAction) {
|
||||
when (action) {
|
||||
is ThreePidsSettingsAction.AddThreePid -> handleAddThreePid(action)
|
||||
is ThreePidsSettingsAction.AddThreePid -> handleAddThreePid(action)
|
||||
is ThreePidsSettingsAction.ContinueThreePid -> handleContinueThreePid(action)
|
||||
is ThreePidsSettingsAction.CancelThreePid -> handleCancelThreePid(action)
|
||||
is ThreePidsSettingsAction.AccountPassword -> handleAccountPassword(action)
|
||||
is ThreePidsSettingsAction.DeleteThreePid -> handleDeleteThreePid(action)
|
||||
is ThreePidsSettingsAction.CancelThreePid -> handleCancelThreePid(action)
|
||||
is ThreePidsSettingsAction.AccountPassword -> handleAccountPassword(action)
|
||||
is ThreePidsSettingsAction.DeleteThreePid -> handleDeleteThreePid(action)
|
||||
is ThreePidsSettingsAction.ChangeState -> handleChangeState(action)
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun handleChangeState(action: ThreePidsSettingsAction.ChangeState) {
|
||||
setState {
|
||||
copy(
|
||||
state = action.newState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAddThreePid(action: ThreePidsSettingsAction.AddThreePid) {
|
||||
isLoading(true)
|
||||
|
||||
|
@ -22,6 +22,7 @@ import com.airbnb.mvrx.Uninitialized
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
|
||||
data class ThreePidsSettingsViewState(
|
||||
val state: ThreePidsSettingsState = ThreePidsSettingsState.Idle,
|
||||
val isLoading: Boolean = false,
|
||||
val threePids: Async<List<ThreePid>> = Uninitialized,
|
||||
val pendingThreePids: Async<List<ThreePid>> = Uninitialized
|
||||
|
@ -14,6 +14,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||
app:errorEnabled="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/formTextInputDivider"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
@ -684,7 +684,6 @@
|
||||
|
||||
<string name="settings_emails">Email addresses</string>
|
||||
<string name="settings_phone_numbers">Phone numbers</string>
|
||||
<string name="settings_phone_numbers_empty">No phone number has been added to your account</string>
|
||||
<string name="settings_remove_three_pid_confirmation_content">Remove %s?</string>
|
||||
<string name="error_threepid_auth_failed">Ensure that you have clicked on the link in the email we have sent to you.</string>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user