diff --git a/README.md b/README.md index 2f98d39..80b7b44 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Latest Version: [![Latest version](https://jitpack.io/v/Ilhasoft/data-binding-va * Minimum/Maximum length validation for text fields; * Validate inputs based on field type (email, credit card, URL, CPF and so on); +* Custom validation by calling a public static method on a string returning a boolean. * Pre-defined error messages translated into English, Portuguese and Spanish; * Custom error messages by field; * Supports [`TextInputLayout`](https://developer.android.com/reference/android/support/design/widget/TextInputLayout.html) and EditText; @@ -127,6 +128,27 @@ You can even validate input by date, for example Email, URL, Username, CreditCar ``` +#### Validate Custom #### + +Adding `validateCustom`, you can set a public static function do validation, for example: + +``` + + +// in MainActivity: +public static boolean validatePassword(String password){ + return password.matches(".*[a-z].*") && + password.matches(".*[A-Z].*") && + password.matches(".*[0-9].*"); +} +``` + ### Applying Validation ### It will be necessary to instantiate `Validator` passing as argument your `ViewDataBinding` instance got from your layout binding. After that you can call `validate()` that will return if your data is valid or not. Example: @@ -224,6 +246,20 @@ By default, the library prompts error messages and doens't dismiss the error aut app:validateDateAutoDismiss="@{true}" /> ``` +### Validate each character ### + +To validate as the user types, use addTextChangedListener. For example: + +``` +binding.password.addTextChangedListener(new TextWatcher() { + @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } + @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } + @Override public void afterTextChanged(Editable s) { + validator.validate(binding.password); + } +}); +``` + ## License ## Copyright 2017-present Ilhasoft diff --git a/build.gradle b/build.gradle index 8854b70..94c3ade 100644 --- a/build.gradle +++ b/build.gradle @@ -2,9 +2,10 @@ buildscript { repositories { maven { url 'https://maven.google.com' } jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.0' + classpath 'com.android.tools.build:gradle:3.1.0' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bb5fcc3..41eeeb1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Sep 20 21:27:17 BRT 2017 +#Thu Apr 05 09:32:46 PDT 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/library/src/main/java/br/com/ilhasoft/support/validation/binding/CustomBindings.java b/library/src/main/java/br/com/ilhasoft/support/validation/binding/CustomBindings.java new file mode 100644 index 0000000..a6d86d4 --- /dev/null +++ b/library/src/main/java/br/com/ilhasoft/support/validation/binding/CustomBindings.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017-present Ilhasoft. + * + * 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 br.com.ilhasoft.support.validation.binding; + +import android.databinding.BindingAdapter; +import android.widget.TextView; + +import br.com.ilhasoft.support.validation.R; +import br.com.ilhasoft.support.validation.rule.CustomRule; +import br.com.ilhasoft.support.validation.util.EditTextHandler; +import br.com.ilhasoft.support.validation.util.ErrorMessageHelper; +import br.com.ilhasoft.support.validation.util.ViewTagHelper; + +/** + * Created by John Lombardo on april 5 2018 + */ +public class CustomBindings { + + @BindingAdapter(value = {"validateCustom", "validateCustomMessage", "validateCustomAutoDismiss"}, requireAll = false) + public static void bindingCustom(TextView view, String staticFunction, String errorMessage, boolean autoDismiss) { + if (autoDismiss) { + EditTextHandler.disableErrorOnChanged(view); + } + + String handledErrorMessage = ErrorMessageHelper.getStringOrDefault(view, + errorMessage, R.string.error_message_custom_validation); + ViewTagHelper.appendValue(R.id.validator_rule, view, new CustomRule(view, staticFunction, handledErrorMessage)); + } + +} diff --git a/library/src/main/java/br/com/ilhasoft/support/validation/rule/CustomRule.java b/library/src/main/java/br/com/ilhasoft/support/validation/rule/CustomRule.java new file mode 100644 index 0000000..91dfad7 --- /dev/null +++ b/library/src/main/java/br/com/ilhasoft/support/validation/rule/CustomRule.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017-present Ilhasoft. + * + * 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 br.com.ilhasoft.support.validation.rule; + +import android.widget.TextView; + +import br.com.ilhasoft.support.validation.util.EditTextHandler; +import br.com.ilhasoft.support.validation.util.CustomRuleCaller; + +/** + * Created by John Lombardo on april 5 2018 + */ +public class CustomRule extends Rule { + + public CustomRule(TextView view, String value, String errorMessage) { + super(view, value, errorMessage); + } + + @Override + public boolean isValid(TextView view) { + return CustomRuleCaller.isString(value, view.getText().toString()); + } + + @Override + public void onValidationSucceeded(TextView view) { + EditTextHandler.removeError(view); + } + + @Override + public void onValidationFailed(TextView view) { + EditTextHandler.setError(view, errorMessage); + } +} diff --git a/library/src/main/java/br/com/ilhasoft/support/validation/util/CustomRuleCaller.java b/library/src/main/java/br/com/ilhasoft/support/validation/util/CustomRuleCaller.java new file mode 100644 index 0000000..93262a2 --- /dev/null +++ b/library/src/main/java/br/com/ilhasoft/support/validation/util/CustomRuleCaller.java @@ -0,0 +1,25 @@ +package br.com.ilhasoft.support.validation.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class CustomRuleCaller { + public static boolean isString(String func, String arg){ + final String clazzName = func.substring(0,func.lastIndexOf(".")); + final String funcName = func.substring(func.lastIndexOf(".")+1); + try { + final Class c = Class.forName(clazzName); + Method m = c.getDeclaredMethod(funcName, String.class); + Object o = m.invoke(null, arg); + return (boolean) o; + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException(e); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException(e); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException(e); + } catch (InvocationTargetException e) { + throw new IllegalArgumentException(e); + } + } +} diff --git a/library/src/main/res/values-es/strings.xml b/library/src/main/res/values-es/strings.xml index 469f822..54b607f 100644 --- a/library/src/main/res/values-es/strings.xml +++ b/library/src/main/res/values-es/strings.xml @@ -4,6 +4,7 @@ Campo no válido. El número máximo de caracteres %1$d Formato de datos no válido Formato no válido + Formato no válido Formato de correo electrónico no válido Formato de CPF no válido diff --git a/library/src/main/res/values-pt/strings.xml b/library/src/main/res/values-pt/strings.xml index cbe2d4f..79ca353 100644 --- a/library/src/main/res/values-pt/strings.xml +++ b/library/src/main/res/values-pt/strings.xml @@ -4,6 +4,7 @@ Campo inválido. O número máximo de caracteres é %1$d Formato de data inválido Formato inválido + Formato inválido Formato do e-mail inválido Formato do CPF inválido diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml index 12d4da7..8070bcf 100644 --- a/library/src/main/res/values/strings.xml +++ b/library/src/main/res/values/strings.xml @@ -4,6 +4,7 @@ Invalid field. The maximum number of characters %1$d Invalid data format Invalid format + Invalid format Invalid email format Invalid username format diff --git a/library/src/test/java/br/com/ilhasoft/support/validation/CustomRuleCallerTest.java b/library/src/test/java/br/com/ilhasoft/support/validation/CustomRuleCallerTest.java new file mode 100644 index 0000000..bc400d1 --- /dev/null +++ b/library/src/test/java/br/com/ilhasoft/support/validation/CustomRuleCallerTest.java @@ -0,0 +1,23 @@ +package br.com.ilhasoft.support.validation; + +import org.junit.Test; + +import br.com.ilhasoft.support.validation.util.CustomRuleCaller; + +import static org.junit.Assert.assertEquals; + +public class CustomRuleCallerTest { + @Test + public void it_is_foo() throws Exception { + assertEquals(true, CustomRuleCaller.isString("br.com.ilhasoft.support.validation.CustomRuleCallerTest.isItFoo", "Foo")); + } + + @Test + public void it_is_not_foo() throws Exception { + assertEquals(false, CustomRuleCaller.isString("br.com.ilhasoft.support.validation.CustomRuleCallerTest.isItFoo", "Bar")); + } + + public static boolean isItFoo(String arg){ + return "foo".equals(arg.toLowerCase()); + } +} \ No newline at end of file diff --git a/sample/src/main/java/br/com/ilhasoft/support/validation/sample/MainActivity.java b/sample/src/main/java/br/com/ilhasoft/support/validation/sample/MainActivity.java index 16deead..fc392ba 100644 --- a/sample/src/main/java/br/com/ilhasoft/support/validation/sample/MainActivity.java +++ b/sample/src/main/java/br/com/ilhasoft/support/validation/sample/MainActivity.java @@ -3,6 +3,8 @@ import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; +import android.text.Editable; +import android.text.TextWatcher; import android.util.Log; import android.view.View; import android.widget.Toast; @@ -39,6 +41,14 @@ protected void onCreate(Bundle savedInstanceState) { binding.validate.setOnClickListener(onValidateAllClickListener); binding.toValidate.setOnClickListener(onValidateAllWithListenerClickListener); + binding.password.addTextChangedListener(new TextWatcher() { + @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } + @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } + @Override public void afterTextChanged(Editable s) { + validator.validate(binding.password); + } + }); + validator = new Validator(binding); validator.setValidationListener(this); validator.enableFormValidationMode(); @@ -80,4 +90,18 @@ private void saveToDatabase() { Log.i(TAG, "Salvar os dados no banco de dados"); } + /** + * Validate the password has a number an upper case character and a lower case character. + * + * Note: This is called through the following tag in activity_main: + * app:validateCustom='@{"br.com.ilhasoft.support.validation.sample.MainActivity.validatePassword"}' + * @param password the string under test + * @return true if it's valid + */ + public static boolean validatePassword(String password){ + return password.matches(".*[a-z].*") && + password.matches(".*[A-Z].*") && + password.matches(".*[0-9].*"); + } + } diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 431c9dd..04e05bd 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -153,7 +153,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Password" - android:inputType="textPassword" /> + android:inputType="textPassword" + app:validateCustom='@{"br.com.ilhasoft.support.validation.sample.MainActivity.validatePassword"}' + app:validateCustomMessage="@{@string/custom_error_password_description}"/> diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index 832085d..7430286 100644 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -6,4 +6,5 @@ Custom message: It\'s not a date! Custom message: This message is too small! Custom message: This message is too big! + Custom message: Password has a lower, an upper and a digit!