diff --git a/README.md b/README.md index 156fb61..5a11059 100644 --- a/README.md +++ b/README.md @@ -2,107 +2,40 @@ ![Logo](logo.png) -__Convalida__ - (Italian for "validation") +**Convalida** - (Italian for "validation") Convalida is a simple, lightweight and powerful field validation library for Android. ## Why Convalida? -- Annotation-based; -- Compile-time; -- Compatible with other annotation-based libraries and frameworks such as [ButterKnife][1], [AndroidAnnotations][2], etc; -- Works with __Stock Android Widgets__; -- Based on [Material Design Error Patterns][4]; +- You can use with annotations or with data binding; +- Compile-time; +- Compatible with other popular libraries such as [ButterKnife][1], [Android Data Binding][2], [Dagger 2][3], etc; +- Works with **Stock Android Widgets**; +- Based on [Material Design Error Patterns][4]; -## Quick Start +## Documentation -__Step 1__ - Annotate your fields with [Convalida Annotations][3]: - -```java -@NotEmptyValidation(R.string.field_required) -EditText nameField; - -@LengthValidation(min = 3, errorMessage = R.string.min_3_characters) -EditText nickNameField; - -@OnlyNumberValidation(R.string.only_numbers) -EditText ageField; - -@EmailValidation(R.string.invalid_email) -EditText emailField; - -@ConfirmEmailValidation(R.string.emails_not_match) -EditText confirmEmailField; - -@PatternValidation(errorMessage = R.string.invalid_phone, pattern = PHONE_PATTERN) -EditText phoneField; - -@PasswordValidation(min = 3, errorMessage = R.string.invalid_password) -EditText passwordField; - -@ConfirmPasswordValidation(R.string.passwords_not_match) -EditText confirmPasswordField; - -@ValidateOnClick -Button validateButton; -``` - -__Step 2__ - Initialize Convalida: - -```java - -@Override -protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_sample); - SampleActivityFieldsValidation.init(this); -} -``` - -__Step 3__ - Run the validations by clicking in the button mapped with ```@ValidateOnClick``` and handle success or error: - -```java -@OnValidationSuccess -public void onValidationSuccess() { - Toast.makeText("Yay!", Toast.LENGTH_LONG).show(); -} - -@OnValidationError -public void onValidationError() { - Toast.makeText("Something is wrong :(", Toast.LENGTH_LONG).show(); -} -``` - -*Note: Only the method annotated with ```@OnValidationSuccess``` is required.* - -__Step 4__ - If you want to clear the validations: - -```java -@ClearValidationsOnClick -Button clearValidationsButton; -``` - -__Remember: You must initialize the views (e.g [ButterKnife][1]) before apply the validations.__ +See the [wiki][5] for more information. ## Download -__Step 1__ - Add the JitPack repository to your root build.gradle file: +**Step 1** - Add the JitPack repository to your root build.gradle file: ```groovy allprojects { repositories { - ... maven { url 'https://jitpack.io' } } } ``` -__Step 2__ - Add the dependencies: +**Step 2** - Add the dependencies: ```groovy dependencies { -  compile 'com.github.WellingtonCosta.convalida:convalida:1.3.7' -  annotationProcessor 'com.github.WellingtonCosta.convalida:convalida-compiler:1.3.7' +  implementation 'com.github.WellingtonCosta.convalida:convalida:2.0.0' +  annotationProcessor 'com.github.WellingtonCosta.convalida:convalida-compiler:2.0.0' } ``` @@ -122,8 +55,12 @@ dependencies { See the License for the specific language governing permissions and limitations under the License. - [1]: https://github.com/JakeWharton/butterknife -[2]: https://github.com/androidannotations/androidannotations -[3]: https://github.com/WellingtonCosta/convalida/tree/master/convalida-annotations/src/main/java/convalida/annotations + +[2]: https://developer.android.com/topic/libraries/data-binding/index.html + +[3]: https://github.com/google/dagger + [4]: https://material.io/guidelines/patterns/errors.html + +[5]: https://github.com/WellingtonCosta/convalida/wiki \ No newline at end of file diff --git a/convalida-annotations/src/main/java/convalida/annotations/NotEmptyValidation.java b/convalida-annotations/src/main/java/convalida/annotations/RequiredValidation.java similarity index 92% rename from convalida-annotations/src/main/java/convalida/annotations/NotEmptyValidation.java rename to convalida-annotations/src/main/java/convalida/annotations/RequiredValidation.java index f6420bc..61aa06c 100644 --- a/convalida-annotations/src/main/java/convalida/annotations/NotEmptyValidation.java +++ b/convalida-annotations/src/main/java/convalida/annotations/RequiredValidation.java @@ -14,7 +14,7 @@ */ @Target(FIELD) @Retention(SOURCE) -public @interface NotEmptyValidation { +public @interface RequiredValidation { @StringRes int errorMessage(); diff --git a/convalida-compiler/src/main/java/convalida/compiler/Constants.java b/convalida-compiler/src/main/java/convalida/compiler/Constants.java index 913e98f..375a96e 100644 --- a/convalida-compiler/src/main/java/convalida/compiler/Constants.java +++ b/convalida-compiler/src/main/java/convalida/compiler/Constants.java @@ -7,27 +7,40 @@ */ class Constants { + static final ClassName LIST = ClassName.get("java.util", "List"); static final ClassName OVERRIDE = ClassName.get("java.lang", "Override"); static final ClassName UI_THREAD = ClassName.get("android.support.annotation", "UiThread"); static final ClassName NON_NULL = ClassName.get("android.support.annotation", "NonNull"); static final ClassName VIEW = ClassName.get("android.view", "View"); + static final ClassName VIEWGROUP = ClassName.get("android.view", "ViewGroup"); + static final ClassName BUTTON = ClassName.get("android.widget", "Button"); static final ClassName VIEW_ONCLICK_LISTENER = ClassName.get("android.view", "View.OnClickListener"); + static final ClassName VIEW_DATA_BINDING = ClassName.get("android.databinding", "ViewDataBinding"); + static final ClassName VIEW_TAG_UTILS = ClassName.get("convalida.databinding", "ViewTagUtils"); + static final ClassName CONVALIDA_DATABINDING_R = ClassName.get("convalida.databinding", "R"); + static final ClassName ABSTRACT_VALIDATOR = ClassName.get("convalida.validators", "AbstractValidator"); static final ClassName VALIDATOR_SET = ClassName.get("convalida.validators", "ValidatorSet"); - static final String NOT_EMPTY_ANNOTATION = "convalida.annotations.NotEmptyValidation"; - static final String EMAIL_ANNOTATION = "convalida.annotations.EmailValidation"; - static final String CONFIRM_EMAIL_VALIDATION = "convalida.annotations.ConfirmEmailValidation"; - static final String PATTERN_ANNOTATION = "convalida.annotations.PatternValidation"; - static final String LENGTH_ANNOTATION = "convalida.annotations.LengthValidation"; - static final String ONLY_NUMBER_ANNOTATION = "convalida.annotations.OnlyNumberValidation"; - static final String PASSWORD_ANNOTATION = "convalida.annotations.PasswordValidation"; - static final String CONFIRM_PASSWORD_ANNOTATION = "convalida.annotations.ConfirmPasswordValidation"; + static final String EDIT_TEXT_TYPE = "android.widget.EditText"; + + static final String REQUIRED_ANNOTATION = "convalida.annotations.RequiredValidation"; + static final String EMAIL_ANNOTATION = "convalida.annotations.EmailValidation"; + static final String CONFIRM_EMAIL_VALIDATION = "convalida.annotations.ConfirmEmailValidation"; + static final String PATTERN_ANNOTATION = "convalida.annotations.PatternValidation"; + static final String LENGTH_ANNOTATION = "convalida.annotations.LengthValidation"; + static final String ONLY_NUMBER_ANNOTATION = "convalida.annotations.OnlyNumberValidation"; + static final String PASSWORD_ANNOTATION = "convalida.annotations.PasswordValidation"; + static final String CONFIRM_PASSWORD_ANNOTATION = "convalida.annotations.ConfirmPasswordValidation"; + static final String VALIDATE_ON_CLICK_ANNOTATION = "convalida.annotations.ConfirmPasswordValidation"; + static final String CLEAR_VALIDATIONS_ON_CLICK_ANNOTATION = "convalida.annotations.ConfirmPasswordValidation"; + static final String ON_VALIDATION_SUCCESS_ANNOTATION = "convalida.annotations.ConfirmPasswordValidation"; + static final String ON_VALIDATION_ERROR_ANNOTATION = "convalida.annotations.ConfirmPasswordValidation"; private static final String VALIDATORS_PACKAGE = "convalida.validators"; - static final ClassName NOT_EMPTY_VALIDATOR = ClassName.get(VALIDATORS_PACKAGE, "NotEmptyValidator"); + static final ClassName REQUIRED_VALIDATOR = ClassName.get(VALIDATORS_PACKAGE, "RequiredValidator"); static final ClassName EMAIL_VALIDATOR = ClassName.get(VALIDATORS_PACKAGE, "EmailValidator"); static final ClassName CONFIRM_EMAIL_VALIDATOR = ClassName.get(VALIDATORS_PACKAGE, "ConfirmEmailValidator"); static final ClassName PATTERN_VALIDATOR = ClassName.get(VALIDATORS_PACKAGE, "PatternValidator"); diff --git a/convalida-compiler/src/main/java/convalida/compiler/ConvalidaProcessor.java b/convalida-compiler/src/main/java/convalida/compiler/ConvalidaProcessor.java index 9a71071..1392e80 100644 --- a/convalida-compiler/src/main/java/convalida/compiler/ConvalidaProcessor.java +++ b/convalida-compiler/src/main/java/convalida/compiler/ConvalidaProcessor.java @@ -8,8 +8,6 @@ import com.sun.tools.javac.tree.JCTree; import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.HashSet; @@ -30,25 +28,23 @@ import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.MirroredTypeException; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; -import javax.tools.Diagnostic.Kind; import convalida.annotations.ClearValidationsOnClick; import convalida.annotations.ConfirmEmailValidation; import convalida.annotations.ConfirmPasswordValidation; import convalida.annotations.EmailValidation; import convalida.annotations.LengthValidation; -import convalida.annotations.NotEmptyValidation; import convalida.annotations.OnValidationError; import convalida.annotations.OnValidationSuccess; import convalida.annotations.OnlyNumberValidation; import convalida.annotations.PasswordValidation; import convalida.annotations.PatternValidation; +import convalida.annotations.RequiredValidation; import convalida.annotations.ValidateOnClick; import convalida.compiler.internal.Id; import convalida.compiler.internal.QualifiedId; @@ -57,37 +53,47 @@ import convalida.compiler.internal.scanners.IdScanner; import convalida.compiler.internal.scanners.RClassScanner; +import static convalida.compiler.Constants.CLEAR_VALIDATIONS_ON_CLICK_ANNOTATION; import static convalida.compiler.Constants.CONFIRM_EMAIL_VALIDATION; import static convalida.compiler.Constants.CONFIRM_PASSWORD_ANNOTATION; import static convalida.compiler.Constants.EMAIL_ANNOTATION; import static convalida.compiler.Constants.LENGTH_ANNOTATION; -import static convalida.compiler.Constants.NOT_EMPTY_ANNOTATION; import static convalida.compiler.Constants.ONLY_NUMBER_ANNOTATION; +import static convalida.compiler.Constants.ON_VALIDATION_ERROR_ANNOTATION; +import static convalida.compiler.Constants.ON_VALIDATION_SUCCESS_ANNOTATION; import static convalida.compiler.Constants.PASSWORD_ANNOTATION; import static convalida.compiler.Constants.PATTERN_ANNOTATION; -import static javax.lang.model.element.ElementKind.CLASS; -import static javax.lang.model.element.ElementKind.FIELD; -import static javax.lang.model.element.Modifier.PRIVATE; -import static javax.lang.model.element.Modifier.STATIC; +import static convalida.compiler.Constants.REQUIRED_ANNOTATION; +import static convalida.compiler.Constants.VALIDATE_ON_CLICK_ANNOTATION; +import static convalida.compiler.Messager.error; +import static convalida.compiler.Messager.logParsingError; +import static convalida.compiler.Preconditions.confirmValidationElementsHasError; +import static convalida.compiler.Preconditions.hasMoreThanOneMethodsAnnotatedWith; +import static convalida.compiler.Preconditions.hasNoMethodAnnotatedWith; +import static convalida.compiler.Preconditions.isInaccessible; +import static convalida.compiler.Preconditions.isInvalid; +import static convalida.compiler.Preconditions.methodHasParams; /** * @author Wellington Costa on 13/06/2017. */ @AutoService(Processor.class) @SupportedAnnotationTypes({ - NOT_EMPTY_ANNOTATION, + REQUIRED_ANNOTATION, EMAIL_ANNOTATION, CONFIRM_EMAIL_VALIDATION, PATTERN_ANNOTATION, LENGTH_ANNOTATION, ONLY_NUMBER_ANNOTATION, PASSWORD_ANNOTATION, - CONFIRM_PASSWORD_ANNOTATION + CONFIRM_PASSWORD_ANNOTATION, + VALIDATE_ON_CLICK_ANNOTATION, + CLEAR_VALIDATIONS_ON_CLICK_ANNOTATION, + ON_VALIDATION_SUCCESS_ANNOTATION, + ON_VALIDATION_ERROR_ANNOTATION }) public class ConvalidaProcessor extends AbstractProcessor { - private static final String EDIT_TEXT_TYPE = "android.widget.EditText"; - private Elements elementUtils; private Types typeUtils; private Messager messager; @@ -103,6 +109,7 @@ public synchronized void init(ProcessingEnvironment processingEnvironment) { this.elementUtils = processingEnvironment.getElementUtils(); this.typeUtils = processingEnvironment.getTypeUtils(); this.messager = processingEnvironment.getMessager(); + convalida.compiler.Messager.init(messager); this.filer = processingEnvironment.getFiler(); try { @@ -113,7 +120,7 @@ public synchronized void init(ProcessingEnvironment processingEnvironment) { private Set> getSupportedAnnotations() { Set> annotations = new LinkedHashSet<>(); - annotations.add(NotEmptyValidation.class); + annotations.add(RequiredValidation.class); annotations.add(EmailValidation.class); annotations.add(ConfirmEmailValidation.class); annotations.add(PatternValidation.class); @@ -121,6 +128,10 @@ private Set> getSupportedAnnotations() { annotations.add(OnlyNumberValidation.class); annotations.add(PasswordValidation.class); annotations.add(ConfirmPasswordValidation.class); + annotations.add(ValidateOnClick.class); + annotations.add(ClearValidationsOnClick.class); + annotations.add(OnValidationSuccess.class); + annotations.add(OnValidationError.class); return annotations; } @@ -150,17 +161,19 @@ public boolean process(Set typeElements, RoundEnvironment private List findAndParseValidations(RoundEnvironment env) { Set parents = new HashSet<>(); List validationFields = new ArrayList<>(); + List validationActions = new ArrayList<>(); + List validationResults = new ArrayList<>(); List validationClasses = new ArrayList<>(); scanForRClasses(env); - // Process each @NotEmptyValidation element - for (Element element : env.getElementsAnnotatedWith(NotEmptyValidation.class)) { + // Process each @RequiredValidation element + for (Element element : env.getElementsAnnotatedWith(RequiredValidation.class)) { if (!SuperficialValidation.validateElement(element)) continue; try { - parseNotEmptyValidation(element, parents, validationFields); + parseRequiredValidation(element, parents, validationFields); } catch (Exception e) { - logParsingError(element, NotEmptyValidation.class, e); + logParsingError(element, RequiredValidation.class, e); } } @@ -234,20 +247,55 @@ private List findAndParseValidations(RoundEnvironment env) { } } + // Process each @ValidateOnClick element. + for (Element element : env.getElementsAnnotatedWith(ValidateOnClick.class)) { + if (!SuperficialValidation.validateElement(element)) continue; + try { + parseValidateOnClick(element, parents, validationActions); + } catch (Exception e) { + logParsingError(element, ValidateOnClick.class, e); + } + } + + // Process each @ClearValidationsOnClick element. + for (Element element : env.getElementsAnnotatedWith(ClearValidationsOnClick.class)) { + if (!SuperficialValidation.validateElement(element)) continue; + try { + parseClearValidationsOnClick(element, parents, validationActions); + } catch (Exception e) { + logParsingError(element, ClearValidationsOnClick.class, e); + } + } + + // Process each @OnValidationSuccess element. + for (Element element : env.getElementsAnnotatedWith(OnValidationSuccess.class)) { + if (!SuperficialValidation.validateElement(element)) continue; + try { + parseOnValidationSuccess(element, parents, validationResults); + } catch (Exception e) { + logParsingError(element, OnValidationSuccess.class, e); + } + } + + // Process each @OnValidationError element. + for (Element element : env.getElementsAnnotatedWith(OnValidationError.class)) { + if (!SuperficialValidation.validateElement(element)) continue; + try { + parseOnValidationError(element, parents, validationResults); + } catch (Exception e) { + logParsingError(element, OnValidationError.class, e); + } + } // Assemble the validation classes and fields for (Element parent : parents) { ValidationClass validationClass = new ValidationClass(parent, this.elementUtils); - for (ValidationField validationField : validationFields) { - Element element = validationField.element; - if (element.getEnclosingElement().equals(parent)) { - validationClass.addField(validationField); - } - } + processValidationFields(parent, validationClass, validationFields); - parseValidateOnClick(parent, validationClass); - parseClearValidationsOnClick(parent, validationClass); + processValidationActions(parent, validationClass, validationActions); + + processValidationResults(parent, validationClass, validationResults); validationClasses.add(validationClass); } @@ -255,153 +303,129 @@ private List findAndParseValidations(RoundEnvironment env) { return validationClasses; } - private void parseValidateOnClick(Element parent, ValidationClass validationClass) { - List elements = new ArrayList<>(); - - for(Element element : parent.getEnclosedElements()) { - if((element.getAnnotation(ValidateOnClick.class) != null)) { - elements.add(element); + private void processValidationFields( + Element parent, + ValidationClass validationClass, + List validationFields) { + for (ValidationField validationField : validationFields) { + Element element = validationField.element; + if (element.getEnclosingElement().equals(parent)) { + validationClass.addField(validationField); } } - - if (elements.size() > 1) { - error( - parent, - "The class %s must have only one element annotated with @ValidateOnClick annotation.", - parent.getSimpleName() - ); - return; - } - - if (elements.size() == 1) { - boolean isInaccessible = isInaccessible(ValidateOnClick.class, elements.get(0)); - if (isInaccessible) return; - - validationClass.setValidateButton(elements.get(0)); - parseOnValidationSuccess(parent, validationClass); - parseOnValidationError(parent, validationClass); - } } - private boolean validationMethodHasNoParams(Class annotationClass, ExecutableElement method) { - boolean hasNoParams = true; - - if (method.getParameters().size() > 0) { - hasNoParams = false; - error(method, "Method annotated with @%s can not have parameters.",annotationClass.getSimpleName()); + private void processValidationActions( + Element parent, + ValidationClass validationClass, + List validationActions) { + for(Element validationAction : validationActions) { + if(validationAction.getEnclosingElement().equals(parent)) { + if(validationAction.getAnnotation(ValidateOnClick.class) != null) { + validationClass.setValidateButton(validationAction); + } + if(validationAction.getAnnotation(ClearValidationsOnClick.class) != null) { + validationClass.setClearValidationsButton(validationAction); + } + } } - - return hasNoParams; } - private void parseOnValidationSuccess(Element parent, ValidationClass validationClass) { - List elements = new ArrayList<>(); - - for(Element element : parent.getEnclosedElements()) { - if(element.getAnnotation(OnValidationSuccess.class) != null) { - elements.add(element); + private void processValidationResults( + Element parent, + ValidationClass validationClass, + List validationResults) { + for(Element validationResult : validationResults) { + if(validationResult.getEnclosingElement().equals(parent)) { + if(validationResult.getAnnotation(OnValidationSuccess.class) != null) { + validationClass.setOnValidationSuccessMethod(validationResult); + } + if(validationResult.getAnnotation(OnValidationError.class) != null) { + validationClass.setOnValidationErrorMethod(validationResult); + } } } + } - if (elements.size() == 0) { - error( - parent, - "The class %s have an element annotated with @ValidateOnClick annotation and it requires a method annotated with @OnValidationSuccess annotation.", - parent.getSimpleName() - ); - return; - } + private void parseValidateOnClick(Element element, Set parents, List validationActions) { + Element parent = element.getEnclosingElement(); + boolean hasError = + isInaccessible(ValidateOnClick.class, element) || + hasMoreThanOneMethodsAnnotatedWith(parent, ValidateOnClick.class); - if (elements.size() > 1) { - error( - parent, - "The class %s must have only one element annotated with @OnValidationSuccess annotation.", - parent.getSimpleName() - ); - return; - } + if(hasError) return; - if (elements.size() == 1) { - boolean isInaccessible = isInaccessible(OnValidationSuccess.class, elements.get(0)); - boolean validationMethodHasNoParams = validationMethodHasNoParams(OnValidationSuccess.class, ((ExecutableElement) elements.get(0))); - if (isInaccessible && !validationMethodHasNoParams) return; - - validationClass.setOnValidationSuccessMethod(elements.get(0)); - } + parents.add(parent); + validationActions.add(element); } - private void parseOnValidationError(Element parent, ValidationClass validationClass) { - List elements = new ArrayList<>(); + private void parseClearValidationsOnClick(Element element, Set parents, List validationActions) { + Element parent = element.getEnclosingElement(); + boolean hasError = + isInaccessible(ClearValidationsOnClick.class, element) || + hasMoreThanOneMethodsAnnotatedWith(parent, ClearValidationsOnClick.class); - for(Element element : parent.getEnclosedElements()) { - if(element.getAnnotation(OnValidationError.class) != null) { - elements.add(element); - } - } + if(hasError) return; - if (elements.size() > 1) { - error( - parent, - "The class %s must have only one element annotated with @OnValidationError annotation.", - parent.getSimpleName() - ); - return; - } + parents.add(parent); + validationActions.add(element); + } - if (elements.size() == 1) { - boolean isInaccessible = isInaccessible(OnValidationError.class, elements.get(0)); - boolean validationMethodHasNoParams = validationMethodHasNoParams(OnValidationError.class, ((ExecutableElement) elements.get(0))); - if (isInaccessible && !validationMethodHasNoParams) return; + private void parseOnValidationSuccess(Element element, Set parents, List validationActions) { + Element parent = element.getEnclosingElement(); + ExecutableElement executableElement = (ExecutableElement)element; + boolean hasError = + isInaccessible(OnValidationSuccess.class, element) || + methodHasParams(executableElement, OnValidationSuccess.class) || + hasMoreThanOneMethodsAnnotatedWith(parent, OnValidationSuccess.class); - validationClass.setOnValidationErrorMethod(elements.get(0)); - } - } + if(hasError) return; - private void parseClearValidationsOnClick(Element parent, ValidationClass validationClass) { - List elements = new ArrayList<>(); + parents.add(parent); + validationActions.add(element); + } - for(Element element : parent.getEnclosedElements()) { - if(element.getAnnotation(ClearValidationsOnClick.class) != null) { - elements.add(element); - } - } + private void parseOnValidationError(Element element, Set parents, List validationActions) { + Element parent = element.getEnclosingElement(); + ExecutableElement executableElement = (ExecutableElement)element; + boolean hasError = + isInaccessible(OnValidationError.class, element) || + methodHasParams(executableElement, OnValidationError.class) || + hasMoreThanOneMethodsAnnotatedWith(parent, OnValidationError.class) || + hasNoMethodAnnotatedWith(parent, OnValidationSuccess.class); - if (elements.size() > 1) { - error( - parent, - "The class %s must have only one element annotated with @ClearValidationsOnClick annotation.", - parent.getSimpleName() - ); - return; - } + if(hasError) return; - if (elements.size() == 1) { - validationClass.setClearValidationsButton(elements.get(0)); - } + parents.add(parent); + validationActions.add(element); } - private void parseNotEmptyValidation(Element element, Set parents, List validationFields) { - boolean hasError = isInvalid(NotEmptyValidation.class, element) || isInaccessible(NotEmptyValidation.class, element); + private void parseRequiredValidation(Element element, Set parents, List validationFields) { + boolean hasError = + isInvalid(RequiredValidation.class, element) || + isInaccessible(RequiredValidation.class, element); if (hasError) { return; } - int errorMessageResourceId = element.getAnnotation(NotEmptyValidation.class).errorMessage(); - boolean autoDismiss = element.getAnnotation(NotEmptyValidation.class).autoDismiss(); + int errorMessageResourceId = element.getAnnotation(RequiredValidation.class).errorMessage(); + boolean autoDismiss = element.getAnnotation(RequiredValidation.class).autoDismiss(); QualifiedId qualifiedId = elementToQualifiedId(element, errorMessageResourceId); parents.add(element.getEnclosingElement()); validationFields.add(new ValidationField( element, - NotEmptyValidation.class, + RequiredValidation.class, getId(qualifiedId), autoDismiss )); } private void parseEmailValidation(Element element, Set parents, List validationFields) { - boolean hasError = isInvalid(EmailValidation.class, element) || isInaccessible(EmailValidation.class, element); + boolean hasError = + isInvalid(EmailValidation.class, element) || + isInaccessible(EmailValidation.class, element); if (hasError) { return; @@ -423,7 +447,7 @@ private void parseEmailValidation(Element element, Set parents, List parents, List validationFields) { boolean hasError = isInvalid(ConfirmEmailValidation.class, element) || isInaccessible(ConfirmEmailValidation.class, element) || - !validateConfirmValidationElements(EmailValidation.class, ConfirmEmailValidation.class, element); + confirmValidationElementsHasError(EmailValidation.class, ConfirmEmailValidation.class, element); if (hasError) return; @@ -441,7 +465,9 @@ private void parseConfirmEmailValidation(Element element, Set parents, } private void parsePatternValidation(Element element, Set parents, List validationFields) { - boolean hasError = isInvalid(PatternValidation.class, element) || isInaccessible(PatternValidation.class, element); + boolean hasError = + isInvalid(PatternValidation.class, element) || + isInaccessible(PatternValidation.class, element); if (hasError) { return; @@ -496,7 +522,9 @@ private void parseLengthValidation(Element element, Set parents, List parents, List validationFields) { - boolean hasError = isInvalid(OnlyNumberValidation.class, element) || isInaccessible(OnlyNumberValidation.class, element); + boolean hasError = + isInvalid(OnlyNumberValidation.class, element) || + isInaccessible(OnlyNumberValidation.class, element); if (hasError) { return; @@ -516,7 +544,9 @@ private void parseOnlyNumberValidation(Element element, Set parents, Li } private void parsePasswordValidation(Element element, Set parents, List validationFields) { - boolean hasError = isInvalid(PasswordValidation.class, element) || isInaccessible(PasswordValidation.class, element); + boolean hasError = + isInvalid(PasswordValidation.class, element) || + isInaccessible(PasswordValidation.class, element); if (hasError) { return; @@ -556,7 +586,7 @@ private void parsePasswordValidation(Element element, Set parents, List private void parseConfirmPasswordValidation(Element element, Set parents, List validationFields) { boolean hasError = isInvalid(ConfirmPasswordValidation.class, element) || isInaccessible(ConfirmPasswordValidation.class, element) || - !validateConfirmValidationElements(PasswordValidation.class, ConfirmPasswordValidation.class, element); + confirmValidationElementsHasError(PasswordValidation.class, ConfirmPasswordValidation.class, element); if (hasError) return; @@ -573,136 +603,7 @@ private void parseConfirmPasswordValidation(Element element, Set parent )); } - private boolean validateConfirmValidationElements( - Class primaryAnnotation, - Class confirmAnnotation, - Element element - ) { - boolean isValid = true; - - String primaryAnnotationClassName = primaryAnnotation.getSimpleName(); - String confirmAnnotationClassName = confirmAnnotation.getSimpleName(); - - int elementsAnnotatedWithPrimaryValidation = 0; - int elementsAnnotatedWithConfirmValidation = 0; - - List elementsOfParent = element.getEnclosingElement().getEnclosedElements(); - - for(int i = 0; i < elementsOfParent.size(); i++) { - if(elementsOfParent.get(i).getAnnotation(primaryAnnotation) != null) { - elementsAnnotatedWithPrimaryValidation ++; - } - - if(elementsOfParent.get(i).getAnnotation(confirmAnnotation) != null) { - elementsAnnotatedWithConfirmValidation ++; - } - } - - if (elementsAnnotatedWithPrimaryValidation == 0 && elementsAnnotatedWithConfirmValidation > 0) { - isValid = false; - TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); - error( - element.getEnclosingElement(), - "%s must have at least one element annotated with @%s.", - enclosingElement.getSimpleName(), - primaryAnnotationClassName - ); - } - - if (elementsAnnotatedWithConfirmValidation > 1) { - isValid = false; - TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); - error( - element.getEnclosingElement(), - "%s must have only one element annotated with @%s.", - enclosingElement.getSimpleName(), - confirmAnnotationClassName - ); - } - - return isValid; - } - - private boolean isInvalid(Class annotationClass, Element element) { - TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); - String elementType = element.asType().toString(); - boolean hasError = false; - - // Verify element kind - if (!element.getKind().equals(FIELD)) { - error( - element, - "@%s must only be applied in fields. (%s.%s)", - annotationClass.getSimpleName(), - enclosingElement.getQualifiedName(), - element.getSimpleName() - ); - hasError = true; - } - - // Verify element type - if (!EDIT_TEXT_TYPE.equals(elementType)) { // improve this check - error( - element, - "@%s must only be applied in fields of the type TextInputLaytout or EditText. (%s.%s)", - annotationClass.getSimpleName(), - enclosingElement.getQualifiedName(), - element.getSimpleName() - ); - - hasError = true; - } - - return hasError; - } - - private boolean isInaccessible(Class annotationClass, Element element) { - TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); - boolean hasError = false; - - // Verify element modifiers - Set modifiers = element.getModifiers(); - if (modifiers.contains(PRIVATE) || modifiers.contains(STATIC)) { - error( - element, - "@%s must not be applied in private or static fields. (%s.%s)", - annotationClass.getSimpleName(), - enclosingElement.getQualifiedName(), - element.getSimpleName() - ); - - hasError = true; - } - - // Verify containing type - if (enclosingElement.getKind() != CLASS) { - error( - enclosingElement, - "@%s fields may only be contained in classes. (%s.%s)", - annotationClass.getSimpleName(), - enclosingElement.getQualifiedName(), - element.getSimpleName() - ); - - hasError = true; - } - - // Verify containing class visibility is not private - if (enclosingElement.getModifiers().contains(PRIVATE)) { - error( - enclosingElement, - "@%s fields may not be contained in private classes. (%s.%s)", - annotationClass.getSimpleName(), - enclosingElement.getQualifiedName(), - element.getSimpleName() - ); - - hasError = true; - } - - return hasError; - } private static AnnotationMirror getMirror(Element element, Class annotation) { for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { @@ -789,18 +690,4 @@ private void parseCompiledR(String respectivePackageName, TypeElement rClass) { } } - private void logParsingError(Element element, Class annotation, Exception e) { - StringWriter stackTrace = new StringWriter(); - e.printStackTrace(new PrintWriter(stackTrace)); - error(element, "Unable to parse @%s validation.\n\n%s", annotation.getSimpleName(), stackTrace); - } - - private void error(Element element, String message, Object... args) { - if (args.length > 0) { - message = String.format(message, args); - } - - this.messager.printMessage(Kind.ERROR, message, element); - } - } \ No newline at end of file diff --git a/convalida-compiler/src/main/java/convalida/compiler/JavaFiler.java b/convalida-compiler/src/main/java/convalida/compiler/JavaFiler.java index b8531cf..ef19ddd 100644 --- a/convalida-compiler/src/main/java/convalida/compiler/JavaFiler.java +++ b/convalida-compiler/src/main/java/convalida/compiler/JavaFiler.java @@ -15,17 +15,19 @@ import convalida.compiler.internal.ValidationClass; import convalida.compiler.internal.ValidationField; +import static convalida.compiler.Constants.ABSTRACT_VALIDATOR; +import static convalida.compiler.Constants.BUTTON; import static convalida.compiler.Constants.CONFIRM_EMAIL_VALIDATION; import static convalida.compiler.Constants.CONFIRM_EMAIL_VALIDATOR; import static convalida.compiler.Constants.CONFIRM_PASSWORD_ANNOTATION; import static convalida.compiler.Constants.CONFIRM_PASSWORD_VALIDATOR; +import static convalida.compiler.Constants.CONVALIDA_DATABINDING_R; import static convalida.compiler.Constants.EMAIL_ANNOTATION; import static convalida.compiler.Constants.EMAIL_VALIDATOR; import static convalida.compiler.Constants.LENGTH_ANNOTATION; import static convalida.compiler.Constants.LENGTH_VALIDATOR; +import static convalida.compiler.Constants.LIST; import static convalida.compiler.Constants.NON_NULL; -import static convalida.compiler.Constants.NOT_EMPTY_ANNOTATION; -import static convalida.compiler.Constants.NOT_EMPTY_VALIDATOR; import static convalida.compiler.Constants.ONLY_NUMBER_ANNOTATION; import static convalida.compiler.Constants.ONLY_NUMBER_VALIDATOR; import static convalida.compiler.Constants.OVERRIDE; @@ -33,10 +35,15 @@ import static convalida.compiler.Constants.PASSWORD_VALIDATOR; import static convalida.compiler.Constants.PATTERN_ANNOTATION; import static convalida.compiler.Constants.PATTERN_VALIDATOR; +import static convalida.compiler.Constants.REQUIRED_ANNOTATION; +import static convalida.compiler.Constants.REQUIRED_VALIDATOR; import static convalida.compiler.Constants.UI_THREAD; import static convalida.compiler.Constants.VALIDATOR_SET; import static convalida.compiler.Constants.VIEW; +import static convalida.compiler.Constants.VIEWGROUP; +import static convalida.compiler.Constants.VIEW_DATA_BINDING; import static convalida.compiler.Constants.VIEW_ONCLICK_LISTENER; +import static convalida.compiler.Constants.VIEW_TAG_UTILS; import static javax.lang.model.element.Modifier.FINAL; import static javax.lang.model.element.Modifier.PRIVATE; import static javax.lang.model.element.Modifier.PUBLIC; @@ -52,9 +59,11 @@ static JavaFile cookJava(ValidationClass validationClass) { .addModifiers(PUBLIC) .addField(VALIDATOR_SET, "validatorSet", PRIVATE) .addMethod(createConstructor(validationClass)) - .addMethod(createValidateOnClickMethod(validationClass)) - .addMethod(createClearValidationsOnClickMethod(validationClass)) - .addMethod(createInitMethod(validationClass)); + .addMethod(createDatabindingConstructor(validationClass)) + .addMethod(createValidateOnClickListener(validationClass)) + .addMethod(createClearValidationsOnClickListener(validationClass)) + .addMethod(createInitMethod(validationClass)) + .addMethod(createInitDatabindingMethod(validationClass)); return JavaFile.builder(validationClass.packageName, validationClassBuilder.build()) .addFileComment("Generated code from Convalida. Do not modify!") @@ -67,12 +76,137 @@ private static MethodSpec createConstructor(ValidationClass validationClass) { .addAnnotation(UI_THREAD) .addParameter(ParameterSpec .builder(validationClass.typeName, "target") + .addModifiers(FINAL) .addAnnotation(NON_NULL) .build() ) .addStatement("validatorSet = new $T()", VALIDATOR_SET) - .addCode("\n") .addCode(createValidationsCodeBlock(validationClass)) + .addCode(createValidateOnClickCodeBlock(validationClass)) + .addCode(createClearValidationsOnClickCodeBlock(validationClass)) + .build(); + } + + private static MethodSpec createDatabindingConstructor(ValidationClass validationClass) { + return MethodSpec.constructorBuilder() + .addModifiers(PRIVATE) + .addAnnotation(UI_THREAD) + .addParameter(ParameterSpec + .builder(validationClass.typeName, "target") + .addModifiers(FINAL) + .addAnnotation(NON_NULL) + .build() + ) + .addParameter(ParameterSpec + .builder(VIEW_DATA_BINDING, "binding") + .addModifiers(FINAL) + .addAnnotation(NON_NULL) + .build() + ) + .addCode("if (binding.hasPendingBindings()) {") + .addCode("\n") + .addCode(CodeBlock.builder().indent().build()) + .addCode("binding.executePendingBindings();") + .addCode("\n") + .addCode(CodeBlock.builder().unindent().build()) + .addCode("}") + .addCode("\n") + .addCode("\n") + .addStatement("validatorSet = new $T()", VALIDATOR_SET) + .addCode( + "$T<$T> views = $T.getViewsByTag(($T) binding.getRoot(), $T.id.validation_type);", + LIST, + VIEW, + VIEW_TAG_UTILS, + VIEWGROUP, + CONVALIDA_DATABINDING_R + ) + .addCode("\n") + .addCode( + "$T<$T> buttons = $T.getViewsByTag(($T) binding.getRoot(), $T.id.validation_action);", + LIST, + VIEW, + VIEW_TAG_UTILS, + VIEWGROUP, + CONVALIDA_DATABINDING_R + ) + .addCode("\n") + .addCode("$T validateButton = null;", BUTTON) + .addCode("\n") + .addCode("$T clearValidationsButton = null;", BUTTON) + .addCode("\n") + .addCode("\n") + .addCode("for (View view : views) {") + .addCode("\n") + .addCode(CodeBlock.builder().indent().build()) + .addCode( + "validatorSet.addValidator(($T) view.getTag($T.id.validation_type));", + ABSTRACT_VALIDATOR, + CONVALIDA_DATABINDING_R + ) + .addCode(CodeBlock.builder().unindent().build()) + .addCode("\n") + .addCode("}") + .addCode("\n") + .addCode("\n") + .addCode("for (View button : buttons) {") + .addCode("\n") + .addCode(CodeBlock.builder().indent().build()) + .addCode( + "if (button.getTag($T.id.validation_action).equals($T.id.validate) && validateButton == null) {", + CONVALIDA_DATABINDING_R, + CONVALIDA_DATABINDING_R + ) + .addCode("\n") + .addCode(CodeBlock.builder().indent().build()) + .addCode("validateButton = ($T) button;", BUTTON) + .addCode(CodeBlock.builder().unindent().build()) + .addCode("\n") + .addCode("}") + .addCode("\n") + .addCode("\n") + .addCode( + "if (button.getTag($T.id.validation_action).equals($T.id.clear) && clearValidationsButton == null) {", + CONVALIDA_DATABINDING_R, + CONVALIDA_DATABINDING_R + ) + .addCode("\n") + .addCode(CodeBlock.builder().indent().build()) + .addCode("clearValidationsButton = ($T) button;", BUTTON) + .addCode(CodeBlock.builder().unindent().build()) + .addCode("\n") + .addCode("}") + .addCode("\n") + .addCode("\n") + .addCode("if (validateButton != null && clearValidationsButton != null) {") + .addCode("\n") + .addCode(CodeBlock.builder().indent().build()) + .addCode("break;") + .addCode(CodeBlock.builder().unindent().build()) + .addCode("\n") + .addCode("}") + .addCode("\n") + .addCode(CodeBlock.builder().unindent().build()) + .addCode("}") + .addCode("\n") + .addCode("\n") + .addCode("if (validateButton != null) {") + .addCode("\n") + .addCode(CodeBlock.builder().indent().build()) + .addCode("validateOnClickListener(validateButton, target);") + .addCode(CodeBlock.builder().unindent().build()) + .addCode("\n") + .addCode("}") + .addCode("\n") + .addCode("\n") + .addCode("if (clearValidationsButton != null) {") + .addCode("\n") + .addCode(CodeBlock.builder().indent().build()) + .addCode("clearValidationsOnClickListener(clearValidationsButton, target);") + .addCode(CodeBlock.builder().unindent().build()) + .addCode("\n") + .addCode("}") + .addCode("\n") .build(); } @@ -81,8 +215,8 @@ private static CodeBlock createValidationsCodeBlock(final ValidationClass valida for(ValidationField field : validationClass.fields) { switch (field.annotationClassName) { - case NOT_EMPTY_ANNOTATION: - builder.add(createNotEmptyValidationCodeBlock(field)); + case REQUIRED_ANNOTATION: + builder.add(createRequiredValidationCodeBlock(field)); break; case EMAIL_ANNOTATION: builder.add(createEmailValidationCodeBlock(field)); @@ -117,17 +251,14 @@ private static CodeBlock createValidationsCodeBlock(final ValidationClass valida break; } } - - builder.add(createValidateOnClickCodeBlock(validationClass)); - builder.add(createClearValidationsOnClickCodeBlock(validationClass)); return builder.build(); } - private static CodeBlock createNotEmptyValidationCodeBlock(ValidationField field) { + private static CodeBlock createRequiredValidationCodeBlock(ValidationField field) { return CodeBlock.builder() .addStatement( "validatorSet.addValidator(new $T(target.$N, target.getString($L), $L))", - NOT_EMPTY_VALIDATOR, + REQUIRED_VALIDATOR, field.name, field.id.code, field.autoDismiss @@ -232,27 +363,52 @@ private static CodeBlock createConfirmPasswordValidationCodeBlock( private static CodeBlock createValidateOnClickCodeBlock(ValidationClass validationClass) { Element button = validationClass.getValidateButton(); - return CodeBlock.builder() - .add("\n") - .addStatement( - "target.$N.setOnClickListener(validateOnClickListener(target))", - button.getSimpleName().toString() - ) - .build(); + if(button != null) { + return CodeBlock.builder() + .add("\n") + .add( + "validateOnClickListener(target.$N, target);", + button.getSimpleName().toString() + ) + .build(); + } + return CodeBlock.of(""); } - private static MethodSpec createValidateOnClickMethod(ValidationClass validationClass) { - MethodSpec.Builder validateOnClickMethod = MethodSpec.methodBuilder("validateOnClickListener") - .addAnnotation(UI_THREAD) + private static CodeBlock createClearValidationsOnClickCodeBlock(ValidationClass validationClass) { + Element button = validationClass.getClearValidationsButton(); + if (button != null) { + return CodeBlock.builder() + .add("\n") + .add( + "clearValidationsOnClickListener(target.$N, target);", + button.getSimpleName().toString() + ) + .add("\n") + .build(); + } + return CodeBlock.of(""); + } + + private static MethodSpec createValidateOnClickListener( + ValidationClass validationClass) { + Element onValidationErrorMethod = validationClass.getOnValidationErrorMethod(); + MethodSpec.Builder method = MethodSpec.methodBuilder("validateOnClickListener") .addModifiers(PRIVATE) - .addParameter(ParameterSpec.builder( - validationClass.typeName, - "target", - FINAL - ).build() + .addAnnotation(UI_THREAD) + .addParameter(ParameterSpec + .builder(BUTTON, "button") + .addAnnotation(NON_NULL) + .build() + ) + .addParameter(ParameterSpec + .builder(validationClass.typeName, "target") + .addModifiers(FINAL) + .addAnnotation(NON_NULL) + .build() ) .addCode( - "return new $T() {", + "button.setOnClickListener(new $T() {", VIEW_ONCLICK_LISTENER ) .addCode("\n") @@ -275,9 +431,8 @@ private static MethodSpec createValidateOnClickMethod(ValidationClass validation .addCode(CodeBlock.builder().unindent().build()) .addCode("}"); - if(validationClass.getOnValidationErrorMethod() != null) { - validateOnClickMethod - .addCode(" else {") + if(onValidationErrorMethod != null) { + method.addCode(" else {") .addCode("\n") .addCode(CodeBlock.builder().indent().build()) .addCode( @@ -289,44 +444,36 @@ private static MethodSpec createValidateOnClickMethod(ValidationClass validation .addCode("}"); } - validateOnClickMethod.addCode("\n") - .addCode(CodeBlock.builder().unindent().build()) - .addCode("}") + method.addCode(CodeBlock.builder().unindent().build()) .addCode("\n") + .addCode("}") .addCode(CodeBlock.builder().unindent().build()) - .addCode("};") .addCode("\n") - .returns(VIEW_ONCLICK_LISTENER); + .addCode("});") + .addCode("\n"); - return validateOnClickMethod.build(); + return method.build(); } - private static CodeBlock createClearValidationsOnClickCodeBlock(ValidationClass validationClass) { - Element clearValidationsButton = validationClass.getClearValidationsButton(); - - if (clearValidationsButton != null) { - return CodeBlock.builder() - .addStatement( - "target.$N.setOnClickListener(clearValidationsOnClickListener(target))", - clearValidationsButton.getSimpleName().toString() - ) - .build(); - } - - return CodeBlock.of(""); - } - - private static MethodSpec createClearValidationsOnClickMethod(ValidationClass validationClass) { + private static MethodSpec createClearValidationsOnClickListener( + ValidationClass validationClass) { return MethodSpec.methodBuilder("clearValidationsOnClickListener") - .addAnnotation(UI_THREAD) .addModifiers(PRIVATE) - .addParameter(ParameterSpec.builder( - validationClass.typeName, - "target", - FINAL - ).build() + .addAnnotation(UI_THREAD) + .addParameter(ParameterSpec + .builder(BUTTON, "button") + .addAnnotation(NON_NULL) + .build() + ) + .addParameter(ParameterSpec + .builder(validationClass.typeName, "target") + .addAnnotation(NON_NULL) + .build() + ) + .addCode( + "button.setOnClickListener(new $T() {", + VIEW_ONCLICK_LISTENER ) - .addCode("return new $T() {", VIEW_ONCLICK_LISTENER) .addCode("\n") .addCode(CodeBlock.builder().indent().build()) .addCode( @@ -342,9 +489,8 @@ private static MethodSpec createClearValidationsOnClickMethod(ValidationClass va .addCode("}") .addCode("\n") .addCode(CodeBlock.builder().unindent().build()) - .addCode("};") + .addCode("});") .addCode("\n") - .returns(VIEW_ONCLICK_LISTENER) .build(); } @@ -362,4 +508,23 @@ private static MethodSpec createInitMethod(ValidationClass validationClass) { .build(); } + private static MethodSpec createInitDatabindingMethod(ValidationClass validationClass) { + ClassName className = ClassName.get(validationClass.packageName, validationClass.className); + return MethodSpec.methodBuilder("init") + .addModifiers(PUBLIC, STATIC) + .addAnnotation(UI_THREAD) + .addParameter(ParameterSpec + .builder(validationClass.typeName, "target") + .addAnnotation(NON_NULL) + .build() + ) + .addParameter(ParameterSpec + .builder(VIEW_DATA_BINDING, "binding") + .addAnnotation(NON_NULL) + .build() + ) + .addStatement("new $T(target, binding)", className) + .build(); + } + } \ No newline at end of file diff --git a/convalida-compiler/src/main/java/convalida/compiler/Messager.java b/convalida-compiler/src/main/java/convalida/compiler/Messager.java new file mode 100644 index 0000000..6614fe5 --- /dev/null +++ b/convalida-compiler/src/main/java/convalida/compiler/Messager.java @@ -0,0 +1,35 @@ +package convalida.compiler; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.annotation.Annotation; + +import javax.lang.model.element.Element; +import javax.tools.Diagnostic; + +/** + * @author wellingtoncosta on 02/04/18 + */ +public class Messager { + + private static javax.annotation.processing.Messager messager; + + public static void init(javax.annotation.processing.Messager messager) { + Messager.messager = messager; + } + + static void logParsingError(Element element, Class annotation, Exception e) { + StringWriter stackTrace = new StringWriter(); + e.printStackTrace(new PrintWriter(stackTrace)); + error(element, "Unable to parse @%s validation.\n\n%s", annotation.getSimpleName(), stackTrace); + } + + static void error(Element element, String message, Object... args) { + if (args.length > 0) { + message = String.format(message, args); + } + + messager.printMessage(Diagnostic.Kind.ERROR, message, element); + } + +} diff --git a/convalida-compiler/src/main/java/convalida/compiler/Preconditions.java b/convalida-compiler/src/main/java/convalida/compiler/Preconditions.java new file mode 100644 index 0000000..24b4633 --- /dev/null +++ b/convalida-compiler/src/main/java/convalida/compiler/Preconditions.java @@ -0,0 +1,219 @@ +package convalida.compiler; + +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; + +import static convalida.compiler.Constants.EDIT_TEXT_TYPE; +import static convalida.compiler.Messager.error; +import static javax.lang.model.element.ElementKind.CLASS; +import static javax.lang.model.element.ElementKind.FIELD; +import static javax.lang.model.element.Modifier.PRIVATE; +import static javax.lang.model.element.Modifier.STATIC; + +/** + * @author wellingtoncosta on 02/04/18 + */ +class Preconditions { + + // Can not be instantiated + private Preconditions() { } + + static boolean methodHasParams(ExecutableElement method, Class annotationClass) { + boolean hasParams = false; + + if (method.getParameters().size() > 0) { + hasParams = true; + error(method, "Method annotated with @%s can not have parameters.",annotationClass.getSimpleName()); + } + + return hasParams; + } + + static boolean hasMoreThanOneMethodsAnnotatedWith( + Element parent, + Class annotationClass) { + boolean hasMoreThanOneElement = false; + List elements = new ArrayList<>(); + + for(Element e : parent.getEnclosedElements()) { + if(e.getAnnotation(annotationClass) != null) { + elements.add(e); + } + } + + if (elements.size() > 1) { + hasMoreThanOneElement = true; + error( + parent, + "The class %s must have only one element annotated with @%s.", + parent.getSimpleName(), + annotationClass.getSimpleName() + ); + } + + return hasMoreThanOneElement; + } + + static boolean hasNoMethodAnnotatedWith( + Element parent, + Class annotationClass) { + boolean hasNoElements = false; + List elements = new ArrayList<>(); + + for(Element e : parent.getEnclosedElements()) { + if(e.getAnnotation(annotationClass) != null) { + elements.add(e); + } + } + + if (elements.size() == 0) { + hasNoElements = true; + error( + parent, + "The class %s must have one method annotated with @%s.", + parent.getSimpleName(), + annotationClass.getSimpleName() + ); + } + + return hasNoElements; + } + + static boolean confirmValidationElementsHasError( + Class primaryAnnotation, + Class confirmAnnotation, + Element element) { + boolean hasError = false; + + String primaryAnnotationClassName = primaryAnnotation.getSimpleName(); + String confirmAnnotationClassName = confirmAnnotation.getSimpleName(); + + int elementsAnnotatedWithPrimaryValidation = 0; + int elementsAnnotatedWithConfirmValidation = 0; + + List elementsOfParent = element.getEnclosingElement().getEnclosedElements(); + + for(int i = 0; i < elementsOfParent.size(); i++) { + if(elementsOfParent.get(i).getAnnotation(primaryAnnotation) != null) { + elementsAnnotatedWithPrimaryValidation ++; + } + + if(elementsOfParent.get(i).getAnnotation(confirmAnnotation) != null) { + elementsAnnotatedWithConfirmValidation ++; + } + } + + if (elementsAnnotatedWithPrimaryValidation == 0 && elementsAnnotatedWithConfirmValidation > 0) { + hasError = true; + TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); + error( + element.getEnclosingElement(), + "%s must have at least one element annotated with @%s.", + enclosingElement.getSimpleName(), + primaryAnnotationClassName + ); + } + + if (elementsAnnotatedWithConfirmValidation > 1) { + hasError = true; + TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); + error( + element.getEnclosingElement(), + "%s must have only one element annotated with @%s.", + enclosingElement.getSimpleName(), + confirmAnnotationClassName + ); + } + + return hasError; + } + + static boolean isInvalid(Class annotationClass, Element element) { + TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); + String elementType = element.asType().toString(); + boolean hasError = false; + + // Verify element kind + if (!element.getKind().equals(FIELD)) { + error( + element, + "@%s must only be applied in fields. (%s.%s)", + annotationClass.getSimpleName(), + enclosingElement.getQualifiedName(), + element.getSimpleName() + ); + + hasError = true; + } + + // Verify element type + if (!EDIT_TEXT_TYPE.equals(elementType)) { // improve this check + error( + element, + "@%s must only be applied in fields of the type TextInputLaytout or EditText. (%s.%s)", + annotationClass.getSimpleName(), + enclosingElement.getQualifiedName(), + element.getSimpleName() + ); + + hasError = true; + } + + return hasError; + } + + static boolean isInaccessible(Class annotationClass, Element element) { + TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); + boolean hasError = false; + + // Verify element modifiers + Set modifiers = element.getModifiers(); + if (modifiers.contains(PRIVATE) || modifiers.contains(STATIC)) { + error( + element, + "@%s must not be applied in private or static fields. (%s.%s)", + annotationClass.getSimpleName(), + enclosingElement.getQualifiedName(), + element.getSimpleName() + ); + + hasError = true; + } + + // Verify containing type + if (enclosingElement.getKind() != CLASS) { + error( + enclosingElement, + "@%s fields may only be contained in classes. (%s.%s)", + annotationClass.getSimpleName(), + enclosingElement.getQualifiedName(), + element.getSimpleName() + ); + + hasError = true; + } + + // Verify containing class visibility is not private + if (enclosingElement.getModifiers().contains(PRIVATE)) { + error( + enclosingElement, + "@%s fields may not be contained in private classes. (%s.%s)", + annotationClass.getSimpleName(), + enclosingElement.getQualifiedName(), + element.getSimpleName() + ); + + hasError = true; + } + + return hasError; + } + +} diff --git a/convalida-databinding/.gitignore b/convalida-databinding/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/convalida-databinding/.gitignore @@ -0,0 +1 @@ +/build diff --git a/convalida-databinding/build.gradle b/convalida-databinding/build.gradle new file mode 100644 index 0000000..91ea143 --- /dev/null +++ b/convalida-databinding/build.gradle @@ -0,0 +1,42 @@ +apply plugin: 'com.android.library' +apply plugin: 'com.github.dcendents.android-maven' +group = 'com.github.WellingtonCosta' + +android { + compileSdkVersion versions.compileSdk + buildToolsVersion versions.buildTools + + defaultConfig { + minSdkVersion versions.minSdk + + javaCompileOptions { + annotationProcessorOptions { + includeCompileClasspath true + } + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_7 + targetCompatibility = JavaVersion.VERSION_1_7 + } + + dataBinding { + enabled true + } +} + +task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier = 'sources' +} + +artifacts { + archives sourcesJar +} + +dependencies { + compile project(':convalida-validators') + + implementation deps.support.design +} \ No newline at end of file diff --git a/convalida-databinding/src/main/AndroidManifest.xml b/convalida-databinding/src/main/AndroidManifest.xml new file mode 100644 index 0000000..9e7ebae --- /dev/null +++ b/convalida-databinding/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/convalida-databinding/src/main/java/convalida/databinding/ValidationBindings.java b/convalida-databinding/src/main/java/convalida/databinding/ValidationBindings.java new file mode 100644 index 0000000..79729ad --- /dev/null +++ b/convalida-databinding/src/main/java/convalida/databinding/ValidationBindings.java @@ -0,0 +1,175 @@ + package convalida.databinding; + + import android.databinding.BindingAdapter; + import android.widget.Button; + import android.widget.EditText; + + import convalida.validators.ConfirmEmailValidator; + import convalida.validators.ConfirmPasswordValidator; + import convalida.validators.EmailValidator; + import convalida.validators.LengthValidator; + import convalida.validators.OnlyNumberValidator; + import convalida.validators.PasswordValidator; + import convalida.validators.PatternValidator; + import convalida.validators.RequiredValidator; + +/** + * @author WellingtonCosta on 29/03/18. + */ +public class ValidationBindings { + + @BindingAdapter(value = { + "requiredValidationErrorMessage", + "requiredValidationAutoDismiss" + }, requireAll = false) + public static void requiredValidationBindings( + EditText field, + String errorMessage, + Boolean autoDismiss + ) { + field.setTag(R.id.validation_type, new RequiredValidator( + field, + errorMessage, + autoDismiss != null ? autoDismiss : true + )); + } + + @BindingAdapter(value = { + "emailValidationErrorMessage", + "emailValidationAutoDismiss" + }, requireAll = false) + public static void emailValidationBindings( + EditText field, + String errorMessage, + Boolean autoDismiss + ) { + field.setTag(R.id.validation_type, new EmailValidator( + field, + errorMessage, + autoDismiss != null ? autoDismiss : true + )); + } + + @BindingAdapter(value = { + "confirmEmailValidationEmailField", + "confirmEmailValidationErrorMessage", + "confirmEmailValidationAutoDismiss" + }, requireAll = false) + public static void confirmEmailValidationBindings( + EditText confirmEmailField, + EditText emailField, + String errorMessage, + Boolean autoDismiss + ) { + confirmEmailField.setTag(R.id.validation_type, new ConfirmEmailValidator( + emailField, + confirmEmailField, + errorMessage, + autoDismiss != null ? autoDismiss : true + )); + } + + @BindingAdapter(value = { + "patternValidationErrorMessage", + "patternValidationPattern", + "patternValidationAutoDismiss" + }, requireAll = false) + public static void patternValidationBindings( + EditText field, + String errorMessage, + String pattern, + Boolean autoDismiss + ) { + field.setTag(R.id.validation_type, new PatternValidator( + field, + errorMessage, + pattern, + autoDismiss != null ? autoDismiss : true + )); + } + + @BindingAdapter(value = { + "lengthValidationMin", + "lengthValidationMax", + "lengthValidationErrorMessage", + "lengthValidationAutoDismiss" + }, requireAll = false) + public static void lengthValidationBindings( + EditText field, + int min, + int max, + String errorMessage, + Boolean autoDismiss + ) { + field.setTag(R.id.validation_type, new LengthValidator( + field, + min, + max, + errorMessage, + autoDismiss != null ? autoDismiss : true + )); + } + + @BindingAdapter(value = { + "onlyNumberValidationErrorMessage", + "onlyNumberValidationAutoDismiss" + }, requireAll = false) + public static void onlyNumberValidationBindings( + EditText field, + String errorMessage, + Boolean autoDismiss + ) { + field.setTag(R.id.validation_type, new OnlyNumberValidator( + field, + errorMessage, + autoDismiss != null ? autoDismiss : true + )); + } + + @BindingAdapter(value = { + "passwordValidationErrorMessage", + "passwordValidationMinLength", + "passwordValidationPattern", + "passwordValidationAutoDismiss" + }, requireAll = false) + public static void passwordValidationBindings( + EditText field, + String errorMessage, + Integer minLength, + String pattern, + Boolean autoDismiss + ) { + field.setTag(R.id.validation_type, new PasswordValidator( + field, + minLength != null ? minLength : 0, + pattern != null ? pattern : "", + errorMessage, + autoDismiss != null ? autoDismiss : true + )); + } + + @BindingAdapter(value = { + "confirmPasswordValidationPasswordField", + "confirmPasswordValidationErrorMessage", + "confirmPasswordValidationAutoDismiss" + }, requireAll = false) + public static void confirmPasswordValidationBindings( + EditText confirmPasswordField, + EditText passwordField, + String errorMessage, + Boolean autoDismiss + ) { + confirmPasswordField.setTag(R.id.validation_type, new ConfirmPasswordValidator( + passwordField, + confirmPasswordField, + errorMessage, + autoDismiss != null ? autoDismiss : true + )); + } + + @BindingAdapter(value = "validationAction") + public static void validationActionBindings(Button button, Integer action) { + button.setTag(R.id.validation_action, action); + } + +} diff --git a/convalida-databinding/src/main/java/convalida/databinding/ViewTagUtils.java b/convalida-databinding/src/main/java/convalida/databinding/ViewTagUtils.java new file mode 100644 index 0000000..bd5d63f --- /dev/null +++ b/convalida-databinding/src/main/java/convalida/databinding/ViewTagUtils.java @@ -0,0 +1,36 @@ +package convalida.databinding; + +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author WellingtonCosta on 29/03/18. + */ +public class ViewTagUtils { + + public static List getViewsByTag(ViewGroup root, int tagId) { + List views = new ArrayList<>(); + int childCount = root.getChildCount(); + for(int i = 0; i < childCount; i++) { + View child = root.getChildAt(i); + if(child != null) { + if (child instanceof ViewGroup) { + views.addAll(getViewsByTag((ViewGroup) child, tagId)); + } + addViewWhenContainsTag(tagId, views, child); + } + } + return views; + } + + private static void addViewWhenContainsTag(int tagId, List views, View view) { + Object tagValue = view.getTag(tagId); + if (tagValue != null) { + views.add(view); + } + } + +} diff --git a/convalida-databinding/src/main/res/values/ids.xml b/convalida-databinding/src/main/res/values/ids.xml new file mode 100644 index 0000000..fcc0f9f --- /dev/null +++ b/convalida-databinding/src/main/res/values/ids.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/convalida-validators/src/main/java/convalida/validators/AbstractValidator.java b/convalida-validators/src/main/java/convalida/validators/AbstractValidator.java index 90b40a2..e4687be 100644 --- a/convalida-validators/src/main/java/convalida/validators/AbstractValidator.java +++ b/convalida-validators/src/main/java/convalida/validators/AbstractValidator.java @@ -8,7 +8,7 @@ /** * @author Wellington Costa on 21/06/2017. */ -public abstract class AbstractValidator implements Validator { +public abstract class AbstractValidator { private EditText editText; private String errorMessage; @@ -45,13 +45,11 @@ private Boolean viewIsVisible() { editText.getVisibility() == View.INVISIBLE); } - @Override public boolean validate() { executeValidation(editText.getText().toString()); return !hasError; } - @Override public void clear() { EditTextUtils.setError(editText, null); } diff --git a/convalida-validators/src/main/java/convalida/validators/NotEmptyValidator.java b/convalida-validators/src/main/java/convalida/validators/RequiredValidator.java similarity index 80% rename from convalida-validators/src/main/java/convalida/validators/NotEmptyValidator.java rename to convalida-validators/src/main/java/convalida/validators/RequiredValidator.java index bd20ed0..e6867f9 100644 --- a/convalida-validators/src/main/java/convalida/validators/NotEmptyValidator.java +++ b/convalida-validators/src/main/java/convalida/validators/RequiredValidator.java @@ -5,9 +5,9 @@ /** * @author Wellington Costa on 21/06/2017. */ -public class NotEmptyValidator extends AbstractValidator { +public class RequiredValidator extends AbstractValidator { - public NotEmptyValidator( + public RequiredValidator( EditText editText, String errorMessage, boolean autoDismiss) { diff --git a/convalida-validators/src/main/java/convalida/validators/Validator.java b/convalida-validators/src/main/java/convalida/validators/Validator.java deleted file mode 100644 index 8c47dbb..0000000 --- a/convalida-validators/src/main/java/convalida/validators/Validator.java +++ /dev/null @@ -1,12 +0,0 @@ -package convalida.validators; - -/** - * @author Wellington Costa on 21/06/2017. - */ -interface Validator { - - boolean validate(); - - void clear(); - -} diff --git a/convalida-validators/src/main/java/convalida/validators/ValidatorSet.java b/convalida-validators/src/main/java/convalida/validators/ValidatorSet.java index 876df60..1efa8d9 100644 --- a/convalida-validators/src/main/java/convalida/validators/ValidatorSet.java +++ b/convalida-validators/src/main/java/convalida/validators/ValidatorSet.java @@ -1,24 +1,23 @@ package convalida.validators; import java.util.ArrayList; -import java.util.HashSet; +import java.util.LinkedList; import java.util.List; -import java.util.Set; /** * @author Wellington Costa on 21/06/2017. */ public final class ValidatorSet { - private Set validators; + private List validators; private boolean isValid; public ValidatorSet() { - this.validators = new HashSet<>(); + this.validators = new LinkedList<>(); this.isValid = true; } - public void addValidator(Validator validator) { + public void addValidator(AbstractValidator validator) { this.validators.add(validator); } @@ -30,7 +29,7 @@ public boolean isValid() { private void executeValidators() { List validationResults = new ArrayList<>(); - for(Validator validator : validators) { + for(AbstractValidator validator : validators) { validationResults.add(validator.validate()); } @@ -43,12 +42,16 @@ private void executeValidators() { } public void clearValidators() { - for (Validator validator : validators) { + for (AbstractValidator validator : validators) { validator.clear(); } } - public int getValidatorsSize() { + public List getValidators() { + return validators; + } + + public int getValidatorsCount() { return validators.size(); } diff --git a/convalida-validators/src/test/java/convalida/validators/NotEmptyValidatorTest.java b/convalida-validators/src/test/java/convalida/validators/RequiredValidatorTest.java similarity index 76% rename from convalida-validators/src/test/java/convalida/validators/NotEmptyValidatorTest.java rename to convalida-validators/src/test/java/convalida/validators/RequiredValidatorTest.java index 6beb2fd..a806fcf 100644 --- a/convalida-validators/src/test/java/convalida/validators/NotEmptyValidatorTest.java +++ b/convalida-validators/src/test/java/convalida/validators/RequiredValidatorTest.java @@ -8,16 +8,16 @@ /** * @author Wellington Costa on 01/11/2017. */ -public class NotEmptyValidatorTest extends BaseTest { +public class RequiredValidatorTest extends BaseTest { @Test public void emptyValue() { - NotEmptyValidator validator = new NotEmptyValidator(mockEditText, errorMessage, true); + RequiredValidator validator = new RequiredValidator(mockEditText, errorMessage, true); when(mockEditText.getText().toString()).thenReturn(""); assertEquals(validator.validate(), false); } @Test public void validValue() { - NotEmptyValidator validator = new NotEmptyValidator(mockEditText, errorMessage, true); + RequiredValidator validator = new RequiredValidator(mockEditText, errorMessage, true); when(mockEditText.getText().toString()).thenReturn("test"); assertEquals(validator.validate(), true); } diff --git a/convalida-validators/src/test/java/convalida/validators/TestSuite.java b/convalida-validators/src/test/java/convalida/validators/TestSuite.java index 8418fe4..e63af93 100644 --- a/convalida-validators/src/test/java/convalida/validators/TestSuite.java +++ b/convalida-validators/src/test/java/convalida/validators/TestSuite.java @@ -9,7 +9,7 @@ */ @RunWith(Suite.class) @SuiteClasses({ - NotEmptyValidatorTest.class, + RequiredValidatorTest.class, EmailValidatorTest.class, ConfirmEmailValidatorTest.class, LengthValidatorTest.class, diff --git a/convalida-validators/src/test/java/convalida/validators/ValidatorSetTest.java b/convalida-validators/src/test/java/convalida/validators/ValidatorSetTest.java index f585d30..8059064 100644 --- a/convalida-validators/src/test/java/convalida/validators/ValidatorSetTest.java +++ b/convalida-validators/src/test/java/convalida/validators/ValidatorSetTest.java @@ -18,37 +18,37 @@ public class ValidatorSetTest extends BaseTest { } @Test public void addOneValidator() { - validatorSet.addValidator(new NotEmptyValidator(mockEditText, errorMessage, true)); - assertEquals(validatorSet.getValidatorsSize(), 1); + validatorSet.addValidator(new RequiredValidator(mockEditText, errorMessage, true)); + assertEquals(validatorSet.getValidatorsCount(), 1); } @Test public void addTwoValidators() { - validatorSet.addValidator(new NotEmptyValidator(mockEditText, errorMessage, true)); + validatorSet.addValidator(new RequiredValidator(mockEditText, errorMessage, true)); validatorSet.addValidator(new EmailValidator(mockEditText, errorMessage, true)); - assertEquals(validatorSet.getValidatorsSize(), 2); + assertEquals(validatorSet.getValidatorsCount(), 2); } @Test public void addThreeValidators() { - validatorSet.addValidator(new NotEmptyValidator(mockEditText, errorMessage, true)); + validatorSet.addValidator(new RequiredValidator(mockEditText, errorMessage, true)); validatorSet.addValidator(new EmailValidator(mockEditText, errorMessage, true)); validatorSet.addValidator(new LengthValidator(mockEditText,0, 5, errorMessage, true)); - assertEquals(validatorSet.getValidatorsSize(), 3); + assertEquals(validatorSet.getValidatorsCount(), 3); } @Test public void executeValidationsWithSuccess() { - validatorSet.addValidator(new NotEmptyValidator(mockEditText, errorMessage, true)); + validatorSet.addValidator(new RequiredValidator(mockEditText, errorMessage, true)); when(mockEditText.getText().toString()).thenReturn("test"); assertEquals(validatorSet.isValid(), true); } @Test public void executeValidationsWithError() { - validatorSet.addValidator(new NotEmptyValidator(mockEditText, errorMessage, true)); + validatorSet.addValidator(new RequiredValidator(mockEditText, errorMessage, true)); when(mockEditText.getText().toString()).thenReturn(""); assertEquals(validatorSet.isValid(), false); } @Test public void clearValidations() { - validatorSet.addValidator(new NotEmptyValidator(mockEditText, errorMessage, true)); + validatorSet.addValidator(new RequiredValidator(mockEditText, errorMessage, true)); validatorSet.clearValidators(); assertEquals(mockEditText.getError(), null); } diff --git a/convalida/build.gradle b/convalida/build.gradle index ca13c39..5bec3d6 100644 --- a/convalida/build.gradle +++ b/convalida/build.gradle @@ -8,6 +8,12 @@ android { defaultConfig { minSdkVersion versions.minSdk + + javaCompileOptions { + annotationProcessorOptions { + includeCompileClasspath true + } + } } compileOptions { @@ -28,6 +34,7 @@ artifacts { dependencies { compile project(':convalida-annotations') compile project(':convalida-validators') + compile project(':convalida-databinding') implementation deps.support.annotations implementation deps.support.compat diff --git a/convalida/src/main/java/convalida/library/util/Patterns.java b/convalida/src/main/java/convalida/library/util/Patterns.java index ed8cfbb..7c7dbac 100644 --- a/convalida/src/main/java/convalida/library/util/Patterns.java +++ b/convalida/src/main/java/convalida/library/util/Patterns.java @@ -7,14 +7,19 @@ public class Patterns { public static final String NUMERIC_ONLY = "^\\d+$"; + public static final String ALPHA_ONLY = "\\w+"; + public static final String LOWER_CASE_ONLY = "^[a-z]+$"; public static final String UPPER_CASE_ONLY = "^[A-Z]+$"; - public static final String LOWER_UPPER_CASE = "^(?=.*[a-z])(?=.*[A-Z]).{1,}+$"; + public static final String ALPHA_MIXED_CASE = "^(?=.*[a-z])(?=.*[A-Z]).{1,}+$"; + + public static final String ALPHA_NUMERIC = "(?=.*[a-zA-Z])(?=.*[\\d]).+"; - public static final String LOWER_UPPER_CASE_NUMERIC = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{1,}+$"; + public static final String MIXED_CASE_NUMERIC = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{1,}+$"; - public static final String LOWER_UPPER_CASE_NUMERIC_SPECIAL = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&+=])(?=\\S+$).{1,}$"; + public static final String ALPHA_NUMERIC_MIXED_CASE = "(?=.*[a-z])(?=.*[A-Z])(?=.*[\\d]).+"; + public static final String ALPHA_NUMERIC_MIXED_CASE_SYMBOLS = "(?=.*[a-z])(?=.*[A-Z])(?=.*[\\d])(?=.*([^\\w])).+"; } diff --git a/sample/build.gradle b/sample/build.gradle index 7466fee..790649b 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -27,6 +27,10 @@ android { minifyEnabled true } } + + dataBinding { + enabled true + } } dependencies { diff --git a/sample/src/androidTest/java/convalida/sample/AnnotataionSampleActivityTest.java b/sample/src/androidTest/java/convalida/sample/AnnotataionSampleActivityTest.java new file mode 100644 index 0000000..8e20efc --- /dev/null +++ b/sample/src/androidTest/java/convalida/sample/AnnotataionSampleActivityTest.java @@ -0,0 +1,155 @@ +package convalida.sample; + +import android.support.test.filters.LargeTest; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard; +import static android.support.test.espresso.action.ViewActions.scrollTo; +import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static convalida.sample.TestUtils.testFieldWithAValidValue; +import static convalida.sample.TestUtils.testFieldWithAnInvalidValue; +import static convalida.sample.TestUtils.testFieldWithEmptyValue; + +/** + * @author Wellington Costa on 12/11/2017. + */ +@LargeTest +@RunWith(AndroidJUnit4.class) +public class AnnotataionSampleActivityTest { + + @Rule + public ActivityTestRule activityTestRule = + new ActivityTestRule<>(AnnotataionSampleActivity.class); + + @Test + public void executeValidationsWithEmptyFields() { + onView(withId(R.id.validate_button)) + .perform(closeSoftKeyboard()) + .perform(scrollTo(), click()); + + onView(withText(R.string.field_required)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + + onView(withText(R.string.min_3_characters)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + + onView(withText(R.string.only_numbers)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + + onView(withText(R.string.invalid_phone)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + + onView(withText(R.string.invalid_email)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + + onView(withText(R.string.invalid_password)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + } + + @Test + public void clearValidations() { + onView(withId(R.id.validate_button)) + .perform(closeSoftKeyboard()) + .perform(scrollTo(), click()); + + onView(withId(R.id.clear_button)) + .perform(scrollTo(), click()); + + onView(withText(R.string.field_required)) + .check(doesNotExist()); + + onView(withText(R.string.min_3_characters)) + .check(doesNotExist()); + + onView(withText(R.string.only_numbers)) + .check(doesNotExist()); + + onView(withText(R.string.invalid_phone)) + .check(doesNotExist()); + + onView(withText(R.string.invalid_email)) + .check(doesNotExist()); + + onView(withText(R.string.emails_not_match)) + .check(doesNotExist()); + + onView(withText(R.string.invalid_password)) + .check(doesNotExist()); + + onView(withText(R.string.passwords_not_match)) + .check(doesNotExist()); + } + + @Test + public void testNameField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.field_required); + testFieldWithAValidValue(R.id.name_field, R.string.field_required, "Wellington"); + } + + @Test + public void testNicknameField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.min_3_characters); + testFieldWithAnInvalidValue(R.id.nickname_field, R.string.min_3_characters, "We"); + testFieldWithAValidValue(R.id.nickname_field, R.string.min_3_characters, "Well"); + } + + @Test + public void testAgeField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.only_numbers); + testFieldWithAnInvalidValue(R.id.age_field, R.string.only_numbers, "abc"); + testFieldWithAValidValue(R.id.age_field, R.string.only_numbers, "21"); + } + + @Test + public void testPhoneField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.invalid_phone); + testFieldWithAnInvalidValue(R.id.phone_field, R.string.invalid_phone, "558586846409"); + testFieldWithAValidValue(R.id.phone_field, R.string.invalid_phone, "+55(85)8684-6409"); + } + + @Test + public void testEmailField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.invalid_email); + testFieldWithAnInvalidValue(R.id.email_field, R.string.invalid_email, "well@email"); + testFieldWithAValidValue(R.id.email_field, R.string.invalid_email, "well@email.com"); + } + + @Test + public void testConfirmEmailField() { + testFieldWithAValidValue(R.id.email_field, R.string.invalid_email, "wellington@email.com"); + testFieldWithAnInvalidValue(R.id.confirm_email_field, R.string.emails_not_match, "wellington@email.co"); + testFieldWithAValidValue(R.id.confirm_email_field, R.string.emails_not_match, "wellington@email.com"); + } + + @Test + public void testPasswordField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.invalid_password); + testFieldWithAnInvalidValue(R.id.password_field, R.string.invalid_password, "asdASD"); + testFieldWithAValidValue(R.id.password_field, R.string.invalid_password, "asdASD123"); + } + + @Test + public void testConfirmPasswordField() { + testFieldWithAValidValue(R.id.password_field, R.string.invalid_password, "asdASD123"); + testFieldWithAnInvalidValue(R.id.confirm_password_field, R.string.passwords_not_match, "asdASD"); + testFieldWithAValidValue(R.id.confirm_password_field, R.string.passwords_not_match, "asdASD123"); + } + +} \ No newline at end of file diff --git a/sample/src/androidTest/java/convalida/sample/AnotherSampleActivityTest.java b/sample/src/androidTest/java/convalida/sample/AnotherSampleActivityTest.java deleted file mode 100644 index e0723e0..0000000 --- a/sample/src/androidTest/java/convalida/sample/AnotherSampleActivityTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package convalida.sample; - -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard; -import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withText; - -/** - * @author Wellington Costa on 14/11/2017. - */ -@RunWith(AndroidJUnit4.class) -public class AnotherSampleActivityTest { - - @Rule - public ActivityTestRule activityTestRule = new ActivityTestRule<>(AnotherSampleActivity.class); - - @Test - public void executeValidationsWithEmptyFields() { - onView(withId(R.id.validate_button)) - .perform(closeSoftKeyboard()) - .check(matches(isDisplayed())) - .perform(click()); - - onView(withText(R.string.field_required)) - .check(matches(isDisplayed())); - - onView(withText(R.string.min_3_characters)) - .check(matches(isDisplayed())); - - onView(withText(R.string.only_numbers)) - .check(matches(isDisplayed())); - - onView(withText(R.string.invalid_phone)) - .check(matches(isDisplayed())); - } - - @Test - public void clearAllValidations() { - onView(withId(R.id.validate_button)) - .perform(closeSoftKeyboard()) - .check(matches(isDisplayed())) - .perform(click()); - - onView(withId(R.id.clear_button)) - .check(matches(isDisplayed())) - .perform(click()); - - onView(withText(R.string.field_required)) - .check(doesNotExist()); - - onView(withText(R.string.min_3_characters)) - .check(doesNotExist()); - - onView(withText(R.string.only_numbers)) - .check(doesNotExist()); - - onView(withText(R.string.invalid_phone)) - .check(doesNotExist()); - } - - @Test - public void testNameField() { - TestUtils.testFieldWithEmptyValue(R.id.validate_button, R.string.field_required); - - TestUtils.testFieldWithAValidValue(R.id.name_field, R.string.field_required, "Wellington"); - } - - @Test - public void testNicknameField() { - TestUtils.testFieldWithEmptyValue(R.id.validate_button, R.string.min_3_characters); - - TestUtils.testFieldWithAnInvalidValue(R.id.nickname_field, R.string.min_3_characters, "We"); - - TestUtils.testFieldWithAValidValue(R.id.nickname_field, R.string.min_3_characters, "Well"); - } - - @Test - public void testAgeField() { - TestUtils.testFieldWithEmptyValue(R.id.validate_button, R.string.only_numbers); - - TestUtils.testFieldWithAnInvalidValue(R.id.age_field, R.string.only_numbers, "abc"); - - TestUtils.testFieldWithAValidValue(R.id.age_field, R.string.only_numbers, "21"); - } - - @Test - public void testPhoneField() { - TestUtils.testFieldWithEmptyValue(R.id.validate_button, R.string.invalid_phone); - - TestUtils.testFieldWithAnInvalidValue(R.id.phone_field, R.string.invalid_phone, "558586846409"); - - TestUtils.testFieldWithAValidValue(R.id.phone_field, R.string.invalid_phone, "+55(85)8684-6409"); - } - -} \ No newline at end of file diff --git a/sample/src/androidTest/java/convalida/sample/DatabindingSampleActivityTest.java b/sample/src/androidTest/java/convalida/sample/DatabindingSampleActivityTest.java new file mode 100644 index 0000000..0a288d4 --- /dev/null +++ b/sample/src/androidTest/java/convalida/sample/DatabindingSampleActivityTest.java @@ -0,0 +1,156 @@ +package convalida.sample; + +import android.support.test.filters.LargeTest; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard; +import static android.support.test.espresso.action.ViewActions.scrollTo; +import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static convalida.sample.TestUtils.testFieldWithAValidValue; +import static convalida.sample.TestUtils.testFieldWithAnInvalidValue; +import static convalida.sample.TestUtils.testFieldWithEmptyValue; + +/** + * @author Wellington Costa on 14/11/2017. + */ +@LargeTest +@RunWith(AndroidJUnit4.class) +public class DatabindingSampleActivityTest { + + + @Rule + public ActivityTestRule activityTestRule = + new ActivityTestRule<>(DatabindingSampleActivity.class); + + @Test + public void executeValidationsWithEmptyFields() { + onView(withId(R.id.validate_button)) + .perform(closeSoftKeyboard()) + .perform(scrollTo(), click()); + + onView(withText(R.string.field_required)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + + onView(withText(R.string.min_3_characters)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + + onView(withText(R.string.only_numbers)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + + onView(withText(R.string.invalid_phone)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + + onView(withText(R.string.invalid_email)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + + onView(withText(R.string.invalid_password)) + .perform(scrollTo()) + .check(matches(isDisplayed())); + } + + @Test + public void clearValidations() { + onView(withId(R.id.validate_button)) + .perform(closeSoftKeyboard()) + .perform(scrollTo(), click()); + + onView(withId(R.id.clear_button)) + .perform(scrollTo(), click()); + + onView(withText(R.string.field_required)) + .check(doesNotExist()); + + onView(withText(R.string.min_3_characters)) + .check(doesNotExist()); + + onView(withText(R.string.only_numbers)) + .check(doesNotExist()); + + onView(withText(R.string.invalid_phone)) + .check(doesNotExist()); + + onView(withText(R.string.invalid_email)) + .check(doesNotExist()); + + onView(withText(R.string.emails_not_match)) + .check(doesNotExist()); + + onView(withText(R.string.invalid_password)) + .check(doesNotExist()); + + onView(withText(R.string.passwords_not_match)) + .check(doesNotExist()); + } + + @Test + public void testNameField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.field_required); + testFieldWithAValidValue(R.id.name_field, R.string.field_required, "Wellington"); + } + + @Test + public void testNicknameField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.min_3_characters); + testFieldWithAnInvalidValue(R.id.nickname_field, R.string.min_3_characters, "We"); + testFieldWithAValidValue(R.id.nickname_field, R.string.min_3_characters, "Well"); + } + + @Test + public void testAgeField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.only_numbers); + testFieldWithAnInvalidValue(R.id.age_field, R.string.only_numbers, "abc"); + testFieldWithAValidValue(R.id.age_field, R.string.only_numbers, "21"); + } + + @Test + public void testPhoneField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.invalid_phone); + testFieldWithAnInvalidValue(R.id.phone_field, R.string.invalid_phone, "558586846409"); + testFieldWithAValidValue(R.id.phone_field, R.string.invalid_phone, "+55(85)8684-6409"); + } + + @Test + public void testEmailField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.invalid_email); + testFieldWithAnInvalidValue(R.id.email_field, R.string.invalid_email, "well@email"); + testFieldWithAValidValue(R.id.email_field, R.string.invalid_email, "well@email.com"); + } + + @Test + public void testConfirmEmailField() { + testFieldWithAValidValue(R.id.email_field, R.string.invalid_email, "wellington@email.com"); + testFieldWithAnInvalidValue(R.id.confirm_email_field, R.string.emails_not_match, "wellington@email.co"); + testFieldWithAValidValue(R.id.confirm_email_field, R.string.emails_not_match, "wellington@email.com"); + } + + @Test + public void testPasswordField() { + testFieldWithEmptyValue(R.id.validate_button, R.string.invalid_password); + testFieldWithAnInvalidValue(R.id.password_field, R.string.invalid_password, "asdASD"); + testFieldWithAValidValue(R.id.password_field, R.string.invalid_password, "asdASD123"); + } + + @Test + public void testConfirmPasswordField() { + testFieldWithAValidValue(R.id.password_field, R.string.invalid_password, "asdASD123"); + testFieldWithAnInvalidValue(R.id.confirm_password_field, R.string.passwords_not_match, "asdASD"); + testFieldWithAValidValue(R.id.confirm_password_field, R.string.passwords_not_match, "asdASD123"); + } + +} \ No newline at end of file diff --git a/sample/src/androidTest/java/convalida/sample/MainActivityTest.java b/sample/src/androidTest/java/convalida/sample/MainActivityTest.java deleted file mode 100644 index 3faf9b9..0000000 --- a/sample/src/androidTest/java/convalida/sample/MainActivityTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package convalida.sample; - -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; - -/** - * @author Wellington Costa on 12/11/2017. - */ -@RunWith(AndroidJUnit4.class) -public class MainActivityTest { - - @Rule - public ActivityTestRule activityTestRule = new ActivityTestRule<>(MainActivity.class); - - @Test - public void showSample1() throws Exception { - onView(withId(R.id.sample_1)) - .check(matches(isDisplayed())) - .perform(click()); - } - - @Test - public void showSample2() throws Exception { - onView(withId(R.id.sample_2)) - .check(matches(isDisplayed())) - .perform(click()); - } - -} \ No newline at end of file diff --git a/sample/src/androidTest/java/convalida/sample/SampleActivityTest.java b/sample/src/androidTest/java/convalida/sample/SampleActivityTest.java deleted file mode 100644 index 5349a5b..0000000 --- a/sample/src/androidTest/java/convalida/sample/SampleActivityTest.java +++ /dev/null @@ -1,115 +0,0 @@ -package convalida.sample; - -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard; -import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withText; - -/** - * @author Wellington Costa on 12/11/2017. - */ -@RunWith(AndroidJUnit4.class) -public class SampleActivityTest { - - @Rule - public ActivityTestRule activityTestRule = new ActivityTestRule<>(SampleActivity.class); - - @Test - public void executeValidationsWithEmptyFields() { - onView(withId(R.id.validate_button)) - .perform(closeSoftKeyboard()) - .check(matches(isDisplayed())) - .perform(click()); - - onView(withText(R.string.field_required)) - .check(matches(isDisplayed())); - - onView(withText(R.string.invalid_email)) - .check(matches(isDisplayed())); - - onView(withText(R.string.invalid_password)) - .check(matches(isDisplayed())); - } - - @Test - public void clearAllValidations() { - onView(withId(R.id.validate_button)) - .perform(closeSoftKeyboard()) - .check(matches(isDisplayed())) - .perform(click()); - - onView(withId(R.id.clear_button)) - .check(matches(isDisplayed())) - .perform(click()); - - onView(withText(R.string.field_required)) - .check(doesNotExist()); - - onView(withText(R.string.invalid_email)) - .check(doesNotExist()); - - onView(withText(R.string.emails_not_match)) - .check(doesNotExist()); - - onView(withText(R.string.invalid_password)) - .check(doesNotExist()); - - onView(withText(R.string.passwords_not_match)) - .check(doesNotExist()); - } - - @Test - public void testNameField() { - TestUtils.testFieldWithEmptyValue(R.id.validate_button, R.string.field_required); - - TestUtils.testFieldWithAValidValue(R.id.name_field, R.string.field_required, "Wellington"); - } - - @Test - public void testEmailField() { - TestUtils.testFieldWithEmptyValue(R.id.validate_button, R.string.invalid_email); - - TestUtils.testFieldWithAnInvalidValue(R.id.email_field, R.string.invalid_email, "well@email"); - - TestUtils.testFieldWithAValidValue(R.id.email_field, R.string.invalid_email, "well@email.com"); - } - - @Test - public void testConfirmEmailField() { - TestUtils.testFieldWithAValidValue(R.id.email_field, R.string.invalid_email, "wellington@email.com"); - - TestUtils.testFieldWithAnInvalidValue(R.id.confirm_email_field, R.string.emails_not_match, "wellington@email.co"); - - TestUtils.testFieldWithAValidValue(R.id.confirm_email_field, R.string.emails_not_match, "wellington@email.com"); - } - - @Test - public void testPasswordField() { - TestUtils.testFieldWithEmptyValue(R.id.validate_button, R.string.invalid_password); - - TestUtils.testFieldWithAnInvalidValue(R.id.password_field, R.string.invalid_password, "asdASD"); - - TestUtils.testFieldWithAValidValue(R.id.password_field, R.string.invalid_password, "asdASD123"); - } - - @Test - public void testConfirmPasswordField() { - TestUtils.testFieldWithAValidValue(R.id.password_field, R.string.invalid_password, "asdASD123"); - - TestUtils.testFieldWithAnInvalidValue(R.id.confirm_password_field, R.string.passwords_not_match, "asdASD"); - - TestUtils.testFieldWithAValidValue(R.id.confirm_password_field, R.string.passwords_not_match, "asdASD123"); - } - -} \ No newline at end of file diff --git a/sample/src/androidTest/java/convalida/sample/TestSuite.java b/sample/src/androidTest/java/convalida/sample/TestSuite.java new file mode 100644 index 0000000..ab61a1f --- /dev/null +++ b/sample/src/androidTest/java/convalida/sample/TestSuite.java @@ -0,0 +1,15 @@ +package convalida.sample; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +/** + * @author wellingtoncosta on 03/04/18 + */ +@RunWith(Suite.class) +@SuiteClasses({ + AnnotataionSampleActivityTest.class, + DatabindingSampleActivityTest.class +}) +public class TestSuite { } \ No newline at end of file diff --git a/sample/src/androidTest/java/convalida/sample/TestUtils.java b/sample/src/androidTest/java/convalida/sample/TestUtils.java index bd5b0cb..0d23c58 100644 --- a/sample/src/androidTest/java/convalida/sample/TestUtils.java +++ b/sample/src/androidTest/java/convalida/sample/TestUtils.java @@ -4,6 +4,7 @@ import static android.support.test.espresso.action.ViewActions.clearText; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard; +import static android.support.test.espresso.action.ViewActions.scrollTo; import static android.support.test.espresso.action.ViewActions.typeText; import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist; import static android.support.test.espresso.assertion.ViewAssertions.matches; @@ -17,10 +18,10 @@ class TestUtils { - static void testFieldWithEmptyValue(int fieldResId, int errorMessageResId) { - onView(withId(fieldResId)) + static void testFieldWithEmptyValue(int validateButtonResId, int errorMessageResId) { + onView(withId(validateButtonResId)) + .perform(scrollTo(), closeSoftKeyboard()) .check(matches(isDisplayed())) - .perform(closeSoftKeyboard()) .perform(click()); onView(withText(errorMessageResId)) @@ -29,7 +30,7 @@ static void testFieldWithEmptyValue(int fieldResId, int errorMessageResId) { static void testFieldWithAValidValue(int fieldResId, int errorMessageResId, String value) { onView(withId(fieldResId)) - .perform(clearText(), typeText(value)) + .perform(scrollTo(), clearText(), typeText(value)) .perform(closeSoftKeyboard()) .check(matches(withText(value))); @@ -39,7 +40,7 @@ static void testFieldWithAValidValue(int fieldResId, int errorMessageResId, Stri static void testFieldWithAnInvalidValue(int fieldResId, int errorMessageResId, String value) { onView(withId(fieldResId)) - .perform(clearText(), typeText(value)) + .perform(scrollTo(), clearText(), typeText(value)) .perform(closeSoftKeyboard()) .check(matches(withText(value))); diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 48a2773..fe116eb 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -15,8 +15,8 @@ - - + + \ No newline at end of file diff --git a/sample/src/main/java/convalida/sample/SampleActivity.java b/sample/src/main/java/convalida/sample/AnnotataionSampleActivity.java similarity index 55% rename from sample/src/main/java/convalida/sample/SampleActivity.java rename to sample/src/main/java/convalida/sample/AnnotataionSampleActivity.java index aefe3e2..a969660 100644 --- a/sample/src/main/java/convalida/sample/SampleActivity.java +++ b/sample/src/main/java/convalida/sample/AnnotataionSampleActivity.java @@ -1,11 +1,11 @@ package convalida.sample; import android.os.Bundle; +import android.support.constraint.ConstraintLayout; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.widget.Button; import android.widget.EditText; -import android.widget.LinearLayout; import butterknife.BindView; import butterknife.ButterKnife; @@ -13,26 +13,43 @@ import convalida.annotations.ConfirmEmailValidation; import convalida.annotations.ConfirmPasswordValidation; import convalida.annotations.EmailValidation; -import convalida.annotations.NotEmptyValidation; +import convalida.annotations.LengthValidation; import convalida.annotations.OnValidationError; import convalida.annotations.OnValidationSuccess; +import convalida.annotations.OnlyNumberValidation; import convalida.annotations.PasswordValidation; +import convalida.annotations.PatternValidation; +import convalida.annotations.RequiredValidation; import convalida.annotations.ValidateOnClick; -import static convalida.library.util.Patterns.LOWER_UPPER_CASE_NUMERIC; +import static convalida.library.util.Patterns.MIXED_CASE_NUMERIC; +import static convalida.sample.Constants.PHONE_PATTERN; + /** * @author Wellington Costa on 05/06/17. */ -public class SampleActivity extends AppCompatActivity { +public class AnnotataionSampleActivity extends AppCompatActivity { - @BindView(R.id.linear_layout) - LinearLayout linearLayout; + @BindView(R.id.constraint_layout) + ConstraintLayout constraintLayout; @BindView(R.id.name_field) - @NotEmptyValidation(errorMessage = R.string.field_required) + @RequiredValidation(errorMessage = R.string.field_required) EditText nameField; + @BindView(R.id.nickname_field) + @LengthValidation(min = 3, errorMessage = R.string.min_3_characters) + EditText nickNameField; + + @BindView(R.id.age_field) + @OnlyNumberValidation(errorMessage = R.string.only_numbers) + EditText ageField; + + @BindView(R.id.phone_field) + @PatternValidation(pattern = PHONE_PATTERN, errorMessage = R.string.invalid_phone) + EditText phoneField; + @BindView(R.id.email_field) @EmailValidation(errorMessage = R.string.invalid_email) EditText emailField; @@ -42,7 +59,7 @@ public class SampleActivity extends AppCompatActivity { EditText confirmEmailField; @BindView(R.id.password_field) - @PasswordValidation(min = 3, pattern = LOWER_UPPER_CASE_NUMERIC, errorMessage = R.string.invalid_password) + @PasswordValidation(min = 3, pattern = MIXED_CASE_NUMERIC, errorMessage = R.string.invalid_password) EditText passwordField; @BindView(R.id.confirm_password_field) @@ -60,19 +77,19 @@ public class SampleActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_sample); + setContentView(R.layout.activity_annotation_sample); ButterKnife.bind(this); - SampleActivityFieldsValidation.init(this); + AnnotataionSampleActivityFieldsValidation.init(this); } @OnValidationSuccess public void onValidationSuccess() { - Snackbar.make(linearLayout, "Yay!", Snackbar.LENGTH_LONG).show(); + Snackbar.make(constraintLayout, "Yay!", Snackbar.LENGTH_LONG).show(); } @OnValidationError public void onValidationError() { - Snackbar.make(linearLayout, "Something is wrong :(", Snackbar.LENGTH_LONG).show(); + Snackbar.make(constraintLayout, "Something is wrong :(", Snackbar.LENGTH_LONG).show(); } } \ No newline at end of file diff --git a/sample/src/main/java/convalida/sample/AnotherSampleActivity.java b/sample/src/main/java/convalida/sample/AnotherSampleActivity.java deleted file mode 100644 index e0bf654..0000000 --- a/sample/src/main/java/convalida/sample/AnotherSampleActivity.java +++ /dev/null @@ -1,73 +0,0 @@ -package convalida.sample; - -import android.os.Bundle; -import android.support.design.widget.Snackbar; -import android.support.v7.app.AppCompatActivity; -import android.widget.Button; -import android.widget.EditText; -import android.widget.LinearLayout; - -import butterknife.BindView; -import butterknife.ButterKnife; -import convalida.annotations.ClearValidationsOnClick; -import convalida.annotations.LengthValidation; -import convalida.annotations.NotEmptyValidation; -import convalida.annotations.OnValidationError; -import convalida.annotations.OnValidationSuccess; -import convalida.annotations.OnlyNumberValidation; -import convalida.annotations.PatternValidation; -import convalida.annotations.ValidateOnClick; - -/** - * @author Wellington Costa on 05/06/17. - */ -public class AnotherSampleActivity extends AppCompatActivity { - - private static final String PHONE_PATTERN = "[\\+]\\d{2}[\\(]\\d{2}[\\)]\\d{4}[\\-]\\d{4}"; - - @BindView(R.id.linear_layout) - LinearLayout linearLayout; - - @BindView(R.id.name_field) - @NotEmptyValidation(errorMessage = R.string.field_required) - EditText nameField; - - @BindView(R.id.nickname_field) - @LengthValidation(min = 3, errorMessage = R.string.min_3_characters) - EditText nickNameField; - - @BindView(R.id.age_field) - @OnlyNumberValidation(errorMessage = R.string.only_numbers) - EditText ageField; - - @BindView(R.id.phone_field) - @PatternValidation(pattern = PHONE_PATTERN, errorMessage = R.string.invalid_phone) - EditText phoneField; - - @ValidateOnClick - @BindView(R.id.validate_button) - Button validateButton; - - @ClearValidationsOnClick - @BindView(R.id.clear_button) - Button clearValidationsButton; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_another_sample); - ButterKnife.bind(this); - AnotherSampleActivityFieldsValidation.init(this); - } - - @OnValidationSuccess - public void onValidationSuccess() { - Snackbar.make(linearLayout, "Yay!", Snackbar.LENGTH_LONG).show(); - } - - @OnValidationError - public void onValidationError() { - Snackbar.make(linearLayout, "Something is wrong :(", Snackbar.LENGTH_LONG).show(); - } - -} \ No newline at end of file diff --git a/sample/src/main/java/convalida/sample/Constants.java b/sample/src/main/java/convalida/sample/Constants.java new file mode 100644 index 0000000..a81a961 --- /dev/null +++ b/sample/src/main/java/convalida/sample/Constants.java @@ -0,0 +1,11 @@ +package convalida.sample; + +/** + * @author WellingtonCosta on 29/03/18. + */ + +public class Constants { + + public static final String PHONE_PATTERN = "[\\+]\\d{2}[\\(]\\d{2}[\\)]\\d{4}[\\-]\\d{4}"; + +} diff --git a/sample/src/main/java/convalida/sample/DatabindingSampleActivity.java b/sample/src/main/java/convalida/sample/DatabindingSampleActivity.java new file mode 100644 index 0000000..593e72b --- /dev/null +++ b/sample/src/main/java/convalida/sample/DatabindingSampleActivity.java @@ -0,0 +1,36 @@ +package convalida.sample; + +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AppCompatActivity; + +import convalida.annotations.OnValidationError; +import convalida.annotations.OnValidationSuccess; +import convalida.sample.databinding.ActivityDatabindingSampleBinding; + +/** + * @author Wellington Costa on 05/06/17. + */ +public class DatabindingSampleActivity extends AppCompatActivity { + + private ActivityDatabindingSampleBinding binding; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = DataBindingUtil.setContentView(this, R.layout.activity_databinding_sample); + DatabindingSampleActivityFieldsValidation.init(this, binding); + } + + @OnValidationSuccess + public void onValidationSuccess() { + Snackbar.make(binding.getRoot(), "Yay!", Snackbar.LENGTH_LONG).show(); + } + + @OnValidationError + public void onValidationError() { + Snackbar.make(binding.getRoot(), "Something is wrong :(", Snackbar.LENGTH_LONG).show(); + } + +} \ No newline at end of file diff --git a/sample/src/main/java/convalida/sample/MainActivity.java b/sample/src/main/java/convalida/sample/MainActivity.java index 6824d3f..41277f7 100644 --- a/sample/src/main/java/convalida/sample/MainActivity.java +++ b/sample/src/main/java/convalida/sample/MainActivity.java @@ -18,11 +18,11 @@ protected void onCreate(Bundle savedInstanceState) { @OnClick(R.id.sample_1) public void showSample1() { - startActivity(new Intent(this, SampleActivity.class)); + startActivity(new Intent(this, AnnotataionSampleActivity.class)); } @OnClick(R.id.sample_2) public void showSample2() { - startActivity(new Intent(this, AnotherSampleActivity.class)); + startActivity(new Intent(this, DatabindingSampleActivity.class)); } } diff --git a/sample/src/main/res/layout/activity_annotation_sample.xml b/sample/src/main/res/layout/activity_annotation_sample.xml new file mode 100644 index 0000000..b6ec3b3 --- /dev/null +++ b/sample/src/main/res/layout/activity_annotation_sample.xml @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample/src/main/res/layout/activity_another_sample.xml b/sample/src/main/res/layout/activity_another_sample.xml deleted file mode 100644 index 5fad0b9..0000000 --- a/sample/src/main/res/layout/activity_another_sample.xml +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -