Skip to content

Commit 54d9f46

Browse files
authored
Merge pull request #19910 from wordpress-mobile/feature/update-site-domains-screen
Add tapping functionality to domain cards on the Site Domain screen
2 parents a2810c5 + e98bb86 commit 54d9f46

File tree

9 files changed

+119
-25
lines changed

9 files changed

+119
-25
lines changed

WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardFragment.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import org.wordpress.android.ui.domains.DomainRegistrationActivity.DomainRegistr
2525
import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.ClaimDomain
2626
import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.GetDomain
2727
import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.GetPlan
28+
import org.wordpress.android.ui.domains.management.details.DomainManagementDetailsActivity
2829
import org.wordpress.android.ui.utils.UiHelpers
2930
import org.wordpress.android.util.config.DomainManagementFeatureConfig
3031
import org.wordpress.android.util.extensions.getSerializableExtraCompat
@@ -100,16 +101,22 @@ class DomainsDashboardFragment : Fragment(R.layout.domains_dashboard_fragment),
100101
action.site,
101102
DOMAIN_PURCHASE
102103
)
104+
103105
is ClaimDomain -> ActivityLauncher.viewDomainRegistrationActivityForResult(
104106
this,
105107
action.site,
106108
CTA_DOMAIN_CREDIT_REDEMPTION
107109
)
110+
108111
is GetPlan -> ActivityLauncher.viewDomainRegistrationActivityForResult(
109112
this,
110113
action.site,
111114
FREE_DOMAIN_WITH_ANNUAL_PLAN
112115
)
116+
117+
is DomainsDashboardNavigationAction.OpenDomainManagement -> startActivity(
118+
DomainManagementDetailsActivity.createIntent(requireContext(), action.domain, action.detailUrl)
119+
)
113120
}
114121

115122
@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")

WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardItem.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.wordpress.android.ui.domains
22

