diff --git a/.github/workflows/Build.yaml b/.github/workflows/build.yaml similarity index 98% rename from .github/workflows/Build.yaml rename to .github/workflows/build.yaml index aa13e95..6b804dc 100644 --- a/.github/workflows/Build.yaml +++ b/.github/workflows/build.yaml @@ -1,4 +1,4 @@ -name: Build +name: build on: push: diff --git a/.github/workflows/doc.yaml b/.github/workflows/doc.yaml new file mode 100644 index 0000000..521fd6d --- /dev/null +++ b/.github/workflows/doc.yaml @@ -0,0 +1,28 @@ +name: doc +on: + push: + branches: + - master +permissions: + contents: write +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Configure Git Credentials + run: | + git config user.name github-actions[bot] + git config user.email 41898282+github-actions[bot]@users.noreply.github.com + - uses: actions/setup-python@v5 + with: + python-version: 3.x + - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV + - uses: actions/cache@v4 + with: + key: mkdocs-material-${{ env.cache_id }} + path: .cache + restore-keys: | + mkdocs-material- + - run: pip install mkdocs-material + - run: mkdocs gh-deploy --force \ No newline at end of file diff --git a/LICENSE b/LICENSE index 7fe4c9c..e4202d4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,13 @@ -MIT License +Copyright 2024 Devscast -Copyright (c) 2021 Devscast +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + http://www.apache.org/licenses/LICENSE-2.0 -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/detekt/config.yml b/detekt/config.yml index 3e738fc..3e96e8d 100644 --- a/detekt/config.yml +++ b/detekt/config.yml @@ -578,8 +578,8 @@ style: value: 'FIXME:' - reason: 'Forbidden STOPSHIP todo marker in comment, please address the problem before shipping the code.' value: 'STOPSHIP:' - - reason: 'Forbidden TODO todo marker in comment, please do the changes.' - value: 'TODO:' +# - reason: 'Forbidden TODO todo marker in comment, please do the changes.' +# value: 'TODO:' allowedPatterns: '' ForbiddenImport: active: false diff --git a/docs/coc.md b/docs/coc.md new file mode 100644 index 0000000..95f5a6f --- /dev/null +++ b/docs/coc.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at contact@devscast.tech. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..0bc1ef1 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,85 @@ +# Validable + +![kotlin-version](https://img.shields.io/badge/kotlin-1.9.20-blue) +[![](https://jitpack.io/v/devscast/validable.svg)](https://jitpack.io/#devscast/validable) +[![Build](https://github.com/devscast/validable/actions/workflows/Build.yaml/badge.svg)](https://github.com/devscast/validable/actions/workflows/build.yaml) + +Validating text fields when using jetpack compose can sometimes be challenging and verbose. + +Validable is an extensible library that allows you to validate your text fields in a simpler way while having a reusable code. + +```kotlin +@Composable +fun MyScreen() { + + val emailField = remember { EmailValidable() } + + TextField( + value = emailField.value, + onValueChange = { emailField.value = it }, // update the text + isError = emailField.hasError(), // check if the field is not valid + ) + + AnimatedVisibility(visible = emailField.hasError()) { + + Text( + text = emailField.errorMessage ?: "", + modifier = Modifier.fillMaxWidth(), + style = LocalTextStyle.current.copy(color = MaterialTheme.colors.error) + ) + + } + + Button(onClick = { + // pass all fields to the withValidable method + withValidable(emailField) { + + // will be executed if all fields are valid + Toast.makeText(context,"All fields are valid",Toast.LENGTH_SHORT).show() + + } + }) { + Text(text = "Submit") + } +} +``` + +## Installation + +**Step 1.** Add the JitPack repository to your build file + +Add it in your root build.gradle at the end of repositories: + +```groovy +allprojects { + repositories { + ... + maven { url 'https://jitpack.io' } + } +} +``` + +**Step 2.** Add the dependency + +```groovy +dependencies { + implementation 'com.github.devscast:validable:x.y.z' +} +``` + +License +-------- + + Copyright 2024 Devscast Community. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/docs/validables/cardscheme.md b/docs/validables/cardscheme.md new file mode 100644 index 0000000..d62b0db --- /dev/null +++ b/docs/validables/cardscheme.md @@ -0,0 +1,24 @@ +Validates that a card number belongs to a specified scheme. + +```kotlin + +// Validate if a text is a MasterCard number +val cardField = CardSchemeValidable( + CardScheme.MasterCard, + "Only MasterCard is supported" +) + +// Supporting multiple cardScheme +val multipleCardField = CardSchemeValidable( + CardScheme.MasterCard,CardScheme.Visa, + "Only MasterCard and Visa are supported" +) + +// Merging multiple CardSchemes into one +val mixedCardScheme = CardScheme.merge(CardScheme.MasterCard, CardScheme.Visa) + +val multipleCardField = CardSchemeValidable( + mixedCardScheme, + "Only MasterCard and Visa are supported" +) +``` \ No newline at end of file diff --git a/docs/validables/email.md b/docs/validables/email.md new file mode 100644 index 0000000..46c9e17 --- /dev/null +++ b/docs/validables/email.md @@ -0,0 +1,5 @@ +Validates that a value is a valid email address. + +```kotlin +val emailField = EmailValidable("invalid email") +``` \ No newline at end of file diff --git a/docs/validables/equal_to.md b/docs/validables/equal_to.md new file mode 100644 index 0000000..d76b9b8 --- /dev/null +++ b/docs/validables/equal_to.md @@ -0,0 +1,11 @@ +Validates that a value is equal to the specified value + +```kotlin + +val comparedValue = "Hello World" + +val textField = EqualToValidable( + comparedValue, + "The value does not match $comparedValue" +) +``` \ No newline at end of file diff --git a/docs/validables/greater_than.md b/docs/validables/greater_than.md new file mode 100644 index 0000000..e8eb29a --- /dev/null +++ b/docs/validables/greater_than.md @@ -0,0 +1,10 @@ +Validates that a value is numerically greater than the specified value. + +```kotlin +val comparedValue = 10 + +val numberField = GreaterThanValidable( + comparedValue, + "The value must be > $comparedValue" +) +``` diff --git a/docs/validables/greater_than_or_equal.md b/docs/validables/greater_than_or_equal.md new file mode 100644 index 0000000..6ebae1d --- /dev/null +++ b/docs/validables/greater_than_or_equal.md @@ -0,0 +1,10 @@ +Validates that a value is numerically greater than or equal to the specified value. + +```kotlin +val minAge = 18 + +val ageTextField = GreaterThanOrEqualValidable( + minAge, + "The minimum allowed age is $minAge" +) +``` \ No newline at end of file diff --git a/docs/validables/host_name.md b/docs/validables/host_name.md new file mode 100644 index 0000000..5fdaa15 --- /dev/null +++ b/docs/validables/host_name.md @@ -0,0 +1,10 @@ +Validates that the given value is a valid host name + +```kotlin +val domainNameField = HostnameValidable( + "Invalid domain name" +) +``` + +> According to [RFC 2606](https://www.rfc-editor.org/rfc/rfc2606.html), top-level domains (TLD) : `.example`, `.invalid`, `.localhost`, and `.test` are reserved +and that's why hostnames containing them are not considered valid. \ No newline at end of file diff --git a/docs/validables/ip.md b/docs/validables/ip.md new file mode 100644 index 0000000..8794edd --- /dev/null +++ b/docs/validables/ip.md @@ -0,0 +1,7 @@ +Validates that a value is a valid IP address + +```kotlin +val ipTextField = IpValidable("Not a valid IP address") +``` + +> **Note** : Currently, IPv6 addresses are not supported. \ No newline at end of file diff --git a/docs/validables/less_than.md b/docs/validables/less_than.md new file mode 100644 index 0000000..bdc5125 --- /dev/null +++ b/docs/validables/less_than.md @@ -0,0 +1,11 @@ +Validates that a value is numerically less than the specified value. + +```kotlin +val limit = 18 + +val numberTextField = LessThanValidable( + limit, + "The value must be < $limit" +) + +``` \ No newline at end of file diff --git a/docs/validables/less_than_or_equal.md b/docs/validables/less_than_or_equal.md new file mode 100644 index 0000000..64b62e0 --- /dev/null +++ b/docs/validables/less_than_or_equal.md @@ -0,0 +1,10 @@ +Validates that a value is numerically less than or equal to the specified value. + +```kotlin +val max = 9 + +val numberTextField = LessThanOrEqualValidable( + max, + "The value must be <= $max" +) +``` \ No newline at end of file diff --git a/docs/validables/negative.md b/docs/validables/negative.md new file mode 100644 index 0000000..7eeb594 --- /dev/null +++ b/docs/validables/negative.md @@ -0,0 +1,5 @@ +Validates that a value is a negative number. + +```kotlin +val numberField = NegativeValidable("The value must be < 0") +``` \ No newline at end of file diff --git a/docs/validables/negative_or_zero.md b/docs/validables/negative_or_zero.md new file mode 100644 index 0000000..da0dfd6 --- /dev/null +++ b/docs/validables/negative_or_zero.md @@ -0,0 +1,5 @@ +Validates that a value is a negative number or equal to zero. + +```kotlin +val numberField = NegativeOrZeroValidable("The value must be <= 0") +``` \ No newline at end of file diff --git a/docs/validables/not_blank.md b/docs/validables/not_blank.md new file mode 100644 index 0000000..4690b88 --- /dev/null +++ b/docs/validables/not_blank.md @@ -0,0 +1,5 @@ +Validates that the value is not blank - neither empty string nor whitespace are valid + +```kotlin +val textField = NotBlankValidable("This field cannot be blank") +``` \ No newline at end of file diff --git a/docs/validables/not_empty.md b/docs/validables/not_empty.md new file mode 100644 index 0000000..ff6cc59 --- /dev/null +++ b/docs/validables/not_empty.md @@ -0,0 +1,5 @@ +Validates that a value is not empty and contains some characters or whitespace characters. + +```kotlin +val textField = NotBlankValidable("This field cannot be blank") +``` \ No newline at end of file diff --git a/docs/validables/not_equal.md b/docs/validables/not_equal.md new file mode 100644 index 0000000..e48d63d --- /dev/null +++ b/docs/validables/not_equal.md @@ -0,0 +1,10 @@ +Validates that a value is not equal to the specified value + +```kotlin +val notAcceptedNumber = 7 + +val numberTextField = NotEqualToValidable( + notAcceptedNumber, + "The value must be different from $notAcceptedNumber" +) +``` \ No newline at end of file diff --git a/docs/validables/positive.md b/docs/validables/positive.md new file mode 100644 index 0000000..7df5162 --- /dev/null +++ b/docs/validables/positive.md @@ -0,0 +1,5 @@ +Validates that a value is a positive number. + +```kotlin +val numberField = PositiveValidable("The value must be > 0") +``` \ No newline at end of file diff --git a/docs/validables/positive_or_zero.md b/docs/validables/positive_or_zero.md new file mode 100644 index 0000000..28e1658 --- /dev/null +++ b/docs/validables/positive_or_zero.md @@ -0,0 +1,5 @@ +Validates that a value is a positive number or equal to zero. + +```kotlin +val numberField = PositiveOrZeroValidable("The value must be >= 0") +``` \ No newline at end of file diff --git a/docs/validables/range.md b/docs/validables/range.md new file mode 100644 index 0000000..1eab688 --- /dev/null +++ b/docs/validables/range.md @@ -0,0 +1,7 @@ +Validates that a given number is between some minimum and maximum. + +```kotlin +val valueTextFiel = RangeValidable(0,9,"The value must be >= 0 and <= 9") +``` + +> **Note** : The range is inclusive \ No newline at end of file diff --git a/docs/validables/regex.md b/docs/validables/regex.md new file mode 100644 index 0000000..136abc2 --- /dev/null +++ b/docs/validables/regex.md @@ -0,0 +1,7 @@ +Validates that a value matches a regular expression. + +```kotlin +val pattern = "^[0-9]+$" + +val textField = RegexValidable(pattern,"This value is not valid.") +``` \ No newline at end of file diff --git a/docs/validables/url.md b/docs/validables/url.md new file mode 100644 index 0000000..27a0f52 --- /dev/null +++ b/docs/validables/url.md @@ -0,0 +1,5 @@ +Validates that a value is a valid URL string. + +```kotlin +val numberField = UrlValidable("This value is not a valid URL.") +``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..0014765 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,86 @@ +# yaml-language-server: $schema=https://squidfunk.github.io/mkdocs-material/schema.json + +# pip install mkdocs mkdocs-material +# mkdocs serve +# mkdocs gh-deploy + +site_name: Validable +repo_name: Validable +repo_url: https://github.com/devscast/validable +site_description: "An easy-to-use text field validator for Kotlin & Jetpack compose." +site_author: Devscast +remote_branch: gh-pages + +copyright: 'Copyright © 2024 Devscast Community' + +theme: + name: 'material' + palette: + - media: '(prefers-color-scheme: light)' + scheme: default + primary: 'white' + accent: 'yellow' + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - media: '(prefers-color-scheme: dark)' + scheme: slate + primary: 'black' + accent: 'yellow' + toggle: + icon: material/brightness-4 + name: Switch to light mode + font: + text: 'Lato' + code: 'Fira Code' + features: + - content.code.copy + - content.code.select + +markdown_extensions: + - smarty + - codehilite: + guess_lang: false + - footnotes + - meta + - toc: + permalink: true + - pymdownx.betterem: + smart_enable: all + - pymdownx.caret + - pymdownx.inlinehilite + - pymdownx.magiclink + - pymdownx.smartsymbols + - pymdownx.superfences + - pymdownx.emoji + - pymdownx.tabbed: + alternate_style: true + - tables + - admonition + - attr_list + - md_in_html + +nav: + - 'Get Started': index.md + - 'Built in validables': + - 'CardSchemeValidable' : validables/cardscheme.md + - 'Email' : validables/email.md + - 'Equal To' : validables/equal_to.md + - 'Greater Than Or Equal' : validables/greater_than_or_equal.md + - 'Greater Than' : validables/greater_than.md + - 'HostName' : validables/host_name.md + - 'IP Address' : validables/ip.md + - validables/less_than.md + - validables/less_than_or_equal.md + - validables/negative_or_zero.md + - validables/negative.md + - validables/not_blank.md + - validables/not_empty.md + - validables/not_equal.md + - validables/positive.md + - validables/positive_or_zero.md + - validables/range.md + - validables/regex.md + - validables/url.md + + - 'Code of conduct': coc.md \ No newline at end of file diff --git a/sample/src/main/java/tech/devscast/validable/sample/ui/screens/InputScreen.kt b/sample/src/main/java/tech/devscast/validable/sample/ui/screens/InputScreen.kt index 5285d37..592a305 100644 --- a/sample/src/main/java/tech/devscast/validable/sample/ui/screens/InputScreen.kt +++ b/sample/src/main/java/tech/devscast/validable/sample/ui/screens/InputScreen.kt @@ -22,6 +22,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import tech.devscast.validable.CardScheme +import tech.devscast.validable.CardSchemeValidable import tech.devscast.validable.EmailValidable import tech.devscast.validable.NotEmptyValidable import tech.devscast.validable.withValidable @@ -34,6 +36,14 @@ fun InputScreen() { val emailField = remember { EmailValidable() } val nameField = remember { NotEmptyValidable() } + val cardField = remember { CardSchemeValidable(CardScheme.MasterCard,) } + val multipleCardField = remember { + CardSchemeValidable( + CardScheme.merge(CardScheme.MasterCard, CardScheme.Visa), + message = "Invalid Card" + ) + } + Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, diff --git a/validable/build.gradle.kts b/validable/build.gradle.kts index ee7a9a4..6a5cad8 100644 --- a/validable/build.gradle.kts +++ b/validable/build.gradle.kts @@ -3,7 +3,6 @@ plugins { id("org.jetbrains.kotlin.android") id("maven-publish") id("io.gitlab.arturbosch.detekt") version "1.23.6" - id("org.jetbrains.dokka") version "1.9.20" id("org.jetbrains.kotlinx.binary-compatibility-validator") version "0.14.0" } @@ -24,7 +23,10 @@ android { buildTypes { release { isMinifyEnabled = false - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) } } @@ -51,12 +53,11 @@ android { } dependencies { - implementation("androidx.core:core-ktx:1.13.0") + implementation("androidx.core:core-ktx:1.13.1") implementation(platform("androidx.compose:compose-bom:2024.04.01")) implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.compose.ui:ui") testImplementation("junit:junit:4.13.2") - dokkaPlugin("org.jetbrains.dokka:android-documentation-plugin:1.9.20") } publishing { diff --git a/validable/src/main/java/tech/devscast/validable/BaseValidable.kt b/validable/src/main/java/tech/devscast/validable/BaseValidable.kt index 7a16dd3..3462987 100644 --- a/validable/src/main/java/tech/devscast/validable/BaseValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/BaseValidable.kt @@ -4,26 +4,59 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +/** + * Base class for implementing custom validations on string values. + * + * This class provides core functionalities for validation, including storing the value, + * checking validity based on a provided [validator] function, and retrieving error messages. + * Subclasses can inherit from this class and override the [validator] and [errorFor] lambdas + * to implement specific validation rules and error messages for their needs. + * + */ open class BaseValidable( private val validator: (String) -> Boolean = { true }, private val errorFor: (String) -> String = { "" } ) { + /** Value to be used by the text field */ + //(must be state to trigger recomposition) var value: String by mutableStateOf("") + + /** The error message if any */ val errorMessage: String? get() = getError() + /** + * Flag to control displaying validation errors. + * + * determines whether validation error messages are shown. + * By default, it's set to false, be cause we can't show the errors when the form is not submitted yet. + * + * Uses [enableShowErrors] to enable error display. + */ private var displayErrors: Boolean by mutableStateOf(false) + /** + * calls the `validator` lambda with the current `value` to check validity. + */ val isValid: Boolean get() = validator(value) + /** + * Enables displaying validation errors. + * Called when the form is submitted + */ fun enableShowErrors() { displayErrors = true } + + /** + * Checks if there's a validation error and errors are enabled for display. + */ fun hasError() = !isValid && displayErrors + /** Retrieves error message passed through [errorFor] */ private fun getError(): String? { return if (hasError()) { errorFor(value) diff --git a/validable/src/main/java/tech/devscast/validable/CardSchemeValidable.kt b/validable/src/main/java/tech/devscast/validable/CardSchemeValidable.kt index 44bf817..009c3b7 100644 --- a/validable/src/main/java/tech/devscast/validable/CardSchemeValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/CardSchemeValidable.kt @@ -4,6 +4,11 @@ import java.util.regex.Pattern /** * Validates that a card number belongs to a specified scheme. + * + * @param scheme + * The [CardScheme] to validate against. + * @param message + * (Optional) Custom error message for validation failure. */ class CardSchemeValidable(vararg schemes: CardScheme, message: String? = null) : BaseValidable( validator = { value -> @@ -16,12 +21,30 @@ class CardSchemeValidable(vararg schemes: CardScheme, message: String? = null) : ) /** + * Represents a card scheme for validation purposes. + * + * A `CardScheme` defines a set of regular expressions used to identify card numbers belonging + * to a specific payment network (e.g., Visa, Mastercard). This class provides a way to validate + * card numbers against these predefined patterns. + * * see https://en.wikipedia.org/wiki/Payment_card_number * see https://www.regular-expressions.info/creditcard.html + * + *@param patterns A list of regular expressions that match valid card numbers for this scheme. */ open class CardScheme protected constructor(val patterns: List) { companion object { + /** + * Merges multiple card schemes into a single one. + * + * This static method combines the regular expression patterns from all the provided + * `CardScheme` objects into a single list. This allows for validating cards against a combination + * of schemes. + * + * @param schemes The `CardScheme` objects to be merged. + * @return A new `CardScheme` object containing the combined patterns. + */ fun merge(vararg schemes: CardScheme): CardScheme { return CardScheme(schemes.flatMap { scheme -> scheme.patterns }) } diff --git a/validable/src/main/java/tech/devscast/validable/EmailValidable.kt b/validable/src/main/java/tech/devscast/validable/EmailValidable.kt index 7f69321..942b857 100644 --- a/validable/src/main/java/tech/devscast/validable/EmailValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/EmailValidable.kt @@ -4,7 +4,10 @@ import java.util.regex.Pattern /** * Validates that a value is a valid email address. - */ + * + * @param message + * (Optional) Custom error message for validation failure. +*/ class EmailValidable(message: String? = null) : BaseValidable( validator = { value -> Pattern.matches("^[A-Za-z](.*)([@]{1})(.+)(\\.)(.+)", value) diff --git a/validable/src/main/java/tech/devscast/validable/EqualToValidable.kt b/validable/src/main/java/tech/devscast/validable/EqualToValidable.kt index a29ed6c..71a70b1 100644 --- a/validable/src/main/java/tech/devscast/validable/EqualToValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/EqualToValidable.kt @@ -1,8 +1,14 @@ package tech.devscast.validable /** - * Validates that a value is equal to another value, - * To force that a value is not equal, see [NotEqualToValidable]. + * Validates that a value is equal to the specified value, + * + * @param comparedValue + * The value to compare against. + * @param message + * (Optional) Custom error message for validation failure. + * + * @see [NotEqualToValidable]. */ class EqualToValidable(comparedValue: String, message: String? = null) : BaseValidable( validator = { value -> value === comparedValue }, diff --git a/validable/src/main/java/tech/devscast/validable/GreaterThanOrEqualValidable.kt b/validable/src/main/java/tech/devscast/validable/GreaterThanOrEqualValidable.kt index 78f3809..84d9054 100644 --- a/validable/src/main/java/tech/devscast/validable/GreaterThanOrEqualValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/GreaterThanOrEqualValidable.kt @@ -1,8 +1,14 @@ package tech.devscast.validable /** - * Validates that a value is greater than or equal to another value. - * To force that a value is greater than another value, see [GreaterThanValidable]. + * Validates that a value is numerically greater than or equal to the specified value. + * + * @param comparedValue + * The value to compare against. + * @param message + * (Optional) Custom error message for validation failure. + * + * @see GreaterThanValidable */ class GreaterThanOrEqualValidable(comparedValue: Int, message: String? = null) : BaseValidable( validator = { value -> diff --git a/validable/src/main/java/tech/devscast/validable/GreaterThanValidable.kt b/validable/src/main/java/tech/devscast/validable/GreaterThanValidable.kt index 5227e75..192ba23 100644 --- a/validable/src/main/java/tech/devscast/validable/GreaterThanValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/GreaterThanValidable.kt @@ -1,10 +1,16 @@ package tech.devscast.validable /** - * Validates that a value is greater than another value - * To force that a value is greater than or equal to another value, see [GreaterThanOrEqualValidable]. - * To force a value is less than another value, see [LessThanValidable]. - */ + * Validates that a value is numerically greater than the specified value. + * + * @param comparedValue + * The value to compare against. + * @param message + * (Optional) Custom error message for validation failure. + * + * @see GreaterThanOrEqualValidable + * @see LessThanValidable +*/ class GreaterThanValidable(comparedValue: Int, message: String? = null) : BaseValidable( validator = { value -> try { diff --git a/validable/src/main/java/tech/devscast/validable/HostnameValidable.kt b/validable/src/main/java/tech/devscast/validable/HostnameValidable.kt index c31c0f3..7141f07 100644 --- a/validable/src/main/java/tech/devscast/validable/HostnameValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/HostnameValidable.kt @@ -7,10 +7,14 @@ private const val HOSTNAME_PATTERN = /** * Validates that the given value is a valid host name - * To forces that value is an IP address see [IpValidable] * * The following top-level domains (TLD) are reserved according to RFC 2606 * and that's why hostnames containing them are not considered valid: .example, .invalid, .localhost, and .test. + * + * @param message + * (Optional) Custom error message for validation failure. + * + * @see [IpValidable] */ class HostnameValidable(message: String? = null) : BaseValidable( validator = { value -> Pattern.matches(HOSTNAME_PATTERN, value) }, diff --git a/validable/src/main/java/tech/devscast/validable/IpValidable.kt b/validable/src/main/java/tech/devscast/validable/IpValidable.kt index 9598e05..9e4bc2e 100644 --- a/validable/src/main/java/tech/devscast/validable/IpValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/IpValidable.kt @@ -6,8 +6,15 @@ private const val IP_V4_PATTERN = "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\ /** * Validates that a value is a valid IP address - * TODO: add support for IP v6 + * + * **Note** : Currently, IPv6 addresses are not supported. + * + * @param message + * Optional) Custom error message for validation failure. + * + * @see HostnameValidable */ +// TODO: add support for IP v6 class IpValidable(message: String? = null) : BaseValidable( validator = { value -> Pattern.matches(IP_V4_PATTERN, value) }, errorFor = { value -> message ?: "$value is not a valid IP address." } diff --git a/validable/src/main/java/tech/devscast/validable/LessThanOrEqualValidable.kt b/validable/src/main/java/tech/devscast/validable/LessThanOrEqualValidable.kt index 60f9503..3ba6397 100644 --- a/validable/src/main/java/tech/devscast/validable/LessThanOrEqualValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/LessThanOrEqualValidable.kt @@ -1,9 +1,16 @@ package tech.devscast.validable /** - * Validates that a value is less than or equal to another value. - * To force that a value is less than another value, see [LessThanValidable]. + * Validates that a value is numerically less than or equal to the specified value. + * + * @param comparedValue + * The value to compare against. + * @param message + * (Optional) Custom error message for validation failure. + * + * @see LessThanValidable */ + class LessThanOrEqualValidable(comparedValue: Int, message: String? = null) : BaseValidable( validator = { value -> try { diff --git a/validable/src/main/java/tech/devscast/validable/LessThanValidable.kt b/validable/src/main/java/tech/devscast/validable/LessThanValidable.kt index c028b2c..73f0778 100644 --- a/validable/src/main/java/tech/devscast/validable/LessThanValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/LessThanValidable.kt @@ -1,9 +1,15 @@ package tech.devscast.validable /** - * Validates that a value is less than another value. - * To force that a value is less than or equal to another value, see [LessThanOrEqualValidable]. - * To force a value is greater than another value, see [GreaterThanValidable]. + * Validates that a value is numerically less than the specified value. + * + * @param comparedValue + * The value to compare against. + * @param message + * (Optional) Custom error message for validation failure. + * + * @see LessThanOrEqualValidable + * @see GreaterThanValidable */ class LessThanValidable(comparedValue: Int, message: String? = null) : BaseValidable( validator = { value -> diff --git a/validable/src/main/java/tech/devscast/validable/NegativeOrZeroValidable.kt b/validable/src/main/java/tech/devscast/validable/NegativeOrZeroValidable.kt index 27cec8e..fc4114b 100644 --- a/validable/src/main/java/tech/devscast/validable/NegativeOrZeroValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/NegativeOrZeroValidable.kt @@ -2,7 +2,11 @@ package tech.devscast.validable /** * Validates that a value is a negative number or equal to zero. - * If you don't want to allow zero as value, use [NegativeValidable] instead. + * + * @param message + * (Optional) Custom error message for validation failure. + * + * @see NegativeValidable */ class NegativeOrZeroValidable(message: String? = null) : BaseValidable( validator = { value -> diff --git a/validable/src/main/java/tech/devscast/validable/NegativeValidable.kt b/validable/src/main/java/tech/devscast/validable/NegativeValidable.kt index 1e011b0..40c7796 100644 --- a/validable/src/main/java/tech/devscast/validable/NegativeValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/NegativeValidable.kt @@ -2,8 +2,11 @@ package tech.devscast.validable /** * Validates that a value is a negative number. - * Zero is neither positive nor negative, - * so you must use [NegativeOrZeroValidable] if you want to allow zero as value. + * + * @param message + * (Optional) Custom error message for validation failure. + * + * @see NegativeOrZeroValidable */ class NegativeValidable(message: String? = null) : BaseValidable( validator = { value -> diff --git a/validable/src/main/java/tech/devscast/validable/NotBlankValidable.kt b/validable/src/main/java/tech/devscast/validable/NotBlankValidable.kt index 196db13..2650b21 100644 --- a/validable/src/main/java/tech/devscast/validable/NotBlankValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/NotBlankValidable.kt @@ -1,7 +1,7 @@ package tech.devscast.validable /** - * Validates that the value is not blank - empty string or whitespace are not valid + * Validates that the value is not blank - neither empty string nor whitespace are valid */ class NotBlankValidable(message: String? = null) : BaseValidable( validator = { value -> value.isNotBlank() }, diff --git a/validable/src/main/java/tech/devscast/validable/NotEmptyValidable.kt b/validable/src/main/java/tech/devscast/validable/NotEmptyValidable.kt index 39529f9..1e349bb 100644 --- a/validable/src/main/java/tech/devscast/validable/NotEmptyValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/NotEmptyValidable.kt @@ -1,7 +1,10 @@ package tech.devscast.validable /** - * Validates that a value is not empty - blank strings are valid. + * Validates that a value is not empty and contains some characters or whitespace characters. + * + * @param message + * (Optional) Custom error message for validation failure. */ class NotEmptyValidable(message: String? = null) : BaseValidable( validator = { value -> value.isNotEmpty() }, diff --git a/validable/src/main/java/tech/devscast/validable/NotEqualToValidable.kt b/validable/src/main/java/tech/devscast/validable/NotEqualToValidable.kt index 69dee43..c5c4a44 100644 --- a/validable/src/main/java/tech/devscast/validable/NotEqualToValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/NotEqualToValidable.kt @@ -1,8 +1,14 @@ package tech.devscast.validable /** - * Validates that a value is not equal to another value, - * To force that a value is equal, see [EqualToValidable]. + * Validates that a value is not equal to the specified value, + * + * @param comparedValue + * The value to compare against. + * @param message + * (Optional) Custom error message for validation failure. + * + * @see EqualToValidable */ class NotEqualToValidable(comparedValue: String, message: String? = null) : BaseValidable( validator = { value -> value !== comparedValue }, diff --git a/validable/src/main/java/tech/devscast/validable/PositiveOrZeroValidable.kt b/validable/src/main/java/tech/devscast/validable/PositiveOrZeroValidable.kt index 6dc711d..7627867 100644 --- a/validable/src/main/java/tech/devscast/validable/PositiveOrZeroValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/PositiveOrZeroValidable.kt @@ -2,7 +2,11 @@ package tech.devscast.validable /** * Validates that a value is a positive number or equal to zero. - * If you don't want to allow zero as value, use [PositiveValidable] instead. + * + * @param message + * (Optional) Custom error message for validation failure. + * + * @see PositiveValidable */ class PositiveOrZeroValidable(message: String? = null) : BaseValidable( validator = { value -> diff --git a/validable/src/main/java/tech/devscast/validable/PositiveValidable.kt b/validable/src/main/java/tech/devscast/validable/PositiveValidable.kt index 5d79648..b20b35e 100644 --- a/validable/src/main/java/tech/devscast/validable/PositiveValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/PositiveValidable.kt @@ -2,8 +2,11 @@ package tech.devscast.validable /** * Validates that a value is a positive number. - * Zero is neither positive nor negative, - * so you must use [PositiveOrZeroValidable] if you want to allow zero as value. + * + * @param message + * (Optional) Custom error message for validation failure. + * + * @see PositiveOrZeroValidable */ class PositiveValidable(message: String? = null) : BaseValidable( validator = { value -> diff --git a/validable/src/main/java/tech/devscast/validable/RangeValidable.kt b/validable/src/main/java/tech/devscast/validable/RangeValidable.kt index 3ad83ea..96c19df 100644 --- a/validable/src/main/java/tech/devscast/validable/RangeValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/RangeValidable.kt @@ -2,6 +2,13 @@ package tech.devscast.validable /** * Validates that a given number is between some minimum and maximum. + * + * @param minValue + * The minimum allowed value. + * @param maxValue + * The maximum allowed value. + * @param message + * (Optional) Custom error message for validation failure. */ class RangeValidable(minValue: Int, maxValue: Int, message: String? = null) : BaseValidable( validator = { value -> diff --git a/validable/src/main/java/tech/devscast/validable/RegexValidable.kt b/validable/src/main/java/tech/devscast/validable/RegexValidable.kt index 2b9e0cb..c16955e 100644 --- a/validable/src/main/java/tech/devscast/validable/RegexValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/RegexValidable.kt @@ -4,6 +4,11 @@ import java.util.regex.Pattern /** * Validates that a value matches a regular expression. + * + * @param pattern + * The regular expression pattern to match against. + * @param message + * (Optional) Custom error message for validation failure. */ class RegexValidable(pattern: String, message: String? = null) : BaseValidable( validator = { value -> Pattern.matches(pattern, value) }, diff --git a/validable/src/main/java/tech/devscast/validable/UrlValidable.kt b/validable/src/main/java/tech/devscast/validable/UrlValidable.kt index 4435834..f0b220d 100644 --- a/validable/src/main/java/tech/devscast/validable/UrlValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/UrlValidable.kt @@ -5,6 +5,11 @@ import java.net.URL /** * Validates that a value is a valid URL string. + * + * @param message + * (Optional) Custom error message for validation failure. + * + * @see HostnameValidable */ class UrlValidable(message: String? = null) : BaseValidable( validator = { value -> diff --git a/validable/src/main/java/tech/devscast/validable/WithValidable.kt b/validable/src/main/java/tech/devscast/validable/WithValidable.kt index a902569..ff54ed5 100644 --- a/validable/src/main/java/tech/devscast/validable/WithValidable.kt +++ b/validable/src/main/java/tech/devscast/validable/WithValidable.kt @@ -1,5 +1,13 @@ package tech.devscast.validable +/** + * Executes a given block of code only if all provided validables are valid. + * + * @param fields + * A variable number validables objects to validate. + * @param next + * the block of code to execute if all validations pass. + */ fun withValidable(vararg fields: BaseValidable, next: () -> Unit) { val errors: List = fields.map { it.enableShowErrors()