Coverage Summary for Class: TransactionEditIdentityBandKt (com.georgeci.moneysurfer.feature.transaction.creation)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| TransactionEditIdentityBandKt |
66.7%
(2/3)
|
50%
(7/14)
|
92.5%
(49/53)
|
94.2%
(474/503)
|
| TransactionEditIdentityBandKt$WhenMappings |
|
| Total |
66.7%
(2/3)
|
50%
(7/14)
|
92.5%
(49/53)
|
94.2%
(474/503)
|
package com.georgeci.moneysurfer.feature.transaction.creation
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
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.graphics.Color
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.text.font.FontWeight
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.components.SurferCategoryBubble
import com.georgeci.moneysurfer.uikit.components.SurferCategoryPalette
import com.georgeci.moneysurfer.uikit.preview.SurferComponentPreview
import com.georgeci.moneysurfer.uikit.theme.AppTheme
import moneysurfer.feature.transaction.generated.resources.Res
import moneysurfer.feature.transaction.generated.resources.transaction_creation_expense
import moneysurfer.feature.transaction.generated.resources.transaction_creation_income
import moneysurfer.feature.transaction.generated.resources.transaction_creation_transfer
import org.jetbrains.compose.resources.stringResource
/** Opacity of the identity band's tint wash — lighter than a pill, it backs a whole block. */
private const val IDENTITY_BAND_WASH_ALPHA = 0.12f
/** Opacity of the band's hairline border, strong enough to read against the wash behind it. */
private const val IDENTITY_BAND_BORDER_ALPHA = 0.18f
private const val IDENTITY_HEADER_SEPARATOR = " · "
/**
* The design's `04b · Edit transaction` band: the category bubble, `EXPENSE · TX-8213`, the note
* and the amount, tinted with the transaction's own colour.
*
* It is what distinguishes editing from creating beyond a word in the title, and it renders the
* *stored* row (see [TransactionEditIdentity]) — so it keeps naming the transaction under edit
* while the fields below it change.
*/
@Composable
internal fun EditIdentityBand(
identity: TransactionEditIdentity,
modifier: Modifier = Modifier,
) {
val visual = SurferCategoryPalette.visualFor(
id = identity.categoryId,
iconKey = identity.categoryIconKey,
hue = identity.categoryHue,
systemKind = identity.categorySystemKind,
)
// A transfer's category is the seeded system one, so its own tint says nothing the type
// colour does not already say better.
val tint = if (identity.type == TransactionTypeUi.Transfer) typeTint(identity.type) else visual.tint
val wash = tint.copy(alpha = IDENTITY_BAND_WASH_ALPHA)
.compositeOver(AppTheme.materialColors.surface)
val typeLabel = stringResource(
when (identity.type) {
TransactionTypeUi.Expense -> Res.string.transaction_creation_expense
TransactionTypeUi.Income -> Res.string.transaction_creation_income
TransactionTypeUi.Transfer -> Res.string.transaction_creation_transfer
},
).uppercase()
Row(
modifier = modifier
.clip(AppTheme.shapes.large)
.background(wash)
.border(1.dp, tint.copy(alpha = IDENTITY_BAND_BORDER_ALPHA), AppTheme.shapes.large)
.padding(horizontal = 14.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp),
) {
SurferCategoryBubble(icon = visual.icon, tint = tint, size = 44.dp)
Column(modifier = Modifier.weight(1f)) {
Text(
text = typeLabel + IDENTITY_HEADER_SEPARATOR + identity.reference,
style = AppTheme.typography.labelMedium,
color = tint,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
if (identity.note.isNotBlank()) {
Text(
text = identity.note,
style = AppTheme.typography.bodyLarge,
color = AppTheme.materialColors.onSurface,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
Text(
text = identity.formattedAmount,
style = AppTheme.typography.titleMedium.copy(fontWeight = FontWeight.SemiBold),
color = AppTheme.materialColors.onSurface,
maxLines = 1,
)
}
}
/** Semantic colour of a transaction type, shared by the band and the amount hero's type pill. */
@Composable
internal fun typeTint(type: TransactionTypeUi): Color = when (type) {
TransactionTypeUi.Expense -> AppTheme.semanticColors.expense
TransactionTypeUi.Income -> AppTheme.semanticColors.income
TransactionTypeUi.Transfer -> AppTheme.semanticColors.transfer
}
@Preview
@Composable
private fun EditIdentityBandPreview() {
SurferComponentPreview {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
EditIdentityBand(
identity = TransactionEditIdentity(
reference = "TX-8213",
type = TransactionTypeUi.Expense,
note = PreviewNote,
formattedAmount = "−€48.20",
categoryId = "preview-cat-1",
categoryIconKey = "",
categoryHue = -1,
categorySystemKind = null,
),
)
EditIdentityBand(
identity = TransactionEditIdentity(
reference = "TX-3C35",
type = TransactionTypeUi.Transfer,
note = "Rainy day top-up",
formattedAmount = "€200.00",
categoryId = "preview-cat-transfer",
categoryIconKey = SurferCategoryPalette.TRANSFER_ICON_KEY,
categoryHue = -1,
categorySystemKind = SurferCategoryPalette.SYSTEM_KIND_TRANSFER,
),
)
}
}
}