Skip to content

Commit

Permalink
Merge pull request #12524 from woocommerce/issue/12520-campaign-stats…
Browse files Browse the repository at this point in the history
…-cut-off

Ensures budget label doesn't get cut off in smaller screens
  • Loading branch information
JorgeMucientes authored Sep 6, 2024
2 parents 67c2342 + e466d99 commit 86a0cf5
Show file tree
Hide file tree
Showing 11 changed files with 79 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package com.woocommerce.android.extensions

import android.icu.number.Notation
import android.icu.number.NumberFormatter
import android.icu.text.CompactDecimalFormat
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import java.text.DecimalFormat
import java.util.Locale
import kotlin.math.roundToInt

fun Float.formatToString(): String {
Expand Down Expand Up @@ -37,4 +43,19 @@ infix fun <T> Comparable<T>?.lesserThan(other: T) =
this?.let { it < other }
?: false

/**
* Shortens a number to the nearest thousand and appends a 'K' to the end. For example, 1000 will be shortened to 1K.
*/
fun compactNumberCompat(number: Long, locale: Locale = Locale.getDefault()): String =
if (VERSION.SDK_INT >= VERSION_CODES.R) {
NumberFormatter.with()
.notation(Notation.compactShort())
.locale(locale)
.format(number)
.toString()
} else {
CompactDecimalFormat.getInstance(locale, CompactDecimalFormat.CompactStyle.SHORT)
.format(number.toDouble())
}

const val PERCENTAGE_BASE = 100.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.woocommerce.android.extensions

import java.util.Locale
import javax.inject.Inject

class NumberExtensionsWrapper @Inject constructor() {
fun compactNumberCompat(
number: Long,
locale: Locale = Locale.getDefault()
): String = compactNumberCompat(number, locale)
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
package com.woocommerce.android.ui.blaze

import com.woocommerce.android.R
import com.woocommerce.android.extensions.NumberExtensionsWrapper
import com.woocommerce.android.util.CurrencyFormatter
import org.wordpress.android.fluxc.model.blaze.BlazeCampaignModel

fun BlazeCampaignModel.toUiState(currencyFormatter: CurrencyFormatter) =
BlazeCampaignUi(
product = BlazeProductUi(
name = title,
imgUrl = imageUrl.orEmpty(),
),
status = CampaignStatusUi.fromString(uiStatus),
isEndlessCampaign = isEndlessCampaign,
impressions = impressions,
clicks = clicks,
formattedBudget = getBudgetValue(this, currencyFormatter),
budgetLabel = getBudgetTitle(this)
)
fun BlazeCampaignModel.toUiState(
currencyFormatter: CurrencyFormatter,
numberExtensionsWrapper: NumberExtensionsWrapper
) = BlazeCampaignUi(
product = BlazeProductUi(
name = title,
imgUrl = imageUrl.orEmpty(),
),
status = CampaignStatusUi.fromString(uiStatus),
isEndlessCampaign = isEndlessCampaign,
impressions = numberExtensionsWrapper.compactNumberCompat(impressions),
clicks = numberExtensionsWrapper.compactNumberCompat(clicks),
formattedBudget = getBudgetValue(this, currencyFormatter),
budgetLabel = getBudgetTitle(this)
)

private fun getBudgetTitle(campaign: BlazeCampaignModel) =
when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ data class BlazeCampaignUi(
val product: BlazeProductUi,
val status: CampaignStatusUi?,
val isEndlessCampaign: Boolean,
val impressions: Long,
val clicks: Long,
val impressions: String,
val clicks: String,
val formattedBudget: String,
@StringRes val budgetLabel: Int
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.woocommerce.android.ui.blaze.campaigs

import android.content.res.Configuration
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
Expand All @@ -15,6 +16,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
Expand Down Expand Up @@ -74,13 +76,19 @@ fun BlazeCampaignItem(
CampaignStat(
statName = stringResource(R.string.blaze_campaign_status_ctr_label),
statValue = stringResource(
id = R.string.blaze_campaign_status_ctr_valur,
id = R.string.blaze_campaign_status_ctr_value_shortened,
campaign.impressions,
campaign.clicks,
campaign.impressions
)
)
Spacer(modifier = Modifier.width(42.dp))
val orientation = LocalConfiguration.current.orientation
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
Spacer(modifier = Modifier.weight(1f))
} else {
Spacer(modifier = Modifier.width(16.dp))
}
CampaignStat(
modifier = Modifier.padding(start = 16.dp),
statName = stringResource(campaign.budgetLabel),
statValue = campaign.formattedBudget
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ fun BlazeCampaignListScreenPreview() {
),
status = Active,
isEndlessCampaign = false,
impressions = 100,
clicks = 10,
impressions = "6k",
clicks = "10",
formattedBudget = "$100",
budgetLabel = R.string.blaze_campaign_status_budget_total
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.woocommerce.android.R
import com.woocommerce.android.analytics.AnalyticsEvent.BLAZE_CAMPAIGN_DETAIL_SELECTED
import com.woocommerce.android.analytics.AnalyticsTracker
import com.woocommerce.android.analytics.AnalyticsTrackerWrapper
import com.woocommerce.android.extensions.NumberExtensionsWrapper
import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.ui.blaze.BlazeCampaignUi
import com.woocommerce.android.ui.blaze.BlazeUrlsHelper
Expand Down Expand Up @@ -36,7 +37,8 @@ class BlazeCampaignListViewModel @Inject constructor(
private val blazeUrlsHelper: BlazeUrlsHelper,
private val appPrefsWrapper: AppPrefsWrapper,
private val analyticsTrackerWrapper: AnalyticsTrackerWrapper,
private val currencyFormatter: CurrencyFormatter
private val currencyFormatter: CurrencyFormatter,
private val numberExtensionsWrapper: NumberExtensionsWrapper
) : ScopedViewModel(savedStateHandle) {
companion object {
private const val LOADING_TRANSITION_DELAY = 200L
Expand All @@ -63,7 +65,7 @@ class BlazeCampaignListViewModel @Inject constructor(
BlazeCampaignListState(
campaigns = campaigns.map {
ClickableCampaign(
campaignUi = it.toUiState(currencyFormatter),
campaignUi = it.toUiState(currencyFormatter, numberExtensionsWrapper),
onCampaignClicked = { onCampaignClicked(it.campaignId) }
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,8 +348,8 @@ fun MyStoreBlazeViewCampaignPreview() {
product = product,
status = CampaignStatusUi.Active,
isEndlessCampaign = false,
impressions = 100,
clicks = 10,
impressions = "32435",
clicks = "43",
formattedBudget = "$100",
budgetLabel = R.string.blaze_campaign_status_budget_total
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.woocommerce.android.analytics.AnalyticsEvent.BLAZE_CAMPAIGN_LIST_ENTR
import com.woocommerce.android.analytics.AnalyticsEvent.BLAZE_ENTRY_POINT_DISPLAYED
import com.woocommerce.android.analytics.AnalyticsTracker
import com.woocommerce.android.analytics.AnalyticsTrackerWrapper
import com.woocommerce.android.extensions.NumberExtensionsWrapper
import com.woocommerce.android.model.DashboardWidget
import com.woocommerce.android.model.Product
import com.woocommerce.android.ui.blaze.BlazeCampaignUi
Expand Down Expand Up @@ -56,7 +57,8 @@ class DashboardBlazeViewModel @AssistedInject constructor(
private val productListRepository: ProductListRepository,
private val blazeUrlsHelper: BlazeUrlsHelper,
private val analyticsTrackerWrapper: AnalyticsTrackerWrapper,
private val currencyFormatter: CurrencyFormatter
private val currencyFormatter: CurrencyFormatter,
private val numberExtensionsWrapper: NumberExtensionsWrapper
) : ScopedViewModel(savedStateHandle) {
private val _refreshTrigger = MutableSharedFlow<RefreshEvent>(extraBufferCapacity = 1)
private val refreshTrigger = merge(_refreshTrigger, (parentViewModel.refreshTrigger))
Expand Down Expand Up @@ -142,7 +144,7 @@ class DashboardBlazeViewModel @AssistedInject constructor(

private fun showUiForCampaign(campaign: BlazeCampaignModel): DashboardBlazeCampaignState {
return Campaign(
campaign = campaign.toUiState(currencyFormatter),
campaign = campaign.toUiState(currencyFormatter, numberExtensionsWrapper),
onCampaignClicked = {
parentViewModel.trackCardInteracted(DashboardWidget.Type.BLAZE.trackingIdentifier)
analyticsTrackerWrapper.track(
Expand Down
2 changes: 1 addition & 1 deletion WooCommerce/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3858,7 +3858,7 @@
<string name="blaze_campaign_status_canceled">Canceled</string>
<string name="blaze_campaign_status_suspended">Suspended</string>
<string name="blaze_campaign_status_ctr_label">Click-throughs</string>
<string name="blaze_campaign_status_ctr_valur">%1$d ➔ %2$d</string>
<string name="blaze_campaign_status_ctr_value_shortened">%1$s ➔ %2$s</string>
<string name="blaze_campaign_status_budget_total">Total</string>
<string name="blaze_campaign_status_budget_remaining">Remaining</string>
<string name="blaze_campaign_status_budget_weekly">Weekly</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.woocommerce.android.ui.blaze.campaigs
import com.woocommerce.android.AppPrefsWrapper
import com.woocommerce.android.R
import com.woocommerce.android.analytics.AnalyticsTrackerWrapper
import com.woocommerce.android.extensions.NumberExtensionsWrapper
import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.ui.blaze.BlazeUrlsHelper
import com.woocommerce.android.util.CurrencyFormatter
Expand Down Expand Up @@ -39,12 +40,14 @@ class BlazeCampaignListViewModelTest : BaseUnitTest() {
private val siteModel: SiteModel = mock()
private val campaignsEntityFlow = flow { emit(listOf(BLAZE_CAMPAIGN_MODEL)) }
private val currencyFormatter: CurrencyFormatter = mock()
private val numberExtensionsWrapper: NumberExtensionsWrapper = mock()

private lateinit var viewModel: BlazeCampaignListViewModel

@Before
fun setup() = testBlocking {
whenever(selectedSite.get()).thenReturn(siteModel)
whenever(numberExtensionsWrapper.compactNumberCompat(any(), any())).thenReturn("0")
whenever(currencyFormatter.formatCurrencyRounded(TOTAL_BUDGET)).thenReturn(TOTAL_BUDGET.toString())
whenever(blazeCampaignsStore.observeBlazeCampaigns(selectedSite.get())).thenReturn(campaignsEntityFlow)
whenever(blazeCampaignsStore.fetchBlazeCampaigns(any(), any(), any(), any(), eq(null)))
Expand Down Expand Up @@ -149,7 +152,8 @@ class BlazeCampaignListViewModelTest : BaseUnitTest() {
blazeUrlsHelper = blazeUrlsHelper,
appPrefsWrapper = appPrefsWrapper,
analyticsTrackerWrapper = analyticsTrackerWrapper,
currencyFormatter = currencyFormatter
currencyFormatter = currencyFormatter,
numberExtensionsWrapper = numberExtensionsWrapper
)
}

Expand Down

0 comments on commit 86a0cf5

Please sign in to comment.