3+
import androidx.annotation.ColorRes
34
import androidx.annotation.DrawableRes
45
import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.ADD_DOMAIN
56
import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.PURCHASE_DOMAIN
@@ -22,8 +23,11 @@ sealed class DomainsDashboardItem(val type: Type) {
2223

2324
data class SiteDomains(
2425
val domain: UiString,
25-
val expiry: UiString,
2626
val isPrimary: Boolean,
27+
val domainStatus: UiString,
28+
@ColorRes val domainStatusColor: Int,
29+
val expiry: UiString?,
30+
val onDomainClick: ListItemInteraction? = null
2731
) : DomainsDashboardItem(SITE_DOMAINS)
2832

2933
data class AddDomain(val onClick: ListItemInteraction) : DomainsDashboardItem(ADD_DOMAIN)

WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardNavigationAction.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package org.wordpress.android.ui.domains
33
import org.wordpress.android.fluxc.model.SiteModel
44

55
sealed class DomainsDashboardNavigationAction {
6+
data class OpenDomainManagement(val domain: String, val detailUrl: String) : DomainsDashboardNavigationAction()
67
data class GetDomain(val site: SiteModel) : DomainsDashboardNavigationAction()
78
data class ClaimDomain(val site: SiteModel) : DomainsDashboardNavigationAction()
89
data class GetPlan(val site: SiteModel) : DomainsDashboardNavigationAction()

WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardViewHolder.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ sealed class DomainsDashboardViewHolder<T : ViewBinding>(
4141
uiHelpers.setTextOrHide(siteDomain, item.domain)
4242
uiHelpers.setTextOrHide(siteDomainExpiryDate, item.expiry)
4343
primarySiteDomainChip.isVisible = item.isPrimary
44+
uiHelpers.setTextOrHide(siteDomainStatus, item.domainStatus)
45+
siteDomainStatus.compoundDrawablesRelative.first().setTint(
46+
siteDomainStatus.context.getColor(item.domainStatusColor)
47+
)
48+
item.onDomainClick?.let { interaction -> root.setOnClickListener { interaction.click() } }
4449
}
4550
}
4651

WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardViewModel.kt

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import org.wordpress.android.analytics.AnalyticsTracker.Stat.DOMAINS_DASHBOARD_V
1212
import org.wordpress.android.analytics.AnalyticsTracker.Stat.DOMAIN_CREDIT_REDEMPTION_TAPPED
1313
import org.wordpress.android.fluxc.model.PlanModel
1414
import org.wordpress.android.fluxc.model.SiteModel
15+
import org.wordpress.android.fluxc.network.rest.wpcom.site.AllDomainsDomain
1516
import org.wordpress.android.fluxc.network.rest.wpcom.site.Domain
17+
import org.wordpress.android.fluxc.network.rest.wpcom.site.StatusType
1618
import org.wordpress.android.fluxc.store.SiteStore
1719
import org.wordpress.android.modules.BG_THREAD
1820
import org.wordpress.android.ui.domains.DomainsDashboardItem.AddDomain
@@ -23,6 +25,10 @@ import org.wordpress.android.ui.domains.DomainsDashboardItem.SiteDomainsHeader
2325
import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.ClaimDomain
2426
import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.GetDomain
2527
import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.GetPlan
28+
import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.OpenDomainManagement
29+
import org.wordpress.android.ui.domains.management.getDomainDetailsUrl
30+
import org.wordpress.android.ui.domains.usecases.AllDomains
31+
import org.wordpress.android.ui.domains.usecases.FetchAllDomainsUseCase
2632
import org.wordpress.android.ui.domains.usecases.FetchPlansUseCase
2733
import org.wordpress.android.ui.plans.isDomainCreditAvailable
2834
import org.wordpress.android.ui.utils.HtmlMessageUtils
@@ -46,6 +52,7 @@ class DomainsDashboardViewModel @Inject constructor(
4652
private val analyticsTrackerWrapper: AnalyticsTrackerWrapper,
4753
private val htmlMessageUtils: HtmlMessageUtils,
4854
private val fetchPlansUseCase: FetchPlansUseCase,
55+
private val fetchAllDomainsUseCase: FetchAllDomainsUseCase,
4956
@Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher
5057
) : ScopedViewModel(bgDispatcher) {
5158
lateinit var site: SiteModel
@@ -80,9 +87,11 @@ class DomainsDashboardViewModel @Inject constructor(
8087

8188
val deferredPlansResult = async { fetchPlansUseCase.execute(site) }
8289
val deferredDomainsResult = async { siteStore.fetchSiteDomains(site) }
90+
val deferredAllDomainsResult = async { fetchAllDomainsUseCase.execute() }
8391

8492
val plansResult = deferredPlansResult.await()
8593
val domainsResult = deferredDomainsResult.await()
94+
val allDomainsResult = deferredAllDomainsResult.await()
8695

8796
if (plansResult.isError) {
8897
AppLog.e(DOMAIN_REGISTRATION, "An error occurred while fetching plans: ${plansResult.error.message}")
@@ -92,10 +101,17 @@ class DomainsDashboardViewModel @Inject constructor(
92101
AppLog.e(DOMAIN_REGISTRATION, "An error occurred while fetching domains: ${domainsResult.error.message}")
93102
}
94103

95-
buildDashboardItems(site, plansResult.plans.orEmpty(), domainsResult.domains.orEmpty())
104+
val allDomains = if (allDomainsResult is AllDomains.Success) allDomainsResult.domains else emptyList()
105+
106+
buildDashboardItems(site, plansResult.plans.orEmpty(), domainsResult.domains.orEmpty(), allDomains)
96107
}
97108

98-
private fun buildDashboardItems(site: SiteModel, plans: List<PlanModel>, domains: List<Domain>) {
109+
private fun buildDashboardItems(
110+
site: SiteModel,
111+
plans: List<PlanModel>,
112+
domains: List<Domain>,
113+
allDomains: List<AllDomainsDomain>
114+
) {
99115
val listItems = mutableListOf<DomainsDashboardItem>()
100116

101117
listItems += SiteDomainsHeader(UiStringRes(R.string.domains_free_domain))
@@ -106,8 +122,10 @@ class DomainsDashboardViewModel @Inject constructor(
106122

107123
listItems += SiteDomains(
108124
UiStringText(freeDomainUrl),
109-
UiStringRes(R.string.domains_site_domain_never_expires),
110-
freeDomainIsPrimary
125+
freeDomainIsPrimary,
126+
UiStringRes(R.string.active),
127+
getStatusColor(StatusType.SUCCESS),
128+
UiStringRes(R.string.domains_site_domain_never_expires)
111129
)
112130

113131
val customDomains = domains.filter { !it.wpcomDomain }
@@ -116,7 +134,7 @@ class DomainsDashboardViewModel @Inject constructor(
116134
val hasPaidPlan = !SiteUtils.onFreePlan(site)
117135

118136
if (hasCustomDomains) {
119-
listItems += buildCustomDomainItems(site, customDomains)
137+
listItems += buildCustomDomainItems(site, customDomains, allDomains)
120138
}
121139

122140
listItems += buildCtaItems(hasCustomDomains, hasDomainCredit, hasPaidPlan)
@@ -125,6 +143,13 @@ class DomainsDashboardViewModel @Inject constructor(
125143
_uiModel.postValue(listItems)
126144
}
127145

146+
private fun getStatusColor(statusType: StatusType?) = when (statusType) {
147+
StatusType.SUCCESS -> R.color.jetpack_green_50
148+
StatusType.NEUTRAL -> R.color.gray_50
149+
StatusType.WARNING -> R.color.orange_50
150+
else -> R.color.red_50
151+
}
152+
128153
private fun buildCtaItems(
129154
hasCustomDomains: Boolean,
130155
hasDomainCredit: Boolean,
@@ -161,7 +186,11 @@ class DomainsDashboardViewModel @Inject constructor(
161186
return listItems
162187
}
163188

164-
private fun buildCustomDomainItems(site: SiteModel, customDomains: List<Domain>): List<DomainsDashboardItem> {
189+
private fun buildCustomDomainItems(
190+
site: SiteModel,
191+
customDomains: List<Domain>,
192+
allDomains: List<AllDomainsDomain>
193+
): List<DomainsDashboardItem> {
165194
val listItems = mutableListOf<DomainsDashboardItem>()
166195
listItems += SiteDomainsHeader(
167196
UiStringResWithParams(
@@ -170,9 +199,18 @@ class DomainsDashboardViewModel @Inject constructor(
170199
)
171200
)
172201
listItems += customDomains.map {
202+
val allDomainsDomain = allDomains.find { allDomainsItem -> it.domain == allDomainsItem.domain }
203+
173204
SiteDomains(
174205
UiStringText(it.domain.orEmpty()),
175-
if (it.expirySoon) {
206+
it.primaryDomain,
207+
allDomainsDomain?.domainStatus?.status?.let { status ->
208+
UiStringText(status)
209+
} ?: UiStringRes(R.string.error),
210+
getStatusColor(allDomainsDomain?.domainStatus?.statusType),
211+
if (!it.hasRegistration) {
212+
null
213+
} else if (it.expirySoon) {
176214
UiStringText(
177215
htmlMessageUtils.getHtmlMessageFromStringFormatResId(
178216
R.string.domains_site_domain_expires_soon,
@@ -185,14 +223,23 @@ class DomainsDashboardViewModel @Inject constructor(
185223
listOf(UiStringText(it.expiry.orEmpty()))
186224
)
187225
},
188-
it.primaryDomain
226+
allDomainsDomain?.let { ListItemInteraction.create(allDomainsDomain, this::onDomainClick) }
189227
)
190228
}
191229
return listItems
192230
}
193231

194232
private fun getCleanUrl(url: String?) = StringUtils.removeTrailingSlash(UrlUtils.removeScheme(url))
195233

234+
private fun onDomainClick(allDomainsDomain: AllDomainsDomain) {
235+
_onNavigation.value = Event(
236+
OpenDomainManagement(
237+
allDomainsDomain.domain ?: return,
238+
allDomainsDomain.getDomainDetailsUrl() ?: return
239+
)
240+
)
241+
}
242+
196243
private fun onGetDomainClick() {
197244
analyticsTrackerWrapper.track(DOMAINS_DASHBOARD_GET_DOMAIN_TAPPED, site)
198245
_onNavigation.value = Event(GetDomain(site))

WordPress/src/main/java/org/wordpress/android/ui/domains/usecases/FetchAllDomainsUseCase.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.wordpress.android.ui.domains.usecases
22

33
import org.wordpress.android.fluxc.network.rest.wpcom.site.AllDomainsDomain
44
import org.wordpress.android.fluxc.store.SiteStore
5+
import org.wordpress.android.util.AppLog
56
import javax.inject.Inject
67

78
class FetchAllDomainsUseCase @Inject constructor(
@@ -10,7 +11,11 @@ class FetchAllDomainsUseCase @Inject constructor(
1011
suspend fun execute(): AllDomains {
1112
val result = siteStore.fetchAllDomains()
1213
return when {
13-
result.isError -> AllDomains.Error
14+
result.isError -> {
15+
AppLog.e(AppLog.T.API, "An error occurred while fetching all domains: ${result.error.message}")
16+
AllDomains.Error
17+
}
18+
1419
result.domains.isNullOrEmpty() -> AllDomains.Empty
1520
else -> AllDomains.Success(requireNotNull(result.domains))
1621
}
@@ -22,7 +27,7 @@ sealed interface AllDomains {
2227
val domains: List<AllDomainsDomain>,
2328
) : AllDomains
2429

25-
object Empty : AllDomains
30+
data object Empty : AllDomains
2631

27-
object Error : AllDomains
32+
data object Error : AllDomains
2833
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<shape xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:shape="oval">
4+
5+
<size
6+
android:width="8dp"
7+
android:height="8dp" />
8+
<solid android:color="@color/white" />
9+
</shape>

WordPress/src/main/res/layout/domain_site_domains_card.xml

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,15 @@
1616
android:layout_height="wrap_content"
1717
android:padding="@dimen/margin_extra_large">
1818

19-
<com.google.android.material.imageview.ShapeableImageView
20-
android:id="@+id/primary_site_domain_actions"
21-
android:layout_width="wrap_content"
22-
android:layout_height="wrap_content"
23-
android:visibility="gone"
24-
app:layout_constraintEnd_toEndOf="parent"
25-
app:layout_constraintTop_toTopOf="parent"
26-
app:srcCompat="@drawable/ic_ellipsis_vertical_white_24dp"
27-
app:tint="?attr/wpColorOnSurfaceMedium" />
28-
2919
<com.google.android.material.textview.MaterialTextView
3020
android:id="@+id/site_domain_expiry_date"
3121
android:layout_width="wrap_content"
3222
android:layout_height="wrap_content"
3323
android:layout_marginTop="@dimen/margin_medium_large"
3424
android:text="@string/domains_site_domain_never_expires"
35-
app:layout_constraintStart_toStartOf="parent"
25+
app:layout_constraintEnd_toEndOf="parent"
26+
app:layout_constraintHorizontal_bias="1"
27+
app:layout_constraintStart_toEndOf="@id/site_domain_status"
3628
app:layout_constraintTop_toBottomOf="@id/primary_site_domain_chip" />
3729

3830
<com.google.android.material.chip.Chip
@@ -55,14 +47,29 @@
5547
app:layout_constraintTop_toBottomOf="@+id/site_domain"
5648
app:textStartPadding="@dimen/margin_small" />
5749

50+
<com.google.android.material.textview.MaterialTextView
51+
style="?attr/textAppearanceBody2"
52+
android:id="@+id/site_domain_status"
53+
android:layout_width="wrap_content"
54+
android:layout_height="wrap_content"
55+
android:layout_marginTop="@dimen/margin_medium_large"
56+
android:drawablePadding="8dp"
57+
android:drawableStart="@drawable/ic_dot_white_8dp"
58+
app:layout_constraintHorizontal_bias="0"
59+
app:layout_constraintStart_toStartOf="parent"
60+
app:layout_constraintTop_toBottomOf="@id/primary_site_domain_chip"
61+
tools:text="Active" />
62+
5863
<com.google.android.material.textview.MaterialTextView
5964
android:id="@+id/site_domain"
6065
style="?attr/textAppearanceSubtitle1"
61-
android:layout_width="match_parent"
66+
android:layout_width="wrap_content"
6267
android:layout_height="wrap_content"
6368
android:text="@string/domains_site_domain"
69+
app:layout_constraintEnd_toEndOf="parent"
70+
app:layout_constraintHorizontal_bias="0"
71+
app:layout_constraintStart_toStartOf="parent"
6472
app:layout_constraintTop_toTopOf="parent"
6573
tools:text="travelwithkids.wordpress.com" />
66-
6774
</androidx.constraintlayout.widget.ConstraintLayout>
6875
</com.google.android.material.card.MaterialCardView>

WordPress/src/test/java/org/wordpress/android/ui/domains/DomainsDashboardViewModelTest.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import org.wordpress.android.BaseUnitTest
1010
import org.wordpress.android.R
1111
import org.wordpress.android.fluxc.model.PlanModel
1212
import org.wordpress.android.fluxc.model.SiteModel
13+
import org.wordpress.android.fluxc.network.rest.wpcom.site.AllDomainsDomain
1314
import org.wordpress.android.fluxc.network.rest.wpcom.site.Domain
1415
import org.wordpress.android.fluxc.store.SiteStore
1516
import org.wordpress.android.fluxc.store.SiteStore.FetchedDomainsPayload
@@ -19,6 +20,8 @@ import org.wordpress.android.ui.domains.DomainsDashboardItem.PurchaseDomain
1920
import org.wordpress.android.ui.domains.DomainsDashboardItem.PurchasePlan
2021
import org.wordpress.android.ui.domains.DomainsDashboardItem.SiteDomains
2122
import org.wordpress.android.ui.domains.DomainsDashboardItem.SiteDomainsHeader
23+
import org.wordpress.android.ui.domains.usecases.AllDomains
24+
import org.wordpress.android.ui.domains.usecases.FetchAllDomainsUseCase
2225
import org.wordpress.android.ui.domains.usecases.FetchPlansUseCase
2326
import org.wordpress.android.ui.plans.PlansConstants.FREE_PLAN_ID
2427
import org.wordpress.android.ui.plans.PlansConstants.PREMIUM_PLAN_ID
@@ -32,6 +35,7 @@ class DomainsDashboardViewModelTest : BaseUnitTest() {
3235
private val analyticsTracker: AnalyticsTrackerWrapper = mock()
3336
private val htmlMessageUtils: HtmlMessageUtils = mock()
3437
private val fetchPlansUseCase: FetchPlansUseCase = mock()
38+
private val fetchAllDomainsUseCase: FetchAllDomainsUseCase = mock()
3539

3640
private lateinit var viewModel: DomainsDashboardViewModel
3741

@@ -44,6 +48,7 @@ class DomainsDashboardViewModelTest : BaseUnitTest() {
4448
analyticsTracker,
4549
htmlMessageUtils,
4650
fetchPlansUseCase,
51+
fetchAllDomainsUseCase,
4752
testDispatcher()
4853
)
4954

@@ -171,6 +176,8 @@ class DomainsDashboardViewModelTest : BaseUnitTest() {
171176

172177
val plan = if (hasDomainCredits) planWithCredits else planWithNoCredits
173178
whenever(fetchPlansUseCase.execute(site)).thenReturn(OnPlansFetched(site, listOf(plan)))
179+
val allDomains = if (hasCustomDomains) listOf(allDomainsDomain) else emptyList()
180+
whenever(fetchAllDomainsUseCase.execute()).thenReturn(AllDomains.Success(allDomains))
174181

175182
viewModel.start(site)
176183
}
@@ -189,6 +196,8 @@ class DomainsDashboardViewModelTest : BaseUnitTest() {
189196
wpcomDomain = false
190197
)
191198

199+
private val allDomainsDomain = AllDomainsDomain(domain = "henna.tattoo")
200+
192201
private val siteWithFreePlan = SiteModel().apply {
193202
siteId = TEST_SITE_ID
194203
url = TEST_DOMAIN_NAME

0 commit comments

Comments
 (0)