Coverage Summary for Class: SurferCategoryBreakdownRowKt (com.georgeci.moneysurfer.uikit.components.category)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| SurferCategoryBreakdownRowKt |
100%
(1/1)
|
75%
(3/4)
|
42.9%
(6/14)
|
100%
(45/45)
|
91.4%
(203/222)
|
package com.georgeci.moneysurfer.uikit.components.category
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
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.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.georgeci.moneysurfer.uikit.atom.SurferCard
import com.georgeci.moneysurfer.uikit.components.SurferCategoryBubble
import com.georgeci.moneysurfer.uikit.components.SurferCategoryPalette
import com.georgeci.moneysurfer.uikit.components.SurferCategoryVisual
import com.georgeci.moneysurfer.uikit.icons.SurferIcons
import com.georgeci.moneysurfer.uikit.preview.SurferComponentPreview
import com.georgeci.moneysurfer.uikit.theme.AppTheme
/**
* One subcategory in the parent's breakdown: bubble, name over a share bar, amount and share.
*
* [share] is the fraction of the parent's total this child accounts for, already computed by the
* caller — the row draws one child and has no view of its siblings. Values outside `0..1` are
* clamped rather than trusted, so a rounding artefact cannot paint a bar past the track.
*
* Takes the resolved [SurferCategoryVisual] rather than a loose icon/tint pair: every call site
* gets one from [SurferCategoryPalette.visualFor] anyway, and the two always travel together.
*/
@Composable
fun SurferCategoryBreakdownRow(
visual: SurferCategoryVisual,
name: String,
formattedAmount: String,
sharePercentLabel: String,
share: Float,
modifier: Modifier = Modifier,
onClick: (() -> Unit)? = null,
) {
SurferCard(modifier = modifier.fillMaxWidth(), onClick = onClick) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp),
) {
SurferCategoryBubble(icon = visual.icon, tint = visual.tint, size = 36.dp)
Column(modifier = Modifier.weight(1f)) {
Text(
text = name,
style = AppTheme.typography.titleSmall,
color = AppTheme.materialColors.onSurface,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Spacer(Modifier.height(6.dp))
Box(
modifier = Modifier
.fillMaxWidth()
.height(TrackHeight)
.clip(AppTheme.shapes.extraSmall)
.background(visual.tint.copy(alpha = TrackAlpha)),
) {
Box(
modifier = Modifier
.fillMaxWidth(share.coerceIn(0f, 1f))
.fillMaxHeight()
.clip(AppTheme.shapes.extraSmall)
.background(visual.tint),
)
}
}
Column(horizontalAlignment = Alignment.End) {
Text(
text = formattedAmount,
style = AppTheme.typography.titleMedium,
color = AppTheme.materialColors.onSurface,
maxLines = 1,
)
Text(
text = sharePercentLabel,
style = AppTheme.typography.labelSmall,
color = AppTheme.materialColors.onSurfaceVariant,
)
}
}
}
}
private val TrackHeight = 4.dp
private const val TrackAlpha = 0.20f
@Preview
@Composable
private fun SurferCategoryBreakdownRowPreview() {
SurferComponentPreview {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
SurferCategoryBreakdownRow(
visual = SurferCategoryVisual(SurferIcons.Receipt, SurferCategoryPalette.tints[5]),
name = "Delivery",
formattedAmount = "€106.15",
sharePercentLabel = "63%",
share = 0.63f,
)
SurferCategoryBreakdownRow(
visual = SurferCategoryVisual(SurferIcons.Cash, SurferCategoryPalette.tints[5]),
name = "Coffee",
formattedAmount = "€62.40",
sharePercentLabel = "37%",
share = 0.37f,
)
}
}
}