Skip to content

Commit 542f981

Browse files
committed
feat: add uiState to ListScreen
1 parent 8440b0a commit 542f981

File tree

6 files changed

+100
-42
lines changed

6 files changed

+100
-42
lines changed

data/src/main/java/io/github/shinhyo/brba/data/repository/CharactersRepositoryImpl.kt

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,50 @@ import io.github.shinhyo.brba.data.mapper.toCharacterEntity
2222
import io.github.shinhyo.brba.data.remote.api.BaBrApi
2323
import io.github.shinhyo.brba.domain.model.Character
2424
import io.github.shinhyo.brba.domain.repository.CharactersRepository
25-
import kotlinx.coroutines.flow.Flow
26-
import kotlinx.coroutines.flow.combine
27-
import kotlinx.coroutines.flow.flow
28-
import kotlinx.coroutines.flow.flowOf
29-
import kotlinx.coroutines.flow.map
25+
import io.github.shinhyo.brba.domain.result.Result
26+
import kotlinx.coroutines.flow.*
27+
import java.util.*
3028
import javax.inject.Inject
29+
import kotlin.random.Random
3130

3231
open class CharactersRepositoryImpl @Inject constructor(
3332
private val api: BaBrApi,
3433
private val db: AppDatabase
3534
) : CharactersRepository {
3635

37-
override fun getCharacterList(): Flow<List<Character>> = flow { emit(api.getCharacters()) }
38-
.map { it.map { r -> r.toCharacter() } }
36+
companion object {
37+
const val MIN_RATIO = 1.2f
38+
}
39+
40+
private val random: Random by lazy { Random(Calendar.getInstance().timeInMillis) }
41+
42+
override fun getCharacterList(): Flow<Result<List<Character>>> {
43+
44+
fun changeRatio(list: List<Character>) =
45+
list.map { c ->
46+
val nextInt = random.nextInt(4) * 0.15f
47+
c.copy(ratio = MIN_RATIO + nextInt)
48+
}
49+
50+
fun addFavoriteToList(list: List<Character>) =
51+
db.characterDao().getAll()
52+
.map { dblist ->
53+
list.toMutableList().map {
54+
it.copy(
55+
favorite = dblist.find { i ->
56+
it.charId == i.charId
57+
}?.favorite ?: false
58+
)
59+
}
60+
}
61+
62+
return flow { emit(api.getCharacters()) }
63+
.map { it.map { r -> r.toCharacter() } }
64+
.map { changeRatio(it) }
65+
.flatMapConcat { addFavoriteToList(it) }
66+
.map { Result.Success(it) }
67+
}
68+
3969

4070
override fun getFavoriteList(isAsc: Boolean): Flow<List<Character>> =
4171
db.characterDao().getFavorite(isAsc = isAsc)
@@ -51,16 +81,6 @@ open class CharactersRepositoryImpl @Inject constructor(
5181
res.copy(favorite = entity?.favorite ?: false)
5282
}
5383

54-
override fun addFavoriteStatus(listCharacter: List<Character>): Flow<List<Character>> =
55-
flowOf(listCharacter)
56-
.combine(
57-
db.characterDao().getAll()
58-
) { list: List<Character>, db: List<CharacterEntity> ->
59-
list.toMutableList().map {
60-
it.copy(favorite = db.find { i -> it.charId == i.charId }?.favorite ?: false)
61-
}
62-
}
63-
6484
override fun updateFavorite(character: Character): Flow<Boolean> = flowOf(character)
6585
.map { it.toCharacterEntity().copy(favorite = !character.favorite) }
6686
.map { db.characterDao().insert(it) }

domain/src/main/java/io/github/shinhyo/brba/domain/repository/CharactersRepository.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
package io.github.shinhyo.brba.domain.repository
1717

1818
import io.github.shinhyo.brba.domain.model.Character
19+
import io.github.shinhyo.brba.domain.result.Result
1920
import kotlinx.coroutines.flow.Flow
2021

2122
interface CharactersRepository {
22-
fun getCharacterList(): Flow<List<Character>>
23+
fun getCharacterList(): Flow<Result<List<Character>>>
2324
fun getFavoriteList(isAsc: Boolean = false): Flow<List<Character>>
2425
fun getCharacterById(id: Long): Flow<Character>
25-
fun addFavoriteStatus(listCharacter: List<Character>): Flow<List<Character>>
2626
fun updateFavorite(character: Character): Flow<Boolean>
2727
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.github.shinhyo.brba.domain.usecase
2+
3+
import io.github.shinhyo.brba.domain.di.IoDispatcher
4+
import io.github.shinhyo.brba.domain.model.Character
5+
import io.github.shinhyo.brba.domain.repository.CharactersRepository
6+
import io.github.shinhyo.brba.domain.result.Result
7+
import kotlinx.coroutines.CoroutineDispatcher
8+
import kotlinx.coroutines.flow.Flow
9+
import javax.inject.Inject
10+
11+
class GetCharacterListUseCase @Inject constructor(
12+
private val charactersRepository: CharactersRepository,
13+
@IoDispatcher dispatcher: CoroutineDispatcher,
14+
) : FlowUseCase<Unit, List<Character>>(dispatcher) {
15+
16+
override fun execute(parameters: Unit): Flow<Result<List<Character>>> =
17+
charactersRepository.getCharacterList()
18+
19+
}

presentation/src/main/java/io/github/shinhyo/brba/presentation/ui/list/ListScreen.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import androidx.compose.material.MaterialTheme
2121
import androidx.compose.material.Surface
2222
import androidx.compose.material.Text
2323
import androidx.compose.runtime.Composable
24-
import androidx.compose.runtime.State
2524
import androidx.compose.runtime.collectAsState
2625
import androidx.compose.ui.Modifier
2726
import androidx.compose.ui.graphics.Brush
@@ -49,14 +48,14 @@ fun ListScreen(
4948
state: ScrollState,
5049
modifier: Modifier = Modifier
5150
) {
52-
val list = viewModel.list.collectAsState()
51+
val uiState = viewModel.uiState.collectAsState()
5352
val clickFavorite: (Character) -> Unit = viewModel::upsertFavorite
54-
Body(list, select, clickFavorite, state, modifier)
53+
Body(uiState.value.list, select, clickFavorite, state, modifier)
5554
}
5655

5756
@Composable
5857
private fun Body(
59-
list: State<List<Character>>,
58+
list: List<Character>,
6059
select: (Character) -> Unit,
6160
clickFavorite: (Character) -> Unit,
6261
state: ScrollState,
@@ -79,7 +78,7 @@ private fun Body(
7978
maxColumnWidth = 160.dp,
8079
modifier = Modifier.padding(4.dp)
8180
) {
82-
list.value.forEach {
81+
list.forEach {
8382
FeaturedList(
8483
character = it, select = select,
8584
clickFavorite = clickFavorite

presentation/src/main/java/io/github/shinhyo/brba/presentation/ui/list/ListViewModel.kt

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,45 +15,64 @@
1515
*/
1616
package io.github.shinhyo.brba.presentation.ui.list
1717

18+
import androidx.annotation.StringRes
1819
import androidx.lifecycle.viewModelScope
1920
import dagger.hilt.android.lifecycle.HiltViewModel
2021
import io.github.shinhyo.brba.domain.model.Character
21-
import io.github.shinhyo.brba.domain.usecase.AddFavoriteToListUseCase
22+
import io.github.shinhyo.brba.domain.result.Result
2223
import io.github.shinhyo.brba.domain.usecase.GetCharacterListUseCase
2324
import io.github.shinhyo.brba.domain.usecase.UpdateFavoriteUseCase
25+
import io.github.shinhyo.brba.presentation.R
2426
import io.github.shinhyo.brba.presentation.ui.BaseFavoriteViewModel
25-
import kotlinx.coroutines.Dispatchers
26-
import kotlinx.coroutines.flow.MutableStateFlow
27-
import kotlinx.coroutines.flow.StateFlow
28-
import kotlinx.coroutines.flow.catch
29-
import kotlinx.coroutines.flow.flatMapConcat
30-
import kotlinx.coroutines.flow.flowOn
31-
import kotlinx.coroutines.flow.launchIn
32-
import kotlinx.coroutines.flow.onEach
27+
import kotlinx.coroutines.flow.*
3328
import javax.inject.Inject
3429

30+
31+
data class ListUiState(
32+
val isLoading: Boolean = false,
33+
@StringRes val errorMessages: Int? = null,
34+
val list: List<Character> = emptyList()
35+
)
36+
3537
@HiltViewModel
3638
class ListViewModel
3739
@Inject constructor(
3840
private val getCharacterListUseCase: GetCharacterListUseCase,
39-
private val addFavoriteToListUseCase: AddFavoriteToListUseCase,
4041
updateFavoriteUseCase: UpdateFavoriteUseCase,
4142
) : BaseFavoriteViewModel(updateFavoriteUseCase) {
4243

43-
private val _list = MutableStateFlow(emptyList<Character>())
44-
val list: StateFlow<List<Character>> get() = _list
44+
private val _uiState = MutableStateFlow(ListUiState())
45+
val uiState = _uiState.asStateFlow()
46+
4547

4648
init {
4749
getCharacterList()
4850
}
4951

5052
private fun getCharacterList() {
51-
getCharacterListUseCase.execute()
52-
.onEach { _list.value = it }
53-
.flatMapConcat { addFavoriteToListUseCase.execute(it) }
54-
.onEach { _list.value = it }
55-
.flowOn(Dispatchers.IO)
56-
.catch { e -> e.printStackTrace() }
53+
_uiState.update { it.copy(isLoading = true) }
54+
55+
getCharacterListUseCase(Unit)
56+
.onEach { result ->
57+
when (result) {
58+
is Result.Success -> {
59+
_uiState.update {
60+
it.copy(
61+
isLoading = true,
62+
list = result.data
63+
)
64+
}
65+
}
66+
is Result.Error -> {
67+
_uiState.update {
68+
it.copy(
69+
isLoading = true,
70+
errorMessages = R.string.error_load
71+
)
72+
}
73+
}
74+
}
75+
}
5776
.launchIn(viewModelScope)
5877
}
5978
}

presentation/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
<string name="app_name">BrBa-Compose</string>
33
<string name="brba">BrBa</string>
44
<string name="empty">Empty</string>
5+
<string name="error_load">Can\'t update</string>
56
</resources>

0 commit comments

Comments
 (0)