From baf5f3753247a11d04f5d00569bd0446088012f1 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Jul 2026 18:54:23 +0000 Subject: [PATCH] feat: render Buzz channel recent-poster facepile with the standard avatar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The recent-posters facepile in a Buzz community's channel rows drew each poster with ObserveAndDrawInnerUserPicture — a bare cropped image wrapped in a surface-coloured ring, overlapped into a deck. That omitted the following badge and trust-score tag every other user avatar in the app carries. Draw each poster with ClickableUserPicture (the regular BaseUserPicture path) instead, so the facepile shows the following icon (top-right) and trust-score tag (bottom-centre). Lay the avatars out with a small gap rather than an overlapping stack so those badges stay readable. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_013f3JZdoChYEEDtqTArFAxn --- .../publicChannels/concord/ConcordFacepile.kt | 54 ++++++------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordFacepile.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordFacepile.kt index 328458adc2..53042dfa2e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordFacepile.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordFacepile.kt @@ -20,65 +20,41 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex -import com.vitorpamplona.amethyst.ui.note.DisplayBlankAuthor -import com.vitorpamplona.amethyst.ui.note.ObserveAndDrawInnerUserPicture +import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser import com.vitorpamplona.quartz.nip01Core.core.HexKey /** - * A horizontal stack of overlapping avatars for the recent posters in a channel — the "who's here" - * cue that makes a busy channel feel alive. Each avatar wears a thin ring in the row's background - * colour so the overlap reads as a deck of cards; the newest poster sits on top (leftmost, highest - * z-index). Renders nothing for an empty [authorHexes], so callers can drop it in unconditionally. + * A horizontal strip of the recent posters in a channel — the "who's here" cue that makes a busy + * channel feel alive. Each poster is drawn with the app's standard profile avatar + * ([ClickableUserPicture]), so it carries the same following badge (top-right) and trust-score tag + * (bottom-centre) shown everywhere else a user appears, instead of a bare cropped image. Laid out + * with a small gap rather than an overlapping stack so those badges stay readable; the newest poster + * is leftmost. Renders nothing for an empty [authorHexes], so callers can drop it in unconditionally. */ @Composable fun ConcordAuthorFacepile( authorHexes: List, accountViewModel: AccountViewModel, modifier: Modifier = Modifier, - avatarSize: Dp = 22.dp, + avatarSize: Dp = 24.dp, maxShown: Int = 4, ) { if (authorHexes.isEmpty()) return val shown = authorHexes.take(maxShown) - // A ring one-and-a-half dp wide, and each avatar pulled left over its neighbour by a third of - // its width — enough overlap to read as a stack without hiding faces. - val ring = 1.5.dp - val overlap = avatarSize * 0.36f - Row(modifier, horizontalArrangement = Arrangement.spacedBy(-overlap)) { - shown.forEachIndexed { index, hex -> - Box( - Modifier - // Newest (index 0) on top so it isn't clipped by the one after it. - .zIndex((shown.size - index).toFloat()) - .size(avatarSize) - .clip(CircleShape) - .background(MaterialTheme.colorScheme.surface) - .padding(ring), - ) { - LoadUser(baseUserHex = hex, accountViewModel) { user -> - if (user != null) { - ObserveAndDrawInnerUserPicture(user, avatarSize - ring * 2, accountViewModel) - } else { - DisplayBlankAuthor(avatarSize - ring * 2, Modifier, accountViewModel) - } - } - } + Row(modifier, horizontalArrangement = Arrangement.spacedBy(2.dp)) { + shown.forEach { hex -> + ClickableUserPicture( + baseUserHex = hex, + size = avatarSize, + accountViewModel = accountViewModel, + ) } } }