Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ jobs:
name: Run tests
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4

- uses: actions/cache@v4
- name: Read cache
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
Expand All @@ -21,10 +23,11 @@ jobs:
restore-keys: |
${{ runner.os }}-gradle-

- uses: actions/setup-java@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '17'
java-version: '21'

- name: Run tests
run: |
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Add the following dependency to your project:

```gradle
dependencies {
implementation("dev.voir.formica:1.0.0-alpha01")
implementation("dev.voir.formica:1.0.0-alpha01") // Not available on public now, you can publish to mavenLocal.
}
```

Expand Down
6 changes: 3 additions & 3 deletions formica/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ android {
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}

kotlin {
jvmToolchain(11)
jvmToolchain(21)
}
}
32 changes: 18 additions & 14 deletions formica/src/commonMain/kotlin/dev/voir/formica/ui/FormicaField.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package dev.voir.formica.ui

import androidx.compose.runtime.Composable
import dev.voir.formica.FormicaField
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.remember
import dev.voir.formica.FormicaFieldResult
import dev.voir.formica.rules.ValidationRule
import dev.voir.formica.scopes.FormicaFieldScope
Expand All @@ -17,18 +18,21 @@ fun <Data, Value : Any?> FormicaScope<Data>.FormicaField(
customValidation: ((Value?) -> FormicaFieldResult)? = null,
validateOnChange: Boolean = true,
content: @Composable FormicaFieldScope<Value?>.() -> Unit
): FormicaField<Value?> {
val field =
registerField(
name = name,
required = required,
requiredError = requiredError,
validators = validators,
customValidation = customValidation,
validateOnChange = validateOnChange
)
val scope = FormicaFieldScope(formField = field)
scope.content()
) {
val scope = remember {
derivedStateOf {
FormicaFieldScope(
formField = registerField(
name = name,
required = required,
requiredError = requiredError,
validators = validators,
customValidation = customValidation,
validateOnChange = validateOnChange
)
)
}
}

return field
scope.value.content()
}
14 changes: 7 additions & 7 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[versions]
agp = "8.7.2"
android-compileSdk = "34"
agp = "8.7.3"
android-compileSdk = "35"
android-minSdk = "24"
android-targetSdk = "34"
compose-plugin = "1.7.1" # https://github.com/JetBrains/compose-multiplatform
android-targetSdk = "35"
compose-plugin = "1.8.1" # https://github.com/JetBrains/compose-multiplatform
junit = "4.13.2"
kotlin = "2.0.21" # https://kotlinlang.org/docs/releases.html
kotlin-coroutines = "1.9.0" # https://github.com/Kotlin/kotlinx.coroutines
androidx-activityCompose = "1.9.3"
kotlin = "2.1.21" # https://kotlinlang.org/docs/releases.html
kotlin-coroutines = "1.10.2" # https://github.com/Kotlin/kotlinx.coroutines
androidx-activityCompose = "1.10.1" # https://mvnrepository.com/artifact/androidx.activity/activity-compose

[libraries]
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
Expand Down
6 changes: 3 additions & 3 deletions sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ kotlin {
androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
jvmTarget.set(JvmTarget.JVM_21)
}
}

Expand Down Expand Up @@ -70,8 +70,8 @@ android {
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
buildFeatures {
compose = true
Expand Down
57 changes: 47 additions & 10 deletions sample/src/commonMain/kotlin/dev/voir/formica/sample/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package dev.voir.formica.sample
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.Checkbox
import androidx.compose.material.Text
Expand All @@ -11,15 +15,18 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import dev.voir.formica.FormicaFieldResult
import dev.voir.formica.FormicaResult
import dev.voir.formica.collectDataAsState
import dev.voir.formica.rememberFormica
import dev.voir.formica.rules.NotEmptyRule
import dev.voir.formica.sample.ui.FormFieldWrapper
import dev.voir.formica.ui.Formica
import dev.voir.formica.ui.FormicaField
import dev.voir.formica.ui.rememberFormica

data class FormSchema(
var text: String,
Expand All @@ -38,18 +45,25 @@ fun App() {
additionalText = null,
)
)
val formData by formica.collectDataAsState()

var formError by remember { mutableStateOf<String?>(null) }
var formResult by remember { mutableStateOf<FormSchema?>(null) }

Column {
Column(modifier = Modifier.fillMaxWidth().padding(24.dp)) {
Formica(formica = formica) {
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.fillMaxWidth()
) {
FormicaField(
name = FormSchema::text,
required = true,
validators = setOf(NotEmptyRule())
) {
FormFieldWrapper {
androidx.compose.material.TextField(
modifier = Modifier.fillMaxWidth(),
value = field.value ?: "",
label = {
Text("Required text")
Expand All @@ -70,6 +84,7 @@ fun App() {
FormicaField(name = FormSchema::optionalText, required = false) {
FormFieldWrapper {
androidx.compose.material.TextField(
modifier = Modifier.fillMaxWidth(),
value = field.value ?: "",
label = {
Text("Optional text")
Expand All @@ -91,13 +106,17 @@ fun App() {
name = FormSchema::activateAdditionalText,
required = true,
) {
Row {
Text("Activate additional text?")
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Checkbox(
checked = field.value ?: false,
onCheckedChange = {
onChange(FormSchema::activateAdditionalText, it)
})
Text("Activate additional text?")
}
}

Expand All @@ -106,16 +125,16 @@ fun App() {
name = FormSchema::additionalText,
required = false,
customValidation = { value ->
if (data.activateAdditionalText && value.isNullOrBlank()) {
if (formData.activateAdditionalText && value.isNullOrBlank()) {
FormicaFieldResult.Error(message = "Field is required")
} else {

FormicaFieldResult.Success
}
}
) {
FormFieldWrapper {
androidx.compose.material.TextField(
modifier = Modifier.fillMaxWidth(),
value = field.value ?: "",
label = {
Text("Required text if checkbox activated")
Expand All @@ -136,22 +155,40 @@ fun App() {
}
}

formError?.let {
Text(text = it, color = Color.Red)
}
Spacer(modifier = Modifier.height(12.dp))

Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
// Reset result and error
formResult = null
formError = null

val state = formica.validate()
if (state is FormicaResult.Valid) {
formError = null
formResult = formica.data.value
} else if (state is FormicaResult.Error) {
formError = state.message
formResult = null
}
}) {
Text("Submit")
}

formError?.let {
Column(modifier = Modifier.fillMaxWidth()) {
Text("Form submit error")
Text(text = it, color = Color.Red)
}
}

formResult?.let {
Column(modifier = Modifier.fillMaxWidth()) {
Text("Form submit result")

Text(text = it.toString())
}
}
}
}
Loading