Skip to content

Commit

Permalink
CHANGE to use type-safe view state to avoid illegal states
Browse files Browse the repository at this point in the history
  • Loading branch information
sebaslogen committed Aug 22, 2024
1 parent 2251484 commit 2042b01
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package nl.q42.template.data.user.local

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import nl.q42.template.data.user.local.model.UserEntity
import javax.inject.Inject

internal class UserLocalDataSource @Inject constructor() {

private val userFlow = MutableStateFlow<UserEntity?>(null) // this is dummy code, replace it with your own local storage implementation.
private val userFlow = MutableSharedFlow<UserEntity?>() // this is dummy code, replace it with your own local storage implementation.

fun setUser(userEntity: UserEntity) {
suspend fun setUser(userEntity: UserEntity) {

// usually you store in DataStore or DB here...

userFlow.update { userEntity } // this is dummy code, replace it with your own local storage implementation.
userFlow.emit(userEntity) // this is dummy code, replace it with your own local storage implementation.
}

fun getUserFlow(): Flow<UserEntity?> = userFlow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import nl.q42.template.actionresult.data.handleAction
import nl.q42.template.domain.user.usecase.FetchUserUseCase
Expand All @@ -29,7 +28,7 @@ class HomeViewModel @Inject constructor(
private val navigator: RouteNavigator,
) : ViewModel(), RouteNavigator by navigator {

private val _uiState = MutableStateFlow<HomeViewState>(HomeViewState())
private val _uiState = MutableStateFlow<HomeViewState>(HomeViewState.Loading)
val uiState: StateFlow<HomeViewState> = _uiState.asStateFlow()

init {
Expand Down Expand Up @@ -58,23 +57,21 @@ class HomeViewModel @Inject constructor(
fun fetchUser() {
viewModelScope.launch {

_uiState.update { it.copy(showError = false, isLoading = true) }
_uiState.value = HomeViewState.Loading

handleAction(
action = fetchUserUseCase(),
onError = { _uiState.update { it.copy(showError = true, isLoading = false) } },
onSuccess = { _uiState.update { it.copy(isLoading = false) } },
onError = { _uiState.value = HomeViewState.Error },
onSuccess = {},
)
}
}

private fun startObservingUserChanges() {
getUserFlowUseCase().filterNotNull().onEach { user ->
_uiState.update {
it.copy(
userEmailTitle = ViewStateString.Res(R.string.emailTitle, user.email.value)
)
}
_uiState.value = HomeViewState.Content(
userEmailTitle = ViewStateString.Res(R.string.emailTitle, user.email.value)
)
}.launchIn(viewModelScope)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package nl.q42.template.home.main.presentation

import nl.q42.template.ui.presentation.ViewStateString

data class HomeViewState(
val userEmailTitle: ViewStateString? = null,
val isLoading: Boolean = false,
val showError: Boolean = false,
)
sealed interface HomeViewState {
data class Content(val userEmailTitle: ViewStateString) : HomeViewState
data object Loading : HomeViewState
data object Error : HomeViewState
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@ internal fun HomeContent(
horizontalAlignment = CenterHorizontally,
) {

/**
* This is dummy. Use the strings file IRL.
*/
viewState.userEmailTitle?.get()?.let { Text(text = it) }

if (viewState.isLoading) CircularProgressIndicator()
if (viewState.showError) Text(text = "Error")
when(viewState) {
is HomeViewState.Content -> {
/**
* This is dummy. Use the strings file IRL.
*/
Text(text = viewState.userEmailTitle.get())
}
HomeViewState.Loading -> CircularProgressIndicator()
HomeViewState.Error -> Text(text = "Error")
}

Button(onClick = onLoadClicked) {
Text("Refresh")
Expand All @@ -55,22 +58,22 @@ internal fun HomeContent(
@Composable
private fun HomeContentErrorPreview() {
PreviewAppTheme {
HomeContent(HomeViewState(showError = true), {}, {}, {})
HomeContent(HomeViewState.Error, {}, {}, {})
}
}

@PreviewLightDark
@Composable
private fun HomeContentLoadingPreview() {
PreviewAppTheme {
HomeContent(HomeViewState(isLoading = true), {}, {}, {})
HomeContent(HomeViewState.Loading, {}, {}, {})
}
}

@PreviewLightDark
@Composable
private fun HomeContentEmptyPreview() {
PreviewAppTheme {
HomeContent(HomeViewState(userEmailTitle = "[email protected]".toViewStateString()), {}, {}, {})
HomeContent(HomeViewState.Content(userEmailTitle = "[email protected]".toViewStateString()), {}, {}, {})
}
}

0 comments on commit 2042b01

Please sign in to comment.