
Implements TEA architecture using coroutines for scalable, testable applications. Offers simplicity, extensibility, and debugging with IntelliJ plugin support. Components reside in single files.
Tea Bag is a simple implementation of TEA
architecture written in Kotlin. This library is based on Kotlin's coroutines, extensively uses an
extension-based approach, and supports both jvm and ios targets.
This library isn't production-ready yet and was originally intended as a pet project to give TEA a try. Later I found that it'd be nice to make it simpler and more lightweight than analogs, add debugging capabilities, etc.
Nothing special: we just need to code our initializer, resolver (tracker function),
updater (computeNewState function), and UI (renderSnapshot function). After that, we should pass
them to an appropriate Component builder overload.
@file:OptIn(ExperimentalTeaApi::class)
package io.github.xlopec.counter
import io.github.xlopec.tea.core.*
import kotlinx.coroutines.runBlocking
/**Async initializer, provides initial state*/
suspend fun initializer(): Initial<Int, Int> = Initial(0)
/**Some tracker*/
fun track(
event: Snapshot<Int, Int, Int>,
ctx: ResolveCtx<Int>,
) {
ctx sideEffect { println("Track: \"$event\"") }
}
/**App logic, for now it just adds delta to count and returns this as result*/
fun add(
delta: Int,
counter: Int,
): Update<Int, Int> = (counter + delta) command delta
/**Some UI, e.g. console*/
suspend fun display(
snapshot: Snapshot<*, *, *>,
) {
println("Display: $snapshot")
}
fun main() = runBlocking {
// Somewhere at the application level
val component = Component(
initializer = ::initializer,
resolver = ::track,
updater = ::add,
scope = this,
)
// UI = component([message1, message2, ..., message N])
component(+1, +2, -3).collect(::display)
}The sample above will print the following:
Display: Initial(currentState=0, commands=[])
Track: "Regular(currentState=1, commands=[1], previousState=0, message=1)"
Track: "Initial(currentState=0, commands=[])"
Track: "Regular(currentState=3, commands=[2], previousState=1, message=2)"
Track: "Regular(currentState=0, commands=[-3], previousState=3, message=-3)"
Display: Regular(currentState=1, commands=[1], previousState=0, message=1)
Display: Regular(currentState=3, commands=[2], previousState=1, message=2)
Display: Regular(currentState=0, commands=[-3], previousState=3, message=-3)
Real-world examples include Android and iOS app samples that use the same application component and share common entities, application, and navigation logic. IntelliJ plugin is built on top of the library as well.
For more info, visit the Wiki page.
jvm, iosX64, and iosArm64 targets.Add the dependency:
implementation("io.github.xlopec:tea-core:[version]")
implementation("io.github.xlopec:tea-time-travel:[version]")
implementation("io.github.xlopec:tea-time-travel-adapter-gson:[version]")
implementation("io.github.xlopec:tea-navigation:[version]")Make sure that you have mavenCentral() in the list of repositories.
Plugin is available on JetBrains marketplace
To build the plugin from sources, use the ./gradlew tea-time-travel-plugin:buildPlugin command.
The installable plugin will be located in the tea-time-travel-plugin/build/distributions directory.
To run IntelliJ IDEA with the installed plugin, use the ./gradlew tea-time-travel-plugin:runIde
command.
To build the Android app sample, run ./gradlew :samples:app:assembleDefaultDebug or ./gradlew :samples:app:assembleRemoteDebug.
The last command assembles a debuggable version of the application that connects to the currently running instance of
the debugger (will try connecting to http://localhost:8080).
kotlinx.serialization.json.Contributions are more than welcome. If something cannot be done, is not convenient, or does not work - create an issue or PR.
Tea Bag is a simple implementation of TEA
architecture written in Kotlin. This library is based on Kotlin's coroutines, extensively uses an
extension-based approach, and supports both jvm and ios targets.
This library isn't production-ready yet and was originally intended as a pet project to give TEA a try. Later I found that it'd be nice to make it simpler and more lightweight than analogs, add debugging capabilities, etc.
Nothing special: we just need to code our initializer, resolver (tracker function),
updater (computeNewState function), and UI (renderSnapshot function). After that, we should pass
them to an appropriate Component builder overload.
@file:OptIn(ExperimentalTeaApi::class)
package io.github.xlopec.counter
import io.github.xlopec.tea.core.*
import kotlinx.coroutines.runBlocking
/**Async initializer, provides initial state*/
suspend fun initializer(): Initial<Int, Int> = Initial(0)
/**Some tracker*/
fun track(
event: Snapshot<Int, Int, Int>,
ctx: ResolveCtx<Int>,
) {
ctx sideEffect { println("Track: \"$event\"") }
}
/**App logic, for now it just adds delta to count and returns this as result*/
fun add(
delta: Int,
counter: Int,
): Update<Int, Int> = (counter + delta) command delta
/**Some UI, e.g. console*/
suspend fun display(
snapshot: Snapshot<*, *, *>,
) {
println("Display: $snapshot")
}
fun main() = runBlocking {
// Somewhere at the application level
val component = Component(
initializer = ::initializer,
resolver = ::track,
updater = ::add,
scope = this,
)
// UI = component([message1, message2, ..., message N])
component(+1, +2, -3).collect(::display)
}The sample above will print the following:
Display: Initial(currentState=0, commands=[])
Track: "Regular(currentState=1, commands=[1], previousState=0, message=1)"
Track: "Initial(currentState=0, commands=[])"
Track: "Regular(currentState=3, commands=[2], previousState=1, message=2)"
Track: "Regular(currentState=0, commands=[-3], previousState=3, message=-3)"
Display: Regular(currentState=1, commands=[1], previousState=0, message=1)
Display: Regular(currentState=3, commands=[2], previousState=1, message=2)
Display: Regular(currentState=0, commands=[-3], previousState=3, message=-3)
Real-world examples include Android and iOS app samples that use the same application component and share common entities, application, and navigation logic. IntelliJ plugin is built on top of the library as well.
For more info, visit the Wiki page.
jvm, iosX64, and iosArm64 targets.Add the dependency:
implementation("io.github.xlopec:tea-core:[version]")
implementation("io.github.xlopec:tea-time-travel:[version]")
implementation("io.github.xlopec:tea-time-travel-adapter-gson:[version]")
implementation("io.github.xlopec:tea-navigation:[version]")Make sure that you have mavenCentral() in the list of repositories.
Plugin is available on JetBrains marketplace
To build the plugin from sources, use the ./gradlew tea-time-travel-plugin:buildPlugin command.
The installable plugin will be located in the tea-time-travel-plugin/build/distributions directory.
To run IntelliJ IDEA with the installed plugin, use the ./gradlew tea-time-travel-plugin:runIde
command.
To build the Android app sample, run ./gradlew :samples:app:assembleDefaultDebug or ./gradlew :samples:app:assembleRemoteDebug.
The last command assembles a debuggable version of the application that connects to the currently running instance of
the debugger (will try connecting to http://localhost:8080).
kotlinx.serialization.json.Contributions are more than welcome. If something cannot be done, is not convenient, or does not work - create an issue or PR.