Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pavelannin/keemun-kotlin
Multiplatform Kotlin framework that provides a way to write shared code using The Elm Architecture pattern
https://github.com/pavelannin/keemun-kotlin
architecture elm elm-architecture kotlin kotlin-multiplatform the-elm-architecture
Last synced: 3 months ago
JSON representation
Multiplatform Kotlin framework that provides a way to write shared code using The Elm Architecture pattern
- Host: GitHub
- URL: https://github.com/pavelannin/keemun-kotlin
- Owner: pavelannin
- License: apache-2.0
- Created: 2023-11-11T13:33:15.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2024-08-19T21:26:04.000Z (5 months ago)
- Last Synced: 2024-10-12T20:02:30.713Z (3 months ago)
- Topics: architecture, elm, elm-architecture, kotlin, kotlin-multiplatform, the-elm-architecture
- Language: Kotlin
- Homepage:
- Size: 381 KB
- Stars: 2
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
![Maven Central](https://img.shields.io/maven-central/v/io.github.pavelannin/keemun-core?label=keemun-core)
![Maven Central](https://img.shields.io/maven-central/v/io.github.pavelannin/keemun-decompose?label=keemun-decompose)
![Maven Central](https://img.shields.io/maven-central/v/io.github.pavelannin/keemun-swiftui?label=keemun-swiftui)# Overview
## What is The Elm Architecture
The Elm Architecture ([Elm Architecture](https://guide.elm-lang.org/architecture/)) is a popular software architecture pattern used in the
Elm programming language. It provides a structure for development based on functional programming and a unidirectional data flow.The Elm Architecture consists of three main components:
- `Model` This is the application state that contains all the data needed for its functioning. The model is immutable and is updated only
through messages (`Msg`).
- `Update` This is a function that takes the current model and a message and returns a new model. It is responsible for handling messages
and updating the application state.
- `View` This is a function that takes the current model and returns the user interface. The view displays data from the model and reacts
to user actions by generating new messages.The Elm Architecture provides a clear separation between the application logic and its presentation, making the code more understandable,
modular, and easily testable. It also ensures error resilience and prevents many common problems associated with mutable state and side
effects.## What is Keemun
Keemun is a multiplatform Kotlin framework that provides a way to write shared code using The Elm Architecture pattern.
# Setup
## Gradle
A number of modules have been published on Maven Central:
- `core` Basic interfaces and functional capabilities of the architecture (multiplatform)
- `decompose` Integration via Decompose (multiplatform)
- `swiftui` Integration for SwiftUI (only Swift)Add the necessary modules to the build.gradle file of your module:
```gradle
implementation "io.github.pavelannin:keemun-:"
```# Componets
## State
`State` is a class that describes the state of your application/feature/screen/view/etc. at a specific moment in time.```kotlin
data class State(
val syncCount: Int,
val asyncCount: Int,
val isAsyncRunning: Boolean,
)
```## Msg
Any `Msg` represents an intention to change the state. `Msg` is sent from the user interface/business logic.```kotlin
/** Common type of messages. */
sealed interface Msg/** External messages (from the user interface). */
sealed class ExternalMsg : Msg {/** Increment the sync counter. */
data object IncrementSync : ExternalMsg()/** Increment the async counter. */
data object IncrementAsync : ExternalMsg()
}/** Internal messages (from EffectHandler). */
sealed class InternalMsg : Msg {/** Result of an async operation. */
data class CompletedAsyncOperation(val value: Int) : InternalMsg()
}
```## Effect
Any `Effect` represents an intention to invoke part of your business logic. `Effect` is sent from the update depending on the received
message.```kotlin
sealed class Effect {/** Increment the counter. */
data class Increment(val value: Int) : CounterEffect()
}
```## Update
`Update` is the place for logic. Its method takes `state` and `msg` as arguments and returns a new `state` and a collection of `effects`.
The idea is to be a pure function that modifies the `state` and sends an side-effect according to the received `message` and the current
`state`.```kotlin
val externalUpdate = Update { msg, state ->
when (msg) {
ExternalMsg.IncrementSync ->
state.copy(syncCount = state.syncCount.inc()) to emptySet()ExternalMsg.IncrementAsync ->
if (state.isAsyncRunning) {
state to emptySet()
} else {
state.copy(isAsyncRunning = true) to setOf(Effect.Increment(state.asyncCount))
}
}
}val internalUpdate = Update { msg, state ->
when (msg) {
is InternalMsg.CompletedAsyncOperation ->
state.copy(asyncCount = msg.value, isAsyncRunning = false) to emptySet()
}
}
```## EffectHandler
`EffectHandler` is the place where business logic is executed. Its method takes `effect` and `dispatch` as arguments. The idea is to be a
function that sends messages to `dispatch` according to the received effect and performs the operation. `EffectHandler` is a
suspend function, and each effect is executed in a separate coroutine.```kotlin
val effectHandler = EffectHandler { effect, dispatch ->
when (effect) {
is Effect.Increment -> {
delay(1_000)
dispatch(InternalMsg.CompletedAsyncOperation(effect.value.inc()))
}
}
}
```## Start
`Start` is the place for initialization. Its method takes `savedState` (if the state is being persisted), and returns the initializing
`state` and the initial set of side-effects.```kotlin
val start = Start { savedState ->
val state = savedState ?: CounterState(
syncCount = deps,
asyncCount = deps,
isAsyncRunning = false,
)
state to emptySet()
}
```## StoreParams
`StoreParams` is a container that holds `Start`, `Update`, and `EffectHandler` in one place for creating a `Store`.
`StoreParams` provides several convenient overridden functions for creating it with optional arguments.```kotlin
val storeParams = StoreParams(
start = { },
update = { },
effectHandler = { },
)
```## Connector
`Connector` is an entity that holds an instance of `Store`.## FeatureParams
`FeatureParams` is a container that holds `StoreParams`, a function for transforming `State` into `ViewState`, and other parameters
required for creating a `Connector`. `FeatureParams` provides several convenient overridden functions for creating it with optional
arguments.```kotlin
val featureParams = FeatureParams(
storeParams = StoreParams(),
viewStateTransform = StateTransform {},
externalMessageTransform = { externalMsg -> },
startedOptions = FeatureStartedOptions.Lazily,
)
```# Template generator plugin
## Intellij / Android Studio
1. Install the `Keemun template` plugin from the marketplace
2. Open the context menu in the package, select: New -> Other -> Keemun feature
3. Fill in the name of the feature
4. Profit# Sample project
The sample project is a screen with two counters: synchronous and asynchronous. The synchronous counter is modified in `Update`,
demonstrating state changes, while the asynchronous counter is modified in `EffectHandler`, simulating asynchronous business logic.
The example is implemented for Android and iOS with shared business logic in Kotlin Multiplatform.## Screenshots