diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/ViewsAndVisitorsDetailUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/ViewsAndVisitorsDetailUseCase.kt index 6e84fdcfa7ac..5ab9cf9c75ca 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/ViewsAndVisitorsDetailUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/ViewsAndVisitorsDetailUseCase.kt @@ -87,6 +87,7 @@ class ViewsAndVisitorsDetailUseCase constructor( site: SiteModel, forced: Boolean ): State { + AppLog.d(T.STATS, selectedDate.toString() ) val response = visitsAndViewsStore.fetchVisits( site, DAYS, @@ -147,7 +148,7 @@ class ViewsAndVisitorsDetailUseCase constructor( val selectedItem = domainModel.dates.getOrNull(index) ?: domainModel.dates.last() items.add( - viewsAndVisitorsMapper.buildTitle( + viewsAndVisitorsMapper.buildWeekTitle( domainModel.dates, DAYS, selectedItem, @@ -165,7 +166,7 @@ class ViewsAndVisitorsDetailUseCase constructor( ) ) items.add( - viewsAndVisitorsMapper.buildInformation( + viewsAndVisitorsMapper.buildWeeksDetailInformation( domainModel.dates, uiState.selectedPosition, this::onTopTipsLinkClick diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TotalStatsMapper.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TotalStatsMapper.kt index be9580a9d0e4..705f009ee93e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TotalStatsMapper.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TotalStatsMapper.kt @@ -8,6 +8,7 @@ import org.wordpress.android.ui.stats.refresh.lists.sections.insights.usecases.T import org.wordpress.android.ui.stats.refresh.lists.sections.insights.usecases.TotalStatsMapper.TotalStatsType.LIKES import org.wordpress.android.ui.stats.refresh.utils.MILLION import org.wordpress.android.ui.stats.refresh.utils.StatsUtils +import org.wordpress.android.util.AppLog import org.wordpress.android.viewmodel.ResourceProvider import javax.inject.Inject @@ -16,10 +17,10 @@ class TotalStatsMapper @Inject constructor( private val statsUtils: StatsUtils ) { fun buildTotalLikesValue(dates: List): ValueWithChartItem { - val currentWeekLikes = getCurrentWeekDays(dates, LIKES) + val currentWeekLikes = getCurrentSevenDays(dates, LIKES) val currentWeekSumFormatted = sum(currentWeekLikes) - val previousWeekLikes = getPreviousWeekDays(dates, LIKES) + val previousWeekLikes = getPreviousSevenDays(dates, LIKES) val positive = currentWeekLikes.sum() >= previousWeekLikes.sum() return ValueWithChartItem( @@ -32,10 +33,10 @@ class TotalStatsMapper @Inject constructor( } fun buildTotalCommentsValue(dates: List): ValueWithChartItem { - val currentWeekComments = getCurrentWeekDays(dates, COMMENTS) + val currentWeekComments = getCurrentSevenDays(dates, COMMENTS) val currentWeekSumFormatted = sum(currentWeekComments) - val previousWeekComments = getPreviousWeekDays(dates, LIKES) + val previousWeekComments = getPreviousSevenDays(dates, LIKES) val positive = currentWeekComments.sum() >= previousWeekComments.sum() return ValueWithChartItem( @@ -51,7 +52,7 @@ class TotalStatsMapper @Inject constructor( currentWeekSum != 0L || previousWeekSum != 0L fun shouldShowCommentsGuideCard(dates: List): Boolean { - return getCurrentWeekDays(dates, COMMENTS).sum() > 0 + return getCurrentSevenDays(dates, COMMENTS).sum() > 0 } fun shouldShowFollowersGuideCard(domainModel: Int): Boolean { @@ -59,7 +60,7 @@ class TotalStatsMapper @Inject constructor( } fun shouldShowLikesGuideCard(dates: List): Boolean { - return getCurrentWeekDays(dates, LIKES).sum() > 0 + return getCurrentSevenDays(dates, LIKES).sum() > 0 } fun buildTotalLikesInformation(dates: List) = buildTotalInformation(dates, LIKES) @@ -67,17 +68,17 @@ class TotalStatsMapper @Inject constructor( fun buildTotalCommentsInformation(dates: List) = buildTotalInformation(dates, COMMENTS) private fun buildTotalInformation(dates: List, type: TotalStatsType): Text? { - val value = getCurrentWeekDays(dates, type).sum() - val previousValue = getPreviousWeekDays(dates, type).sum() + val value = getCurrentSevenDays(dates, type).sum() + val previousValue = getPreviousSevenDays(dates, type).sum() if (!shouldShowTotalInformation(value, previousValue)) { return null } val positive = value >= previousValue val change = statsUtils.buildChange(previousValue, value, positive, true).toString() val stringRes = if (positive) { - R.string.stats_insights_total_stats_positive + R.string.stats_insights_total_stats_seven_days_positive } else { - R.string.stats_insights_total_stats_negative + R.string.stats_insights_total_stats_seven_days_negative } return Text( @@ -97,33 +98,53 @@ class TotalStatsMapper @Inject constructor( /** * Gives list of data with StatsType for the current week. */ - private fun getCurrentWeekDays(dates: List, type: TotalStatsType): List { - val currentWeekDays = dates.takeLast(DAY_COUNT_FOR_CURRENT_WEEK) - return mapToStatsType(currentWeekDays, type) + fun getCurrentSevenDays(dates: List, type: TotalStatsType): List { + // taking data for last 14 days excluding today + AppLog.d(AppLog.T.STATS, dates.toString()) + return mapToStatsType(dates.dropLast(1).takeLast(DAY_COUNT_FOR_CURRENT_WEEK), type) } /** * Gives list of data with StatsType for previous week. */ - private fun getPreviousWeekDays(dates: List, type: TotalStatsType): List { - if (dates.size < DAY_COUNT_TOTAL) { - return emptyList() + fun getPreviousSevenDays(dates: List, type: TotalStatsType): List { + return if (dates.size < DAY_COUNT_TOTAL) { + emptyList() + } else { + mapToStatsType(dates.take(DAY_COUNT_FOR_PREVIOUS_WEEK), type) + } + } + + /** + * Gives list of data with StatsType for the current week. + */ + fun getCurrentWeekDays(dates: List, type: TotalStatsType): List { + // taking data for last 14 days excluding today + AppLog.d(AppLog.T.STATS, dates.toString()) + return mapToStatsType(dates.takeLast(DAY_COUNT_FOR_CURRENT_WEEK), type) + } + + /** + * Gives list of data with StatsType for previous week. + */ + fun getPreviousWeekDays(dates: List, type: TotalStatsType): List { + return if (dates.size < DAY_COUNT_TOTAL) { + emptyList() + } else { + mapToStatsType(dates.drop(1).take(DAY_COUNT_FOR_PREVIOUS_WEEK), type) } - val previousWeekDays = dates.subList( - dates.lastIndex - DAY_COUNT_TOTAL + 1, - dates.lastIndex - DAY_COUNT_FOR_PREVIOUS_WEEK + 1 - ) - return mapToStatsType(previousWeekDays, type) } private fun mapToStatsType(dates: List, type: TotalStatsType) = dates.map { when (type) { + TotalStatsType.VIEWS -> it.views + TotalStatsType.VISITORS -> it.visitors LIKES -> it.likes COMMENTS -> it.comments } } - private enum class TotalStatsType { LIKES, COMMENTS } + enum class TotalStatsType { VIEWS, VISITORS, LIKES, COMMENTS } companion object { private const val DAY_COUNT_FOR_CURRENT_WEEK = 7 // Last 7 days diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsMapper.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsMapper.kt index fbd2670b58a0..691c5db56f4c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsMapper.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsMapper.kt @@ -33,7 +33,8 @@ class ViewsAndVisitorsMapper private val statsDateFormatter: StatsDateFormatter, private val resourceProvider: ResourceProvider, private val statsUtils: StatsUtils, - private val contentDescriptionHelper: ContentDescriptionHelper + private val contentDescriptionHelper: ContentDescriptionHelper, + private val totalStatsMapper: TotalStatsMapper ) { private val units = listOf( string.stats_views, @@ -59,13 +60,13 @@ class ViewsAndVisitorsMapper } fun buildChartLegendsBlue() = ChartLegendsBlue( - string.stats_timeframe_this_week, - string.stats_timeframe_previous_week + string.stats_timeframe_last_seven_days, + string.stats_timeframe_previous_seven_days ) fun buildChartLegendsPurple() = ChartLegendsPurple( - string.stats_timeframe_this_week, - string.stats_timeframe_previous_week + string.stats_timeframe_last_seven_days, + string.stats_timeframe_previous_seven_days ) fun buildTitle( @@ -100,6 +101,38 @@ class ViewsAndVisitorsMapper ) } + fun buildWeekTitle( + dates: List, + statsGranularity: StatsGranularity = DAYS, + selectedItem: PeriodData, + selectedPosition: Int, + startValue: Int = MILLION + ): ValuesItem { + val (thisWeekCount, prevWeekCount) = mapDatesToWeeksDetail(dates, selectedPosition) + + return ValuesItem( + selectedItem = selectedPosition, + value1 = statsUtils.toFormattedString(thisWeekCount, startValue), + unit1 = units[selectedPosition], + contentDescription1 = resourceProvider.getString( + string.stats_overview_content_description, + thisWeekCount, + resourceProvider.getString(units[selectedPosition]), + statsDateFormatter.printGranularDate(selectedItem.period, statsGranularity), + "" + ), + value2 = statsUtils.toFormattedString(prevWeekCount, startValue), + unit2 = units[selectedPosition], + contentDescription2 = resourceProvider.getString( + string.stats_overview_content_description, + prevWeekCount, + resourceProvider.getString(units[selectedPosition]), + statsDateFormatter.printGranularDate(selectedItem.period, statsGranularity), + "" + ) + ) + } + private fun PeriodData.getValue(selectedPosition: Int) = when (SelectedType.valueOf(selectedPosition)) { Views -> this.views Visitors -> this.visitors @@ -179,17 +212,68 @@ class ViewsAndVisitorsMapper val stringRes = when (SelectedType.valueOf(selectedPosition)) { Views -> { when { - positive -> string.stats_insights_views_and_visitors_views_positive - else -> string.stats_insights_views_and_visitors_views_negative + positive -> string.stats_insights_views_and_visitors_seven_days_views_positive + else -> string.stats_insights_views_and_visitors_seven_days_views_negative } } Visitors -> { when { - positive -> string.stats_insights_views_and_visitors_visitors_positive - else -> string.stats_insights_views_and_visitors_visitors_negative + positive -> string.stats_insights_views_and_visitors_seven_days_visitors_positive + else -> string.stats_insights_views_and_visitors_seven_days_visitors_negative } } - else -> string.stats_insights_views_and_visitors_views_positive + else -> string.stats_insights_views_and_visitors_seven_days_views_positive + } + + return Text( + text = resourceProvider.getString(stringRes, change), + color = when { + positive -> mapOf(color.stats_color_positive to change) + else -> mapOf(color.stats_color_negative to change) + } + ) + } + + fun buildWeeksDetailInformation( + dates: List, + selectedPosition: Int, + navigationAction: (() -> Unit?)? = null + ): Text { + val (thisWeekCount, prevWeekCount) = mapDatesToWeeksDetail(dates, selectedPosition) + + if (thisWeekCount <= 0 || prevWeekCount <= 0) { + return Text( + text = resourceProvider.getString( + string.stats_insights_views_and_visitors_visitors_empty_state, + EXTERNAL_LINK_ICON_TOKEN + ), + links = listOf( + Clickable( + icon = R.drawable.ic_external_white_24dp, + navigationAction = ListItemInteraction.create( + action = { navigationAction?.invoke() } + ) + ) + ) + ) + } + + val positive = thisWeekCount >= prevWeekCount + val change = statsUtils.buildChange(prevWeekCount, thisWeekCount, positive, true).toString() + val stringRes = when (SelectedType.valueOf(selectedPosition)) { + Views -> { + when { + positive -> string.stats_insights_views_and_visitors_seven_days_views_positive + else -> string.stats_insights_views_and_visitors_seven_days_views_negative + } + } + Visitors -> { + when { + positive -> string.stats_insights_views_and_visitors_seven_days_visitors_positive + else -> string.stats_insights_views_and_visitors_seven_days_visitors_negative + } + } + else -> string.stats_insights_views_and_visitors_seven_days_views_positive } return Text( @@ -228,20 +312,21 @@ class ViewsAndVisitorsMapper } private fun mapDatesToWeeks(dates: List, selectedPosition: Int): Pair { - val values = dates.map { - val value = it.getValue(selectedPosition) - value.toInt() - } + val statsType = TotalStatsMapper.TotalStatsType.values()[selectedPosition] - val hasData = values.isNotEmpty() && values.size >= 7 + val prevWeekData = totalStatsMapper.getPreviousSevenDays(dates, statsType) + val thisWeekData = totalStatsMapper.getCurrentSevenDays(dates, statsType) + + return Pair(thisWeekData.sum(), prevWeekData.sum()) + } - val prevWeekData = if (hasData) values.subList(0, 7) else values.subList(0, values.size) - val thisWeekData = if (hasData) values.subList(7, values.size) else emptyList() + private fun mapDatesToWeeksDetail(dates: List, selectedPosition: Int): Pair { + val statsType = TotalStatsMapper.TotalStatsType.values()[selectedPosition] - val prevWeekCount = prevWeekData.fold(0L) { acc, next -> acc + next } - val thisWeekCount = thisWeekData.fold(0L) { acc, next -> acc + next } + val prevWeekData = totalStatsMapper.getPreviousWeekDays(dates, statsType) + val thisWeekData = totalStatsMapper.getCurrentWeekDays(dates, statsType) - return Pair(thisWeekCount, prevWeekCount) + return Pair(thisWeekData.sum(), prevWeekData.sum()) } companion object { diff --git a/WordPress/src/main/res/layout/stats_block_legends_blue_item.xml b/WordPress/src/main/res/layout/stats_block_legends_blue_item.xml index db8fd30270a2..5215bb0a714d 100644 --- a/WordPress/src/main/res/layout/stats_block_legends_blue_item.xml +++ b/WordPress/src/main/res/layout/stats_block_legends_blue_item.xml @@ -10,7 +10,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:importantForAccessibility="no" - android:text="@string/stats_timeframe_this_week" + android:text="@string/stats_timeframe_last_seven_days" app:layout_constraintEnd_toStartOf="@id/legend2" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -22,7 +22,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:importantForAccessibility="no" - android:text="@string/stats_timeframe_previous_week" + android:text="@string/stats_timeframe_previous_seven_days" app:layout_constraintStart_toEndOf="@id/legend1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" diff --git a/WordPress/src/main/res/layout/stats_block_legends_purple_item.xml b/WordPress/src/main/res/layout/stats_block_legends_purple_item.xml index 6971f417b214..8b1ee5ff205f 100644 --- a/WordPress/src/main/res/layout/stats_block_legends_purple_item.xml +++ b/WordPress/src/main/res/layout/stats_block_legends_purple_item.xml @@ -10,7 +10,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:importantForAccessibility="no" - android:text="@string/stats_timeframe_this_week" + android:text="@string/stats_timeframe_last_seven_days" app:layout_constraintEnd_toStartOf="@id/legend2" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -22,7 +22,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:importantForAccessibility="no" - android:text="@string/stats_timeframe_previous_week" + android:text="@string/stats_timeframe_previous_seven_days" app:layout_constraintStart_toEndOf="@id/legend1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 363160932a13..451d5af283cb 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -1265,9 +1265,8 @@ Weeks Months Years - This Week - Previous Week - + Last 7-days + Previous 7-days Views Visitors Likes @@ -1323,10 +1322,10 @@ All-time posts, views, and visitors Today\'s Stats Views & Visitors - Your views this week are %1$s higher than the previous week. - Your views this week are %1$s lower than the previous week. - Your visitors this week are %1$s higher than the previous week. - Your visitors this week are %1$s lower than the previous week. + Your views in the last 7-days are %1$s higher than the previous 7-days. + Your views in the last 7-days are %1$s lower than the previous 7-days. + Your visitors in the last 7-days are %1$s higher than the previous 7-days. + Your visitors in the last 7-days are %1$s lower than the previous 7-days. Check out our top tips to increase your views and traffic %1$s %1$s %2$s Latest Post Summary @@ -1339,8 +1338,8 @@ Total comments Avg comments/post Total likes - %1$s higher than the previous week - %1$s lower than the previous week + %1$s higher than the previous 7-days + %1$s lower than the previous 7-days Avg likes/post Total words Avg words/post diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TotalStatsMapperTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TotalStatsMapperTest.kt index 604111e981fc..3924feee86c0 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TotalStatsMapperTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TotalStatsMapperTest.kt @@ -21,7 +21,7 @@ class TotalStatsMapperTest : BaseUnitTest() { lateinit var statsUtils: StatsUtils private lateinit var mapper: TotalStatsMapper private val previousWeekData = listOf(5L, 10, 15, 20, 25, 30, 35) - private val currentWeekData = listOf(40L, 45, 50, 55, 60, 65, 70) + private val currentWeekData = listOf(40L, 45, 50, 55, 60, 65, 70, 20) private val dates = (previousWeekData + currentWeekData).map { PeriodData("", 0, 0, it, 0, it, 0) } @@ -34,7 +34,7 @@ class TotalStatsMapperTest : BaseUnitTest() { @Test fun `builds value`() { - val totalLikes = currentWeekData.sum() + val totalLikes = currentWeekData.dropLast(1).sum() val totalLikesResult = mapper.buildTotalLikesValue(dates) assertThat(totalLikesResult.value).isEqualTo(totalLikes.toString()) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsMapperTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsMapperTest.kt index 76ca4f7041b4..44c8c4868ed3 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsMapperTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsMapperTest.kt @@ -30,6 +30,9 @@ class ViewsAndVisitorsMapperTest : BaseUnitTest() { @Mock lateinit var statsUtils: StatsUtils + @Mock + lateinit var totalStatsMapper: TotalStatsMapper + @Mock lateinit var contentDescriptionHelper: ContentDescriptionHelper private lateinit var mapper: ViewsAndVisitorsMapper @@ -37,18 +40,32 @@ class ViewsAndVisitorsMapperTest : BaseUnitTest() { private val prevWeekViews: Long = 323 private val thisWeekVisitors: Long = 174 private val prevWeekVisitors: Long = 133 - private val selectedItem = PeriodData("2022-04-18", 78, 28, 3, 0, 13, 2) + private val selectedItem = PeriodData("2022-04-19", 79, 29, 4, 0, 14, 3) private val viewsTitle = "Views" private val visitorsTitle = "Visitors" - private val printedDate = "18. 04. 2022" + private val printedDate = "19. 04. 2022" @Before fun setUp() { - mapper = ViewsAndVisitorsMapper(statsDateFormatter, resourceProvider, statsUtils, contentDescriptionHelper) + mapper = ViewsAndVisitorsMapper( + statsDateFormatter, + resourceProvider, + statsUtils, + contentDescriptionHelper, + totalStatsMapper + ) whenever(resourceProvider.getString(string.stats_views)).thenReturn(viewsTitle) whenever(resourceProvider.getString(string.stats_visitors)).thenReturn(visitorsTitle) whenever(statsDateFormatter.printGranularDate(any(), any())).thenReturn(printedDate) whenever(statsUtils.toFormattedString(any(), any())).then { (it.arguments[0] as Long).toString() } + whenever(totalStatsMapper.getCurrentSevenDays(buildPeriodData(), TotalStatsMapper.TotalStatsType.VIEWS)) + .thenReturn(listOf(thisWeekViews)) + whenever(totalStatsMapper.getPreviousSevenDays(buildPeriodData(), TotalStatsMapper.TotalStatsType.VIEWS)) + .thenReturn(listOf(prevWeekViews)) + whenever(totalStatsMapper.getCurrentSevenDays(buildPeriodData(), TotalStatsMapper.TotalStatsType.VISITORS)) + .thenReturn(listOf(thisWeekVisitors)) + whenever(totalStatsMapper.getPreviousSevenDays(buildPeriodData(), TotalStatsMapper.TotalStatsType.VISITORS)) + .thenReturn(listOf(prevWeekVisitors)) } @Test @@ -137,7 +154,8 @@ class ViewsAndVisitorsMapperTest : BaseUnitTest() { PeriodData("2022-04-15", 99, 35, 21, 0, 23, 1), PeriodData("2022-04-16", 8, 5, 1, 0, 0, 0), PeriodData("2022-04-17", 7, 4, 0, 0, 0, 0), - PeriodData("2022-04-18", 78, 28, 3, 0, 13, 2) + PeriodData("2022-04-18", 78, 28, 3, 0, 13, 2), + PeriodData("2022-04-19", 79, 29, 4, 0, 14, 3) ) } }