Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSD - Handle Single Dashboard Card Error in UI #15893

Merged
merged 24 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7f2b462
Build: Update FluxC hash
ashiagr Feb 2, 2022
681f46e
Feature: Add mocked data for cards with errors
ashiagr Feb 1, 2022
6dfc54e
Feature: Add post card error data class
ashiagr Feb 2, 2022
098b009
Feature: Add error within card vh
ashiagr Feb 2, 2022
23d43c4
Analysis: Fix detekt warning
ashiagr Feb 7, 2022
942b881
Refactor: Rename today's stats card and move it inside a parent seale…
ashiagr Feb 7, 2022
3b84c84
Refactor: Optimize import
ashiagr Feb 7, 2022
ea89fb0
Feature: Add today's stats error card
ashiagr Feb 7, 2022
f262d68
Feature: Track error cards
ashiagr Feb 7, 2022
248ecf5
Feature: Support today's stats error card in adapter
ashiagr Feb 7, 2022
c894537
Feature: Add show error within card condition
ashiagr Feb 7, 2022
414e40a
Tests: Add tests for error within cards
ashiagr Feb 7, 2022
1e57281
Analysis: Replace existing mocked JSON to include errors.
ashiagr Feb 8, 2022
7729b2b
Refactor: Rename today's card error type
ashiagr Feb 8, 2022
94bbb12
Fix: Make title non-nullable
ashiagr Feb 17, 2022
7c5f5f5
Refactor: Introduce handleError and separate out createTodaysStatsCar…
ashiagr Feb 17, 2022
c4ea7c8
Merge branch 'issue/15201-stats-card-ui' into issue/15750-handle-sing…
ashiagr Feb 17, 2022
a267093
Build: Update fluxc commit
ashiagr Feb 17, 2022
2b97401
Fix existing test
ashiagr Feb 17, 2022
ca9a91f
Merge branch 'issue/15201-stats-card-ui' into issue/15750-handle-sing…
ashiagr Feb 18, 2022
6c05538
Update FluxC trunk hash
ashiagr Feb 18, 2022
301699e
Merge branch 'issue/15201-stats-card-ui' into issue/15750-handle-sing…
AjeshRPai Feb 18, 2022
2da5131
Update utils lib hash to get AppLog.MY_SITE_DASHBOARD tag
ashiagr Feb 18, 2022
7d589c7
Log card-based errors
ashiagr Feb 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ sealed class MySiteCardAndItem(open val type: Type, open val activeQuickStartIte

enum class DashboardCardType {
ERROR_CARD,
TODAYS_STATS_CARD_ERROR,
TODAYS_STATS_CARD,
POST_CARD_ERROR,
POST_CARD_WITHOUT_POST_ITEMS,
POST_CARD_WITH_POST_ITEMS
}
Expand Down Expand Up @@ -97,20 +99,35 @@ sealed class MySiteCardAndItem(open val type: Type, open val activeQuickStartIte
open val dashboardCardType: DashboardCardType
) {
data class ErrorCard(
override val dashboardCardType: DashboardCardType = DashboardCardType.ERROR_CARD,
val onRetryClick: ListItemInteraction
) : DashboardCard(dashboardCardType)
) : DashboardCard(dashboardCardType = DashboardCardType.ERROR_CARD)

data class TodaysStatsCard(
val views: UiString,
val visitors: UiString,
val likes: UiString
) : DashboardCard(DashboardCardType.TODAYS_STATS_CARD)
interface ErrorWithinCard {
val title: UiString
}

sealed class TodaysStatsCard(
override val dashboardCardType: DashboardCardType
) : DashboardCard(dashboardCardType) {
data class Error(
override val title: UiString
) : TodaysStatsCard(dashboardCardType = DashboardCardType.TODAYS_STATS_CARD_ERROR), ErrorWithinCard

data class TodaysStatsCardWithData(
val views: UiString,
val visitors: UiString,
val likes: UiString
) : TodaysStatsCard(dashboardCardType = DashboardCardType.TODAYS_STATS_CARD)
}

sealed class PostCard(
override val dashboardCardType: DashboardCardType,
open val footerLink: FooterLink
open val footerLink: FooterLink? = null
) : DashboardCard(dashboardCardType) {
data class Error(
override val title: UiString
) : PostCard(dashboardCardType = DashboardCardType.POST_CARD_ERROR), ErrorWithinCard

data class PostCardWithoutPostItems(
val postCardType: PostCardType,
val title: UiString,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import androidx.recyclerview.widget.RecyclerView.Adapter
import org.apache.commons.lang3.NotImplementedException
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.ErrorCard
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.ErrorWithinCard
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard.PostCardWithPostItems
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard.PostCardWithoutPostItems
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.TodaysStatsCard
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.TodaysStatsCard.TodaysStatsCardWithData
import org.wordpress.android.ui.mysite.MySiteCardAndItem.DashboardCardType
import org.wordpress.android.ui.mysite.cards.dashboard.error.ErrorCardViewHolder
import org.wordpress.android.ui.mysite.cards.dashboard.error.ErrorWithinCardViewHolder
import org.wordpress.android.ui.mysite.cards.dashboard.posts.PostCardViewHolder
import org.wordpress.android.ui.mysite.cards.dashboard.todaysstats.TodaysStatsCardViewHolder

Expand All @@ -27,6 +29,8 @@ class CardsAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder<*> {
return when (viewType) {
DashboardCardType.ERROR_CARD.ordinal -> ErrorCardViewHolder(parent)
DashboardCardType.TODAYS_STATS_CARD_ERROR.ordinal,
DashboardCardType.POST_CARD_ERROR.ordinal -> ErrorWithinCardViewHolder(parent, uiHelpers)
DashboardCardType.TODAYS_STATS_CARD.ordinal -> TodaysStatsCardViewHolder(parent, uiHelpers)
DashboardCardType.POST_CARD_WITHOUT_POST_ITEMS.ordinal ->
PostCardViewHolder.PostCardWithoutPostItemsViewHolder(parent, imageManager, uiHelpers)
Expand All @@ -41,7 +45,8 @@ class CardsAdapter(
override fun onBindViewHolder(holder: CardViewHolder<*>, position: Int) {
when (holder) {
is ErrorCardViewHolder -> holder.bind(items[position] as ErrorCard)
is TodaysStatsCardViewHolder -> holder.bind(items[position] as TodaysStatsCard)
is ErrorWithinCardViewHolder -> holder.bind(items[position] as ErrorWithinCard)
is TodaysStatsCardViewHolder -> holder.bind(items[position] as TodaysStatsCardWithData)
is PostCardViewHolder<*> -> holder.bind(items[position] as PostCard)
}
}
Expand All @@ -65,7 +70,8 @@ class CardsAdapter(

return oldItem.dashboardCardType == newItem.dashboardCardType && when {
oldItem is ErrorCard && newItem is ErrorCard -> true
oldItem is TodaysStatsCard && newItem is TodaysStatsCard -> true
oldItem is ErrorWithinCard && newItem is ErrorWithinCard -> true
oldItem is TodaysStatsCardWithData && newItem is TodaysStatsCardWithData -> true
oldItem is PostCardWithPostItems && newItem is PostCardWithPostItems -> true
oldItem is PostCardWithoutPostItems && newItem is PostCardWithoutPostItems -> true
else -> throw NotImplementedException("Diff not implemented yet")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import org.wordpress.android.analytics.AnalyticsTracker.Stat
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.ErrorCard
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard.PostCardWithPostItems
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard.PostCardWithoutPostItems
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.TodaysStatsCard
import org.wordpress.android.ui.mysite.cards.dashboard.CardsTracker.Type.ERROR
import org.wordpress.android.ui.mysite.cards.dashboard.CardsTracker.Type.TODAYS_STATS
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.TodaysStatsCard.TodaysStatsCardWithData
import org.wordpress.android.ui.mysite.cards.dashboard.CardsTracker.Type
import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper
import javax.inject.Inject

Expand All @@ -31,13 +32,25 @@ class CardsShownTracker @Inject constructor(
is ErrorCard -> trackCardShown(
Pair(
card.dashboardCardType.toTypeValue().label,
ERROR.label
Type.ERROR.label
)
)
is TodaysStatsCard -> trackCardShown(
is TodaysStatsCard.Error -> trackCardShown(
Pair(
card.dashboardCardType.toTypeValue().label,
TODAYS_STATS.label
Type.TODAYS_STATS.label
)
)
is TodaysStatsCardWithData -> trackCardShown(
Pair(
card.dashboardCardType.toTypeValue().label,
Type.TODAYS_STATS.label
)
)
is PostCard.Error -> trackCardShown(
Pair(
card.dashboardCardType.toTypeValue().label,
Type.POST.label
)
)
is PostCardWithoutPostItems -> trackCardShown(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ class CardsTracker @Inject constructor(
fun DashboardCardType.toTypeValue(): Type {
return when (this) {
DashboardCardType.ERROR_CARD -> Type.ERROR
DashboardCardType.TODAYS_STATS_CARD_ERROR -> Type.ERROR
DashboardCardType.TODAYS_STATS_CARD -> Type.TODAYS_STATS
DashboardCardType.POST_CARD_ERROR -> Type.ERROR
DashboardCardType.POST_CARD_WITHOUT_POST_ITEMS -> Type.POST
DashboardCardType.POST_CARD_WITH_POST_ITEMS -> Type.POST
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.wordpress.android.ui.mysite.cards.dashboard.error

import android.view.ViewGroup
import org.wordpress.android.databinding.MySiteCardToolbarBinding
import org.wordpress.android.databinding.MySiteErrorWithinCardBinding
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.ErrorWithinCard
import org.wordpress.android.ui.mysite.cards.dashboard.CardViewHolder
import org.wordpress.android.ui.utils.UiHelpers
import org.wordpress.android.ui.utils.UiString
import org.wordpress.android.util.viewBinding

class ErrorWithinCardViewHolder(
parent: ViewGroup,
private val uiHelpers: UiHelpers
) : CardViewHolder<MySiteErrorWithinCardBinding>(
parent.viewBinding(MySiteErrorWithinCardBinding::inflate)
) {
fun bind(card: ErrorWithinCard) = with(binding) {
mySiteToolbar.update(card.title)
}

private fun MySiteCardToolbarBinding.update(title: UiString) {
uiHelpers.setTextOrHide(mySiteCardToolbarTitle, title)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package org.wordpress.android.ui.mysite.cards.dashboard.posts
import org.wordpress.android.R
import org.wordpress.android.fluxc.model.dashboard.CardModel.PostsCardModel
import org.wordpress.android.fluxc.model.dashboard.CardModel.PostsCardModel.PostCardModel
import org.wordpress.android.fluxc.store.dashboard.CardsStore.PostCardError
import org.wordpress.android.fluxc.store.dashboard.CardsStore.PostCardErrorType
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard.FooterLink
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.PostCard.PostCardWithPostItems
Expand All @@ -22,20 +24,37 @@ import javax.inject.Inject
class PostCardBuilder @Inject constructor(
private val localeManagerWrapper: LocaleManagerWrapper
) {
fun build(params: PostCardBuilderParams): List<PostCard> = mutableListOf<PostCard>().apply {
val posts = params.posts
posts?.hasPublished?.takeIf { !posts.hasDraftsOrScheduledPosts() }
?.let { hasPublished ->
if (hasPublished) {
add(createNextPostCard(params.onFooterLinkClick))
} else {
add(createFirstPostCard(params.onFooterLinkClick))
}
}
posts?.draft?.takeIf { it.isNotEmpty() }?.let { add(it.createDraftPostsCard(params)) }
posts?.scheduled?.takeIf { it.isNotEmpty() }?.let { add(it.createScheduledPostsCard(params)) }
fun build(params: PostCardBuilderParams): List<PostCard> {
val error = params.posts?.error
return if (error != null) {
buildPostCardWithError(error)
} else {
buildPostCardsWithData(params)
}
}

private fun buildPostCardWithError(error: PostCardError) =
if (shouldShowError(error)) listOf(createPostErrorCard()) else emptyList()

private fun buildPostCardsWithData(params: PostCardBuilderParams) =
mutableListOf<PostCard>().apply {
val posts = params.posts
posts?.hasPublished?.takeIf { !posts.hasDraftsOrScheduledPosts() }
?.let { hasPublished ->
if (hasPublished) {
add(createNextPostCard(params.onFooterLinkClick))
} else {
add(createFirstPostCard(params.onFooterLinkClick))
}
}
posts?.draft?.takeIf { it.isNotEmpty() }?.let { add(it.createDraftPostsCard(params)) }
posts?.scheduled?.takeIf { it.isNotEmpty() }?.let { add(it.createScheduledPostsCard(params)) }
}.toList()

private fun createPostErrorCard() = PostCard.Error(
title = UiStringRes(R.string.posts)
)

private fun createFirstPostCard(onFooterLinkClick: (postCardType: PostCardType) -> Unit) =
PostCardWithoutPostItems(
postCardType = PostCardType.CREATE_FIRST,
Expand Down Expand Up @@ -122,6 +141,8 @@ class PostCardBuilder @Inject constructor(
private fun constructPostDate(date: Date) =
SimpleDateFormat(MONTH_DAY_FORMAT, localeManagerWrapper.getLocale()).format(date)

private fun shouldShowError(error: PostCardError) = error.type == PostCardErrorType.GENERIC_ERROR

companion object {
private const val MONTH_DAY_FORMAT = "MMM d"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,43 @@
package org.wordpress.android.ui.mysite.cards.dashboard.todaysstats

import org.wordpress.android.R
import org.wordpress.android.fluxc.model.dashboard.CardModel.TodaysStatsCardModel
import org.wordpress.android.fluxc.store.dashboard.CardsStore.TodaysStatsCardError
import org.wordpress.android.fluxc.store.dashboard.CardsStore.TodaysStatsCardErrorType
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.TodaysStatsCard
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.TodaysStatsCard.TodaysStatsCardWithData
import org.wordpress.android.ui.mysite.MySiteCardAndItemBuilderParams.TodaysStatsCardBuilderParams
import org.wordpress.android.ui.stats.refresh.utils.StatsUtils
import org.wordpress.android.ui.utils.UiString.UiStringRes
import org.wordpress.android.ui.utils.UiString.UiStringText
import javax.inject.Inject

class TodaysStatsCardBuilder @Inject constructor(
private val statsUtils: StatsUtils
) {
fun build(params: TodaysStatsCardBuilderParams) = params.todaysStatsCard?.let {
TodaysStatsCard(
views = statToUiString(it.views),
visitors = statToUiString(it.visitors),
likes = statToUiString(it.likes)
)
val error = it.error
if (error != null) {
handleError(error)
} else {
createTodaysStatsCardWithData(it)
}
}

private fun handleError(error: TodaysStatsCardError) =
if (shouldShowError(error)) createTodaysStatsCardWithError() else null

private fun createTodaysStatsCardWithError() = TodaysStatsCard.Error(
title = UiStringRes(R.string.my_site_todays_stat_card_title)
)

private fun createTodaysStatsCardWithData(model: TodaysStatsCardModel) = TodaysStatsCardWithData(
views = statToUiString(model.views),
visitors = statToUiString(model.visitors),
likes = statToUiString(model.likes)
)

private fun shouldShowError(error: TodaysStatsCardError) = error.type == TodaysStatsCardErrorType.GENERIC_ERROR

private fun statToUiString(stat: Int) = UiStringText(statsUtils.toFormattedString(stat))
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.wordpress.android.ui.mysite.cards.dashboard.todaysstats

import android.view.ViewGroup
import org.wordpress.android.databinding.MySiteTodaysStatsCardBinding
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.TodaysStatsCard
import org.wordpress.android.ui.mysite.MySiteCardAndItem.Card.DashboardCards.DashboardCard.TodaysStatsCard.TodaysStatsCardWithData
import org.wordpress.android.ui.mysite.cards.dashboard.CardViewHolder
import org.wordpress.android.ui.utils.UiHelpers
import org.wordpress.android.util.viewBinding
Expand All @@ -13,7 +13,7 @@ class TodaysStatsCardViewHolder(
) : CardViewHolder<MySiteTodaysStatsCardBinding>(
parent.viewBinding(MySiteTodaysStatsCardBinding::inflate)
) {
fun bind(card: TodaysStatsCard) = with(binding) {
fun bind(card: TodaysStatsCardWithData) = with(binding) {
uiHelpers.setTextOrHide(viewsCount, card.views)
uiHelpers.setTextOrHide(visitorsCount, card.visitors)
uiHelpers.setTextOrHide(likesCount, card.likes)
Expand Down
49 changes: 49 additions & 0 deletions WordPress/src/main/res/layout/my_site_error_within_card.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/WordPress.CardView.Unelevated"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<include
android:id="@+id/my_site_toolbar"
layout="@layout/my_site_card_toolbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/MySiteErrorCardTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingEnd="@dimen/margin_extra_extra_large"
android:paddingStart="@dimen/margin_extra_extra_large"
android:paddingTop="@dimen/margin_extra_medium_large"
android:text="@string/my_site_error_card_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/my_site_toolbar" />

<com.google.android.material.textview.MaterialTextView
android:id="@+id/subtitle"
style="@style/MySiteErrorCardSubtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/margin_extra_extra_large"
android:paddingEnd="@dimen/margin_extra_extra_large"
android:paddingStart="@dimen/margin_extra_extra_large"
android:text="@string/my_site_error_within_card_subtitle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />

</androidx.constraintlayout.widget.ConstraintLayout>

</com.google.android.material.card.MaterialCardView>
Loading