├── Gemfile ├── core ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── res │ │ │ ├── values │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── attrs.xml │ │ │ ├── anim │ │ │ │ ├── double_cycle_interpolator.xml │ │ │ │ └── shake_error.xml │ │ │ └── xml │ │ │ │ └── settings.xml │ │ └── java │ │ │ └── com │ │ │ └── sha │ │ │ └── formvalidator │ │ │ ├── textview │ │ │ ├── validator │ │ │ │ ├── pattern │ │ │ │ │ ├── AlphaValidator.kt │ │ │ │ │ ├── AlphaNumericValidator.kt │ │ │ │ │ ├── DomainValidator.kt │ │ │ │ │ ├── PersonNameValidator.kt │ │ │ │ │ ├── PersonFullNameValidator.kt │ │ │ │ │ ├── WebUrlValidator.kt │ │ │ │ │ ├── IpAddressValidator.kt │ │ │ │ │ ├── PhoneValidator.kt │ │ │ │ │ ├── EmailValidator.kt │ │ │ │ │ └── PatternValidator.kt │ │ │ │ ├── CustomValidator.kt │ │ │ │ ├── DummyValidator.kt │ │ │ │ ├── SuffixValidator.kt │ │ │ │ ├── RequiredValidator.kt │ │ │ │ ├── PrefixValidator.kt │ │ │ │ ├── InverseValidator.kt │ │ │ │ ├── ValueMatchValidator.kt │ │ │ │ ├── LengthRangeValidator.kt │ │ │ │ ├── TextValidator.kt │ │ │ │ ├── composite │ │ │ │ │ ├── CompositeValidator.kt │ │ │ │ │ ├── OrValidator.kt │ │ │ │ │ └── AndValidator.kt │ │ │ │ ├── FloatNumericRangeValidator.kt │ │ │ │ ├── NumericRangeValidator.kt │ │ │ │ ├── NumericValidator.kt │ │ │ │ ├── DateValidator.kt │ │ │ │ └── CreditCardValidator.kt │ │ │ ├── TextViewValidators.kt │ │ │ ├── TextViewValidationType.kt │ │ │ ├── TextViewAttrInfo.kt │ │ │ ├── TextValidationHandler.kt │ │ │ ├── ValidatorFactory.kt │ │ │ ├── TextViewValidatorFactory.kt │ │ │ └── DefTextValidationHandler.kt │ │ │ ├── Validatable.kt │ │ │ ├── model │ │ │ ├── OnOffValidation.kt │ │ │ ├── RequiredValidation.kt │ │ │ ├── CheckedValidation.kt │ │ │ ├── helper │ │ │ │ └── AnimationHelper.kt │ │ │ ├── CompositeValidatorInfo.kt │ │ │ └── FormOptions.kt │ │ │ ├── AbstractFormValidator.kt │ │ │ ├── FormValidator.kt │ │ │ ├── Form.kt │ │ │ ├── FormHelper.kt │ │ │ └── widget │ │ │ ├── FormToggleButton.kt │ │ │ ├── FormCheckBox.kt │ │ │ ├── FormSwitch.kt │ │ │ ├── FormSeekBar.kt │ │ │ ├── FormRatingBar.kt │ │ │ ├── FormAutoCompleteTextView.kt │ │ │ └── FormEditText.kt │ └── test │ │ └── java │ │ └── com │ │ └── sha │ │ └── formvalidator │ │ ├── validator │ │ ├── NumberOneCustomValidator.kt │ │ ├── CustomValidatorTest.kt │ │ ├── DummyValidatorTest.kt │ │ ├── PrefixValidatorTest.kt │ │ ├── SuffixValidatorTest.kt │ │ ├── RequiredValidatorTest.kt │ │ ├── pattern │ │ │ ├── AlphaValidatorTest.kt │ │ │ ├── DomainValidatorTest.kt │ │ │ ├── PersonNameValidatorTest.kt │ │ │ ├── AlphaNumericValidatorTest.kt │ │ │ └── PersonFullNameValidatorTest.kt │ │ ├── CreditCardValidatorTest.kt │ │ ├── LengthRangeValidatorTest.kt │ │ ├── NumericLengthRangeValidatorTest.kt │ │ ├── AlphaNumericValidatorTest.kt │ │ ├── FloatNumericLengthRangeValidatorTest.kt │ │ ├── InverseValidatorTest.kt │ │ ├── NumericValidatorTest.kt │ │ ├── ValueMatchValidatorTest.kt │ │ ├── DateValidatorTest.kt │ │ ├── AndValidatorTest.kt │ │ └── OrValidatorTest.kt │ │ ├── FormValidatorTest.kt │ │ ├── FormOptionsTest.kt │ │ └── RxFormValidatorTest.kt ├── build.gradle └── proguard-rules.pro ├── settings.gradle ├── blob ├── logo.png └── master │ └── raw │ └── diagragm.png ├── rxjava ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ ├── res │ │ ├── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── attrs.xml │ │ └── anim │ │ │ ├── double_cycle_interpolator.xml │ │ │ └── shake_error.xml │ │ └── java │ │ └── com │ │ └── sha │ │ └── formvalidator │ │ └── rxjava │ │ └── RxFormValidator.kt ├── build.gradle └── proguard-rules.pro ├── common-android-library.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── sample ├── src │ └── main │ │ ├── res │ │ ├── drawable │ │ │ ├── play_store_icon.png │ │ │ ├── bg_round_corners.xml │ │ │ └── rect_border.xml │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ ├── drawable-hdpi │ │ │ └── ic_settings_white_24dp.png │ │ ├── drawable-mdpi │ │ │ └── ic_settings_white_24dp.png │ │ ├── drawable-xhdpi │ │ │ └── ic_settings_white_24dp.png │ │ ├── drawable-xxhdpi │ │ │ └── ic_settings_white_24dp.png │ │ ├── drawable-xxxhdpi │ │ │ └── ic_settings_white_24dp.png │ │ ├── values │ │ │ ├── custom_validators.xml │ │ │ ├── dimens.xml │ │ │ ├── attrs.xml │ │ │ ├── colors.xml │ │ │ ├── styles.xml │ │ │ └── strings.xml │ │ ├── menu │ │ │ ├── menu.xml │ │ │ └── styling_options_menu.xml │ │ └── layout │ │ │ ├── activity_examples.xml │ │ │ ├── field_alpha.xml │ │ │ ├── field_date.xml │ │ │ ├── field_personname.xml │ │ │ ├── field_personfullname.xml │ │ │ ├── field_date_custom.xml │ │ │ ├── field_ip_address.xml │ │ │ ├── field_domain_name.xml │ │ │ ├── item_example.xml │ │ │ ├── field_phone.xml │ │ │ ├── field_email.xml │ │ │ ├── field_creditcard.xml │ │ │ ├── field_weburl.xml │ │ │ ├── field_no_check.xml │ │ │ ├── field_regex.xml │ │ │ ├── field_email_or_creditcard.xml │ │ │ ├── field_numeric.xml │ │ │ ├── field_allowempty.xml │ │ │ ├── field_custom_validation_type.xml │ │ │ ├── field_float_numeric_range.xml │ │ │ ├── field_phone_custommessages.xml │ │ │ ├── field_alpha_textinputlayout.xml │ │ │ ├── activity_main.xml │ │ │ ├── activity_auto_complete.xml │ │ │ ├── activity_field.xml │ │ │ ├── activity_password.xml │ │ │ └── activity_form.xml │ │ ├── java │ │ └── com │ │ │ └── sha │ │ │ └── formvalidatorsample │ │ │ ├── App.kt │ │ │ ├── validator │ │ │ └── NumberOneCustomValidator.kt │ │ │ ├── presentation │ │ │ ├── MainActivity.kt │ │ │ ├── AutoCompleteTextViewActivity.kt │ │ │ ├── RxFormActivity.kt │ │ │ ├── FieldsActivity.kt │ │ │ ├── FormActivity.kt │ │ │ ├── PasswordValidatorActivity.kt │ │ │ ├── EmailOrCreditCardActivity.kt │ │ │ ├── PrefixAndRangeValidatorActivity.kt │ │ │ ├── FieldActivity.kt │ │ │ └── CountrySpinner.kt │ │ │ ├── util │ │ │ └── SnackBarUtil.kt │ │ │ └── adapter │ │ │ ├── FieldItem.kt │ │ │ ├── RecyclerAdapter.kt │ │ │ └── FieldInfo.kt │ │ └── AndroidManifest.xml ├── build.gradle └── proguard-rules.pro ├── fastlane ├── Appfile ├── report.xml ├── README.md └── Fastfile ├── .gitignore ├── CHANGELOG.md ├── gradle.properties ├── common.gradle ├── gradlew.bat ├── TEXTVIEW.md ├── gradlew ├── Gemfile.lock └── README.md /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" -------------------------------------------------------------------------------- /core/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':sample' 2 | include ':core' 3 | include ':rxjava' 4 | -------------------------------------------------------------------------------- /blob/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MalekKamel/FormValidator/HEAD/blob/logo.png -------------------------------------------------------------------------------- /rxjava/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /common-android-library.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Plugins.androidLibrary 2 | apply from: "$rootDir/common.gradle" -------------------------------------------------------------------------------- /blob/master/raw/diagragm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MalekKamel/FormValidator/HEAD/blob/master/raw/diagragm.png -------------------------------------------------------------------------------- /core/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #F4A890 3 | 4 | -------------------------------------------------------------------------------- /rxjava/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #F4A890 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MalekKamel/FormValidator/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /sample/src/main/res/drawable/play_store_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MalekKamel/FormValidator/HEAD/sample/src/main/res/drawable/play_store_icon.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MalekKamel/FormValidator/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-hdpi/ic_settings_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MalekKamel/FormValidator/HEAD/sample/src/main/res/drawable-hdpi/ic_settings_white_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-mdpi/ic_settings_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MalekKamel/FormValidator/HEAD/sample/src/main/res/drawable-mdpi/ic_settings_white_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xhdpi/ic_settings_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MalekKamel/FormValidator/HEAD/sample/src/main/res/drawable-xhdpi/ic_settings_white_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MalekKamel/FormValidator/HEAD/sample/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxxhdpi/ic_settings_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MalekKamel/FormValidator/HEAD/sample/src/main/res/drawable-xxxhdpi/ic_settings_white_24dp.png -------------------------------------------------------------------------------- /core/src/main/res/anim/double_cycle_interpolator.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rxjava/src/main/res/anim/double_cycle_interpolator.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /fastlane/Appfile: -------------------------------------------------------------------------------- 1 | json_key_file("") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one 2 | package_name("com.sha.formvalidatorsample") # e.g. com.krausefx.app 3 | -------------------------------------------------------------------------------- /sample/src/main/res/values/custom_validators.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NumberOne 5 | 6 | -------------------------------------------------------------------------------- /sample/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 48dp 5 | 40dp 6 | 7 | -------------------------------------------------------------------------------- /sample/src/main/res/menu/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/pattern/AlphaValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.pattern 2 | 3 | class AlphaValidator(errorMessage: String) : PatternValidator(errorMessage, "[A-z\u00C0-\u00ff \\./-\\?]*") 4 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable/bg_round_corners.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed May 19 17:29:13 EET 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .DS_Store 4 | 5 | /local.properties 6 | /.idea/workspace.xml 7 | /.idea/libraries 8 | .idea 9 | 10 | 11 | /build 12 | /*/build/ 13 | build 14 | 15 | /captures 16 | .externalNativeBuild 17 | 18 | *.apk 19 | *.aab 20 | 21 | app/release 22 | app/debug 23 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/Validatable.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator 2 | 3 | /** 4 | * The interface that every field must implement to be validated 5 | * return true if valid, false otherwise. 6 | */ 7 | interface Validatable { 8 | fun validate(): Boolean 9 | } 10 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/pattern/AlphaNumericValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.pattern 2 | 3 | 4 | class AlphaNumericValidator(errorMessage: String): 5 | PatternValidator(errorMessage, "[a-zA-Z0-9\u00C0-\u00FF \\./-\\?]*") 6 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/pattern/DomainValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.pattern 2 | 3 | import androidx.core.util.PatternsCompat 4 | 5 | class DomainValidator(errorMessage: String) : PatternValidator(errorMessage, PatternsCompat.DOMAIN_NAME) 6 | -------------------------------------------------------------------------------- /core/src/main/res/anim/shake_error.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /core/src/main/res/xml/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /rxjava/src/main/res/anim/shake_error.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/TextViewValidators.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview 2 | 3 | import com.sha.formvalidator.textview.validator.CustomValidator 4 | import java.util.* 5 | 6 | object TextViewValidators { 7 | var customValidators: List = ArrayList() 8 | } 9 | -------------------------------------------------------------------------------- /rxjava/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Plugins.androidLibrary 2 | apply from: "$rootDir/${GradleName.common}" 3 | apply plugin: Plugins.kotlinAndroid 4 | apply plugin: Plugins.kotlinAndroidExtensions 5 | apply plugin: Plugins.dcendents 6 | 7 | dependencies { 8 | api project(path: ':core') 9 | api Deps.rxJava 10 | } 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## Version 2.0.0 3 | 4 | - [ ] Form: widgets wrapper for triggering validation with single click. 5 | - [ ] Kotlin migration. 6 | - [ ] Unit testing. 7 | - [ ] Separate module for RxJava. 8 | 9 | ## Version 2.2.0 10 | - [ ] Allow hiding the error message in case the error message displaying is disabled. 11 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/CustomValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator 2 | 3 | import android.content.Context 4 | 5 | abstract class CustomValidator(errorMessage: String) : TextValidator(errorMessage) { 6 | abstract fun customValidationType(context: Context): String 7 | } 8 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/pattern/PersonNameValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.pattern 2 | 3 | class PersonNameValidator(errorMessage: String)// will allow people with hyphens in his name or surname. Supports also unicode 4 | : PatternValidator(errorMessage, "[\\p{L}-]+") 5 | -------------------------------------------------------------------------------- /fastlane/report.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/DummyValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator 2 | 3 | /** 4 | * This is a dummy validator. It just returns true on each input. 5 | * 6 | */ 7 | class DummyValidator : TextValidator("") { 8 | override fun isValid(text: String): Boolean = true 9 | } 10 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/pattern/PersonFullNameValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.pattern 2 | 3 | class PersonFullNameValidator(errorMessage: String)// will allow people with hyphens in his name or surname. Supports also unicode 4 | : PatternValidator(errorMessage, "[\\p{L}- ]+") 5 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_examples.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/model/OnOffValidation.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.model 2 | 3 | enum class OnOffValidation constructor(var value: Int) { 4 | ON(0), 5 | OFF(1); 6 | 7 | companion object { 8 | fun fromValue(value: Int?): OnOffValidation = values().firstOrNull { it.value == value } ?: ON 9 | } 10 | } -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/model/RequiredValidation.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.model 2 | 3 | enum class RequiredValidation constructor(var value: Int) { 4 | REQUIRED(0), 5 | NOT_REQUIRED(1); 6 | 7 | companion object { 8 | fun fromValue(value: Int?) = values().firstOrNull { it.value == value } ?: REQUIRED 9 | } 10 | } -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_alpha.xml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_date.xml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_personname.xml: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_personfullname.xml: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /sample/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/model/CheckedValidation.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.model 2 | 3 | enum class CheckedValidation constructor(var value: Int) { 4 | CHECKED(0), 5 | UNCHECKED(1); 6 | 7 | companion object { 8 | fun fromValue(value: Int?): CheckedValidation = values().firstOrNull { it.value == value } ?: CHECKED 9 | } 10 | } -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/pattern/WebUrlValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.pattern 2 | 3 | import android.util.Patterns 4 | 5 | /** 6 | * Validates a web url in the format: 7 | * scheme + authority + path 8 | * 9 | */ 10 | class WebUrlValidator(errorMessage: String) : PatternValidator(errorMessage, Patterns.WEB_URL) 11 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_date_custom.xml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/pattern/IpAddressValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.pattern 2 | 3 | import android.util.Patterns 4 | 5 | /** 6 | * Validates the ipaddress. The regexp was taken from the android source code. 7 | * 8 | */ 9 | class IpAddressValidator(errorMessage: String) : PatternValidator(errorMessage, Patterns.IP_ADDRESS) 10 | -------------------------------------------------------------------------------- /sample/src/main/res/menu/styling_options_menu.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_ip_address.xml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_domain_name.xml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/item_example.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/SuffixValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator 2 | 3 | /** 4 | * A validator that returns true only if the input field contains only numbers. 5 | * 6 | */ 7 | class SuffixValidator(private val suffix: String, errorMessage: String) : TextValidator(errorMessage) { 8 | override fun isValid(text: String): Boolean = text.endsWith(suffix) 9 | } 10 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_phone.xml: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/RequiredValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator 2 | 3 | /** 4 | * A simple validator that validates the field only if the field is not empty. 5 | * 6 | */ 7 | class RequiredValidator(errorMessage: String = "") : TextValidator(errorMessage) { 8 | 9 | override fun isValid(text: String): Boolean = text.trim { it <= ' ' }.isNotEmpty() 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/PrefixValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator 2 | 3 | /** 4 | * A validator that returns true only if the input field contains only numbers. 5 | * 6 | */ 7 | class PrefixValidator(private val prefix: String, errorMessage: String) : TextValidator(errorMessage) { 8 | 9 | override fun isValid(text: String): Boolean = text.startsWith(prefix) 10 | } 11 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_email.xml: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_creditcard.xml: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_weburl.xml: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_no_check.xml: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_regex.xml: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_email_or_creditcard.xml: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/pattern/PhoneValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.pattern 2 | 3 | import android.util.Patterns 4 | 5 | /** 6 | * It validates phone numbers. 7 | * Regexp was taken from the android source code. 8 | */ 9 | class PhoneValidator(errorMessage: String) 10 | // sdd = space, dot, or dash 11 | // +* 12 | // ()* 13 | : PatternValidator(errorMessage, Patterns.PHONE) 14 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_numeric.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_allowempty.xml: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/NumberOneCustomValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import android.content.Context 4 | import com.sha.formvalidator.textview.validator.CustomValidator 5 | 6 | class NumberOneCustomValidator(errorMessage: String) : CustomValidator(errorMessage) { 7 | override fun customValidationType(context: Context): String { 8 | return "Num1" 9 | } 10 | override fun isValid(text: String) = text == "1" 11 | } -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Plugins.androidApplication 2 | apply from: "$rootDir/${GradleName.common}" 3 | apply plugin: Plugins.kotlinAndroid 4 | apply plugin: Plugins.kotlinAndroidExtensions 5 | 6 | dependencies { 7 | implementation project(Lib.core) 8 | implementation project(Lib.rxJava) 9 | 10 | implementation Deps.androidx_appCompat 11 | implementation Deps.android_material 12 | implementation Deps.androidx_core_ktx 13 | implementation Deps.multidex 14 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/sha/formvalidatorsample/App.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidatorsample 2 | 3 | import android.app.Application 4 | import com.sha.formvalidator.textview.TextViewValidators 5 | import com.sha.formvalidatorsample.validator.NumberOneCustomValidator 6 | 7 | class App : Application() { 8 | override fun onCreate() { 9 | super.onCreate() 10 | TextViewValidators.customValidators = listOf(NumberOneCustomValidator("Value doesn't equal 1")) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/InverseValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator 2 | 3 | /** 4 | * It's a validator that applies the "NOT" logical operator to the validator it wraps. 5 | * 6 | */ 7 | class InverseValidator(validator: TextValidator, errorMessage: String = "") : TextValidator(errorMessage) { 8 | private var v: TextValidator = validator 9 | 10 | override fun isValid(text: String): Boolean = !v.isValid(text) 11 | 12 | } 13 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_custom_validation_type.xml: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/model/helper/AnimationHelper.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.model.helper 2 | 3 | import android.view.View 4 | import android.view.animation.AnimationUtils 5 | import com.sha.formvalidator.R 6 | 7 | internal object AnimationHelper { 8 | 9 | fun error(v: View) { 10 | v.startAnimation( 11 | AnimationUtils.loadAnimation( 12 | v.context, 13 | R.anim.shake_error) 14 | ) 15 | } 16 | } -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/ValueMatchValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator 2 | 3 | /** 4 | * A simple validator that validates the field only if the value is the same as another one. 5 | * 6 | */ 7 | class ValueMatchValidator(errorMessage: String, vararg texts: String) : TextValidator(errorMessage) { 8 | private val tvs: List = listOf(*texts) 9 | 10 | override fun isValid(text: String): Boolean = tvs.all { it == text } 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/LengthRangeValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator 2 | 3 | /** 4 | * A validator that returns true only if the text is within the given range. 5 | * 6 | */ 7 | class LengthRangeValidator(errorMessage: String, private val min: Int, private val max: Int) : TextValidator(errorMessage) { 8 | 9 | override fun isValid(text: String): Boolean { 10 | val length = text.length 11 | return length in min..max 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | @color/black 4 | @color/black 5 | #fcbf10 6 | #E6AE0E 7 | @color/yellow 8 | #F4A890 9 | #000 10 | #fff 11 | #545554 12 | 13 | 14 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/pattern/EmailValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.pattern 2 | 3 | import android.util.Patterns 4 | 5 | /** 6 | * This validates an email using regexps. 7 | * Note that if an email passes the validation with this validator it doesn't mean it's a valid email - it means it's a valid email format 8 | * 9 | */ 10 | class EmailValidator(errorMessage: String = "") : PatternValidator(errorMessage, Patterns.EMAIL_ADDRESS) { 11 | } 12 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_float_numeric_range.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_phone_custommessages.xml: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sha/formvalidatorsample/validator/NumberOneCustomValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidatorsample.validator 2 | 3 | import android.content.Context 4 | import com.sha.formvalidator.textview.validator.CustomValidator 5 | import com.sha.formvalidatorsample.R 6 | 7 | class NumberOneCustomValidator(errorMessage: String) : CustomValidator(errorMessage) { 8 | override fun customValidationType(context: Context): String { 9 | return context.getString(R.string.custom_validator_number_one) 10 | } 11 | override fun isValid(text: String) = text == "1" 12 | } 13 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/field_alpha_textinputlayout.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | 13 | -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/CustomValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | import org.junit.Before 5 | import org.junit.Test 6 | 7 | class CustomValidatorTest { 8 | lateinit var validator: TextValidator 9 | 10 | @Before 11 | fun setup() { 12 | validator = NumberOneCustomValidator("Invalid!") 13 | } 14 | 15 | @Test 16 | fun validate_valid() { 17 | assert(validator.isValid("1")) 18 | } 19 | 20 | @Test 21 | fun validate_invalid() { 22 | assert(!validator.isValid("2")) 23 | } 24 | } -------------------------------------------------------------------------------- /core/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: Plugins.androidLibrary 2 | apply from: "$rootDir/${GradleName.common}" 3 | apply plugin: Plugins.kotlinAndroid 4 | apply plugin: Plugins.kotlinAndroidExtensions 5 | apply plugin: Plugins.dcendents 6 | 7 | dependencies { 8 | implementation Deps.androidx_appCompat 9 | implementation Deps.androidx_preference 10 | implementation Deps.android_material 11 | implementation Deps.androidx_core_ktx 12 | 13 | testImplementation TestDeps.junit 14 | testImplementation TestDeps.androidx_junit 15 | testImplementation TestDeps.androidx_espressoCore 16 | testImplementation TestDeps.androidx_test_core_ktx 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/TextValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator 2 | 3 | import android.widget.TextView 4 | 5 | /** 6 | * Validator abstract class. To be used with FormEditText 7 | * 8 | */ 9 | abstract class TextValidator(var errorMessage: String = "") { 10 | 11 | /** 12 | * Should check if the [TextView] is valid. 13 | * 14 | * @param text the [TextView] under evaluation 15 | * @return true if the edittext is valid, false otherwise 16 | */ 17 | abstract fun isValid(text: String): Boolean 18 | 19 | fun hasErrorMessage(): Boolean = errorMessage.isNotEmpty() 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/composite/CompositeValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.composite 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | 5 | /** 6 | * Abstract class for a multi-validator. 7 | * 8 | * @see AndValidator 9 | * 10 | * @see OrValidator 11 | */ 12 | abstract class CompositeValidator(message: String, vararg validators: TextValidator) : TextValidator(message) { 13 | protected val validators: MutableList = mutableListOf(*validators) 14 | 15 | fun enqueue(newValidator: TextValidator) { 16 | validators.add(newValidator) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/FloatNumericRangeValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator 2 | 3 | /** 4 | * A validator that returns true only if the input field contains only numbers 5 | * and the number is within the given range. 6 | * 7 | * @author Said Tahsin Dane @gmail.com> 8 | */ 9 | class FloatNumericRangeValidator(errorMessage: String, private val floatMin: Double, private val floatMax: Double) : TextValidator(errorMessage) { 10 | override fun isValid(text: String): Boolean { 11 | return try { text.toDouble() in floatMin..floatMax } 12 | catch (e: NumberFormatException) { false } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/DummyValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.DummyValidator 4 | import com.sha.formvalidator.textview.validator.TextValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class DummyValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = DummyValidator() 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("kkkkk")) 19 | } 20 | 21 | @Test 22 | fun validate_validIfEmpty() { 23 | assert(validator.isValid("")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/NumericRangeValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator 2 | 3 | /** 4 | * A validator that returns true only if the input field contains only numbers 5 | * and the number is within the given range. 6 | * 7 | */ 8 | class NumericRangeValidator(errorMessage: String, private val min: Long, private val max: Long) : TextValidator(errorMessage) { 9 | 10 | override fun isValid(text: String): Boolean { 11 | return try { 12 | val value = java.lang.Long.parseLong(text) 13 | value in min..max 14 | } catch (e: NumberFormatException) { 15 | false 16 | } 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/PrefixValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.PrefixValidator 4 | import com.sha.formvalidator.textview.validator.TextValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class PrefixValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = PrefixValidator("prefix", "Invalid!") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("prefixXX")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("11")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/SuffixValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.SuffixValidator 4 | import com.sha.formvalidator.textview.validator.TextValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class SuffixValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = SuffixValidator("suffix", "Invalid!") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("XXsuffix")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("11")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/RequiredValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.RequiredValidator 4 | import com.sha.formvalidator.textview.validator.TextValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class RequiredValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = RequiredValidator("Invalid!") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("378734493671000")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/pattern/AlphaValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator.pattern 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | import com.sha.formvalidator.textview.validator.pattern.AlphaValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class AlphaValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = AlphaValidator("Invalid!") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("rrlll")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("11*%")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/CreditCardValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.CreditCardValidator 4 | import com.sha.formvalidator.textview.validator.TextValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class CreditCardValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = CreditCardValidator("Invalid!") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("378734493671000")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("11")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/LengthRangeValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.LengthRangeValidator 4 | import com.sha.formvalidator.textview.validator.TextValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class LengthRangeValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = LengthRangeValidator("Invalid!", 1, 5) 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("1")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("123456")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/pattern/DomainValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator.pattern 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | import com.sha.formvalidator.textview.validator.pattern.DomainValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class DomainValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = DomainValidator("Invalid!") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("www.google.com")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("11")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/troy379/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/NumericLengthRangeValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.NumericRangeValidator 4 | import com.sha.formvalidator.textview.validator.TextValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class NumericLengthRangeValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = NumericRangeValidator("Invalid!", 1, 5) 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("1")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("6")) 24 | } 25 | } -------------------------------------------------------------------------------- /rxjava/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/troy379/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/troy379/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/AlphaNumericValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | import com.sha.formvalidator.textview.validator.pattern.AlphaNumericValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class AlphaNumericValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = AlphaNumericValidator("Invalid!") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("rr378734493671000")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("11*%")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/pattern/PersonNameValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator.pattern 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | import com.sha.formvalidator.textview.validator.pattern.PersonNameValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class PersonNameValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = PersonNameValidator("Invalid!") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("Shaban")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("Shaban 123")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/pattern/AlphaNumericValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator.pattern 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | import com.sha.formvalidator.textview.validator.pattern.AlphaNumericValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class AlphaNumericValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = AlphaNumericValidator("Invalid!") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("rrlll2233")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("11*%")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/FloatNumericLengthRangeValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.FloatNumericRangeValidator 4 | import com.sha.formvalidator.textview.validator.TextValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class FloatNumericLengthRangeValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = FloatNumericRangeValidator("Invalid!", 1.0, 5.0) 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("1")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("6")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/pattern/PersonFullNameValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator.pattern 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | import com.sha.formvalidator.textview.validator.pattern.PersonFullNameValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class PersonFullNameValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = PersonFullNameValidator("Invalid!") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("Shaban Kamel")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | assert(!validator.isValid("Shaban 123")) 24 | } 25 | } -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/TextViewValidationType.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview 2 | 3 | enum class TextViewValidationType constructor(var value: Int) { 4 | REGEX(0), 5 | NUMERIC(1), 6 | ALPHA(2), 7 | ALPHA_NUMERIC(3), 8 | EMAIL(4), 9 | CREDIT_CARD(5), 10 | PHONE(6), 11 | DOMAIN_NAME(7), 12 | IP_ADDRESS(8), 13 | WEB_URL(9), 14 | NOT_EMPTY(10), 15 | PERSON_NAME(11), 16 | PERSON_FULL_NAME(12), 17 | DATE(13), 18 | NUMERIC_RANGE(14), 19 | FLOAT_NUMERIC_RANGE(15), 20 | NOT_DETECTABLE(2000); 21 | 22 | companion object { 23 | fun fromValue(value: Int): TextViewValidationType { 24 | return values().firstOrNull { it.value == value } ?: NOT_DETECTABLE 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/InverseValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.CreditCardValidator 4 | import com.sha.formvalidator.textview.validator.InverseValidator 5 | import com.sha.formvalidator.textview.validator.TextValidator 6 | import org.junit.Before 7 | import org.junit.Test 8 | 9 | class InverseValidatorTest { 10 | lateinit var validator: TextValidator 11 | 12 | @Before 13 | fun setup() { 14 | validator = InverseValidator(CreditCardValidator(), "Invalid!") 15 | } 16 | 17 | @Test 18 | fun validate_valid() { 19 | assert(validator.isValid("11")) 20 | } 21 | 22 | @Test 23 | fun validate_invalid() { 24 | assert(!validator.isValid("378734493671000")) 25 | } 26 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/sha/formvalidatorsample/presentation/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidatorsample.presentation 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.view.View 7 | 8 | import com.sha.formvalidatorsample.R 9 | 10 | class MainActivity : Activity() { 11 | 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | setContentView(R.layout.activity_main) 15 | 16 | findViewById(R.id.btnFields).setOnClickListener { show(FieldsActivity::class.java) } 17 | findViewById(R.id.btnForm).setOnClickListener { show(FormActivity::class.java) } 18 | } 19 | 20 | private fun show(clazz: Class<*>) = startActivity(Intent(this, clazz)) 21 | 22 | } 23 | -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/NumericValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.NumericValidator 4 | import com.sha.formvalidator.textview.validator.TextValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class NumericValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = NumericValidator("Invalid!") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("1")) 19 | } 20 | 21 | @Test 22 | fun validate_invalidIfWrong() { 23 | assert(!validator.isValid("6f")) 24 | } 25 | 26 | @Test 27 | fun validate_invalidIfEmpty() { 28 | assert(!validator.isValid("")) 29 | } 30 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/ValueMatchValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | import com.sha.formvalidator.textview.validator.ValueMatchValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class ValueMatchValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | } 14 | 15 | @Test 16 | fun validate_valid() { 17 | validator = ValueMatchValidator("Invalid!", "378734493671000") 18 | assert(validator.isValid("378734493671000")) 19 | } 20 | 21 | @Test 22 | fun validate_invalid() { 23 | validator = ValueMatchValidator("Invalid!", "11") 24 | assert(!validator.isValid("378734493671000")) 25 | } 26 | } -------------------------------------------------------------------------------- /core/src/test/java/com/sha/formvalidator/validator/DateValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.validator 2 | 3 | import com.sha.formvalidator.textview.validator.DateValidator 4 | import com.sha.formvalidator.textview.validator.TextValidator 5 | import org.junit.Before 6 | import org.junit.Test 7 | 8 | class DateValidatorTest { 9 | lateinit var validator: TextValidator 10 | 11 | @Before 12 | fun setup() { 13 | validator = DateValidator("Invalid!", "YYYY:MM:DD") 14 | } 15 | 16 | @Test 17 | fun validate_valid() { 18 | assert(validator.isValid("2019:12:14")) 19 | } 20 | 21 | @Test 22 | fun validate_invalidIfWrong() { 23 | assert(!validator.isValid("2019")) 24 | } 25 | 26 | @Test 27 | fun validate_invalidIfEmpty() { 28 | assert(!validator.isValid("")) 29 | } 30 | } -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/composite/OrValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.composite 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | 5 | /** 6 | * The or validator checks if one of passed validators is returning true.

7 | * Validator's priority is maintained by index, the lower index is the higher priority. 8 | * Note: the message that will be shown is the one passed to the Constructor 9 | * 10 | */ 11 | class OrValidator(message: String, vararg validators: TextValidator) : CompositeValidator(message, *validators) { 12 | 13 | override fun isValid(text: String): Boolean { 14 | for (v in validators) 15 | if (v.isValid(text)) return true // Remember :) We're acting like an || operator. 16 | 17 | return false 18 | } 19 | 20 | } 21 | 22 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | android.enableJetifier=true 13 | android.useAndroidX=true 14 | org.gradle.jvmargs=-Xmx1536m 15 | 16 | # When configured, Gradle will run in incubating parallel mode. 17 | # This option should only be used with decoupled projects. More details, visit 18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 19 | # org.gradle.parallel=true 20 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/pattern/PatternValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.pattern 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | 5 | import java.util.regex.Pattern 6 | 7 | /** 8 | * Base class for regexp based validators. 9 | * 10 | * @see DomainValidator 11 | * 12 | * @see EmailValidator 13 | * 14 | * @see IpAddressValidator 15 | * 16 | * @see PhoneValidator 17 | * 18 | * @see WebUrlValidator 19 | */ 20 | open class PatternValidator(_customErrorMessage: String, private val pattern: Pattern) : TextValidator(_customErrorMessage) { 21 | 22 | constructor(errorMessage: String, regex: String) : this(errorMessage, Pattern.compile(regex)) 23 | 24 | override fun isValid(text: String): Boolean { 25 | return pattern.matcher(text).matches() 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sha/formvalidatorsample/presentation/AutoCompleteTextViewActivity.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidatorsample.presentation 2 | 3 | import android.app.Activity 4 | import android.os.Bundle 5 | import android.view.View 6 | import android.widget.Toast 7 | import com.sha.formvalidator.widget.FormAutoCompleteTextView 8 | import com.sha.formvalidatorsample.R 9 | 10 | class AutoCompleteTextViewActivity : Activity() { 11 | 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | setContentView(R.layout.activity_auto_complete) 15 | } 16 | 17 | fun onClickValidate(v: View) { 18 | val autoCompleteTv = findViewById(R.id.autoCompleteTv) 19 | if (autoCompleteTv.validate()) 20 | Toast.makeText(this, "Valid", Toast.LENGTH_LONG).show() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/TextViewAttrInfo.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview 2 | 3 | import android.content.Context 4 | import android.text.TextUtils 5 | import com.sha.formvalidator.R 6 | 7 | class TextViewAttrInfo { 8 | var errorMessage: String = "" 9 | var required = true 10 | var validationType: TextViewValidationType? = null 11 | var customValidationType: String = "" 12 | 13 | var regex: String = "" 14 | var dateFormat: String = "" 15 | 16 | var emptyErrorMessage: String = "" 17 | 18 | var minNumber: Int = 0 19 | var maxNumber: Int = 0 20 | 21 | var floatMinNumber: Float = 0f 22 | var floatMaxNumber: Float = 0f 23 | 24 | fun emptyErrorMessage(context: Context): String { 25 | return if (!TextUtils.isEmpty(emptyErrorMessage)) 26 | emptyErrorMessage else context.getString(R.string.required) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sha/formvalidatorsample/presentation/RxFormActivity.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidatorsample.presentation 2 | 3 | import android.app.Activity 4 | import android.os.Bundle 5 | import android.widget.Toast 6 | import com.sha.formvalidatorsample.R 7 | import io.reactivex.disposables.CompositeDisposable 8 | import kotlinx.android.synthetic.main.activity_form.* 9 | 10 | class RxFormActivity : Activity() { 11 | private val compositeDisposable = CompositeDisposable() 12 | 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | setContentView(R.layout.activity_form) 16 | 17 | form.validateOnClick(btnValidateFormLayout) { 18 | Toast.makeText(this, "Form result: $it", Toast.LENGTH_SHORT).show() 19 | } 20 | } 21 | 22 | override fun onDestroy() { 23 | super.onDestroy() 24 | compositeDisposable.dispose() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/com/sha/formvalidator/textview/validator/composite/AndValidator.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidator.textview.validator.composite 2 | 3 | import com.sha.formvalidator.textview.validator.TextValidator 4 | 5 | /** 6 | * The AND validator checks if all of the passed validators is returning true.

7 | * Note: the message that will be shown is the one of the first failing validator 8 | * 9 | */ 10 | class AndValidator(vararg validators: TextValidator) : CompositeValidator("", *validators) { 11 | 12 | override fun isValid(text: String): Boolean { 13 | val anyFails = validators.firstOrNull { !it.isValid(text) } 14 | anyFails?.let { 15 | // error message equals the first failing validator 16 | this.errorMessage = it.errorMessage 17 | return false // Remember :) We're acting like an && operator. 18 | } 19 | // true if no one fails 20 | return true 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sha/formvalidatorsample/util/SnackBarUtil.kt: -------------------------------------------------------------------------------- 1 | package com.sha.formvalidatorsample.util 2 | 3 | import android.os.Handler 4 | import android.view.View 5 | import android.widget.TextView 6 | 7 | import com.google.android.material.snackbar.Snackbar 8 | import com.sha.formvalidatorsample.R 9 | 10 | object SnackBarUtil { 11 | 12 | fun gotIt(view: View, text: String) { 13 | Handler().postDelayed({ 14 | multilineSnackbar( 15 | Snackbar.make( 16 | view, text, Snackbar.LENGTH_INDEFINITE) 17 | .setAction("Got it") { 18 | 19 | } 20 | ).show() 21 | }, 200) 22 | } 23 | 24 | private fun multilineSnackbar(snackbar: Snackbar): Snackbar { 25 | val textView = snackbar.view.findViewById(R.id.snackbar_text) 26 | textView.maxLines = 5 27 | return snackbar 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable/rect_border.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 12 | 15 | 16 | 22 | 23 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |