feat(deck): бейдж чек-пунктов «☑ x/total» на карточке (P1 diff — CardBadges)

deckChecklistCounts парсит чекбоксы описания (regex как веб). Green compile+detekt.
This commit is contained in:
b-mob-deck
2026-07-13 08:47:25 +00:00
parent c31adb5692
commit eff3f1c843
@@ -362,7 +362,9 @@ private fun DeckCardRow(card: DeckCard, onClick: () -> Unit, onToggleDone: () ->
)
}
val due = card.duedate?.let { formatDeckDue(it) }
if (due != null || card.assignees.isNotEmpty() || card.commentsCount > 0) {
val (checked, total) = deckChecklistCounts(card.description)
val hasMeta = listOf(due != null, total > 0, card.commentsCount > 0, card.assignees.isNotEmpty())
if (hasMeta.any { it }) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
@@ -371,6 +373,10 @@ private fun DeckCardRow(card: DeckCard, onClick: () -> Unit, onToggleDone: () ->
if (due != null) {
Text("🗓 $due", style = MaterialTheme.typography.labelMedium, color = F7Colors.TextSecondary)
}
if (total > 0) {
val todo = "$checked/$total"
Text(todo, style = MaterialTheme.typography.labelMedium, color = F7Colors.TextSecondary)
}
if (card.commentsCount > 0) {
val comments = "💬 ${card.commentsCount}"
Text(comments, style = MaterialTheme.typography.labelMedium, color = F7Colors.TextSecondary)
@@ -403,6 +409,17 @@ internal fun DeckLabelChip(label: DeckLabel) {
}
}
private val deckChecklistRe = Regex("(?im)^\\s*([*+-]|\\d\\.)\\s+\\[\\s*(\\s|[xX])\\s*\\].*$")
private val deckCheckedRe = Regex("(?im)^\\s*([*+-]|\\d\\.)\\s+\\[\\s*[xX]\\s*\\].*$")
/** Чек-пункты из описания карточки (как веб CardBadges): (отмечено, всего). */
internal fun deckChecklistCounts(description: String): Pair<Int, Int> {
if (description.isBlank()) return 0 to 0
val total = deckChecklistRe.findAll(description).count()
val checked = deckCheckedRe.findAll(description).count()
return checked to total
}
/** Цвет Deck («RRGGBB» без #, иногда с #). */
internal fun parseDeckColor(hex: String?): Color? {
val h = hex?.trim()?.removePrefix("#")?.takeIf { it.length == 6 } ?: return null