Challenge 3: A Full ViewModel with Loading State — Solution data class PostsUiState( val isLoading: Boolean = false, val posts: List = emptyList(), val errorMessage: String? = null ) class PostsViewModel(private val api: PostApiService) : ViewModel() { private val _uiState = MutableStateFlow(PostsUiState()) val uiState: StateFlow = _uiState.asStateFlow() init { loadPosts() } fun loadPosts() { viewModelScope.launch { _uiState.value = _uiState.value.copy(isLoading = true, errorMessage = null) when (val result = fetchPosts(api)) { is Success -> _uiState.value = _uiState.value.copy( isLoading = false, posts = result.data ) is Error -> _uiState.value = _uiState.value.copy( isLoading = false, errorMessage = result.message ) Loading -> Unit } } } } Notes: - init { loadPosts() } triggers the network call as soon as the ViewModel is created — the same construction-time-setup idea as an Activity's onCreate (Course 1, Chapter 2), applied to a ViewModel. - Setting errorMessage = null at the start of loadPosts() clears any previous error before retrying — without this, a failed load followed by a successful retry could otherwise leave a stale error message displayed alongside fresh data. - The "when (val result = fetchPosts(api))" pattern combines Kotlin Fundamentals Chapter 5's exhaustive when over a sealed class with capturing the matched value as "result" — every branch updates _uiState.value via copy(), keeping isLoading/posts/errorMessage always internally consistent, per Chapter 2's UiState pattern. - The Loading branch is required for the when to be exhaustive even though fetchPosts() as written never actually returns NetworkResult.Loading — sealed classes force every possible case to be handled, not just the ones a particular function happens to produce.