Skip to content

Commit 3c9faae

Browse files
committed
Migrate to ui state
1 parent 0446f84 commit 3c9faae

File tree

4 files changed

+84
-22
lines changed

4 files changed

+84
-22
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package app.web.drjackycv.core.network.entity
2+
3+
import app.web.drjackycv.common.exceptions.Failure
4+
import kotlinx.coroutines.flow.Flow
5+
import kotlinx.coroutines.flow.catch
6+
import kotlinx.coroutines.flow.map
7+
import kotlinx.coroutines.flow.onStart
8+
import java.net.SocketTimeoutException
9+
import java.net.UnknownHostException
10+
import java.util.concurrent.TimeoutException
11+
12+
sealed interface Result<out T> {
13+
data class Success<T>(val data: T) : Result<T>
14+
data class Error(val failure: Failure) : Result<Nothing>
15+
object Loading : Result<Nothing>
16+
}
17+
18+
fun <T> Flow<T>.asResult(): Flow<Result<T>> {
19+
return this
20+
.map<T, Result<T>> {
21+
Result.Success(it)
22+
}
23+
.onStart { emit(Result.Loading) }
24+
.catch { e ->
25+
when (e) {
26+
is UnknownHostException, is SocketTimeoutException -> {
27+
emit(Result.Error(Failure.NoInternet(e.message)))
28+
}
29+
is TimeoutException -> {
30+
emit(Result.Error(Failure.Timeout(e.message)))
31+
}
32+
else -> {
33+
emit(Result.Error(Failure.Unknown(e.message)))
34+
}
35+
}
36+
}
37+
}

features/characters/src/main/java/app/web/drjackycv/features/characters/data/CharactersPagingSource.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class CharactersPagingSource @Inject constructor(
3939

4040
toLoadResult(responseCharacters, position)
4141
} catch (e: Exception) {
42-
when (e) {
42+
when (e.cause?.cause) {
4343
is UnknownHostException, is SocketTimeoutException -> {
4444
LoadResult.Error(
4545
Failure.NoInternet(e.message)

features/characters/src/main/java/app/web/drjackycv/features/characters/presentation/Characters.kt

+12-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import androidx.navigation.fragment.FragmentNavigatorExtras
1111
import androidx.navigation.fragment.findNavController
1212
import androidx.paging.CombinedLoadStates
1313
import androidx.paging.LoadState
14-
import androidx.paging.PagingData
1514
import androidx.recyclerview.widget.GridLayoutManager
1615
import androidx.recyclerview.widget.RecyclerView
1716
import app.web.drjackycv.common.exceptions.Failure
@@ -83,10 +82,18 @@ class Characters : Fragment(R.layout.characters) {
8382
}
8483
}
8584

86-
private fun addCharactersList(charactersList: PagingData<CharacterDetail>) {
87-
loadingUI(false)
88-
binding.rvCharactersList.visible()
89-
charactersAdapter.submitData(lifecycle, charactersList)
85+
private fun addCharactersList(uiState: CharactersUiState) {
86+
when (uiState) {
87+
is CharactersUiState.Success -> {
88+
loadingUI(false)
89+
binding.rvCharactersList.visible()
90+
charactersAdapter.submitData(lifecycle, uiState.items)
91+
}
92+
else -> {
93+
//no-op: is handled by addLoadStateListener
94+
}
95+
}
96+
9097
}
9198

9299
private fun loadingUI(isLoading: Boolean) {

features/characters/src/main/java/app/web/drjackycv/features/characters/presentation/CharactersListViewModel.kt

+34-16
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ import androidx.paging.PagingData
88
import androidx.paging.cachedIn
99
import app.web.drjackycv.common.exceptions.Failure
1010
import app.web.drjackycv.common.models.fragment.CharacterDetail
11+
import app.web.drjackycv.core.network.entity.Result
12+
import app.web.drjackycv.core.network.entity.asResult
1113
import app.web.drjackycv.features.characters.R
1214
import app.web.drjackycv.features.characters.domain.GetCharactersListUseCase
1315
import dagger.hilt.android.lifecycle.HiltViewModel
1416
import kotlinx.coroutines.channels.Channel
15-
import kotlinx.coroutines.flow.Flow
16-
import kotlinx.coroutines.flow.MutableStateFlow
17-
import kotlinx.coroutines.flow.first
18-
import kotlinx.coroutines.flow.receiveAsFlow
17+
import kotlinx.coroutines.flow.*
1918
import kotlinx.coroutines.launch
2019
import javax.inject.Inject
2120

@@ -30,21 +29,32 @@ class CharactersListViewModel @Inject constructor(
3029

3130
private val _failure: Channel<Failure> = Channel(Channel.BUFFERED)
3231
val failure: Flow<Failure> = _failure.receiveAsFlow()
33-
private val _charactersList =
34-
MutableStateFlow<PagingData<CharacterDetail>>(PagingData.empty())
35-
val charactersList: Flow<PagingData<CharacterDetail>> = _charactersList
3632

37-
38-
init {
33+
val charactersList: StateFlow<CharactersUiState> =
3934
getCharacters()
40-
}
35+
.stateIn(
36+
scope = viewModelScope,
37+
started = SharingStarted.WhileSubscribed(5000),
38+
initialValue = CharactersUiState.Loading
39+
)
4140

42-
private fun getCharacters() {
43-
viewModelScope.launch {
44-
_charactersList.value = getCharactersListUseCase()
45-
.cachedIn(viewModelScope).first()
46-
}
47-
}
41+
private fun getCharacters() =
42+
getCharactersListUseCase()
43+
.cachedIn(viewModelScope)
44+
.asResult()
45+
.map { result ->
46+
when (result) {
47+
is Result.Success -> {
48+
CharactersUiState.Success(result.data)
49+
}
50+
is Result.Error -> {
51+
CharactersUiState.Error(result.failure)
52+
}
53+
is Result.Loading -> {
54+
CharactersUiState.Loading
55+
}
56+
}
57+
}
4858

4959
fun handleFailure(throwable: Throwable, retryAction: () -> Unit) {
5060
val failure = when (throwable) {
@@ -71,4 +81,12 @@ class CharactersListViewModel @Inject constructor(
7181
}
7282
}
7383

84+
}
85+
86+
sealed interface CharactersUiState {
87+
data class Success(val items: PagingData<CharacterDetail> = PagingData.empty()) :
88+
CharactersUiState
89+
90+
data class Error(val error: Failure) : CharactersUiState
91+
object Loading : CharactersUiState
7492
}

0 commit comments

Comments
 (0)