From eff3f1c843a7a3043ae9750d990089252f6db6e9 Mon Sep 17 00:00:00 2001 From: b-mob-deck Date: Mon, 13 Jul 2026 08:47:25 +0000 Subject: [PATCH] =?UTF-8?q?feat(deck):=20=D0=B1=D0=B5=D0=B9=D0=B4=D0=B6=20?= =?UTF-8?q?=D1=87=D0=B5=D0=BA-=D0=BF=D1=83=D0=BD=D0=BA=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=20=C2=AB=E2=98=91=20x/total=C2=BB=20=D0=BD=D0=B0=20=D0=BA?= =?UTF-8?q?=D0=B0=D1=80=D1=82=D0=BE=D1=87=D0=BA=D0=B5=20(P1=20diff=20?= =?UTF-8?q?=E2=80=94=20CardBadges)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit deckChecklistCounts парсит чекбоксы описания (regex как веб). Green compile+detekt. --- .../f7cloud/feature/deck/DeckScreen.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/feature/deck/src/main/java/ru/forbion/f7cloud/feature/deck/DeckScreen.kt b/feature/deck/src/main/java/ru/forbion/f7cloud/feature/deck/DeckScreen.kt index ac40eb2..d0e8d4c 100644 --- a/feature/deck/src/main/java/ru/forbion/f7cloud/feature/deck/DeckScreen.kt +++ b/feature/deck/src/main/java/ru/forbion/f7cloud/feature/deck/DeckScreen.kt @@ -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 { + 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