From f84da3e99f998122c7c22cd521d000a3f4a2da83 Mon Sep 17 00:00:00 2001 From: Nek-12 Date: Mon, 23 Dec 2024 19:36:52 +0100 Subject: [PATCH] docs: update readme and quickstart --- README.md | 23 +++++++------------ .../pro/respawn/flowmvi/dsl/StoreDsl.kt | 4 ---- docs/CONTRIBUTING.md | 2 +- docs/quickstart.md | 20 +++++++++------- .../sample/features/simple/SimpleScreen.kt | 1 - 5 files changed, 21 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 09cf002e..23157cd3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ ![GitHub last commit](https://img.shields.io/github/last-commit/respawn-app/FlowMVI) ![Issues](https://img.shields.io/github/issues/respawn-app/FlowMVI) ![GitHub top language](https://img.shields.io/github/languages/top/respawn-app/flowMVI) -[![CodeFactor](https://www.codefactor.io/repository/github/respawn-app/flowMVI/badge)](https://www.codefactor.io/repository/github/respawn-app/flowMVI) [![AndroidWeekly #563](https://androidweekly.net/issues/issue-563/badge)](https://androidweekly.net/issues/issue-563/) [![Slack channel](https://img.shields.io/badge/Chat-Slack-orange.svg?style=flat&logo=slack)](https://kotlinlang.slack.com/messages/flowmvi/) @@ -122,12 +121,12 @@ All you have to do is: ```kotlin sealed interface State : MVIState { + data object Loading : State data class Error(val e: Exception) : State data class Content(val counter: Int = 0) : State } - sealed interface Intent : MVIIntent { data object ClickedCounter : Intent } @@ -141,25 +140,19 @@ sealed interface Action : MVIAction { ```kotlin val counterStore = store(initial = State.Loading, scope = coroutineScope) { + + install(analyticsPlugin) // install plugins you need - // install plugins you need - install(analyticsPlugin) - - // recover from errors - recover { e: Exception -> + recover { e: Exception -> // recover from errors updateState { State.Error(e) } null } - - // load data - init { + init { // load data updateState { State.Content(counter = repository.loadCounter()) } } - - // respond to events - reduce { intent: Intent -> + reduce { intent: Intent -> // respond to events when (intent) { is ClickedCounter -> updateState { action(ShowMessage("Incremented!")) @@ -320,7 +313,7 @@ Enjoy testable UI and free `@Preview`s. ### Android Support -No more subclassing `ViewModel`. Use generic `StoreViewModel` instead and make your business logic multiplatform. +No more subclassing `ViewModel`. Use `StoreViewModel` instead and make your business logic multiplatform. ```kotlin val module = module { // Koin example @@ -412,7 +405,7 @@ Begin by reading the [Quickstart Guide](https://opensource.respawn.pro/FlowMVI/# ## License ``` - Copyright 2022-2024 Respawn Team and contributors + Copyright 2022-2025 Respawn Team and contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/core/src/commonMain/kotlin/pro/respawn/flowmvi/dsl/StoreDsl.kt b/core/src/commonMain/kotlin/pro/respawn/flowmvi/dsl/StoreDsl.kt index eed203b1..39dce6f5 100644 --- a/core/src/commonMain/kotlin/pro/respawn/flowmvi/dsl/StoreDsl.kt +++ b/core/src/commonMain/kotlin/pro/respawn/flowmvi/dsl/StoreDsl.kt @@ -3,7 +3,6 @@ package pro.respawn.flowmvi.dsl import kotlinx.coroutines.CoroutineScope import pro.respawn.flowmvi.api.ActionShareBehavior import pro.respawn.flowmvi.api.FlowMVIDSL -import pro.respawn.flowmvi.api.ImmutableStore import pro.respawn.flowmvi.api.MVIAction import pro.respawn.flowmvi.api.MVIIntent import pro.respawn.flowmvi.api.MVIState @@ -107,6 +106,3 @@ public inline fun lazyStore( mode: LazyThreadSafetyMode = LazyThreadSafetyMode.SYNCHRONIZED, @BuilderInference crossinline configure: BuildStore, ): Lazy> = lazy(mode) { store(initial, configure).apply { start(scope) } } - -public inline val Store.immutable: ImmutableStore - get() = this diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index e23b553a..b7a787e8 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -12,7 +12,7 @@ release=false ``` * Make sure you have these installed: - * Android Studio latest Canary or Beta, depending on the current project's AGP (yes, we're on the edge). + * Android Studio latest Stable or Beta, depending on the current project's AGP. * Kotlin Multiplatform suite (run `kdoctor` to verify proper setup) * Detekt plugin * Kotest plugin diff --git a/docs/quickstart.md b/docs/quickstart.md index 89da8527..87e1596a 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -20,7 +20,7 @@ First of all, here's how the library works: ![Maven Central](https://img.shields.io/maven-central/v/pro.respawn.flowmvi/core?label=Maven%20Central) -
+
Version catalogs ```toml @@ -308,7 +308,7 @@ configure { actionShareBehavior = ActionShareBehavior.Distribute() onOverflow = BufferOverflow.DROP_OLDEST intentCapacity = Channel.UNLIMITED - atomicStateUpdates = true + stateStrategy = StateStrategy.Atomic(reentrant = true) allowIdleSubscriptions = false logger = if (debuggable) PlatformStoreLogger else NoOpStoreLogger verifyPlugins = debuggable @@ -343,12 +343,16 @@ configure { * `Channel.CONFLATED` - A buffer of 1 * `Channel.RENDEZVOUS` - Zero buffer (all events not ready to be processed are dropped) * `Channel.BUFFERED` - Default system buffer capacity -* `atomicStateUpdates` - Enables transaction serialization for state updates, making state updates atomic and - suspendable. Synchronizes state updates, allowing only **one** client to read and/or update the state at a time. All - other clients that attempt to get the state will wait in a FIFO queue and suspend the parent coroutine. For one-time - usage of non-atomic updates, see `updateStateImmediate`. Learn - more [here](https://proandroiddev.com/how-to-safely-update-state-in-your-kotlin-apps-bf51ccebe2ef). - Has a small performance impact because of coroutine context switching and mutex usage when enabled. +* `stateStrategy` - Strategy for serializing state transactions. Choose one of the following: + * `Atomic(reentrant = false)` - Enables transaction serialization for state updates, making state updates atomic and + suspendable. Synchronizes state updates, allowing only **one** client to read and/or update the state at a time. + All other clients that attempt to get the state will wait in a FIFO queue and suspend the parent coroutine. For + one-time usage of non-atomic updates, see `updateStateImmediate`. Recommended for most cases. + * `Atomic(reentrant = true)` - Same as above, but allows nested state updates + without causing a deadlock, like this: `updateState { updateState { } }`. This strategy is 15x slower than other + options, but still negligible for managing UI and other non-performance-critical tasks. This is the default. + * `Immediate` - 2 times faster than atomic with no reentrancy, but provides no state consistency guarantees + and no thread-safety. Equivalent to always using `updateStateImmediate`. * `allowIdleSubscriptions` - A flag to indicate that clients may subscribe to this store even while it is not started. If you intend to stop and restart your store while the subscribers are present, set this to `true`. By default, will use the opposite value of the `debuggable` parameter (`true` on production). diff --git a/sample/src/commonMain/kotlin/pro/respawn/flowmvi/sample/features/simple/SimpleScreen.kt b/sample/src/commonMain/kotlin/pro/respawn/flowmvi/sample/features/simple/SimpleScreen.kt index 7f0856eb..94ac9701 100644 --- a/sample/src/commonMain/kotlin/pro/respawn/flowmvi/sample/features/simple/SimpleScreen.kt +++ b/sample/src/commonMain/kotlin/pro/respawn/flowmvi/sample/features/simple/SimpleScreen.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding