Skip to content

Latest commit

 

History

History
200 lines (157 loc) · 10.2 KB

README.md

File metadata and controls

200 lines (157 loc) · 10.2 KB

CarlosFormito

Carlos Logo

Easy form state management for Jetpack Compose.

Introduction

Working with forms in your application? Carlos can be your ultimate wingman.
While building forms might seem straightforward, a closer look reveals the need to manage:

  1. Validation strategies
  2. Field state changes
  3. Cross-field dependencies, and more...

"I don't want to reinvent the wheel.
Many common user flows and use cases appear across mobile applications."


There’s an effective solution for this, right? - The answer is yes!
Carlos handles the heavy lifting so you can focus on creating forms effectively and quickly.

Adding Carlos to Your project

repositories {
    mavenCentral()
}

dependencies {
    // Carlos core functionality
    implementation("com.icell.external.carlosformito:carlosformito-core:$carlos_version")

    // Carlos built-in FormFields for material3 (optional usage)
    implementation("com.icell.external.carlosformito:carlosformito-material3:$carlos_version")

    // Carlos built-in FormFields for material (optional usage)
    implementation("com.icell.external.carlosformito:carlosformito-material:$carlos_version")
}

Using Carlos

// Define the form fields, initial states and it's validators
val formFields = listOf(
    FormField(
        id = KEY_USERNAME,
        validators = listOf(
            ValueRequiredValidator(R.string.value_required_error),
            TextMinLengthValidator(minLength = 3, R.string.min_length_error)
        )
    ),
    FormField(
        id = KEY_PASSWORD,
        validators = listOf(
            ValueRequiredValidator(R.string.value_required_error),
            TextMinLengthValidator(minLength = 8)
        )
    )
)

// Initialize the form manager with the fields and a validation strategy
val formManager = CarlosFormManager(formFields, FormFieldValidationStrategy.MANUAL)

// Implement a form using the formManager
@Composable
fun LoginForm(formManager: FormManager) {
    val scope = rememberCoroutineScope()

    // Initialize the form manager
    LaunchedEffect(Unit) {
        formManager.initFormManager()
    }

    Column {

        // Bind the FieldItem to the FormField composable
        FormTextField(
            fieldItem = formManager.getFieldItem(KEY_USERNAME),
            label = {
                Text("Name*")
            },
            supportingText = "Please enter your username."
        )

        FormPasswordTextField(
            fieldItem = formManager.getFieldItem(KEY_PASSWORD),
            label = {
                Text("Password*")
            },
            supportingText = "Please enter your password."
        )

        Button(
            onClick = {
                // Validate the form when clicking the submit button
                scope.launch {
                    formManager.validateForm()
                }
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Submit")
        }
    }
}

Steps to build a Carlos form

  1. Define FormField elements, specifying field keys, initial states, and validators.
  2. Create a CarlosFormManager, configure it with the fields, and select a validation strategy.
  3. Build a Composable form UI using Carlos's built-in fields or your custom fields.
  4. Bind FieldItems to the respective UI elements.

Validation strategies

Validation strategy Description
Manual (default) Validates the form manually in a sequential top-down order.
Automatic on focus clear Validates each field automatically when its focus is cleared.
Automatic inline Validates each field automatically upon any value change event.

Try each strategy using the provided demo to determine the best fit for your project.

Built-in validators

Validator Description
ValueRequiredValidator Ensures that a value is not null or blank (for String types).
TextMinLengthValidator Checks if a String value meets the minimum length requirement.
TextRegexValidator Verifies that a String value matches a specified regex pattern.
IntegerMinValidator Ensures that an integer value is no less than a specified minimum.
IntegerMaxValidator Ensures that an integer value does not exceed a specified maximum value.
IntegerMinMaxValidator Confirms that an integer value is within a specified range.
DateMinValidator Checks that a LocalDate value is not earlier than a specified minimum date.
DateMaxValidator Ensures that a LocalDate value does not exceed a specified maximum date.
DateMinMaxValidator Confirms that a LocalDate value falls within a specific date range.
TimeMinValidator Checks that a LocalTime value is not earlier than a minimum time.
TimeMaxValidator Ensures that a LocalTime value does not exceed a maximum time.
TimeMinMaxValidator Confirms that a LocalTime falls within a specified range.
ContainsNumberValidator Ensures that a String contains at least one numeric digit.
ContainsSpecialCharacterValidator Ensures that a String contains at least one special character.
ContainsUpperAndLowercaseValidator Confirms that a String includes both uppercase and lowercase characters.

Note: To create custom validators, inherit from FormFieldValidator - learn more here.

Cross-field validation

Carlos leverages cross-field validation. In the validation callback, alongside the field input, a FormContext parameter provides access to other field states, enabling comprehensive validation.

By specifying a connectedFieldId, Carlos supports automatic validation between connected fields through the ConnectionValidator, tracking field changes and interactions seamlessly.

Connection validator

The ConnectionValidator facilitates validation in various scenarios:

  • Ensuring a field’s value matches another field’s value (e.g., password confirmation).
  • Validating a field whose value depends on another field (e.g., country code + phone number).

Carlos manages field connections during user interactions:

  1. Manual strategy: Clears the validation results for both the field and connected field when the field’s value changes.
  2. Auto on focus clear strategy: If the connected field has a value, triggers auto-validation on the connected field when the primary field loses focus.
  3. Auto inline strategy: If the connected field has a value, runs auto-validation on the connected field when the primary field’s value changes.
Built-in connection validators
Validator Description
EqualsToValidator Ensures that a field’s value matches another field’s value.
NotEqualsToValidator Confirms that a field’s value differs from another field’s value.
CompareToValidator Compares a field’s value against another field’s value.

Note: create a custom connection validator, inherit from ConnectionValidator - learn more here.

Built-in form fields

Form field name Purpose & key features
FormTextField A customizable text field ideal for general input, with placeholder text, character limits, and input patterns.
FormPasswordTextField A password field with a toggle to show/hide text, ensuring secure input.
FormIntegerField A text field that accepts only integer values. Ideal for numerical data like age or quantity.
FormPickerField A picker for selecting from predefined options. Suitable for lists like countries or categories.
FormDatePickerField A date picker field with support for min/max dates and custom formats, perfect for selecting dates.
FormTimePickerField A time picker field supporting both AM/PM and 24-hour formats, ideal for time selection.

Use cases

  1. USE CASE 1 - Using the built-in fields
  2. USE CASE 2 - Creating a custom field
  3. USE CASE 3 - Long running validations
  4. USE CASE 4 - EqualsTo validation
  5. USE CASE 5 - Connected fields validation

Contribution

Want to contribute to Carlos? Have suggestions or issues with a specific feature or use case?

  1. Open an issue to discuss your solution or idea.
  2. After validating your approach, feel free to open a PR.