android-presentation-mvilisted
Install: claude install-skill lenorebreakneck630/claude-zero-to-hero-android-KMP
# Android / KMP Presentation Layer (MVI)
## Overview
Every screen has:
1. **State** — a single data class holding all UI state fields.
2. **Action** (Intent) — a sealed interface of all user-triggered actions.
3. **Event** — a sealed interface of one-time side effects (navigation, snackbar).
4. **ViewModel** — holds `StateFlow<State>`, processes `Action`, emits `Event` via `Channel`.
---
## State
```kotlin
data class NoteListState(
val notes: List<NoteUi> = emptyList(),
val isLoading: Boolean = false,
val error: UiText? = null
)
```
Always update state with `.update { }` — never replace the entire flow:
```kotlin
_state.update { it.copy(isLoading = true) }
```
---
## Action (Intent)
```kotlin
sealed interface NoteListAction {
data object OnRefreshClick : NoteListAction
data class OnNoteClick(val noteId: String) : NoteListAction
data class OnDeleteNote(val noteId: String) : NoteListAction
}
```
---
## Event (one-time side effects)
```kotlin
sealed interface NoteListEvent {
data class NavigateToDetail(val noteId: String) : NoteListEvent
data class ShowSnackbar(val message: UiText) : NoteListEvent
}
```
---
## ViewModel
```kotlin
class NoteListViewModel(
private val noteRepository: NoteRepository
) : ViewModel() {
private val _state = MutableStateFlow(NoteListState())
val state = _state.asStateFlow()
private val _events = Channel<NoteListEvent>()
val events = _events.receiveAsFlow()
fun o