Coverage Summary for Class: DashboardBurnRateWidgetKt (com.georgeci.moneysurfer.feature.dashboard)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| DashboardBurnRateWidgetKt |
100%
(3/3)
|
58.3%
(7/12)
|
88.9%
(32/36)
|
91.3%
(325/356)
|
| DashboardBurnRateWidgetKt$WhenMappings |
|
| Total |
100%
(3/3)
|
58.3%
(7/12)
|
88.9%
(32/36)
|
91.3%
(325/356)
|
package com.georgeci.moneysurfer.feature.dashboard
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import com.georgeci.moneysurfer.domain.model.BurnRatePace
import com.georgeci.moneysurfer.uikit.components.budget.SurferBudgetStatus
import com.georgeci.moneysurfer.uikit.widgets.SurferBurnRateBar
import com.georgeci.moneysurfer.uikit.widgets.SurferBurnRateData
import com.georgeci.moneysurfer.uikit.widgets.SurferBurnRateEmpty
import com.georgeci.moneysurfer.uikit.widgets.SurferBurnRatePace
import com.georgeci.moneysurfer.uikit.widgets.SurferBurnRateWidget
import moneysurfer.feature.dashboard.generated.resources.Res
import moneysurfer.feature.dashboard.generated.resources.dashboard_burn_rate_average
import moneysurfer.feature.dashboard.generated.resources.dashboard_burn_rate_caption
import moneysurfer.feature.dashboard.generated.resources.dashboard_burn_rate_chart_a11y
import moneysurfer.feature.dashboard.generated.resources.dashboard_burn_rate_empty_subtitle
import moneysurfer.feature.dashboard.generated.resources.dashboard_burn_rate_empty_title
import moneysurfer.feature.dashboard.generated.resources.dashboard_burn_rate_off_pace
import moneysurfer.feature.dashboard.generated.resources.dashboard_burn_rate_on_track
import moneysurfer.feature.dashboard.generated.resources.dashboard_burn_rate_projection
import moneysurfer.feature.dashboard.generated.resources.dashboard_burn_rate_title
import org.jetbrains.compose.resources.stringResource
/**
* What the week has been costing per day, and where the month lands if it keeps costing that.
*
* Like the safe-to-spend card this one keeps drawing with no budget behind it — the chart, the
* average and the projection are arithmetic over transactions. Only the pace pill needs a cap, and
* it is simply left off without one rather than the widget standing down.
*/
@Composable
internal fun BurnRateWidget(state: DashboardState.Content) {
SurferBurnRateWidget(
title = stringResource(Res.string.dashboard_burn_rate_title),
data = state.burnRate?.toWidgetData(),
empty = SurferBurnRateEmpty(
title = stringResource(Res.string.dashboard_burn_rate_empty_title),
subtitle = stringResource(Res.string.dashboard_burn_rate_empty_subtitle),
),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
.padding(vertical = 8.dp)
.testTag(DashboardTestTags.BurnRate),
)
}
/**
* The sentences around the numbers. The chart restates money the card prints nowhere else, so its
* screen-reader line carries the week's total and its busiest day rather than seven bar heights.
*/
@Composable
private fun BurnRateUi.toWidgetData(): SurferBurnRateData = SurferBurnRateData(
average = stringResource(Res.string.dashboard_burn_rate_average, averageFormatted),
caption = stringResource(Res.string.dashboard_burn_rate_caption),
bars = days.map {
SurferBurnRateBar(
label = it.dayOfMonth.toString(),
fraction = it.fraction,
isToday = it.isToday,
)
},
projection = stringResource(Res.string.dashboard_burn_rate_projection, projectedFormatted),
pace = pace?.toWidgetPace(),
chartContentDescription = stringResource(
Res.string.dashboard_burn_rate_chart_a11y,
weekTotalFormatted,
busiestDayFormatted,
),
)
/**
* `uikit` does not depend on `domain`, so the verdict crosses over here.
*
* Off pace borrows the Over colour rather than a warning one: the projection has already passed the
* cap in the only sense a projection can, and a second amber step between "fine" and "not" would be
* a distinction the maths does not make.
*/
@Composable
private fun BurnRatePace.toWidgetPace(): SurferBurnRatePace = when (this) {
BurnRatePace.OnTrack -> SurferBurnRatePace(
label = stringResource(Res.string.dashboard_burn_rate_on_track),
status = SurferBudgetStatus.Ok,
)
BurnRatePace.OffPace -> SurferBurnRatePace(
label = stringResource(Res.string.dashboard_burn_rate_off_pace),
status = SurferBudgetStatus.Over,
)
}