Add account name validation to CreateAccountFragment using Kotlin extension functions and RxJava debounce operator.

This commit is contained in:
Severiano Jaramillo 2019-01-05 20:47:04 -06:00
parent 9236e374bc
commit e530dc531e
3 changed files with 56 additions and 2 deletions

View file

@ -9,6 +9,8 @@ import androidx.navigation.fragment.findNavController
import com.jakewharton.rxbinding3.widget.textChanges import com.jakewharton.rxbinding3.widget.textChanges
import cy.agorise.bitsybitshareswallet.R import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.utils.Constants import cy.agorise.bitsybitshareswallet.utils.Constants
import cy.agorise.bitsybitshareswallet.utils.containsDigits
import cy.agorise.bitsybitshareswallet.utils.containsVowels
import cy.agorise.bitsybitshareswallet.utils.toast import cy.agorise.bitsybitshareswallet.utils.toast
import cy.agorise.graphenej.Address import cy.agorise.graphenej.Address
import cy.agorise.graphenej.BrainKey import cy.agorise.graphenej.BrainKey
@ -28,6 +30,7 @@ class CreateAccountFragment : ConnectedFragment() {
private const val TAG = "CreateAccountFragment" private const val TAG = "CreateAccountFragment"
private const val BRAINKEY_FILE = "brainkeydict.txt" private const val BRAINKEY_FILE = "brainkeydict.txt"
private const val MIN_ACCOUNT_NAME_LENGTH = 8
} }
private lateinit var mBrainKey: BrainKey private lateinit var mBrainKey: BrainKey
@ -36,7 +39,7 @@ class CreateAccountFragment : ConnectedFragment() {
/** Variables used to store the validation status of the form fields */ /** Variables used to store the validation status of the form fields */
private var isPINValid = false private var isPINValid = false
private var isPINConfirmationValid = false private var isPINConfirmationValid = false
private var isAccountValid = true // TODO make false private var isAccountValidAndAvailable = false
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
setHasOptionsMenu(true) setHasOptionsMenu(true)
@ -47,6 +50,15 @@ class CreateAccountFragment : ConnectedFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
// Use RxJava Debounce to check the validity and availability of the user's proposed account name
mDisposables.add(
tietAccountName.textChanges()
.skipInitialValue()
.debounce(500, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { validateAccountName(it.toString()) }
)
// Use RxJava Debounce to update the PIN error only after the user stops writing for > 500 ms // Use RxJava Debounce to update the PIN error only after the user stops writing for > 500 ms
mDisposables.add( mDisposables.add(
tietPin.textChanges() tietPin.textChanges()
@ -73,6 +85,31 @@ class CreateAccountFragment : ConnectedFragment() {
generateKeys() generateKeys()
} }
private fun validateAccountName(accountName: String) {
isAccountValidAndAvailable = false
if ( !isAccountNameValid(accountName) ) {
tilAccountName.error = getString(R.string.error__invalid_account_name)
tilAccountName.helperText = ""
} else {
tilAccountName.isErrorEnabled = false
tilAccountName.helperText = getString(R.string.text__verifying_account_availability)
}
enableDisableCreateButton()
}
/**
* Method used to determine if the account name entered by the user is valid
* @param accountName The proposed account name
* @return True if the name is valid, false otherwise
*/
private fun isAccountNameValid(accountName: String): Boolean {
return accountName.length >= MIN_ACCOUNT_NAME_LENGTH &&
(accountName.containsDigits() || !accountName.containsVowels()) &&
!accountName.contains("_")
}
private fun validatePIN() { private fun validatePIN() {
val pin = tietPin.text.toString() val pin = tietPin.text.toString()
@ -102,7 +139,7 @@ class CreateAccountFragment : ConnectedFragment() {
} }
private fun enableDisableCreateButton() { private fun enableDisableCreateButton() {
btnCreate.isEnabled = (isPINValid && isPINConfirmationValid && isAccountValid) btnCreate.isEnabled = (isPINValid && isPINConfirmationValid && isAccountValidAndAvailable)
} }
override fun handleJsonRpcResponse(response: JsonRpcResponse<*>) { override fun handleJsonRpcResponse(response: JsonRpcResponse<*>) {

View file

@ -5,6 +5,7 @@ import android.content.res.ColorStateList
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton
import java.util.regex.Pattern
/** /**
* Creates an enabled state, by enabling the button and using the given [colorResource] to color it. * Creates an enabled state, by enabling the button and using the given [colorResource] to color it.
@ -27,4 +28,18 @@ fun FloatingActionButton.disable(colorResource: Int) {
*/ */
fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_LONG) { fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_LONG) {
Toast.makeText(this, message, duration).show() Toast.makeText(this, message, duration).show()
}
/**
* Verifies that the current string contains at least one digit
*/
fun String.containsDigits(): Boolean {
return Pattern.matches("\\d", this)
}
/**
* Verifies that the current string contains at least one vowel
*/
fun String.containsVowels(): Boolean {
return Pattern.matches("[aeiou]", this)
} }

View file

@ -28,6 +28,8 @@
<!-- Create Account --> <!-- Create Account -->
<string name="text__bitshares_account_name">BitShares account name</string> <string name="text__bitshares_account_name">BitShares account name</string>
<string name="error__read_dict_file">Error reading dictionary file</string> <string name="error__read_dict_file">Error reading dictionary file</string>
<string name="error__invalid_account_name">The account name has to either have more than 8 characters, contain a number or have no vowels. The underscore character is also not allowed. </string>
<string name="text__verifying_account_availability">Verifying account availability…</string>
<!-- Home --> <!-- Home -->
<string name="title_transactions">Transactions</string> <string name="title_transactions">Transactions</string>