Orbit¶
A Compose-driven architecture for Kotlin Multiplatform.
A presenter is a @Composable that returns state. A UI is a @Composable that renders
that state and sends events back. A screen is the key that pairs the two. That is the whole
model.
@Composable
override fun present(): CounterState {
var count by rememberRetained { mutableIntStateOf(0) }
return CounterState(count) { event ->
when (event) {
CounterEvent.Increment -> count++
}
}
}
Because presenters are Composables rather than ViewModels, they are ordinary Kotlin with no Android dependencies — the same presenter runs on Android, Desktop and iOS, and can be tested without an emulator.
Install¶
[versions]
orbit = "0.0.11"
[libraries]
orbit-foundation = { module = "io.github.avelon1a:orbit-foundation", version.ref = "orbit" }
orbit-overlay = { module = "io.github.avelon1a:orbit-overlay", version.ref = "orbit" }
orbit-test = { module = "io.github.avelon1a:orbit-test", version.ref = "orbit" }
Modules¶
| Artifact | Contents | Compose dependency |
|---|---|---|
orbit-runtime |
Screen, Presenter, Navigator, PopResult, rememberRetained |
compose-runtime only |
orbit-foundation |
Orbit registry, Ui, OrbitContent, back stack, nav decorations |
compose-ui, foundation, animation |
orbit-overlay |
Overlay, OverlayHost, ContentWithOverlays |
compose-ui, foundation |
orbit-test |
Presenter.test { }, FakeNavigator, FakeOverlayHost |
test only |
orbit-foundation brings orbit-runtime with it. Feature modules that contain presenters but
no UI should depend on orbit-runtime alone — it never pulls in compose-ui, which keeps
presenter modules light and fast to compile.
What is different here¶
No Parcelable. Screen is a plain commonMain interface. Persistence runs through
kotlinx-serialization on every platform, so there is no @Parcelize, no expect/actual
annotation shim, and no Android-only supertype leaking into shared code.
No annotation processor. Presenter and UI factories are registered by hand on
Orbit.Builder. Nothing is generated, so nothing is hidden.
Overlays return values. overlayHost.show(overlay) suspends and returns the user's choice,
which removes the usual showDialog / onDismiss state juggling.
State that outlives configuration changes. rememberRetained keeps values across rotation
and across navigating away and back, without you writing a ViewModel.
Where to go next¶
- Quick start — a running screen in a few minutes.
- Screens, presenters and UIs — the core loop in detail.
- Navigation — back stack, results and persistence.
- Testing — presenters without an emulator.
License¶
Apache 2.0.