fix(chat): restore follow mark and NIP-85 score on chat faces

ChatRoomFaces (group rows in Messages and the chat header) and
ChatAuthorAvatar (the face beside a run in a group chat) drew bare
pictures and dropped the follow icon and the trust score. Draw every
face through BaseUserPicture again so both badges come back, keeping
the two-face layout and the avatar outside the bubble.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113Y3NP1fRnbQJyrH6D6YQj
This commit is contained in:
Claude
2026-10-02 12:38:50 +00:00
parent b5b0fed04c
commit 81d205f60b
2 changed files with 16 additions and 38 deletions
@@ -224,10 +224,9 @@ fun ClickableUserPicture(
}
/**
* The faces of a Messages-list room. A 1:1 room shows its counterpart with the usual follow and
* trust badges. A group shows at most two faces, overlapped, and no badges: at list size a 2x2
* mosaic leaves each face ~24dp, and a trust score plus a follow shield on every one of them is
* noise nobody can read.
* The faces of a chat room (Messages-list rows, chat headers). A 1:1 room shows its counterpart;
* a group shows at most two faces, overlapped, instead of a 2x2 mosaic. Every face keeps the
* usual follow mark and NIP-85 trust score, as [BaseUserPicture] draws them everywhere else.
*/
@Composable
fun ChatRoomFaces(
@@ -249,7 +248,7 @@ fun ChatRoomFaces(
val ring = 2.dp
Box(Modifier.size(size)) {
Box(Modifier.align(Alignment.TopStart)) {
BadgelessUserPicture(userHexList[0], face, accountViewModel)
BaseUserPicture(userHexList[0], face, accountViewModel)
}
// The front face sits in a disc of the background color, which cuts a clean ring
// out of the face behind it instead of letting the two pictures smear together.
@@ -261,28 +260,13 @@ fun ChatRoomFaces(
.size(face + ring * 2)
.background(MaterialTheme.colorScheme.background, CircleShape),
) {
BadgelessUserPicture(userHexList[1], face, accountViewModel)
BaseUserPicture(userHexList[1], face, accountViewModel)
}
}
}
}
}
@Composable
private fun BadgelessUserPicture(
userHex: HexKey,
size: Dp,
accountViewModel: AccountViewModel,
) {
LoadUser(userHex) {
if (it != null) {
ObserveAndDrawInnerUserPicture(it, size, accountViewModel)
} else {
InnerUserPicture(userHex = userHex, userPicture = null, userName = null, size = size, modifier = Modifier)
}
}
}
@Composable
fun NonClickableUserPictures(
room: ChatroomKey,
@@ -23,14 +23,13 @@ package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.layout.size
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@@ -45,8 +44,7 @@ import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChann
import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserDisplayNickname
import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.note.InnerUserPicture
import com.vitorpamplona.amethyst.commons.ui.note.LoadUser
import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji
import com.vitorpamplona.amethyst.commons.ui.theme.isLight
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
@@ -106,9 +104,9 @@ val ChatAuthorNameWeight = FontWeight.SemiBold
val ChatAuthorNameSize = 13.sp
/**
* The author's face beside the last bubble of their run in a group chat. Plain picture: the
* trust score and follow mark it used to carry inside the bubble were unreadable at this size
* and live on the profile one tap away.
* The author's face beside the last bubble of their run in a group chat, with the follow mark
* and NIP-85 trust score [BaseUserPicture] draws on every profile picture. Tapping it opens the
* profile.
*/
@Composable
fun ChatAuthorAvatar(
@@ -116,16 +114,12 @@ fun ChatAuthorAvatar(
accountViewModel: AccountViewModel,
onClick: () -> Unit,
) {
LoadUser(baseUserHex = userHex) { user ->
val userState = user?.let { observeUserInfo(it, accountViewModel).value }
InnerUserPicture(
userHex = userHex,
userPicture = userState?.info?.picture,
userName = userState?.info?.bestName(),
size = ChatAuthorAvatarSize,
modifier = Modifier.clip(CircleShape).clickable(onClick = onClick),
)
}
BaseUserPicture(
baseUserHex = userHex,
size = ChatAuthorAvatarSize,
accountViewModel = accountViewModel,
outerModifier = Modifier.size(ChatAuthorAvatarSize).clickable(onClick = onClick),
)
}
@Composable