Skip to content
apegroupPublic

About

Immutable event based state management framework for Kotlin Multiplatform Mobile

Resources

Code of conduct

Stars

42 stars

Watchers

4 watching

Forks

Repository files navigation

Revolver

Immutable event-based state management for Kotlin Multiplatform


Overview

Revolver is a Kotlin Multiplatform state management library that enforces a single immutable state and unidirectional data flow. Clients send Events to a ViewModel, which processes them and emits States and Effects back via Kotlin Flows.

Client ──emit(Event)──► RevolverViewModel ──► EventHandler
                                                    │
                              ┌─────────────────────┤
                              ▼                     ▼
                        StateFlow<State>    SharedFlow<Effect>
                              │                     │
                              └──────────► Clients ◄┘
Type Direction Purpose
RevolverEvent Client → ViewModel User actions or lifecycle triggers
RevolverState ViewModel → Client Immutable snapshot of what to display
RevolverEffect ViewModel → Client One-shot side effect (navigation, toast, etc.)

Installation

Add the GitHub Packages Maven repository to your settings.gradle.kts:

dependencyResolutionManagement {
    repositories {
        maven {
            url = uri("https://maven.pkg.github.com/apegroup/revolver/")
            credentials {
                username = System.getenv("GH_USERNAME") ?: ""
                password = System.getenv("GH_TOKEN") ?: ""
            }
        }
    }
}

Then declare the dependency in your commonMain source set:

implementation("com.umain:revolver:1.6.0")

Quick Start

1. Define your sealed classes

sealed class ExampleEvent : RevolverEvent {
    object Refresh : ExampleEvent()
}

sealed class ExampleState : RevolverState {
    object Loading : ExampleState()
    data class Loaded(val result: String) : ExampleState()
    data class Error(val message: String) : ExampleState()
}

sealed class ExampleEffect : RevolverEffect {
    data class ShowToast(val message: String) : ExampleEffect()
}

Prefer object for states with no data and data class for states that carry data. The state flow skips values equal to the current one, so structural equality avoids redundant updates.

2. Implement your ViewModel

class ExampleViewModel : RevolverViewModel<ExampleEvent, ExampleState, ExampleEffect>(
    initialState = ExampleState.Loading,
) {

    init {
        addEventHandler<ExampleEvent.Refresh>(::onRefresh)
        addErrorHandler(RevolverDefaultErrorHandler(ExampleState.Error("Something went wrong")))
    }

    private suspend fun onRefresh(
        event: ExampleEvent.Refresh,
        emit: Emitter<ExampleState, ExampleEffect>,
    ) {
        emit.state(ExampleState.Loading)
        val data = fetchData()
        emit.state(ExampleState.Loaded(data))
        emit.effect(ExampleEffect.ShowToast("Loaded!"))
    }
}

3. Collect state and effects (Android — Jetpack Compose)

@Composable
fun ExampleScreen(viewModel: ExampleViewModel) {
    val state by viewModel.state.collectAsState()
    val context = LocalContext.current

    LaunchedEffect(Unit) {
        viewModel.emit(ExampleEvent.Refresh)
        viewModel.effect.collect { effect ->
            when (effect) {
                is ExampleEffect.ShowToast -> Toast.makeText(context, effect.message, Toast.LENGTH_SHORT).show()
            }
        }
    }

    when (val s = state) {
        is ExampleState.Loading -> CircularProgressIndicator()
        is ExampleState.Loaded  -> Text(s.result)
        is ExampleState.Error   -> Text(s.message)
    }
}

For iOS, see iOS integration.


Documentation

The docs/ directory is an Open Knowledge Format bundle: plain markdown with YAML frontmatter that people and AI agents can both read.

Page Covers
Getting started Installation, platform support, first ViewModel
Core concepts Event, State, Effect, Emitter, and runtime behaviour
Error handling Built-in, per-type and reusable error handlers
Testing Testing ViewModels with Turbine and kotlinx-coroutines-test
iOS integration watch, DisposableHandle, SwiftUI and UIKit patterns
API reference Every public type and function

Contribution

Bug reports, feature requests, and pull requests are welcome. This library is in active development — production use is at your own discretion.

Run the test suite with ./scripts/run_test_suite.sh, and publish to your local Maven repository with ./scripts/build_deploy_to_local_maven.sh.

About

Immutable event based state management framework for Kotlin Multiplatform Mobile

Resources

Code of conduct

Stars

42 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages