{"id":13658879,"url":"https://github.com/freeletics/FlowRedux","last_synced_at":"2025-04-24T11:33:00.426Z","repository":{"id":35839209,"uuid":"184753749","full_name":"freeletics/FlowRedux","owner":"freeletics","description":"Kotlin Multiplatform Statemachine library with nice DSL based on Flow from Kotlin Coroutine's.","archived":false,"fork":false,"pushed_at":"2025-04-22T05:52:03.000Z","size":6788,"stargazers_count":726,"open_issues_count":13,"forks_count":27,"subscribers_count":27,"default_branch":"main","last_synced_at":"2025-04-22T07:12:27.381Z","etag":null,"topics":["android","architecture","coroutines","kotlin","mvi","mvi-android"],"latest_commit_sha":null,"homepage":"https://freeletics.github.io/FlowRedux/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/freeletics.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"docs/contributing.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-05-03T12:44:23.000Z","updated_at":"2025-04-22T05:52:06.000Z","dependencies_parsed_at":"2023-10-20T09:57:04.029Z","dependency_job_id":"1a0f2547-708e-4688-88ca-aead2f1ff29f","html_url":"https://github.com/freeletics/FlowRedux","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/freeletics%2FFlowRedux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/freeletics%2FFlowRedux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/freeletics%2FFlowRedux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/freeletics%2FFlowRedux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/freeletics","download_url":"https://codeload.github.com/freeletics/FlowRedux/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250618710,"owners_count":21460140,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","architecture","coroutines","kotlin","mvi","mvi-android"],"created_at":"2024-08-02T05:01:03.424Z","updated_at":"2025-04-24T11:32:59.712Z","avatar_url":"https://github.com/freeletics.png","language":"Kotlin","funding_links":[],"categories":["Libraries"],"sub_categories":["🏗 Architecture"],"readme":"# FlowRedux\n\nBuilding async. running Kotlin Multiplatform state machine made easy with a DSL and coroutines.\n\n## Usage\n\nFull documentation and best practices can be found here: https://freeletics.github.io/FlowRedux/\n\n```kotlin\nsealed interface State\n\nobject Loading : State\ndata class ContentState(val items : List\u003cItem\u003e) : State\ndata class Error(val error : Throwable) : State\n\n\nsealed interface Action\nobject RetryLoadingAction : Action\n\n\nclass MyStateMachine : FlowReduxStateMachine\u003cState, Action\u003e(initialState = Loading){\n    init {\n        spec {\n            inState\u003cLoading\u003e {\n                onEnter { state : State\u003cLoading\u003e -\u003e\n                    // executes this block whenever we enter Loading state\n                    try {\n                        val items = loadItems() // suspending function / coroutine to load items\n                        state.override { ContentState(items) } // Transition to ContentState\n                    } catch (t : Throwable) {\n                        state.override { Error(t) } // Transition to Error state\n                    }\n                }\n            }\n\n            inState\u003cError\u003e {\n                on\u003cRetryLoadingAction\u003e { action : RetryLoadingAction, state : State\u003cError\u003e -\u003e\n                    // executes this block whenever Error state is current state and RetryLoadingAction is emitted\n                    state.override { Loading } // Transition to Loading state which loads list again\n                 }\n            }\n\n            inState\u003cContentState\u003e {\n                collectWhileInState( flowOf(1,2,3) ) { value : Int, state : State\u003cContentState\u003e -\u003e\n                    // observes the given flow as long as state is ContentState.\n                    // Once state is changed to another state the flow will automatically\n                    // stop emitting.\n                    state.mutate {\n                        copy( items = this.items + Item(\"New item $value\"))\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n```kotlin\nval statemachine = MyStateMachine()\n\nlaunch {  // Launch a coroutine\n    statemachine.state.collect { state -\u003e\n      // do something with new state like update UI\n      renderUI(state)\n    }\n}\n\n// emit an Action\nlaunch { // Launch a coroutine\n    statemachine.dispatch(action)\n}\n```\n\nIn an Android Application you could use it with AndroidX `ViewModel` like that:\n\n```kotlin\nclass MyViewModel @Inject constructor(private val stateMachine : MyStateMachine) : ViewModel() {\n    val state = MutableLiveData\u003cState\u003e()\n\n    init {\n        viewModelScope.launch { // automatically canceled once ViewModel lifecycle reached destroyed.\n            stateMachine.state.collect { newState -\u003e\n                state.value = newState\n            }\n        }\n    }\n\n    fun dispatch(action : Action) {\n        viewModelScope.launch {\n            stateMachine.dispatch(action)\n        }\n    }\n}\n```\n\n## Dependencies\nThere are two artifacts that you can include as dependencis:\n\n1. `flowredux`: this is the core library and includes the DSL.\n2. `compose`: contains some convenient extensions to work with `FlowReduxStateMachine` in [Jetpack Compose](https://developer.android.com/jetpack/compose).\n\n[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/freeletics/flowredux?logo=github\u0026sort=semver)](https://github.com/freeletics/flowredux/releases)\n\n### JVM / Android only\n```groovy\nimplementation 'com.freeletics.flowredux:flowredux-jvm:\u003clatest-version\u003e'\nimplementation 'com.freeletics.flowredux:compose:\u003clatest-version\u003e'\n```\n\n### Multiplatform\n```groovy\nimplementation 'com.freeletics.flowredux:flowredux:\u003clatest-version\u003e'\n```\n\nFlowRedux is supported on:\n\n- JVM / Android\n- iOS\n- watchOS\n- tvOS\n- macOS\n- Linux\n- Windows\n\nWe do plan to add support for JavaScript but it’s not available yet.\n\n### Snapshot\nLatest snapshot (directly published from `main` branch from CI on each change):\n\n```groovy\nallprojects {\n    repositories {\n        // Your repositories.\n        // ...\n        // Add url to snapshot repository\n        maven {\n            url \"https://oss.sonatype.org/content/repositories/snapshots/\"\n        }\n    }\n}\n```\n\nThen just use `-SNAPSHOT`suffix as version name like\n\n```groovy\nimplementation 'com.freeletics.flowredux:flowredux:1.2.1-SNAPSHOT'\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffreeletics%2FFlowRedux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffreeletics%2FFlowRedux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffreeletics%2FFlowRedux/lists"}