Compare commits

..
7 changed files with 56 additions and 5 deletions

View file

@ -6,6 +6,6 @@ plugins {
}
allprojects {
version = "0.3.3"
version = "0.4.0"
group = "de.thetadev.formconductor"
}

View file

@ -9,7 +9,7 @@ import de.thetadev.formconductor.FieldResult
*
* @param V type of field value
*/
interface FormFieldScope<V : Any?> {
interface FormFieldScope<V> {
/**
* Observable State instance of field value
@ -30,7 +30,19 @@ interface FormFieldScope<V : Any?> {
*
* You're encouraged to set the field value only using this function
*
* @param input input value
* @param input Field value
* @param validate Validate the input on update
*/
fun setField(input: V?, validate: Boolean = true)
/**
* A setter function for field value or error.
*
* Set the field value if the input is successful, fail validation if the input is an error.
*
* To be used for custom fields with built-in validation.
*
* @param input Field value or error
*/
fun setFieldResult(input: Result<V?>)
}

View file

@ -21,4 +21,8 @@ internal class FormFieldScopeImpl<V>(
override fun setField(input: V?, validate: Boolean) {
formField.setField(input, validate)
}
override fun setFieldResult(input: Result<V?>) {
formField.setFieldResult(input)
}
}

View file

@ -50,10 +50,22 @@ interface FormField<V> {
*
* The function validates the field if the input is not **empty** or the field isn't **optional**
*
* @param input
* @param input Field value
* @param validate Validate the input on update
*/
fun setField(input: V?, validate: Boolean = true)
/**
* A setter function for field value or error.
*
* Set the field value if the input is successful, fail validation if the input is an error.
*
* To be used for custom fields with built-in validation.
*
* @param input Field value or error
*/
fun setFieldResult(input: Result<V?>)
/**
* Validate the field without updating its value
*

View file

@ -1,6 +1,7 @@
package de.thetadev.formconductor
import de.thetadev.formconductor.validation.optionalFlags.OptionalFlag
import de.thetadev.formconductor.validation.rules.ExternalValidationErrorRule
import de.thetadev.formconductor.validation.rules.OptionalRule
import de.thetadev.formconductor.validation.validators.FieldValidator
import de.thetadev.formconductor.validation.validators.StatelessFieldValidator
@ -48,6 +49,7 @@ internal class FormFieldImpl<T : Any, V>(
valueStream.value = input ?: defaultValue
if (validate) {
if (hasExternalValidationError()) resultStream.value = FieldResult.NoInput
validateField()
} else if (input == null || input == "") {
resultStream.value = FieldResult.NoInput
@ -56,10 +58,23 @@ internal class FormFieldImpl<T : Any, V>(
}
}
override fun setFieldResult(input: Result<V?>) {
input.fold(
onSuccess = { setField(it) },
onFailure = {
resultStream.value =
FieldResult.Error("Validation error", ExternalValidationErrorRule)
}
)
}
/**
* Validates the current input value and updates the field's result
*/
override fun validateField(soft: Boolean) {
if (hasExternalValidationError()) {
return
}
val input = valueStream.value
// Null and empty strings are skipped for validation
if (input != null && input != "") {
@ -110,4 +125,9 @@ internal class FormFieldImpl<T : Any, V>(
optionalStateEvaluators.all(OptionalFlag::evaluate)
}
}
private fun hasExternalValidationError(): Boolean {
val result = resultStream.value
return result is FieldResult.Error && result.failedRule is ExternalValidationErrorRule
}
}

View file

@ -0,0 +1,3 @@
package de.thetadev.formconductor.validation.rules
object ExternalValidationErrorRule : ValidationRule

View file

@ -1,5 +1,5 @@
[versions]
agp = "9.4.0"
agp = "9.4.1"
kotlinReflect = "1.7.10"
kotlin = "2.4.10"
kotlinxCoroutinesCore = "1.11.0"