@@ -2,65 +2,105 @@ package com.hoc.mergeadapter_sample
22
33import androidx.annotation.MainThread
44import androidx.lifecycle.*
5+ import com.hoc.mergeadapter_sample.PlaceholderState.*
56import kotlinx.coroutines.launch
7+ import kotlin.LazyThreadSafetyMode.NONE
68
9+ sealed class PlaceholderState {
10+ object Idle : PlaceholderState()
11+ object Loading : PlaceholderState()
12+ data class Failure (val throwable : Throwable ) : PlaceholderState()
13+ }
714
8- class MainVM : ViewModel () {
9- private val usersD = MutableLiveData <List <User >>().apply { value = emptyList() }
10- val userLiveData: LiveData <List <User >> get() = usersD
15+ class MainVM (private val getUsers : suspend (start: Int , limit: Int ) -> List <User >) : ViewModel() {
1116
12- private val loadingStateD =
13- MutableLiveData <PlaceholderState >().apply { value = PlaceholderState .Idle }
14- val loadingStateLiveData: LiveData <List <LoadingState >>
15- get() = loadingStateD.map {
16- when (it) {
17- null -> emptyList()
18- PlaceholderState .Idle -> emptyList()
19- PlaceholderState .Loading -> listOf (LoadingState .Loading )
20- is PlaceholderState .Error -> listOf (LoadingState .Error (it.throwable))
21- }
17+ // region Private
18+ private val usersD by lazy(NONE ) {
19+ MutableLiveData <List <User >>()
20+ .apply { value = emptyList() }
21+ .also { loadNextPage() /* load first page when first accessing*/ }
22+ }
23+ private val loadingStateD = MutableLiveData <PlaceholderState >().apply { value = Idle }
24+ private val firstPageStateD = MutableLiveData <PlaceholderState >().apply { value = Idle }
25+
26+ private var isFirstPage = true
27+
28+ private val shouldLoadNextPage: Boolean
29+ get() = if (isFirstPage) {
30+ firstPageStateD.value!! == Idle
31+ } else {
32+ loadingStateD.value!! == Idle
2233 }
2334
35+ private val shouldRetryNextPage: Boolean
36+ get() = if (isFirstPage) {
37+ firstPageStateD.value!! is Failure
38+ } else {
39+ loadingStateD.value!! is Failure
40+ }
41+
42+ // endregion
43+
44+ // region Public LiveDatas
45+
46+ val userLiveData: LiveData <List <User >> get() = usersD
47+
48+ val firstPageStateLiveData: LiveData <PlaceholderState > = firstPageStateD
49+
50+ val loadingStateLiveData: LiveData <List <PlaceholderState >>
51+ get() = loadingStateD.map { if (it == Idle ) emptyList() else listOf (it) }
52+
53+ // endregion
54+
55+ // region Public methods
2456 @MainThread
2557 fun loadNextPage () {
26- val state = loadingStateD.value
27- if (state == = null || state is PlaceholderState .Idle ) {
28- _loadNextPage ()
58+ if (shouldLoadNextPage) {
59+ loadNextPageInternal()
2960 }
3061 }
3162
3263 @MainThread
3364 fun retryNextPage () {
34- if (loadingStateD.value is PlaceholderState . Error ) {
35- _loadNextPage ()
65+ if (shouldRetryNextPage ) {
66+ loadNextPageInternal ()
3667 }
3768 }
69+ // endregion
3870
39- @Suppress(" FunctionName" )
40- private fun _loadNextPage () {
71+ private fun loadNextPageInternal () {
4172 viewModelScope.launch {
42- loadingStateD.value = PlaceholderState .Loading
73+ if (isFirstPage) {
74+ firstPageStateD.value = Loading
75+ } else {
76+ loadingStateD.value = Loading
77+ }
4378
44- val currentList = usersD.value ? : emptyList()
45- kotlin.runCatching { getUsers(start = currentList.size, limit = LIMIT ) }
79+ val currentList = usersD.value!!
80+
81+ runCatching { getUsers(currentList.size, LIMIT ) }
4682 .fold(
4783 onSuccess = {
84+ isFirstPage = currentList.isEmpty()
4885 usersD.value = currentList + it
49- loadingStateD.value = PlaceholderState .Idle
86+
87+ if (isFirstPage) {
88+ firstPageStateD.value = Idle
89+ } else {
90+ loadingStateD.value = Idle
91+ }
5092 },
5193 onFailure = {
52- loadingStateD.value = PlaceholderState .Error (it)
94+ if (isFirstPage) {
95+ firstPageStateD.value = Failure (it)
96+ } else {
97+ loadingStateD.value = Failure (it)
98+ }
5399 }
54100 )
55101 }
56102 }
57103
58- private sealed class PlaceholderState {
59- object Idle : PlaceholderState()
60- object Loading : PlaceholderState()
61- data class Error (val throwable : Throwable ) : PlaceholderState()
62- }
63-
64104 private companion object {
65105 const val LIMIT = 20
66106 }
0 commit comments