Coverage Summary for Class: DashboardBudgetsWidgetKt (com.georgeci.moneysurfer.feature.dashboard)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| DashboardBudgetsWidgetKt |
100%
(3/3)
|
53.8%
(7/13)
|
100%
(33/33)
|
98.1%
(366/373)
|
| DashboardBudgetsWidgetKt$WhenMappings |
|
| Total |
100%
(3/3)
|
53.8%
(7/13)
|
100%
(33/33)
|
98.1%
(366/373)
|
package com.georgeci.moneysurfer.feature.dashboard
import androidx.compose.foundation.layout.defaultMinSize
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.BudgetStatus
import com.georgeci.moneysurfer.domain.primitives.BudgetId
import com.georgeci.moneysurfer.uikit.widgets.SurferBudgetItem
import com.georgeci.moneysurfer.uikit.widgets.SurferBudgetsWidget
import moneysurfer.feature.dashboard.generated.resources.Res
import moneysurfer.feature.dashboard.generated.resources.dashboard_budgets_empty_subtitle
import moneysurfer.feature.dashboard.generated.resources.dashboard_budgets_empty_title
import moneysurfer.feature.dashboard.generated.resources.dashboard_budgets_left
import moneysurfer.feature.dashboard.generated.resources.dashboard_budgets_over
import moneysurfer.feature.dashboard.generated.resources.dashboard_budgets_see_all
import moneysurfer.feature.dashboard.generated.resources.dashboard_budgets_spent_of
import moneysurfer.feature.dashboard.generated.resources.dashboard_budgets_status_ok
import moneysurfer.feature.dashboard.generated.resources.dashboard_budgets_status_over
import moneysurfer.feature.dashboard.generated.resources.dashboard_budgets_status_warn
import moneysurfer.feature.dashboard.generated.resources.dashboard_budgets_title
import org.jetbrains.compose.resources.stringResource
/**
* The budgets nearest their limit, each as spend against the cap plus the bar between them.
*
* Keeps drawing with nothing behind it, the way the safe-to-spend card does: "no budgets" is a
* state worth a row on the dashboard, and its empty card is what points at the budgets screen.
*/
@Composable
internal fun BudgetsWidget(
state: DashboardState.Content,
onEvent: (DashboardEvent) -> Unit,
) {
SurferBudgetsWidget(
items = state.budgets.map { it.toWidgetItem() },
title = stringResource(Res.string.dashboard_budgets_title),
seeAllLabel = stringResource(Res.string.dashboard_budgets_see_all),
onSeeAllClick = { onEvent(DashboardEvent.OnSeeAllBudgetsClick) },
onItemClick = { item -> onEvent(DashboardEvent.OnBudgetClick(BudgetId(item.id))) },
emptyTitle = stringResource(Res.string.dashboard_budgets_empty_title),
emptySubtitle = stringResource(Res.string.dashboard_budgets_empty_subtitle),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
.defaultMinSize(minHeight = DASHBOARD_WIDGET_MIN_HEIGHT)
.padding(vertical = 8.dp)
.testTag(DashboardTestTags.Budgets),
seeAllTestTag = DashboardTestTags.BudgetsSeeAll,
)
}
/**
* The sentences around the numbers. The bar restates figures the row already prints, so its
* screen-reader line is the spend against the limit rather than a percentage read off the shape.
*/
@Composable
private fun BudgetSummaryUi.toWidgetItem(): SurferBudgetItem = SurferBudgetItem(
id = id.value,
name = name,
statusLabel = stringResource(status.labelResource()),
status = status.toWidgetStatus(),
spentOfLimit = stringResource(Res.string.dashboard_budgets_spent_of, spentFormatted, limitFormatted),
// "€25.10 over" rather than a negative remainder: the row states the overshoot, and the sign
// would read as headroom next to the amounts above it.
remaining = if (isOver) {
stringResource(Res.string.dashboard_budgets_over, remainderFormatted)
} else {
stringResource(Res.string.dashboard_budgets_left, remainderFormatted)
},
progress = progress,
alertFraction = alertFraction,
)
private fun BudgetStatus.labelResource() = when (this) {
BudgetStatus.OK -> Res.string.dashboard_budgets_status_ok
BudgetStatus.WARN -> Res.string.dashboard_budgets_status_warn
BudgetStatus.OVER -> Res.string.dashboard_budgets_status_over
}