add MVI screen pattern skill and ObserverAsEvent helper - #119
Merged
Conversation
Establishes the architecture pattern we follow for screens going forward:
Screen + ScreenContent + ViewModel + UiState + UiEvent + UiEffect, with
initial fetches in the VM init {} block and one-shot effects collected
through a lifecycle-aware ObserverAsEvent.
- ObserverAsEvent in uicomponent/.../util/ ties effect collection to the
STARTED lifecycle state with Dispatchers.Main.immediate, so navigation
and snackbars only fire while the screen is visible.
- lifecycle-runtime-compose added to support androidx.lifecycle.compose
LocalLifecycleOwner and repeatOnLifecycle.
- Full pattern with templates lives in .claude/skills/mvi-screen.md.
CLAUDE.md carries a short pointer so the pattern gets applied on every
screen task without needing an explicit skill invocation.
- .gitignore now excludes .claude/settings.local.json (local user file)
while keeping the skills folder tracked.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Establishes the screen architecture we follow going forward, and ships the small helper the pattern depends on.
What's in
ObserverAsEventinuicomponent/src/main/java/com/android/swingmusic/uicomponent/presentation/util/. Lifecycle-aware effect collector. Ties collection to theSTARTEDstate and usesDispatchers.Main.immediateso navigation feels synchronous and effects don't fire while the screen is hidden.Added
lifecycle-runtime-composeto the version catalog and touicomponent's deps so we can useandroidx.lifecycle.compose.LocalLifecycleOwnerandrepeatOnLifecycle. Existing lifecycle version (2.8.7) already supports it, no version bump..claude/skills/mvi-screen.md— the full pattern with templates for each of the five files (Screen + ScreenContent, ViewModel, UiState, UiEvent, UiEffect). Invoke as/mvi-screenfor the templates. Key conventions baked in:init { }block. NoLaunchedEffectfor fetches in the Screen.Channel<UiEffect>and are always collected withObserverAsEvent. Never rawLaunchedEffect { effects.collect { } }.loadedInitialDataflag, the VM lifecycle handles it.ScreenContentis stateless so it can be@Previewd. The outerScreenbinds the VM and effects.CLAUDE.md— added a short pointer in the Architecture section so the pattern gets applied on every screen task without needing the skill to be explicitly invoked..gitignore— excludes.claude/settings.local.json(local user settings) while keeping the skills folder tracked.Why now
While working on #104 we noticed the folder screen refetches on every back-nav. Joel asked why, and the answer surfaced that we don't have a standard pattern for "data lives in the VM, screen just reads from it." This PR sets the baseline. Future screen work follows it; existing screens can be migrated incrementally when we touch them.
Not in scope
No existing screens are migrated in this PR. That can happen one screen at a time as we work on each feature.