Improve ImportBrainkeyActivity by automatically showing errors if the PIN is not long enough, the PIN Confirmation does not match or if the brainkey does not have the correct format as the user types but with a small debunce to avoid showing errors while the user is typing. Once the three fields are correct then the Import button is enabled.

This commit is contained in:
Severiano Jaramillo 2018-12-11 13:25:15 -06:00
parent bada77f224
commit 2dc0deb23f
2 changed files with 83 additions and 27 deletions

View file

@ -4,10 +4,10 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.util.Log import android.util.Log
import android.view.inputmethod.EditorInfo
import android.widget.Toast import android.widget.Toast
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItemsSingleChoice import com.afollestad.materialdialogs.list.listItemsSingleChoice
import com.jakewharton.rxbinding2.widget.RxTextView
import cy.agorise.bitsybitshareswallet.R import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.database.entities.Authority import cy.agorise.bitsybitshareswallet.database.entities.Authority
import cy.agorise.bitsybitshareswallet.repositories.AuthorityRepository import cy.agorise.bitsybitshareswallet.repositories.AuthorityRepository
@ -20,9 +20,12 @@ import cy.agorise.graphenej.api.calls.GetAccounts
import cy.agorise.graphenej.api.calls.GetKeyReferences import cy.agorise.graphenej.api.calls.GetKeyReferences
import cy.agorise.graphenej.models.AccountProperties import cy.agorise.graphenej.models.AccountProperties
import cy.agorise.graphenej.models.JsonRpcResponse import cy.agorise.graphenej.models.JsonRpcResponse
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.activity_import_brainkey.* import kotlinx.android.synthetic.main.activity_import_brainkey.*
import org.bitcoinj.core.ECKey import org.bitcoinj.core.ECKey
import java.util.ArrayList import java.util.ArrayList
import java.util.concurrent.TimeUnit
// TODO Add method to load the 20? most important assets // TODO Add method to load the 20? most important assets
// TODO add progress bar or something while the user waits for the import response from the node // TODO add progress bar or something while the user waits for the import response from the node
@ -51,41 +54,90 @@ class ImportBrainkeyActivity : ConnectedActivity() {
private var keyReferencesRequestId: Long = 0 private var keyReferencesRequestId: Long = 0
private var getAccountsRequestId: Long = 0 private var getAccountsRequestId: Long = 0
private var mDisposables = CompositeDisposable()
private var isPINValid = false
private var isPINConfirmationValid = false
private var isBrainKeyValid = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_import_brainkey) setContentView(R.layout.activity_import_brainkey)
// Custom event to activate import account from the keyboard // Use RxJava Debounce to update the PIN error only after the user stops writing for > 500 ms
tietBrainKey.setOnEditorActionListener { _, actionId, _ -> mDisposables.add(
if (actionId == EditorInfo.IME_ACTION_DONE) { RxTextView.textChanges(tietPin)
importAccount() .skipInitialValue()
true .debounce(500, TimeUnit.MILLISECONDS)
} else .observeOn(AndroidSchedulers.mainThread())
false .subscribe { validatePIN() }
} )
btnImport.setOnClickListener { importAccount() } // Use RxJava Debounce to update the PIN Confirmation error only after the user stops writing for > 500 ms
mDisposables.add(
RxTextView.textChanges(tietPinConfirmation)
.skipInitialValue()
.debounce(500, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { validatePINConfirmation() }
)
// Use RxJava Debounce to update the BrainKey error only after the user stops writing for > 500 ms
mDisposables.add(
RxTextView.textChanges(tietBrainKey)
.skipInitialValue()
.debounce(500, TimeUnit.MILLISECONDS)
.map { it.toString().trim() }
.observeOn(AndroidSchedulers.mainThread())
.subscribe { validateBrainKey(it) }
)
btnImport.isEnabled = false
btnImport.setOnClickListener { verifyBrainKey(false) }
} }
private fun importAccount() { private fun validatePIN() {
tilPin.isErrorEnabled = false val pin = tietPin.text.toString()
tilPinConfirmation.isErrorEnabled = false
tilBrainKey.isErrorEnabled = false
if (tietPin.text!!.length < Constants.MIN_PIN_LENGTH) if (pin.length < Constants.MIN_PIN_LENGTH) {
tilPin.error = getString(R.string.error__pin_too_short) tilPin.error = getString(R.string.error__pin_too_short)
else if (tietPin.text.toString() != tietPinConfirmation.text.toString()) isPINValid = false
tilPinConfirmation.error = getString(R.string.error__pin_mismatch) } else {
else if (tietBrainKey.text!!.isEmpty() || !tietBrainKey.text.toString().contains(" ")) tilPin.isErrorEnabled = false
tilBrainKey.error = getString(R.string.error__enter_correct_brainkey) isPINValid = true
else {
val brainKey = tietBrainKey.text.toString()
if (brainKey.split(" ").size in 12..16)
verifyBrainKey(false)
else
tilBrainKey.error = getString(R.string.error__enter_correct_brainkey)
} }
validatePINConfirmation()
}
private fun validatePINConfirmation() {
val pinConfirmation = tietPinConfirmation.text.toString()
if (pinConfirmation != tietPin.text.toString()) {
tilPinConfirmation.error = getString(R.string.error__pin_mismatch)
isPINConfirmationValid = false
} else {
tilPinConfirmation.isErrorEnabled = false
isPINConfirmationValid = true
}
enableDisableImportButton()
}
private fun validateBrainKey(brainKey: String) {
if (brainKey.isEmpty() || !brainKey.contains(" ") || brainKey.split(" ").size !in 12..16) {
tilBrainKey.error = getString(R.string.error__enter_correct_brainkey)
isBrainKeyValid = false
} else {
tilBrainKey.isErrorEnabled = false
isBrainKeyValid = true
}
enableDisableImportButton()
}
private fun enableDisableImportButton() {
btnImport.isEnabled = (isPINValid && isPINConfirmationValid && isBrainKeyValid)
} }
/** /**
@ -296,4 +348,10 @@ class ImportBrainkeyActivity : ConnectedActivity() {
val authorityRepository = AuthorityRepository(this) val authorityRepository = AuthorityRepository(this)
authorityRepository.insert(authority) authorityRepository.insert(authority)
} }
override fun onDestroy() {
super.onDestroy()
if (!mDisposables.isDisposed) mDisposables.dispose()
}
} }

View file

@ -5,7 +5,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent" android:layout_height="match_parent"
android:focusableInTouchMode="true"
android:orientation="vertical" android:orientation="vertical"
tools:context=".activities.ImportBrainkeyActivity"> tools:context=".activities.ImportBrainkeyActivity">
@ -78,7 +77,6 @@
android:layout_marginTop="@dimen/spacing_different_topic" android:layout_marginTop="@dimen/spacing_different_topic"
android:layout_marginStart="@dimen/activity_horizontal_margin" android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin" android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:backgroundTint="@color/colorPrimary"
android:text="@string/button__import"/> android:text="@string/button__import"/>
<View <View