From c040b7a6c611c74c80de991005e80af60e0155d4 Mon Sep 17 00:00:00 2001 From: PTah Date: Sat, 20 Jun 2026 19:13:58 +1000 Subject: [PATCH] feat: yellow RDG flap badge on dashboard and events (0.5.9) Match SAC styling for RDG session flap events on the home screen and events list. --- README.md | 2 +- app/build.gradle.kts | 4 +- .../seaca/ui/components/RdgFlapBadge.kt | 43 +++++++++++++++++ .../seaca/ui/screens/ListScreens.kt | 47 ++++++++++++++----- 4 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/ru/kalinamall/seaca/ui/components/RdgFlapBadge.kt diff --git a/README.md b/README.md index a809bfe..08328ff 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Android-клиент [Security Alert Center (SAC)](https://git.kalinamall.ru/PapaTramp/security-alert-center). -**Версия:** `0.5.8` (versionCode 22) +**Версия:** `0.5.9` (versionCode 23) ## Возможности diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5060684..36fa822 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -13,8 +13,8 @@ android { applicationId = "ru.kalinamall.seaca" minSdk = 26 targetSdk = 35 - versionCode = 22 - versionName = "0.5.8" + versionCode = 23 + versionName = "0.5.9" } buildTypes { diff --git a/app/src/main/java/ru/kalinamall/seaca/ui/components/RdgFlapBadge.kt b/app/src/main/java/ru/kalinamall/seaca/ui/components/RdgFlapBadge.kt new file mode 100644 index 0000000..a92e416 --- /dev/null +++ b/app/src/main/java/ru/kalinamall/seaca/ui/components/RdgFlapBadge.kt @@ -0,0 +1,43 @@ +package ru.kalinamall.seaca.ui.components + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +private val RdgFlapText = Color(0xFFF0C674) +private val RdgFlapBackground = Color(0x1FF0C674) +private val RdgFlapBorder = Color(0x73F0C674) + +@Composable +fun RdgFlapBadge( + modifier: Modifier = Modifier, + pairEventId: Long? = null, +) { + val label = buildString { + append("RDG FLAP") + if (pairEventId != null) append(" #$pairEventId") + } + Surface( + modifier = modifier + .border(1.dp, RdgFlapBorder, RoundedCornerShape(4.dp)), + shape = RoundedCornerShape(4.dp), + color = RdgFlapBackground, + ) { + Text( + text = label, + modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp), + color = RdgFlapText, + fontSize = 11.sp, + fontWeight = FontWeight.SemiBold, + letterSpacing = 0.3.sp, + ) + } +} diff --git a/app/src/main/java/ru/kalinamall/seaca/ui/screens/ListScreens.kt b/app/src/main/java/ru/kalinamall/seaca/ui/screens/ListScreens.kt index d9588d2..bf4948d 100644 --- a/app/src/main/java/ru/kalinamall/seaca/ui/screens/ListScreens.kt +++ b/app/src/main/java/ru/kalinamall/seaca/ui/screens/ListScreens.kt @@ -46,6 +46,7 @@ import ru.kalinamall.seaca.data.HostSummary import ru.kalinamall.seaca.data.ProblemSummary import ru.kalinamall.seaca.data.SacRepository import ru.kalinamall.seaca.ui.components.BackArrowButton +import ru.kalinamall.seaca.ui.components.RdgFlapBadge import ru.kalinamall.seaca.ui.components.ForwardArrowButton import ru.kalinamall.seaca.ui.util.SacDateTimes import ru.kalinamall.seaca.ui.util.hasRdgFlapUi @@ -122,12 +123,16 @@ fun DashboardScreen(repo: SacRepository, refreshKey: Int = 0) { horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.Top, ) { - Text( - dashboardRecentEventLine(e), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.weight(1f), - ) + Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) { + if (hasRdgFlapUi(e)) { + RdgFlapBadge(pairEventId = e.rdgFlapPairEventId) + } + Text( + dashboardRecentEventLine(e), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurface, + ) + } Text( SacDateTimes.format(e.occurredAt, dateMode), style = MaterialTheme.typography.bodySmall, @@ -190,11 +195,10 @@ fun EventsScreen(repo: SacRepository, onOpen: (Long) -> Unit) { res.items to res.total }, itemKey = EventSummary::id, - itemLabel = { - val prefix = if (hasRdgFlapUi(it)) "RDG flap · " else "" - "$prefix${it.severity} · ${it.title}" - }, + itemLabel = { "${it.severity} · ${it.title}" }, itemSub = { "${it.hostname} · ${SacDateTimes.format(it.occurredAt, dateMode)}" }, + itemRdgFlap = { hasRdgFlapUi(it) }, + itemRdgFlapPairId = { it.rdgFlapPairEventId }, onOpen = onOpen, severities = listOf(null, "info", "warning", "high", "critical"), hostnameFilter = hostname, @@ -331,6 +335,8 @@ private fun PagedListScreen( itemSub: (T) -> String, onOpen: (Long) -> Unit, severities: List, + itemRdgFlap: ((T) -> Boolean)? = null, + itemRdgFlapPairId: ((T) -> Long?)? = null, filterLabel: String = "Severity", hostnameFilter: String = "", headerContent: @Composable () -> Unit = {}, @@ -389,7 +395,13 @@ private fun PagedListScreen( ) { LazyColumn { items(items, key = { itemKey(it) }) { item -> - ListRow(itemLabel(item), itemSub(item)) { onOpen(itemKey(item)) } + ListRow( + title = itemLabel(item), + subtitle = itemSub(item), + onClick = { onOpen(itemKey(item)) }, + rdgFlap = itemRdgFlap?.invoke(item) == true, + rdgFlapPairId = itemRdgFlapPairId?.invoke(item), + ) } } } @@ -398,7 +410,13 @@ private fun PagedListScreen( } @Composable -private fun ListRow(title: String, subtitle: String, onClick: () -> Unit) { +private fun ListRow( + title: String, + subtitle: String, + onClick: () -> Unit, + rdgFlap: Boolean = false, + rdgFlapPairId: Long? = null, +) { Card( Modifier .fillMaxWidth() @@ -409,7 +427,10 @@ private fun ListRow(title: String, subtitle: String, onClick: () -> Unit) { contentColor = MaterialTheme.colorScheme.onSurface, ), ) { - Column(Modifier.padding(12.dp)) { + Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(4.dp)) { + if (rdgFlap) { + RdgFlapBadge(pairEventId = rdgFlapPairId) + } Text(title, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurface) Text(subtitle, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) }