← ClaudeAtlas

android-presentation-mvilisted

MVI presentation layer for Android/KMP - State, Action, Event, ViewModel, Root/Screen composable split, UI models, UiText error mapping, and process death with SavedStateHandle. Use this skill whenever creating or reviewing a ViewModel, defining screen state, actions, or events, structuring composables, mapping errors to UI strings, or handling process death. Trigger on phrases like "add a ViewModel", "create a screen", "MVI", "state", "action", "event", "screen composable", "UiText", "SavedStateHandle", "ObserveAsEvents", or "UI model".
lenorebreakneck630/claude-zero-to-hero-android-KMP · ★ 1 · AI & Automation · score 64
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