Skip to content

Commit

Permalink
Integrate with serialization-bundle
Browse files Browse the repository at this point in the history
The form and space modules now have an optional API that allows you to use kotlin.serialization instead of implementing
Parcelable.

refs: #35
  • Loading branch information
ogaclejapan committed Jun 23, 2024
1 parent 8e42d08 commit a40ebd2
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 2 deletions.
1 change: 1 addition & 0 deletions soil-form/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ kotlin {
implementation(compose.ui)
implementation(compose.foundation)
implementation(libs.kotlinx.coroutines.core)
api(projects.soilSerializationBundle)
}

val skikoMain by creating {
Expand Down
52 changes: 52 additions & 0 deletions soil-form/src/commonMain/kotlin/soil/form/compose/Form.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,21 @@ import androidx.compose.runtime.saveable.mapSaver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.toMutableStateMap
import androidx.compose.ui.Modifier
import androidx.core.bundle.Bundle
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.serializer
import soil.form.FieldErrors
import soil.form.FieldName
import soil.form.FieldValidateOn
import soil.form.FormFieldNames
import soil.form.FormPolicy
import soil.form.FormRule
import soil.form.FormValidationException
import soil.serialization.bundle.Bundler

/**
* A Form to manage the state and actions of input fields, and create a child block of [FormScope].
Expand Down Expand Up @@ -151,6 +156,53 @@ fun <T : Any> Form(
}
}

/**
* Create an [Saver] for Kotlin Serialization.
*
* Usage:
*
* ```kotlin
* @Serializable
* data class FormData(
* val firstName: String = "",
* val lastName: String = "",
* val email: String = "",
* val mobileNumber: String = "",
* val title: Title? = null,
* val developer: Boolean? = null
* )
*
* enum class Title {
* Mr,
* Mrs,
* Miss,
* Dr,
* }
*
* Form(
* onSubmit = { .. },
* initialValue = FormData(),
* modifier = modifier,
* saver = serializationSaver()
* ) { .. }
* ```
*
* @param T The type of the value to save and restore.
* @param serializer The serializer to use for the value.
* @param bundler The bundler to encode and decode the value. Default is [Bundler].
* @return The [Saver] for the value.
*/
@ExperimentalSerializationApi
inline fun <reified T> serializationSaver(
serializer: KSerializer<T> = serializer(),
bundler: Bundler = Bundler
): Saver<T, Any> {
return Saver(
save = { value -> bundler.encodeToBundle(value, serializer) },
restore = { bundle -> bundler.decodeFromBundle(bundle as Bundle, serializer) }
)
}

@Suppress("UNCHECKED_CAST")
private val errorsSaver = mapSaver(
save = { stateMap -> stateMap.toMap() },
Expand Down
4 changes: 2 additions & 2 deletions soil-serialization-bundle/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ kotlin {

sourceSets {
commonMain.dependencies {
implementation(libs.kotlinx.serialization.core)
implementation(libs.jbx.core.bundle)
api(libs.kotlinx.serialization.core)
api(libs.jbx.core.bundle)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
Expand Down
1 change: 1 addition & 0 deletions soil-space/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ kotlin {
implementation(libs.jbx.lifecycle.viewmodel.savedstate)
api(libs.jbx.savedstate)
api(libs.jbx.core.bundle)
api(projects.soilSerializationBundle)
}

androidMain.dependencies {
Expand Down
42 changes: 42 additions & 0 deletions soil-space/src/commonMain/kotlin/soil/space/Atom.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ package soil.space

import androidx.compose.runtime.Immutable
import androidx.core.bundle.Bundle
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.serializer
import soil.serialization.bundle.Bundler
import kotlin.jvm.JvmName

/**
Expand Down Expand Up @@ -259,6 +263,44 @@ interface AtomSaver<T> {

typealias AtomSaverKey = String

/**
* Create an [AtomSaver] for Kotlin Serialization.
*
* Usage:
*
* ```kotlin
* @Serializable
* data class CounterData(
* val value: Int = 0
* )
*
* @OptIn(ExperimentalSerializationApi::class)
* private val counterAtom = atom(CounterData(), saver = serializationSaver("counter"))
*```
*
* @param T The type of the value to save and restore.
* @param key The key to be used to save and restore the value.
* @param serializer The serializer to use for the value.
* @param bundler The bundler to encode and decode the value. Default is [Bundler].
* @return The [AtomSaver] for the value.
*/
@ExperimentalSerializationApi
inline fun <reified T> serializationSaver(
key: AtomSaverKey,
serializer: KSerializer<T> = serializer(),
bundler: Bundler = Bundler
): AtomSaver<T> {
return object : AtomSaver<T> {
override fun save(bundle: Bundle, value: T) {
bundle.putBundle(key, bundler.encodeToBundle(value, serializer))
}

override fun restore(bundle: Bundle): T? {
return bundle.getBundle(key)?.let { bundler.decodeFromBundle(it, serializer) }
}
}
}

@PublishedApi
internal fun stringSaver(key: AtomSaverKey): AtomSaver<String> {
return object : AtomSaver<String> {
Expand Down

0 comments on commit a40ebd2

Please sign in to comment.