Skip to content

Instantly share code, notes, and snippets.

@fvilarino
Last active April 12, 2021 23:52
Show Gist options
  • Save fvilarino/0bc71576b593396d9e446eec23b9cf4b to your computer and use it in GitHub Desktop.
Save fvilarino/0bc71576b593396d9e446eec23b9cf4b to your computer and use it in GitHub Desktop.
Cities MVI ViewModel
enum class LoadState {
IDLE,
LOADING,
LOADED,
ERROR
}
data class CityState(
val loadState: LoadState,
val cities: List<CityResultModel>,
val errorMessage: CharSequence,
) : State {
companion object {
val initial = CityState(
loadState = LoadState.IDLE,
cities = emptyList(),
errorMessage = "",
)
}
}
sealed class CityMviIntent : MviIntent {
data class PrefixUpdated(val prefix: String) : CityMviIntent()
}
sealed class CityReduceAction : ReduceAction {
object Loading : CityReduceAction()
data class Loaded(val cities: List<CityResultModel>) : CityReduceAction()
data class LoadError(val message: CharSequence) : CityReduceAction()
}
private const val MIN_CITY_LENGTH_FOR_SEARCH = 3
@HiltViewModel
class CityViewModel @Inject constructor(
private val getCitiesInteractor: GetCitiesInteractor,
private val navigator: Navigator,
) : MviViewModel<CityState, CityMviIntent, CityReduceAction>(
initialState = CityState.initial
) {
/* handles Intents from the View */
override suspend fun executeIntent(mviIntent: CityMviIntent) {
when (mviIntent) {
is CityMviIntent.PrefixUpdated -> {
if (mviIntent.prefix.length >= MIN_CITY_LENGTH_FOR_SEARCH) {
handle(CityReduceAction.Loading)
val result = getCitiesInteractor.execute(mviIntent.prefix)
result.fold(
onSuccess = { response ->
handle(
CityReduceAction.Loaded(
cities = response.map { city -> city.toCityResultModel() }
)
)
},
onFailure = {
handle(CityReduceAction.LoadError("Failed to load cities"))
}
)
} else {
handle(CityReduceAction.Loaded(emptyList()))
}
}
}
}
/* creates a new state as a result of actions distilled from Intents */
override fun reduce(state: CityState, reduceAction: CityReduceAction): CityState =
when (reduceAction) {
CityReduceAction.Loading -> state.copy(
loadState = LoadState.LOADING,
errorMessage = "",
)
is CityReduceAction.Loaded -> state.copy(
loadState = LoadState.LOADED,
cities = reduceAction.cities,
errorMessage = "",
)
is CityReduceAction.LoadError -> state.copy(
loadState = LoadState.ERROR,
errorMessage = reduceAction.message,
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment