From 7a8f577754668eff1fa7f725671b52e6b3ee1f2e Mon Sep 17 00:00:00 2001 From: Andrea Baccega Date: Thu, 15 Sep 2016 13:18:24 +0200 Subject: [PATCH] Added FloatNumericRangeValidator, refactored some code --- README.md | 30 +++-- library/res/values-ar/fet_attrs.xml | 33 ------ library/res/values/fet_attrs.xml | 1 + .../FloatNumericRangeValidator.java | 30 +++++ .../widget/DefaultEditTextValidator.java | 100 +++++++--------- .../widget/EditTextValidator.java | 108 +++++++++--------- 6 files changed, 149 insertions(+), 153 deletions(-) delete mode 100644 library/res/values-ar/fet_attrs.xml create mode 100644 library/src/com/andreabaccega/formedittextvalidator/FloatNumericRangeValidator.java diff --git a/README.md b/README.md index e2eb172..32735fd 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,12 @@ The app source code is located under this repo! This library can be found in maven central repo. If you're using Android studio you can include it by writing the following in the corresponding _dependencies_ block #### Gradle: ```groovy +allprojects { + repositories { + ... + maven { url "https://jitpack.io" } + } +} dependencies { // ... compile 'com.andreabaccega:android-form-edittext:1.2.1@aar' @@ -25,6 +31,12 @@ dependencies { ``` ####Maven ```xml + + + jitpack.io + https://jitpack.io + + com.andreabaccega android-form-edittext @@ -34,15 +46,13 @@ dependencies { ``` -Since 1.2.+ the library comes with a new optional dependency: [com.android.support.design](http://android-developers.blogspot.it/2015/05/android-design-support-library.html). This will enable the new [TextInputLayout](http://developer.android.com/reference/android/support/design/widget/TextInputLayout.html) features to be used with the validation engine. -Version 1.2.+ depends on com.android.support.design:2.2.0 but if you're not using the support design library you can safely exclude it while including this with gradle by doing so: +Since 1.3.+ the library comes with a new optional dependency: [com.android.support.design](http://android-developers.blogspot.it/2015/05/android-design-support-library.html). This will enable the new [TextInputLayout](http://developer.android.com/reference/android/support/design/widget/TextInputLayout.html) features to be used with the validation engine. +Version 1.3.+ depends on com.android.support.design:2.2.0 but if you're not using the support design library you can safely exclude it while including this with gradle by doing so: ```groovy dependencies { // .. - compile ('com.andreabaccega:android-form-edittext:1.2.1@aar'){ - exclude module: 'design' - } + compile ('com.andreabaccega:android-form-edittext:1.3.+') // .. } ``` @@ -96,15 +106,17 @@ There are several values you can set to the test attribute: - **numeric**: for an only numeric field - **alpha**: for an alpha only field - **alphaNumeric**: guess what? -- **personName**: checks if the entered text is a person first or last name. -- **personFullName**: checks if the entered value is a complete full name. - **email**: checks that the field is a valid email - **creditCard**: checks that the field contains a valid credit card using [Luhn Algorithm](http://en.wikipedia.org/wiki/Luhn_algorithm) - **phone**: checks that the field contains a valid phone number -- **domainName**: checks that field contains a valid domain name ( always passes the test in API Level < 8 ) +- **domainName**: checks that field contains a valid domain name - **ipAddress**: checks that the field contains a valid ip address -- **webUrl**: checks that the field contains a valid url ( always passes the test in API Level < 8 ) +- **webUrl**: checks that the field contains a valid url +- **personName**: checks if the entered text is a person first or last name. +- **personFullName**: checks if the entered value is a complete full name. - **date**: checks that the field is a valid date/datetime format ( if customFormat is set, checks with customFormat ) +- **numericRange**: checks that the field is a valid value between integers. (minNumber and maxNumber must be set) +- **floatNumericRange**: checks that the field is a valid value between integers (but decimal values are allowed). (minNumber and maxNumber must be set) - **nocheck**: It does not check anything except the emptyness of the field. For most of the test type values this library comes with a couple of default strings. This means that error strings ( english only ) are already available for the following test types: numeric, alpha, alphanumeric diff --git a/library/res/values-ar/fet_attrs.xml b/library/res/values-ar/fet_attrs.xml deleted file mode 100644 index 4f2a91f..0000000 --- a/library/res/values-ar/fet_attrs.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/library/res/values/fet_attrs.xml b/library/res/values/fet_attrs.xml index 4f2a91f..d9aa9fe 100644 --- a/library/res/values/fet_attrs.xml +++ b/library/res/values/fet_attrs.xml @@ -19,6 +19,7 @@ + diff --git a/library/src/com/andreabaccega/formedittextvalidator/FloatNumericRangeValidator.java b/library/src/com/andreabaccega/formedittextvalidator/FloatNumericRangeValidator.java new file mode 100644 index 0000000..d7d7d1a --- /dev/null +++ b/library/src/com/andreabaccega/formedittextvalidator/FloatNumericRangeValidator.java @@ -0,0 +1,30 @@ +package com.andreabaccega.formedittextvalidator; + +import android.widget.EditText; + +/** + * A validator that returns true only if the input field contains only numbers + * and the number is within the given range. + * + * @author Said Tahsin Dane + * + */ +public class FloatNumericRangeValidator extends Validator{ + + private int min, max; + + public FloatNumericRangeValidator(String _customErrorMessage, int min, int max) { + super(_customErrorMessage); + this.min = min; + this.max = max; + } + + public boolean isValid(EditText et) { + try { + double value = Double.parseDouble(et.getText().toString()); + return value >= min && value <= max; + } catch(NumberFormatException e) { + return false; + } + } +} diff --git a/library/src/com/andreabaccega/widget/DefaultEditTextValidator.java b/library/src/com/andreabaccega/widget/DefaultEditTextValidator.java index 74ffcba..774a4ca 100644 --- a/library/src/com/andreabaccega/widget/DefaultEditTextValidator.java +++ b/library/src/com/andreabaccega/widget/DefaultEditTextValidator.java @@ -8,35 +8,14 @@ import android.text.TextWatcher; import android.util.AttributeSet; import android.widget.EditText; - import com.andreabaccega.formedittext.R; -import com.andreabaccega.formedittextvalidator.AlphaNumericValidator; -import com.andreabaccega.formedittextvalidator.AlphaValidator; -import com.andreabaccega.formedittextvalidator.AndValidator; -import com.andreabaccega.formedittextvalidator.CreditCardValidator; -import com.andreabaccega.formedittextvalidator.DateValidator; -import com.andreabaccega.formedittextvalidator.DomainValidator; -import com.andreabaccega.formedittextvalidator.DummyValidator; -import com.andreabaccega.formedittextvalidator.EmailValidator; -import com.andreabaccega.formedittextvalidator.EmptyValidator; -import com.andreabaccega.formedittextvalidator.IpAddressValidator; -import com.andreabaccega.formedittextvalidator.MultiValidator; -import com.andreabaccega.formedittextvalidator.NotValidator; -import com.andreabaccega.formedittextvalidator.NumericRangeValidator; -import com.andreabaccega.formedittextvalidator.NumericValidator; -import com.andreabaccega.formedittextvalidator.OrValidator; -import com.andreabaccega.formedittextvalidator.PersonFullNameValidator; -import com.andreabaccega.formedittextvalidator.PersonNameValidator; -import com.andreabaccega.formedittextvalidator.PhoneValidator; -import com.andreabaccega.formedittextvalidator.RegexpValidator; -import com.andreabaccega.formedittextvalidator.Validator; -import com.andreabaccega.formedittextvalidator.WebUrlValidator; +import com.andreabaccega.formedittextvalidator.*; /** * Default implementation of an {@link EditTextValidator} */ public class DefaultEditTextValidator - implements EditTextValidator { + implements EditTextValidator { /** * The custom validators setted using */ @@ -76,7 +55,7 @@ public DefaultEditTextValidator(EditText editText, AttributeSet attrs, Context c customRegexp = typedArray.getString(R.styleable.FormEditText_customRegexp); emptyErrorString = typedArray.getString(R.styleable.FormEditText_emptyErrorString); customFormat = typedArray.getString(R.styleable.FormEditText_customFormat); - if ( testType == TEST_NUMERIC_RANGE ) { + if (testType == TEST_NUMERIC_RANGE || testType == TEST_FLOAT_NUMERIC_RANGE) { minNumber = typedArray.getInt(R.styleable.FormEditText_minNumber, Integer.MIN_VALUE); maxNumber = typedArray.getInt(R.styleable.FormEditText_maxNumber, Integer.MAX_VALUE); } @@ -89,8 +68,8 @@ public DefaultEditTextValidator(EditText editText, AttributeSet attrs, Context c @Override public void addValidator(Validator theValidator) - throws IllegalArgumentException { - if ( theValidator == null ) { + throws IllegalArgumentException { + if (theValidator == null) { throw new IllegalArgumentException("theValidator argument should not be null"); } mValidator.enqueue(theValidator); @@ -109,7 +88,7 @@ public EditText getEditText() { } public void setEditText(EditText editText) { - if ( this.editText != null ) { + if (this.editText != null) { this.editText.removeTextChangedListener(getTextWatcher()); } this.editText = editText; @@ -126,7 +105,7 @@ public int getTestType() { @Override public TextWatcher getTextWatcher() { - if ( tw == null ) { + if (tw == null) { tw = new TextWatcher() { public void afterTextChanged(Editable s) { @@ -137,7 +116,7 @@ public void beforeTextChanged(CharSequence s, int start, int count, int after) { public void onTextChanged(CharSequence s, int start, int before, int count) { - if ( !TextUtils.isEmpty(s) && isErrorShown()) { + if (!TextUtils.isEmpty(s) && isErrorShown()) { try { TextInputLayout textInputLayout = (TextInputLayout) editText.getParent(); textInputLayout.setErrorEnabled(false); @@ -173,25 +152,30 @@ public void resetValidators(Context context) { case TEST_ALPHA: toAdd = - new AlphaValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_only_standard_letters_are_allowed) - : testErrorString); + new AlphaValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_only_standard_letters_are_allowed) + : testErrorString); break; case TEST_ALPHANUMERIC: toAdd = - new AlphaNumericValidator( - TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_this_field_cannot_contain_special_character) - : testErrorString); + new AlphaNumericValidator( + TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_this_field_cannot_contain_special_character) + : testErrorString); break; case TEST_NUMERIC: toAdd = - new NumericValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_only_numeric_digits_allowed) - : testErrorString); + new NumericValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_only_numeric_digits_allowed) + : testErrorString); break; case TEST_NUMERIC_RANGE: toAdd = - new NumericRangeValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_only_numeric_digits_range_allowed, minNumber, maxNumber) - : testErrorString, minNumber, maxNumber); + new NumericRangeValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_only_numeric_digits_range_allowed, minNumber, maxNumber) + : testErrorString, minNumber, maxNumber); + break; + case TEST_FLOAT_NUMERIC_RANGE: + toAdd = + new FloatNumericRangeValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_only_numeric_digits_range_allowed, minNumber, maxNumber) + : testErrorString, minNumber, maxNumber); break; case TEST_REGEXP: @@ -199,47 +183,47 @@ public void resetValidators(Context context) { break; case TEST_CREDITCARD: toAdd = - new CreditCardValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_creditcard_number_not_valid) - : testErrorString); + new CreditCardValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_creditcard_number_not_valid) + : testErrorString); break; case TEST_EMAIL: toAdd = - new EmailValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_email_address_not_valid) - : testErrorString); + new EmailValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_email_address_not_valid) + : testErrorString); break; case TEST_PHONE: toAdd = - new PhoneValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_phone_not_valid) : testErrorString); + new PhoneValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_phone_not_valid) : testErrorString); break; case TEST_DOMAINNAME: toAdd = - new DomainValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_domain_not_valid) - : testErrorString); + new DomainValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_domain_not_valid) + : testErrorString); break; case TEST_IPADDRESS: toAdd = - new IpAddressValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_ip_not_valid) : testErrorString); + new IpAddressValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_ip_not_valid) : testErrorString); break; case TEST_WEBURL: toAdd = - new WebUrlValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_url_not_valid) : testErrorString); + new WebUrlValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_url_not_valid) : testErrorString); break; case TEST_PERSONNAME: toAdd = - new PersonNameValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_notvalid_personname) : testErrorString); + new PersonNameValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_notvalid_personname) : testErrorString); break; case TEST_PERSONFULLNAME: toAdd = - new PersonFullNameValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_notvalid_personfullname) : testErrorString); + new PersonFullNameValidator(TextUtils.isEmpty(testErrorString) ? context.getString(R.string.error_notvalid_personfullname) : testErrorString); break; case TEST_CUSTOM: // must specify the fully qualified class name & an error message - if ( classType == null ) { + if (classType == null) { throw new RuntimeException("Trying to create a custom validator but no classType has been specified."); } - if ( TextUtils.isEmpty(testErrorString) ) { + if (TextUtils.isEmpty(testErrorString)) { throw new RuntimeException(String.format("Trying to create a custom validator (%s) but no error string specified.", classType)); } @@ -247,7 +231,7 @@ public void resetValidators(Context context) { try { Class loadedClass = this.getClass().getClassLoader().loadClass(classType); - if ( ! Validator.class.isAssignableFrom(loadedClass) ) { + if (!Validator.class.isAssignableFrom(loadedClass)) { throw new RuntimeException(String.format("Custom validator (%s) does not extend %s", classType, Validator.class.getName())); } customValidatorClass = (Class) loadedClass; @@ -259,7 +243,7 @@ public void resetValidators(Context context) { toAdd = customValidatorClass.getConstructor(String.class).newInstance(testErrorString); } catch (Exception e) { throw new RuntimeException(String.format("Unable to construct custom validator (%s) with argument: %s", classType, - testErrorString)); + testErrorString)); } break; @@ -270,7 +254,7 @@ public void resetValidators(Context context) { } MultiValidator tmpValidator; - if ( ! emptyAllowed ) { // If the xml tells us that this is a required field, we will add the EmptyValidator. + if (!emptyAllowed) { // If the xml tells us that this is a required field, we will add the EmptyValidator. tmpValidator = new AndValidator(); tmpValidator.enqueue(new EmptyValidator(emptyErrorStringActual)); tmpValidator.enqueue(toAdd); @@ -300,7 +284,7 @@ public void setEmptyAllowed(boolean emptyAllowed, Context context) { } public void setEmptyErrorString(String emptyErrorString) { - if ( ! TextUtils.isEmpty(emptyErrorString) ) { + if (!TextUtils.isEmpty(emptyErrorString)) { emptyErrorStringActual = emptyErrorString; } else { emptyErrorStringActual = defaultEmptyErrorString; @@ -325,7 +309,7 @@ public boolean testValidity() { @Override public boolean testValidity(boolean showUIError) { boolean isValid = mValidator.isValid(editText); - if ( ! isValid && showUIError ) { + if (!isValid && showUIError) { showUIError(); } return isValid; @@ -333,7 +317,7 @@ public boolean testValidity(boolean showUIError) { @Override public void showUIError() { - if ( mValidator.hasErrorMessage() ) { + if (mValidator.hasErrorMessage()) { try { TextInputLayout parent = (TextInputLayout) editText.getParent(); parent.setErrorEnabled(true); @@ -349,7 +333,7 @@ public boolean isErrorShown() { TextInputLayout parent = (TextInputLayout) editText.getParent(); return true; // might sound like a bug. but there's no way to know if the error is shown (not with public api) } catch (Throwable e) { - return ! TextUtils.isEmpty(editText.getError()); + return !TextUtils.isEmpty(editText.getError()); } } diff --git a/library/src/com/andreabaccega/widget/EditTextValidator.java b/library/src/com/andreabaccega/widget/EditTextValidator.java index 699ca0d..98a9d37 100644 --- a/library/src/com/andreabaccega/widget/EditTextValidator.java +++ b/library/src/com/andreabaccega/widget/EditTextValidator.java @@ -3,85 +3,87 @@ import android.content.Context; import android.text.TextWatcher; import android.widget.EditText; - import com.andreabaccega.formedittextvalidator.Validator; /** * Interface for encapsulating validation of an EditText control */ public interface EditTextValidator { - /** - * Add a validator to this FormEditText. The validator will be added in the - * queue of the current validators. - * - * @param theValidator - * @throws IllegalArgumentException - * if the validator is null - */ - public void addValidator(Validator theValidator) - throws IllegalArgumentException; + /** + * Add a validator to this FormEditText. The validator will be added in the + * queue of the current validators. + * + * @param theValidator + * @throws IllegalArgumentException if the validator is null + */ + void addValidator(Validator theValidator) + throws IllegalArgumentException; + + /** + * This should be used with {@link #addTextChangedListener(TextWatcher)}. It + * fixes the non-hiding error popup behaviour. + */ + TextWatcher getTextWatcher(); + + boolean isEmptyAllowed(); - /** - * This should be used with {@link #addTextChangedListener(TextWatcher)}. It - * fixes the non-hiding error popup behaviour. - */ - public TextWatcher getTextWatcher(); + /** + * Resets the {@link Validator}s + */ + void resetValidators(Context context); - public boolean isEmptyAllowed(); + /** + * Calling *testValidity()* will cause the EditText to go through + * customValidators and call {@link #Validator.isValid(EditText)} + * Same as {@link #testValidity(boolean)} with first parameter true + * + * @return true if the validity passes false otherwise. + */ + boolean testValidity(); - /** - * Resets the {@link Validator}s - */ - public void resetValidators(Context context); + /** + * Calling *testValidity()* will cause the EditText to go through + * customValidators and call {@link #Validator.isValid(EditText)} + * + * @param showUIError determines if this call should show the UI error. + * @return true if the validity passes false otherwise. + */ + boolean testValidity(boolean showUIError); - /** - * Calling *testValidity()* will cause the EditText to go through - * customValidators and call {@link #Validator.isValid(EditText)} - * Same as {@link #testValidity(boolean)} with first parameter true - * @return true if the validity passes false otherwise. - */ - public boolean testValidity(); + void showUIError(); - /** - * Calling *testValidity()* will cause the EditText to go through - * customValidators and call {@link #Validator.isValid(EditText)} - * @param showUIError determines if this call should show the UI error. - * @return true if the validity passes false otherwise. - */ - public boolean testValidity(boolean showUIError); + int TEST_REGEXP = 0; - public void showUIError(); + int TEST_NUMERIC = 1; - final int TEST_REGEXP = 0; + int TEST_ALPHA = 2; - final int TEST_NUMERIC = 1; + int TEST_ALPHANUMERIC = 3; - final int TEST_ALPHA = 2; + int TEST_EMAIL = 4; - final int TEST_ALPHANUMERIC = 3; + int TEST_CREDITCARD = 5; - final int TEST_EMAIL = 4; + int TEST_PHONE = 6; - final int TEST_CREDITCARD = 5; + int TEST_DOMAINNAME = 7; - final int TEST_PHONE = 6; + int TEST_IPADDRESS = 8; - final int TEST_DOMAINNAME = 7; + int TEST_WEBURL = 9; - final int TEST_IPADDRESS = 8; + int TEST_NOCHECK = 10; - final int TEST_WEBURL = 9; + int TEST_CUSTOM = 11; - final int TEST_NOCHECK = 10; + int TEST_PERSONNAME = 12; - final int TEST_CUSTOM = 11; + int TEST_PERSONFULLNAME = 13; - final int TEST_PERSONNAME = 12; + int TEST_DATE = 14; - final int TEST_PERSONFULLNAME = 13; + int TEST_NUMERIC_RANGE = 15; - final int TEST_DATE = 14; - - final int TEST_NUMERIC_RANGE = 15; + int TEST_FLOAT_NUMERIC_RANGE = 16; }