Skip to content

Commit

Permalink
Merge pull request #37 from soil-kt/integate-with-serialization-bundle
Browse files Browse the repository at this point in the history
Integrate with serialization-bundle
  • Loading branch information
ogaclejapan authored Jun 23, 2024
2 parents 8e42d08 + a40ebd2 commit b8b409c
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 b8b409c

Please sign in to comment.