Skip to content

Commit 4009f43

Browse files
authored
Merge pull request #15637 from wordpress-mobile/issue/15498-connect-dashboard-cards-store-with-source
My Site Dashboard [Phase 2]: Connect Dashboard Cards Store with Source
2 parents 4dae40f + 3097529 commit 4009f43

27 files changed

+835
-710
lines changed

WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteAdapter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.SiteInfoCard
1313
import org.wordpress.android.ui.mysite.MySiteCardAndItem.DynamicCard.QuickStartDynamicCard
1414
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Item.CategoryHeaderItem
1515
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Item.ListItem
16+
import org.wordpress.android.ui.mysite.cards.dashboard.posts.PostCardViewHolder
1617
import org.wordpress.android.ui.mysite.cards.domainregistration.DomainRegistrationViewHolder
17-
import org.wordpress.android.ui.mysite.cards.post.PostCardViewHolder
1818
import org.wordpress.android.ui.mysite.cards.quickactions.QuickActionsViewHolder
1919
import org.wordpress.android.ui.mysite.cards.quickstart.QuickStartCardViewHolder
2020
import org.wordpress.android.ui.mysite.cards.siteinfo.MySiteInfoViewHolder

WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteCardAndItem.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import org.wordpress.android.ui.mysite.MySiteCardAndItem.Type.QUICK_ACTIONS_CARD
1414
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Type.QUICK_START_CARD
1515
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Type.QUICK_START_DYNAMIC_CARD
1616
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Type.SITE_INFO_CARD
17-
import org.wordpress.android.ui.mysite.cards.post.PostCardType
17+
import org.wordpress.android.ui.mysite.cards.dashboard.posts.PostCardType
1818
import org.wordpress.android.ui.utils.ListItemInteraction
1919
import org.wordpress.android.ui.utils.UiString
2020

WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteCardAndItemBuilderParams.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package org.wordpress.android.ui.mysite
22

33
import org.wordpress.android.fluxc.model.SiteModel
4+
import org.wordpress.android.fluxc.model.dashboard.CardModel.PostsCardModel
45
import org.wordpress.android.fluxc.store.QuickStartStore.QuickStartTask
56
import org.wordpress.android.fluxc.store.QuickStartStore.QuickStartTaskType
6-
import org.wordpress.android.ui.mysite.cards.post.PostCardType
7-
import org.wordpress.android.ui.mysite.cards.post.mockdata.MockedPostsData
7+
import org.wordpress.android.ui.mysite.cards.dashboard.posts.PostCardType
88
import org.wordpress.android.ui.mysite.cards.quickstart.QuickStartRepository.QuickStartCategory
99
import org.wordpress.android.ui.mysite.items.listitem.ListItemAction
1010

@@ -15,7 +15,7 @@ sealed class MySiteCardAndItemBuilderParams {
1515
) : MySiteCardAndItemBuilderParams()
1616

1717
data class PostCardBuilderParams(
18-
val mockedPostsData: MockedPostsData?,
18+
val posts: PostsCardModel?,
1919
val onPostItemClick: (postId: Int) -> Unit,
2020
val onFooterLinkClick: (postCardType: PostCardType) -> Unit
2121
) : MySiteCardAndItemBuilderParams()

WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteSourceManager.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import org.wordpress.android.analytics.AnalyticsTracker.Stat
77
import org.wordpress.android.ui.mysite.MySiteSource.MySiteRefreshSource
88
import org.wordpress.android.ui.mysite.MySiteSource.SiteIndependentSource
99
import org.wordpress.android.ui.mysite.MySiteUiState.PartialState
10+
import org.wordpress.android.ui.mysite.cards.dashboard.CardsSource
1011
import org.wordpress.android.ui.mysite.cards.domainregistration.DomainRegistrationSource
11-
import org.wordpress.android.ui.mysite.cards.post.PostCardsSource
1212
import org.wordpress.android.ui.mysite.cards.quickstart.QuickStartCardSource
1313
import org.wordpress.android.ui.mysite.dynamiccards.DynamicCardMenuViewModel.DynamicCardMenuInteraction
1414
import org.wordpress.android.ui.mysite.dynamiccards.DynamicCardMenuViewModel.DynamicCardMenuInteraction.Hide
@@ -27,7 +27,7 @@ class MySiteSourceManager @Inject constructor(
2727
private val quickStartCardSource: QuickStartCardSource,
2828
private val scanAndBackupSource: ScanAndBackupSource,
2929
private val selectedSiteSource: SelectedSiteSource,
30-
postCardsSource: PostCardsSource,
30+
cardsSource: CardsSource,
3131
siteIconProgressSource: SiteIconProgressSource,
3232
private val mySiteDashboardPhase2FeatureConfig: MySiteDashboardPhase2FeatureConfig
3333
) {
@@ -39,7 +39,7 @@ class MySiteSourceManager @Inject constructor(
3939
domainRegistrationSource,
4040
scanAndBackupSource,
4141
dynamicCardsSource,
42-
postCardsSource
42+
cardsSource
4343
)
4444

4545
fun build(coroutineScope: CoroutineScope, siteLocalId: Int?): List<LiveData<out PartialState>> {

WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteUiState.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@ package org.wordpress.android.ui.mysite
22

33
import org.wordpress.android.fluxc.model.DynamicCardType
44
import org.wordpress.android.fluxc.model.SiteModel
5+
import org.wordpress.android.fluxc.model.dashboard.CardModel
56
import org.wordpress.android.fluxc.store.QuickStartStore.QuickStartTask
7+
import org.wordpress.android.fluxc.store.dashboard.CardsStore.CardsResult
8+
import org.wordpress.android.ui.mysite.MySiteUiState.PartialState.CardsUpdate
69
import org.wordpress.android.ui.mysite.MySiteUiState.PartialState.CurrentAvatarUrl
710
import org.wordpress.android.ui.mysite.MySiteUiState.PartialState.DomainCreditAvailable
811
import org.wordpress.android.ui.mysite.MySiteUiState.PartialState.DynamicCardsUpdate
912
import org.wordpress.android.ui.mysite.MySiteUiState.PartialState.JetpackCapabilities
10-
import org.wordpress.android.ui.mysite.MySiteUiState.PartialState.PostsUpdate
1113
import org.wordpress.android.ui.mysite.MySiteUiState.PartialState.QuickStartUpdate
1214
import org.wordpress.android.ui.mysite.MySiteUiState.PartialState.SelectedSite
1315
import org.wordpress.android.ui.mysite.MySiteUiState.PartialState.ShowSiteIconProgressBar
14-
import org.wordpress.android.ui.mysite.cards.post.mockdata.MockedPostsData
1516
import org.wordpress.android.ui.mysite.cards.quickstart.QuickStartRepository.QuickStartCategory
1617

1718
data class MySiteUiState(
@@ -25,7 +26,7 @@ data class MySiteUiState(
2526
val quickStartCategories: List<QuickStartCategory> = listOf(),
2627
val pinnedDynamicCard: DynamicCardType? = null,
2728
val visibleDynamicCards: List<DynamicCardType> = listOf(),
28-
val mockedPostsData: MockedPostsData? = null
29+
val cards: CardsResult<List<CardModel>>? = null
2930
) {
3031
sealed class PartialState {
3132
data class CurrentAvatarUrl(val url: String) : PartialState()
@@ -43,7 +44,7 @@ data class MySiteUiState(
4344
val cards: List<DynamicCardType>
4445
) : PartialState()
4546

46-
data class PostsUpdate(val mockedPostsData: MockedPostsData? = null) : PartialState()
47+
data class CardsUpdate(val cards: CardsResult<List<CardModel>>) : PartialState()
4748
}
4849

4950
fun update(partialState: PartialState): MySiteUiState {
@@ -64,7 +65,7 @@ data class MySiteUiState(
6465
pinnedDynamicCard = partialState.pinnedDynamicCard,
6566
visibleDynamicCards = partialState.cards
6667
)
67-
is PostsUpdate -> this.copy(mockedPostsData = partialState.mockedPostsData)
68+
is CardsUpdate -> this.copy(cards = partialState.cards)
6869
}
6970
}
7071
}

WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteViewModel.kt

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ import org.wordpress.android.analytics.AnalyticsTracker.Stat
1616
import org.wordpress.android.fluxc.model.DynamicCardType
1717
import org.wordpress.android.fluxc.model.MediaModel
1818
import org.wordpress.android.fluxc.model.SiteModel
19+
import org.wordpress.android.fluxc.model.dashboard.CardModel
20+
import org.wordpress.android.fluxc.model.dashboard.CardModel.PostsCardModel
1921
import org.wordpress.android.fluxc.store.AccountStore
2022
import org.wordpress.android.fluxc.store.QuickStartStore.QuickStartTask
2123
import org.wordpress.android.fluxc.store.QuickStartStore.QuickStartTaskType
24+
import org.wordpress.android.fluxc.store.dashboard.CardsStore.CardsResult
2225
import org.wordpress.android.modules.BG_THREAD
2326
import org.wordpress.android.modules.UI_THREAD
2427
import org.wordpress.android.ui.PagePostCreationSourcesDetail.STORY_FROM_MY_SITE
@@ -35,8 +38,7 @@ import org.wordpress.android.ui.mysite.SiteDialogModel.AddSiteIconDialogModel
3538
import org.wordpress.android.ui.mysite.SiteDialogModel.ChangeSiteIconDialogModel
3639
import org.wordpress.android.ui.mysite.SiteDialogModel.ShowRemoveNextStepsDialog
3740
import org.wordpress.android.ui.mysite.cards.CardsBuilder
38-
import org.wordpress.android.ui.mysite.cards.post.PostCardType
39-
import org.wordpress.android.ui.mysite.cards.post.mockdata.MockedPostsData
41+
import org.wordpress.android.ui.mysite.cards.dashboard.posts.PostCardType
4042
import org.wordpress.android.ui.mysite.cards.quickstart.QuickStartCardBuilder
4143
import org.wordpress.android.ui.mysite.cards.quickstart.QuickStartRepository
4244
import org.wordpress.android.ui.mysite.cards.quickstart.QuickStartRepository.QuickStartCategory
@@ -134,19 +136,19 @@ class MySiteViewModel @Inject constructor(
134136
val onShowSwipeRefreshLayout = _onShowSwipeRefreshLayout
135137

136138
val state: LiveData<MySiteUiState> =
137-
selectedSiteRepository.siteSelected.switchMap { siteLocalId ->
138-
val result = MediatorLiveData<SiteIdToState>()
139-
for (newSource in mySiteSourceManager.build(viewModelScope, siteLocalId)) {
140-
result.addSource(newSource) { partialState ->
141-
if (partialState != null) {
142-
result.value = (result.value ?: SiteIdToState(siteLocalId)).update(partialState)
139+
selectedSiteRepository.siteSelected.switchMap { siteLocalId ->
140+
val result = MediatorLiveData<SiteIdToState>()
141+
for (newSource in mySiteSourceManager.build(viewModelScope, siteLocalId)) {
142+
result.addSource(newSource) { partialState ->
143+
if (partialState != null) {
144+
result.value = (result.value ?: SiteIdToState(siteLocalId)).update(partialState)
145+
}
143146
}
144147
}
145-
}
146-
// We want to filter out the empty state where we have a site ID but site object is missing.
147-
// Without this check there is an emission of a NoSites state even if we have the site
148-
result.filter { it.siteId == null || it.state.site != null }.map { it.state }
149-
}.distinctUntilChanged()
148+
// We want to filter out the empty state where we have a site ID but site object is missing.
149+
// Without this check there is an emission of a NoSites state even if we have the site
150+
result.filter { it.siteId == null || it.state.site != null }.map { it.state }
151+
}.distinctUntilChanged()
150152

151153
val uiModel: LiveData<UiModel> = state.map { (
152154
currentAvatarUrl,
@@ -159,7 +161,7 @@ class MySiteViewModel @Inject constructor(
159161
quickStartCategories,
160162
pinnedDynamicCard,
161163
visibleDynamicCards,
162-
mockedPostData
164+
cards
163165
) ->
164166
val state = if (site != null) {
165167
buildSiteSelectedStateAndScroll(
@@ -172,7 +174,7 @@ class MySiteViewModel @Inject constructor(
172174
visibleDynamicCards,
173175
backupAvailable,
174176
scanAvailable,
175-
mockedPostData
177+
cards
176178
)
177179
} else {
178180
buildNoSiteState()
@@ -191,7 +193,7 @@ class MySiteViewModel @Inject constructor(
191193
visibleDynamicCards: List<DynamicCardType>,
192194
backupAvailable: Boolean,
193195
scanAvailable: Boolean,
194-
mockedPostsData: MockedPostsData?
196+
cards: CardsResult<List<CardModel>>?
195197
): SiteSelected {
196198
val siteItems = buildSiteSelectedState(
197199
site,
@@ -203,7 +205,7 @@ class MySiteViewModel @Inject constructor(
203205
visibleDynamicCards,
204206
backupAvailable,
205207
scanAvailable,
206-
mockedPostsData
208+
cards
207209
)
208210
scrollToQuickStartTaskIfNecessary(
209211
activeTask,
@@ -223,14 +225,14 @@ class MySiteViewModel @Inject constructor(
223225
visibleDynamicCards: List<DynamicCardType>,
224226
backupAvailable: Boolean,
225227
scanAvailable: Boolean,
226-
mockedPostsData: MockedPostsData?
228+
cards: CardsResult<List<CardModel>>?
227229
) = cardsBuilder.build(
228230
DomainRegistrationCardBuilderParams(
229231
isDomainCreditAvailable = isDomainCreditAvailable,
230232
domainRegistrationClick = this::domainRegistrationClick
231233
),
232234
PostCardBuilderParams(
233-
mockedPostsData = mockedPostsData,
235+
posts = cards?.model?.firstOrNull { it is PostsCardModel } as? PostsCardModel,
234236
onPostItemClick = this::onPostItemClick,
235237
onFooterLinkClick = this::onPostCardFooterLinkClick
236238
),

WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/CardsBuilder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import org.wordpress.android.ui.mysite.MySiteCardAndItemBuilderParams.PostCardBu
88
import org.wordpress.android.ui.mysite.MySiteCardAndItemBuilderParams.QuickActionsCardBuilderParams
99
import org.wordpress.android.ui.mysite.MySiteCardAndItemBuilderParams.QuickStartCardBuilderParams
1010
import org.wordpress.android.ui.mysite.MySiteCardAndItemBuilderParams.SiteInfoCardBuilderParams
11-
import org.wordpress.android.ui.mysite.cards.post.PostCardBuilder
11+
import org.wordpress.android.ui.mysite.cards.dashboard.posts.PostCardBuilder
1212
import org.wordpress.android.ui.mysite.cards.quickactions.QuickActionsCardBuilder
1313
import org.wordpress.android.ui.mysite.cards.quickstart.QuickStartCardBuilder
1414
import org.wordpress.android.ui.mysite.cards.siteinfo.SiteInfoCardBuilder
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package org.wordpress.android.ui.mysite.cards.dashboard
2+
3+
import androidx.lifecycle.LiveData
4+
import androidx.lifecycle.MediatorLiveData
5+
import androidx.lifecycle.MutableLiveData
6+
import kotlinx.coroutines.CoroutineDispatcher
7+
import kotlinx.coroutines.CoroutineScope
8+
import kotlinx.coroutines.flow.collect
9+
import kotlinx.coroutines.launch
10+
import org.wordpress.android.fluxc.model.SiteModel
11+
import org.wordpress.android.fluxc.store.dashboard.CardsStore
12+
import org.wordpress.android.fluxc.store.dashboard.CardsStore.CardsError
13+
import org.wordpress.android.fluxc.store.dashboard.CardsStore.CardsErrorType
14+
import org.wordpress.android.fluxc.store.dashboard.CardsStore.CardsResult
15+
import org.wordpress.android.modules.BG_THREAD
16+
import org.wordpress.android.ui.mysite.MySiteSource.MySiteRefreshSource
17+
import org.wordpress.android.ui.mysite.MySiteUiState.PartialState.CardsUpdate
18+
import org.wordpress.android.ui.mysite.SelectedSiteRepository
19+
import javax.inject.Inject
20+
import javax.inject.Named
21+
import javax.inject.Singleton
22+
23+
@Singleton
24+
class CardsSource @Inject constructor(
25+
private val selectedSiteRepository: SelectedSiteRepository,
26+
private val cardsStore: CardsStore,
27+
@param:Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher
28+
) : MySiteRefreshSource<CardsUpdate> {
29+
override val refresh: MutableLiveData<Boolean> = MutableLiveData<Boolean>(false)
30+
31+
override fun build(coroutineScope: CoroutineScope, siteLocalId: Int): LiveData<CardsUpdate> {
32+
val result = MediatorLiveData<CardsUpdate>()
33+
result.getData(coroutineScope, siteLocalId)
34+
result.refreshData(coroutineScope, siteLocalId)
35+
result.addSource(refresh) { result.refreshData(coroutineScope, siteLocalId, refresh.value) }
36+
return result
37+
}
38+
39+
private fun MediatorLiveData<CardsUpdate>.getData(
40+
coroutineScope: CoroutineScope,
41+
siteLocalId: Int
42+
) {
43+
val selectedSite = selectedSiteRepository.getSelectedSite()
44+
if (selectedSite != null && selectedSite.id == siteLocalId) {
45+
coroutineScope.launch(bgDispatcher) {
46+
cardsStore.getCards(selectedSite).collect { result ->
47+
postState(CardsUpdate(result))
48+
}
49+
}
50+
} else {
51+
postState(CardsUpdate(CardsResult(CardsError(CardsErrorType.GENERIC_ERROR))))
52+
}
53+
}
54+
55+
private fun MediatorLiveData<CardsUpdate>.refreshData(
56+
coroutineScope: CoroutineScope,
57+
siteLocalId: Int,
58+
isRefresh: Boolean? = null
59+
) {
60+
when (isRefresh) {
61+
null, true -> refreshData(coroutineScope, siteLocalId)
62+
else -> Unit // Do nothing
63+
}
64+
}
65+
66+
private fun MediatorLiveData<CardsUpdate>.refreshData(
67+
coroutineScope: CoroutineScope,
68+
siteLocalId: Int
69+
) {
70+
val selectedSite = selectedSiteRepository.getSelectedSite()
71+
if (selectedSite != null && selectedSite.id == siteLocalId) {
72+
fetchCardsAndPostErrorIfAvailable(coroutineScope, selectedSite)
73+
} else {
74+
postState(CardsUpdate(CardsResult(CardsError(CardsErrorType.GENERIC_ERROR))))
75+
}
76+
}
77+
78+
private fun MediatorLiveData<CardsUpdate>.fetchCardsAndPostErrorIfAvailable(
79+
coroutineScope: CoroutineScope,
80+
selectedSite: SiteModel
81+
) {
82+
coroutineScope.launch(bgDispatcher) {
83+
val result = cardsStore.fetchCards(selectedSite)
84+
result.error?.let {
85+
postState(CardsUpdate(result))
86+
}
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)