@@ -2,10 +2,8 @@ package com.hoc081098.paginationmviflow.ui.main
22
33import androidx.lifecycle.ViewModel
44import androidx.lifecycle.viewModelScope
5- import com.hoc081098.flowext.flatMapFirst
6- import com.hoc081098.flowext.withLatestFrom
75import com.hoc081098.paginationmviflow.FlowTransformer
8- import com.hoc081098.paginationmviflow.ui.main.MainContract.Interactor
6+ import com.hoc081098.paginationmviflow.pipe
97import com.hoc081098.paginationmviflow.ui.main.MainContract.PartialStateChange
108import com.hoc081098.paginationmviflow.ui.main.MainContract.PartialStateChange.PhotoFirstPage
119import com.hoc081098.paginationmviflow.ui.main.MainContract.PartialStateChange.PhotoNextPage
@@ -24,9 +22,7 @@ import kotlinx.coroutines.flow.StateFlow
2422import kotlinx.coroutines.flow.asStateFlow
2523import kotlinx.coroutines.flow.filter
2624import kotlinx.coroutines.flow.filterIsInstance
27- import kotlinx.coroutines.flow.flatMapMerge
2825import kotlinx.coroutines.flow.launchIn
29- import kotlinx.coroutines.flow.map
3026import kotlinx.coroutines.flow.merge
3127import kotlinx.coroutines.flow.onEach
3228import kotlinx.coroutines.flow.receiveAsFlow
@@ -43,7 +39,9 @@ import com.hoc081098.paginationmviflow.ui.main.MainContract.ViewState as VS
4339 FlowPreview ::class
4440)
4541@HiltViewModel
46- class MainVM @Inject constructor(private val interactor : Interactor ) : ViewModel() {
42+ class MainVM @Inject constructor(
43+ private val mainProcessors : MainProcessors ,
44+ ) : ViewModel() {
4745 private val initialVS = VS .initial()
4846
4947 private val _stateSF = MutableStateFlow (initialVS)
@@ -55,121 +53,52 @@ class MainVM @Inject constructor(private val interactor: Interactor) : ViewModel
5553
5654 suspend fun processIntent (intent : VI ) = _intentSF .emit(intent)
5755
58- private val initialProcessor :
59- FlowTransformer < VI . Initial , PartialStateChange > = { intents ->
56+ private val toPartialStateChange : FlowTransformer < VI , PartialStateChange > =
57+ FlowTransformer { intents ->
6058 intents
61- .withLatestFrom(_stateSF )
62- .filter { (_, vs) -> vs.photoItems.isEmpty() }
63- .flatMapMerge {
59+ .shareIn(viewModelScope, SharingStarted .WhileSubscribed ())
60+ .let { shared ->
6461 merge(
65- interactor.photoFirstPageChanges(limit = PHOTO_PAGE_SIZE ),
66- interactor.postFirstPageChanges(limit = POST_PAGE_SIZE )
62+ shared.filterIsInstance<VI .Initial >()
63+ .pipe(mainProcessors.getInitialProcessor(stateFlow)),
64+ shared.filterIsInstance<VI .LoadNextPage >()
65+ .pipe(mainProcessors.getNextPageProcessor(stateFlow)),
66+ shared.filterIsInstance<VI .RetryLoadPage >()
67+ .pipe(mainProcessors.getRetryLoadPageProcessor(stateFlow)),
68+ shared.filterIsInstance<VI .LoadNextPageHorizontal >()
69+ .pipe(mainProcessors.getLoadNextPageHorizontalProcessor(stateFlow)),
70+ shared.filterIsInstance<VI .RetryLoadPageHorizontal >()
71+ .pipe(mainProcessors.getRetryLoadPageHorizontalProcessor(stateFlow)),
72+ shared.filterIsInstance<VI .RetryHorizontal >()
73+ .pipe(mainProcessors.getRetryHorizontalProcessor(stateFlow)),
74+ shared.filterIsInstance<VI .Refresh >()
75+ .pipe(mainProcessors.getRefreshProcessor(stateFlow))
6776 )
6877 }
78+ .pipe(sendSingleEvent)
6979 }
7080
71- private val nextPageProcessor: FlowTransformer <VI .LoadNextPage , PartialStateChange > =
72- { intents ->
73- intents
74- .withLatestFrom(_stateSF )
75- .filter { (_, vs) -> vs.canLoadNextPage() }
76- .map { (_, vs) -> vs.photoItems.size }
77- .flatMapFirst { interactor.photoNextPageChanges(start = it, limit = PHOTO_PAGE_SIZE ) }
78- }
79-
80- private val retryLoadPageProcessor: FlowTransformer <VI .RetryLoadPage , PartialStateChange > =
81- { intents ->
82- intents
83- .withLatestFrom(_stateSF )
84- .filter { (_, vs) -> vs.shouldRetry() }
85- .map { (_, vs) -> vs.photoItems.size }
86- .flatMapFirst { interactor.photoNextPageChanges(start = it, limit = PHOTO_PAGE_SIZE ) }
87- }
88-
89- private val loadNextPageHorizontalProcessor: FlowTransformer <VI .LoadNextPageHorizontal , PartialStateChange > =
90- { intents ->
91- intents
92- .withLatestFrom(_stateSF )
93- .filter { (_, vs) -> vs.canLoadNextPageHorizontal() }
94- .map { (_, vs) -> vs.getHorizontalListCount() }
95- .flatMapFirst { interactor.postNextPageChanges(start = it, limit = POST_PAGE_SIZE ) }
96- }
97-
98- private val retryLoadPageHorizontalProcessor: FlowTransformer <VI .RetryLoadPageHorizontal , PartialStateChange > =
99- { intents ->
100- intents
101- .withLatestFrom(_stateSF )
102- .filter { (_, vs) -> vs.shouldRetryNextPageHorizontal() }
103- .map { (_, vs) -> vs.getHorizontalListCount() }
104- .flatMapFirst { interactor.postNextPageChanges(start = it, limit = POST_PAGE_SIZE ) }
105- }
106-
107- private val retryHorizontalProcessor: FlowTransformer <VI .RetryHorizontal , PartialStateChange > =
108- { intents ->
109- intents
110- .withLatestFrom(_stateSF )
111- .filter { (_, vs) -> vs.shouldRetryHorizontal() }
112- .flatMapFirst { interactor.postFirstPageChanges(limit = POST_PAGE_SIZE ) }
113- }
114-
115- private val refreshProcessor: FlowTransformer <VI .Refresh , PartialStateChange > =
116- { intents ->
117- intents
118- .withLatestFrom(_stateSF )
119- .filter { (_, vs) -> vs.enableRefresh }
120- .flatMapFirst {
121- interactor.refreshAll(
122- limitPhoto = PHOTO_PAGE_SIZE ,
123- limitPost = POST_PAGE_SIZE
124- )
125- }
126- }
127-
128- private val toPartialStateChange: FlowTransformer <VI , PartialStateChange > = { intents ->
129- intents
130- .shareIn(viewModelScope, SharingStarted .WhileSubscribed ())
131- .let { shared ->
132- merge(
133- shared.filterIsInstance<VI .Initial >()
134- .let (initialProcessor),
135- shared.filterIsInstance<VI .LoadNextPage >()
136- .let (nextPageProcessor),
137- shared.filterIsInstance<VI .RetryLoadPage >()
138- .let (retryLoadPageProcessor),
139- shared.filterIsInstance<VI .LoadNextPageHorizontal >()
140- .let (loadNextPageHorizontalProcessor),
141- shared.filterIsInstance<VI .RetryLoadPageHorizontal >()
142- .let (retryLoadPageHorizontalProcessor),
143- shared.filterIsInstance<VI .RetryHorizontal >()
144- .let (retryHorizontalProcessor),
145- shared.filterIsInstance<VI .Refresh >()
146- .let (refreshProcessor)
147- )
148- }
149- .let (sendSingleEvent)
150- }
151-
15281 private val sendSingleEvent: FlowTransformer <PartialStateChange , PartialStateChange > =
153- { changes ->
82+ FlowTransformer { changes ->
15483 changes
15584 .onEach { change ->
15685 when (change) {
15786 is PhotoFirstPage .Data -> if (change.photos.isEmpty()) _singleEventChannel .send(SE .HasReachedMax )
15887 is PhotoFirstPage .Error -> _singleEventChannel .send(SE .GetPhotosFailure (change.error))
15988 PhotoFirstPage .Loading -> Unit
160- // /
89+ //
16190 is PhotoNextPage .Data -> if (change.photos.isEmpty()) _singleEventChannel .send(SE .HasReachedMax )
16291 is PhotoNextPage .Error -> _singleEventChannel .send(SE .GetPhotosFailure (change.error))
16392 PhotoNextPage .Loading -> Unit
164- // /
93+ //
16594 is PostFirstPage .Data -> if (change.posts.isEmpty()) _singleEventChannel .send(SE .HasReachedMaxHorizontal )
16695 is PostFirstPage .Error -> _singleEventChannel .send(SE .GetPostsFailure (change.error))
16796 PostFirstPage .Loading -> Unit
168- // /
97+ //
16998 is PostNextPage .Data -> if (change.posts.isEmpty()) _singleEventChannel .send(SE .HasReachedMaxHorizontal )
17099 is PostNextPage .Error -> _singleEventChannel .send(SE .GetPostsFailure (change.error))
171100 PostNextPage .Loading -> Unit
172- // /
101+ //
173102 is Refresh .Success -> _singleEventChannel .send(SE .RefreshSuccess )
174103 is Refresh .Error -> _singleEventChannel .send(SE .RefreshFailure (change.error))
175104 Refresh .Refreshing -> Unit
@@ -179,15 +108,15 @@ class MainVM @Inject constructor(private val interactor: Interactor) : ViewModel
179108
180109 init {
181110 _intentSF
182- .let (intentFilterer)
183- .let (toPartialStateChange)
111+ .pipe (intentFilterer)
112+ .pipe (toPartialStateChange)
184113 .scan(initialVS) { vs, change -> change.reduce(vs) }
185114 .onEach { _stateSF .value = it }
186115 .launchIn(viewModelScope)
187116 }
188117
189- private companion object {
190- val intentFilterer: FlowTransformer <VI , VI > = { intents ->
118+ internal companion object {
119+ val intentFilterer: FlowTransformer <VI , VI > = FlowTransformer { intents ->
191120 merge(
192121 intents.filterIsInstance<VI .Initial >().take(1 ),
193122 intents.filter { it !is VI .Initial }
0 commit comments