From 40b60e7bcc5f19e17299ad972390b98f7660ea21 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 3 Jun 2026 18:50:13 +0000 Subject: [PATCH] fix: compact relay markers + no '0 relays' flash on the DM loading card Two UI papercuts in the per-relay DM history surface: - RelayReachMarker listed every relay name comma-joined per state, so a gap shared by many relays (e.g. all nine clustered at the live-tail floor on first open) overflowed into an unreadable line. Now each state shows the relay's host name only when it is the sole one of its state at that depth (the usual converged case); otherwise just a count, with maxLines/ellipsis as a backstop. - The history status card briefly read 'loading from 0 relays': the count populated a beat after loadingMore flipped true (and again as the last relay settled). Set the relay count before raising the spinner in loadMore, and defensively drop the relay clause from the card subtitle when the count is 0. https://claude.ai/code/session_01B1fmmmX8JjQWH3amMLdvcW --- .../loggedIn/chats/feed/DmLoadMoreIndicator.kt | 3 +++ .../loggedIn/chats/feed/layouts/RelayReachMarker.kt | 13 ++++++++++--- .../datasource/ChatroomNip04HistorySubAssembler.kt | 3 +++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DmLoadMoreIndicator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DmLoadMoreIndicator.kt index 08c2f7e5fe..e408d4188d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DmLoadMoreIndicator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DmLoadMoreIndicator.kt @@ -162,6 +162,9 @@ private fun historySubtitle( relayCount: Int, reachedBack: Long?, ): String { + // A transient frame can carry loading=true with relayCount=0 (the count updates a beat after the + // spinner flips, and again as the last relay settles); don't render a nonsensical "0 relays". + if (relayCount <= 0) return protocolTag val backLabel = remember(reachedBack) { reachedBack?.let { SimpleDateFormat("MMM yyyy", Locale.getDefault()).format(Date(it * 1000)) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/layouts/RelayReachMarker.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/layouts/RelayReachMarker.kt index ae1bd607ea..5152955297 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/layouts/RelayReachMarker.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/layouts/RelayReachMarker.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.ui.theme.DividerThickness @@ -58,6 +59,11 @@ data class RelayReach( * As a relay loads older history its reached cursor drops, so the caller places this marker further * down (older) in the stream — relays that race ahead leave their marker deep while slower relays' * markers trail higher up, converging as they catch up. + * + * Each state in the gap renders one compact label: a relay's host name when it is the only one of its + * state there (the usual converged case, where each relay sits at its own depth), or just a count when + * several pile up at the same depth (e.g. all nine clustered at the live-tail floor on first open) so + * the line can't grow into an unreadable comma list. */ @Composable fun RelayReachMarker(entries: List) { @@ -65,20 +71,21 @@ fun RelayReachMarker(entries: List) { Row( verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(6.dp), + horizontalArrangement = Arrangement.spacedBy(10.dp), modifier = HalfPadding, ) { HorizontalDivider(modifier = Modifier.weight(1f), thickness = DividerThickness) - // Group by state so a gap shared by several relays reads as e.g. "✓ vitor, nos.lol ↓ wine". entries .groupBy { it.state } .toSortedMap(compareBy { it.ordinal }) .forEach { (state, list) -> Text( - text = glyph(state) + " " + list.joinToString(", ") { it.name }, + text = glyph(state) + " " + if (list.size == 1) list.first().name else list.size.toString(), color = color(state), fontSize = 11.sp, fontWeight = FontWeight.Medium, + maxLines = 1, + overflow = TextOverflow.Ellipsis, ) } HorizontalDivider(modifier = Modifier.weight(1f), thickness = DividerThickness) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomNip04HistorySubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomNip04HistorySubAssembler.kt index f35bd3bbf6..f29d7f88ac 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomNip04HistorySubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomNip04HistorySubAssembler.kt @@ -200,6 +200,9 @@ class ChatroomNip04HistorySubAssembler( if (!windowActive) { windowActive = true windowFloor = startUntil() + // Populate the relay count BEFORE raising the spinner, so the status card never renders + // a "loading from 0 relays" frame between loadingMore flipping true and the first progress. + publishProgress() _loadingMore.value = true windowLoad.startLoading(it) }