diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 488107be9189..1467e8bf47f2 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -2,6 +2,7 @@ 22.2 ----- +* [**] [Jetpack-only] Adds a dashboard card for purchasing domains. [https://github.com/wordpress-mobile/WordPress-Android/pull/18240] * [**] [Jetpack-only] Blogging Prompts: adds the ability to view other users' responses to a prompt. [https://github.com/wordpress-mobile/WordPress-Android/pull/18265] 22.1 diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteCardAndItem.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteCardAndItem.kt index d96b4f67c5b7..b8bcf12ed2c5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteCardAndItem.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteCardAndItem.kt @@ -58,6 +58,7 @@ sealed class MySiteCardAndItem(open val type: Type, open val activeQuickStartIte POST_CARD_WITH_POST_ITEMS, BLOGGING_PROMPT_CARD, PROMOTE_WITH_BLAZE_CARD, + DASHBOARD_DOMAIN_CARD, PAGES_CARD_ERROR, PAGES_CARD } @@ -302,6 +303,14 @@ sealed class MySiteCardAndItem(open val type: Type, open val activeQuickStartIte val onHideMenuItemClick: ListItemInteraction, val onMoreMenuClick: ListItemInteraction, ): DashboardCard(dashboardCardType = DashboardCardType.PROMOTE_WITH_BLAZE_CARD) + + data class DashboardDomainCard( + val title: UiString?, + val subtitle: UiString?, + val onClick: ListItemInteraction, + val onHideMenuItemClick: ListItemInteraction, + val onMoreMenuClick: ListItemInteraction, + ): DashboardCard(dashboardCardType = DashboardCardType.DASHBOARD_DOMAIN_CARD) } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsAdapter.kt index ef00dcb0d0a8..0eef5dbe7006 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsAdapter.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsAdapter.kt @@ -5,6 +5,7 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil.Callback import androidx.recyclerview.widget.RecyclerView.Adapter import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard +import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.DashboardDomainCard import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PromoteWithBlazeCard import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.BloggingPromptCard.BloggingPromptCardWithData import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.ErrorCard @@ -23,6 +24,7 @@ import org.wordpress.android.ui.mysite.cards.dashboard.error.ErrorWithinCardView import org.wordpress.android.ui.mysite.cards.dashboard.pages.PagesCardViewHolder import org.wordpress.android.ui.mysite.cards.dashboard.posts.PostCardViewHolder import org.wordpress.android.ui.mysite.cards.dashboard.todaysstats.TodaysStatsCardViewHolder +import org.wordpress.android.ui.mysite.cards.domain.DashboardDomainCardViewHolder import org.wordpress.android.ui.utils.UiHelpers import org.wordpress.android.util.HtmlCompatWrapper import org.wordpress.android.util.image.ImageManager @@ -54,6 +56,7 @@ class CardsAdapter( learnMoreClicked ) DashboardCardType.PROMOTE_WITH_BLAZE_CARD.ordinal -> PromoteWithBlazeCardViewHolder(parent, uiHelpers) + DashboardCardType.DASHBOARD_DOMAIN_CARD.ordinal -> DashboardDomainCardViewHolder(parent, uiHelpers) DashboardCardType.PAGES_CARD.ordinal -> PagesCardViewHolder(parent, uiHelpers) else -> throw IllegalArgumentException("Unexpected view type") } @@ -69,6 +72,7 @@ class CardsAdapter( is PostCardViewHolder<*> -> holder.bind(items[position] as PostCard) is BloggingPromptCardViewHolder -> holder.bind(items[position] as BloggingPromptCardWithData) is PromoteWithBlazeCardViewHolder -> holder.bind(items[position] as PromoteWithBlazeCard) + is DashboardDomainCardViewHolder -> holder.bind(items[position] as DashboardDomainCard) is PagesCardViewHolder -> holder.bind(items[position] as PagesCard) } } @@ -99,6 +103,7 @@ class CardsAdapter( oldItem is PostCardWithoutPostItems && newItem is PostCardWithoutPostItems -> true oldItem is BloggingPromptCardWithData && newItem is BloggingPromptCardWithData -> true oldItem is PromoteWithBlazeCard && newItem is PromoteWithBlazeCard -> true + oldItem is DashboardDomainCard && newItem is DashboardDomainCard -> true oldItem is PagesCard && newItem is PagesCard -> true else -> throw UnsupportedOperationException("Diff not implemented yet") } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsBuilder.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsBuilder.kt index ae6ed2295b43..73221eb8baab 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsBuilder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsBuilder.kt @@ -10,6 +10,7 @@ import org.wordpress.android.ui.mysite.cards.dashboard.bloggingprompts.BloggingP import org.wordpress.android.ui.mysite.cards.dashboard.pages.PagesCardBuilder import org.wordpress.android.ui.mysite.cards.dashboard.posts.PostCardBuilder import org.wordpress.android.ui.mysite.cards.dashboard.todaysstats.TodaysStatsCardBuilder +import org.wordpress.android.ui.mysite.cards.domain.DashboardDomainCardBuilder import org.wordpress.android.ui.utils.ListItemInteraction import javax.inject.Inject @@ -18,6 +19,7 @@ class CardsBuilder @Inject constructor( private val postCardBuilder: PostCardBuilder, private val bloggingPromptCardBuilder: BloggingPromptCardBuilder, private val promoteWithBlazeCardBuilder: PromoteWithBlazeCardBuilder, + private val dashboardDomainCardBuilder: DashboardDomainCardBuilder, private val pagesCardBuilder: PagesCardBuilder ) { fun build( @@ -38,6 +40,10 @@ class CardsBuilder @Inject constructor( add(it) } + dashboardDomainCardBuilder.build(dashboardCardsBuilderParams.dashboardCardDomainBuilderParams)?.let { + add(it) + } + todaysStatsCardBuilder.build(dashboardCardsBuilderParams.todaysStatsCardBuilderParams) ?.let { add(it) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsShownTracker.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsShownTracker.kt index 215db317f1d1..d7efe04664a8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsShownTracker.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsShownTracker.kt @@ -4,6 +4,7 @@ import org.wordpress.android.analytics.AnalyticsTracker.Stat import org.wordpress.android.ui.blaze.BlazeFlowSource import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard +import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.DashboardDomainCard import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.BloggingPromptCard.BloggingPromptCardWithData import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.ErrorCard import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard @@ -34,6 +35,7 @@ class CardsShownTracker @Inject constructor( } } + @Suppress("LongMethod") private fun trackCardShown(card: DashboardCard) = when (card) { is ErrorCard -> trackCardShown( Pair( @@ -83,6 +85,12 @@ class CardsShownTracker @Inject constructor( Type.PROMOTE_WITH_BLAZE.label ) ) + is DashboardDomainCard -> trackCardShown( + Pair( + card.dashboardCardType.toTypeValue().label, + Type.DASHBOARD_CARD_DOMAIN.label + ) + ) is DashboardCard.PagesCard -> trackCardShown( Pair( card.dashboardCardType.toTypeValue().label, diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsTracker.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsTracker.kt index 801b201f7cd0..4e023d72b52a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsTracker.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsTracker.kt @@ -25,6 +25,7 @@ class CardsTracker @Inject constructor( POST("post"), BLOGGING_PROMPT("blogging_prompt"), PROMOTE_WITH_BLAZE("promote_with_blaze"), + DASHBOARD_CARD_DOMAIN("dashboard_card_domain"), PAGES("pages") } @@ -120,6 +121,7 @@ fun DashboardCardType.toTypeValue(): Type { DashboardCardType.POST_CARD_WITH_POST_ITEMS -> Type.POST DashboardCardType.BLOGGING_PROMPT_CARD -> Type.BLOGGING_PROMPT DashboardCardType.PROMOTE_WITH_BLAZE_CARD -> Type.PROMOTE_WITH_BLAZE + DashboardCardType.DASHBOARD_DOMAIN_CARD -> Type.DASHBOARD_CARD_DOMAIN DashboardCardType.PAGES_CARD -> Type.PAGES DashboardCardType.PAGES_CARD_ERROR -> Type.ERROR } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/domain/DashboardDomainCardBuilder.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/domain/DashboardDomainCardBuilder.kt new file mode 100644 index 000000000000..c5eae1bc8f4a --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/domain/DashboardDomainCardBuilder.kt @@ -0,0 +1,24 @@ +package org.wordpress.android.ui.mysite.cards.domain + +import org.wordpress.android.R +import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.DashboardDomainCard +import org.wordpress.android.ui.mysite.MySiteCardAndItemBuilderParams.DashboardCardDomainBuilderParams +import org.wordpress.android.ui.utils.ListItemInteraction +import org.wordpress.android.ui.utils.UiString +import javax.inject.Inject + +class DashboardDomainCardBuilder @Inject constructor() { + fun build(params: DashboardCardDomainBuilderParams):DashboardDomainCard? { + return if (params.isEligible) { + DashboardDomainCard( + title = UiString.UiStringRes(R.string.dashboard_card_domain_title), + subtitle = UiString.UiStringRes(R.string.dashboard_card_domain_sub_title), + onClick = ListItemInteraction.create(params.onClick), + onHideMenuItemClick = ListItemInteraction.create(params.onHideMenuItemClick), + onMoreMenuClick = ListItemInteraction.create(params.onMoreMenuClick) + ) + } else { + null + } + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/domain/DashboardDomainCardViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/domain/DashboardDomainCardViewHolder.kt new file mode 100644 index 000000000000..d7ad5c180e0d --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/domain/DashboardDomainCardViewHolder.kt @@ -0,0 +1,51 @@ +package org.wordpress.android.ui.mysite.cards.domain + +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.widget.PopupMenu +import org.wordpress.android.R +import org.wordpress.android.databinding.DashboardCardDomainBinding +import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.DashboardDomainCard +import org.wordpress.android.ui.mysite.cards.dashboard.CardViewHolder +import org.wordpress.android.ui.utils.ListItemInteraction +import org.wordpress.android.ui.utils.UiHelpers +import org.wordpress.android.util.extensions.viewBinding + +class DashboardDomainCardViewHolder( + parent: ViewGroup, + private val uiHelpers: UiHelpers +) : CardViewHolder( + parent.viewBinding(DashboardCardDomainBinding::inflate) +) { + fun bind(card: DashboardDomainCard) = with(binding) { + uiHelpers.setTextOrHide(dashboardCardDomainTitle, card.title) + dashboardCardDomainCta.setOnClickListener { card.onClick.click() } + dashboardDomainCardMore.setOnClickListener { + showMoreMenu( + card.onHideMenuItemClick, + card.onMoreMenuClick, + dashboardDomainCardMore, + ) + } + } + + private fun showMoreMenu( + onHideMenuItemClick: ListItemInteraction, + onMoreMenuClick: ListItemInteraction, + anchor: View + ) { + onMoreMenuClick.click() + val popupMenu = PopupMenu(itemView.context, anchor) + popupMenu.setOnMenuItemClickListener { + when (it.itemId) { + R.id.dashboard_card_domain_menu_item_hide_this -> { + onHideMenuItemClick.click() + return@setOnMenuItemClickListener true + } + else -> return@setOnMenuItemClickListener true + } + } + popupMenu.inflate(R.menu.dashboard_card_domain_menu) + popupMenu.show() + } +} diff --git a/WordPress/src/main/res/layout/dashboard_card_domain.xml b/WordPress/src/main/res/layout/dashboard_card_domain.xml new file mode 100644 index 000000000000..1eb8cab08a3f --- /dev/null +++ b/WordPress/src/main/res/layout/dashboard_card_domain.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + diff --git a/WordPress/src/main/res/menu/dashboard_card_domain_menu.xml b/WordPress/src/main/res/menu/dashboard_card_domain_menu.xml new file mode 100644 index 000000000000..5de817e0fed5 --- /dev/null +++ b/WordPress/src/main/res/menu/dashboard_card_domain_menu.xml @@ -0,0 +1,7 @@ + + + + diff --git a/WordPress/src/main/res/values/dashboard_card_styles.xml b/WordPress/src/main/res/values/dashboard_card_styles.xml new file mode 100644 index 000000000000..9a0190e4889f --- /dev/null +++ b/WordPress/src/main/res/values/dashboard_card_styles.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 4136a30c4e99..ad0dba0272f0 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -4435,6 +4435,11 @@ translators: %s: Select control option value e.g: "Auto, 25%". --> Contact support Close + + Own your online identity with a custom domain + Stake your claim on your corner of the web with a site address that\'s easy to find, share, and follow. + Hide this + Promote your content with Blaze Display your work across millions of sites. diff --git a/WordPress/src/test/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsBuilderTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsBuilderTest.kt index c76700688f06..40db70107fef 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsBuilderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/mysite/cards/dashboard/CardsBuilderTest.kt @@ -15,6 +15,7 @@ import org.wordpress.android.BaseUnitTest import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.BloggingPromptCard import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.BloggingPromptCard.BloggingPromptCardWithData +import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.DashboardDomainCard import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.ErrorCard import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard.FooterLink import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard.PostCardWithPostItems @@ -36,6 +37,7 @@ import org.wordpress.android.ui.mysite.cards.dashboard.posts.PostCardBuilder import org.wordpress.android.ui.mysite.cards.dashboard.posts.PostCardType.CREATE_FIRST import org.wordpress.android.ui.mysite.cards.dashboard.posts.PostCardType.DRAFT import org.wordpress.android.ui.mysite.cards.dashboard.todaysstats.TodaysStatsCardBuilder +import org.wordpress.android.ui.mysite.cards.domain.DashboardDomainCardBuilder import org.wordpress.android.ui.utils.UiString.UiStringText @ExperimentalCoroutinesApi @@ -53,6 +55,9 @@ class CardsBuilderTest : BaseUnitTest() { @Mock lateinit var promoteWithBlazeCardBuilder: PromoteWithBlazeCardBuilder + @Mock + lateinit var dashboardDomainCardBuilder: DashboardDomainCardBuilder + @Mock lateinit var pagesCardBuilder: PagesCardBuilder @@ -65,6 +70,7 @@ class CardsBuilderTest : BaseUnitTest() { postCardBuilder, bloggingPromptCardsBuilder, promoteWithBlazeCardBuilder, + dashboardDomainCardBuilder, pagesCardBuilder ) } @@ -182,6 +188,20 @@ class CardsBuilderTest : BaseUnitTest() { assertThat(cards.findPromoteWithBlazeCard()).isNotNull } + @Test + fun `given is not eligible for domain, when cards are built, then domain card is not built`() { + val cards = buildDashboardCards(isEligibleForDomainCard = false) + + assertThat(cards.findDashboardDomainCard()).isNull() + } + + @Test + fun `given is eligible for domain, when cards are built, then domain card is built`() { + val cards = buildDashboardCards(isEligibleForDomainCard = true) + + assertThat(cards.findDashboardDomainCard()).isNotNull + } + @Test fun `given has pages, when cards are built, then pages card is not built`() { val cards = buildDashboardCards(hasPagesCard = false) @@ -211,6 +231,9 @@ class CardsBuilderTest : BaseUnitTest() { private fun DashboardCards.findPromoteWithBlazeCard() = this.cards.find { it is PromoteWithBlazeCard } as? PromoteWithBlazeCard + private fun DashboardCards.findDashboardDomainCard() = + this.cards.find { it is DashboardDomainCard } as? DashboardDomainCard + private fun DashboardCards.findPagesCard() = this.cards.find { it is PagesCardWithData } as? PagesCardWithData @@ -222,6 +245,8 @@ class CardsBuilderTest : BaseUnitTest() { private val promoteWithBlazeCard = mock() + private val dashboardDomainCard = mock() + private val pagesCard = mock() private fun createPostCards() = listOf( @@ -259,6 +284,8 @@ class CardsBuilderTest : BaseUnitTest() { doAnswer { if (hasBlogginPrompt) blogingPromptCard else null }.whenever(bloggingPromptCardsBuilder).build(any()) doAnswer { if (isEligibleForBlaze) promoteWithBlazeCard else null }.whenever(promoteWithBlazeCardBuilder) .build(any()) + doAnswer { if (isEligibleForDomainCard) dashboardDomainCard else null }.whenever(dashboardDomainCardBuilder) + .build(any()) doAnswer { if(hasPagesCard) pagesCard else null }.whenever(pagesCardBuilder).build(any()) return cardsBuilder.build( dashboardCardsBuilderParams = DashboardCardsBuilderParams( diff --git a/WordPress/src/test/java/org/wordpress/android/ui/mysite/cards/dashboard/domain/DashboardDomainCardBuilderTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/mysite/cards/dashboard/domain/DashboardDomainCardBuilderTest.kt new file mode 100644 index 000000000000..269d092a5f2c --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/mysite/cards/dashboard/domain/DashboardDomainCardBuilderTest.kt @@ -0,0 +1,62 @@ +package org.wordpress.android.ui.mysite.cards.dashboard.domain + +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.wordpress.android.R +import org.wordpress.android.ui.mysite.MySiteCardAndItemBuilderParams +import org.wordpress.android.ui.mysite.cards.domain.DashboardDomainCardBuilder +import org.wordpress.android.ui.utils.UiString + +class DashboardDomainCardBuilderTest { + private lateinit var builder: DashboardDomainCardBuilder + + @Before + fun setUp() { + builder = DashboardDomainCardBuilder() + } + @Test + fun `when is eligible for domain, then return the DashboardDomainCard`() { + // Arrange + val params = MySiteCardAndItemBuilderParams.DashboardCardDomainBuilderParams( + isEligible = true, + onClick = { }, + onHideMenuItemClick = { }, + onMoreMenuClick = { } + ) + + // Act + val result = builder.build(params) + + // Assert + Assert.assertNotNull(result) + Assert.assertEquals( + R.string.dashboard_card_domain_title, + (result!!.title as UiString.UiStringRes).stringRes + ) + Assert.assertEquals( + R.string.dashboard_card_domain_sub_title, + (result.subtitle as UiString.UiStringRes).stringRes + ) + Assert.assertNotNull(result.onClick) + Assert.assertNotNull(result.onHideMenuItemClick) + Assert.assertNotNull(result.onMoreMenuClick) + } + + @Test + fun `when is not eligible for blaze, then return null`() { + // Arrange + val params = MySiteCardAndItemBuilderParams.DashboardCardDomainBuilderParams( + isEligible = false, + onClick = { }, + onHideMenuItemClick = { }, + onMoreMenuClick = { } + ) + + // Act + val result = builder.build(params) + + // Assert + Assert.assertNull(result) + } +}