Skip to content

Instantly share code, notes, and snippets.

@mattmook
Created July 14, 2021 10:44
Show Gist options
  • Save mattmook/ea9805da5972732d37eff042f308f97e to your computer and use it in GitHub Desktop.
Save mattmook/ea9805da5972732d37eff042f308f97e to your computer and use it in GitHub Desktop.
The state of MVI on Android - Roxie - NoteListViewModel
class NoteListViewModel(
initialState: State?,
private val loadNoteListUseCase: GetNoteListUseCase
) : CoroutineViewModel<Action, State>() {
override val initialState = initialState ?: State(isIdle = true)
private val reducer: Reducer<State, Change> = { state, change ->
when (change) {
is Change.Loading -> state.copy(
isIdle = false,
isLoading = true,
notes = emptyList(),
isError = false
)
is Change.Notes -> state.copy(
isLoading = false,
notes = change.notes
)
is Change.Error -> state.copy(
isLoading = false,
isError = true
)
}
}
init {
bindActions()
}
private fun bindActions() {
val loadNotesChange: Flow<Change> = actions.asFlow()
.ofType<Action.LoadNotes>()
.flatMapLatest {
loadNoteListUseCase.loadAll()
.flowOn(Dispatchers.IO)
.map { Change.Notes(it) }
.defaultOnEmpty(Change.Notes(emptyList()))
.catch<Change> {
emit(Change.Error(it))
}
.onStart { emit(Change.Loading) }
}
// to handle multiple Changes, use Observable.merge to merge them into a single stream:
// val allChanges = Observable.merge(loadNotesChange, ...)
loadNotesChange
.scan(initialState) { state, change ->
reducer.invoke(state, change)
}
.filter { !it.isIdle }
.distinctUntilChanged()
.flowOn(Dispatchers.Main)
.observeState()
.catch {
Timber.e(it)
}
.launchHere()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment