From 57888f8d9e38bea4a64f6cd69e286fbf4b050bc8 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 6 Oct 2026 16:27:35 +0200 Subject: [PATCH] android: display member avatars in conversations and member details --- .../ui/components/ConversationMessages.kt | 12 +++++++++++- .../com/utun/chat/ui/screens/DmChatScreen.kt | 3 +++ .../utun/chat/ui/screens/MemberListScreen.kt | 19 ++++++++++--------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/ConversationMessages.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/ConversationMessages.kt index 676adb3f..415e3c71 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/ConversationMessages.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/ConversationMessages.kt @@ -11,6 +11,7 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.Modifier +import androidx.compose.ui.Alignment import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size @@ -77,7 +78,16 @@ fun ConversationMessages(target: ConversationTarget, messages: List, st LazyColumn(modifier = modifier.then(backgroundModifier), state = state, reverseLayout = true) { item { Spacer(Modifier.height(8.dp)) } items(messages.reversed(), key = { "${target.nativeId}:${it.isOutgoing}:${it.id}" }) { message -> - MessageBubble(message, playbackState, onPlayVoice, onSeekVoice, onDownloadFile, onOpenFile, onOpenImage, onPlayVideo, onLink) + val group = (target as? ConversationTarget.Channel)?.id + Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.Bottom) { + if (!message.isOutgoing) UserAvatar(group, message.authorNodeId, message.author, + modifier = Modifier.padding(start = 8.dp, bottom = 4.dp), size = 32.dp) + Box(Modifier.weight(1f)) { + MessageBubble(message, playbackState, onPlayVoice, onSeekVoice, onDownloadFile, onOpenFile, onOpenImage, onPlayVideo, onLink) + } + if (message.isOutgoing) UserAvatar(group, message.authorNodeId, message.author, + modifier = Modifier.padding(end = 8.dp, bottom = 4.dp), size = 32.dp) + } } } } diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/DmChatScreen.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/DmChatScreen.kt index 5c05c528..4fb6f390 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/DmChatScreen.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/DmChatScreen.kt @@ -1,6 +1,7 @@ package com.utun.chat.ui.screens import com.utun.chat.R +import com.utun.chat.ui.components.UserAvatar import com.utun.chat.data.AppLanguage import androidx.compose.ui.res.stringResource import androidx.activity.compose.rememberLauncherForActivityResult @@ -64,6 +65,8 @@ fun DmChatScreen(conv: DmConversation, messages: List, viewModel: ChatV Column(Modifier.fillMaxSize().imePadding()) { TopAppBar(title = { Row(verticalAlignment = Alignment.CenterVertically) { + UserAvatar(null, conv.peerNodeId, conv.displayName, size = 32.dp) + Spacer(Modifier.width(8.dp)) PeerStatusDot(callAvailable) Spacer(Modifier.width(8.dp)) Text(conv.displayName) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/MemberListScreen.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/MemberListScreen.kt index 7c4b28bb..9f3ad06e 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/MemberListScreen.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/MemberListScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape +import com.utun.chat.ui.components.UserAvatar import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack @@ -91,6 +92,7 @@ fun MemberListScreen( val m = members[idx] MemberListItem( member = m, + group = channel.id, isSelected = selectedMember?.nodeId == m.nodeId, onClick = { viewModel.showMemberDetail(channel.id, m.nodeId) }, onCall = { viewModel.startCall(channel.id, m.nodeId, m.name) }, @@ -152,6 +154,7 @@ fun MemberListScreen( @Composable private fun MemberListItem( member: ChatMember, + group: String, isSelected: Boolean = false, onClick: () -> Unit, onCall: () -> Unit, @@ -176,15 +179,11 @@ private fun MemberListItem( modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp), verticalAlignment = Alignment.CenterVertically ) { - if (member.isSelf) { - Text("✓", fontSize = 12.sp, color = Color(0xFF81C784)) - } else { - Box( - modifier = Modifier - .size(10.dp) - .clip(CircleShape) - .background(onlineColor) - ) + Box { + UserAvatar(group, member.nodeId, member.name) + if (member.isSelf) Text("✓", modifier = Modifier.align(Alignment.BottomEnd), + fontSize = 12.sp, color = Color(0xFF81C784)) + else Box(Modifier.align(Alignment.BottomEnd).size(10.dp).clip(CircleShape).background(onlineColor)) } Spacer(Modifier.width(10.dp)) @@ -280,6 +279,8 @@ private fun MemberDetailCard( ) { Column(modifier = Modifier.padding(12.dp).verticalScroll(rememberScrollState())) { Row(verticalAlignment = Alignment.CenterVertically) { + UserAvatar(detail.channelId, detail.nodeId, detail.name) + Spacer(Modifier.width(8.dp)) Column(modifier = Modifier.weight(1f)) { Row(verticalAlignment = Alignment.CenterVertically) { val dotColor = if (detail.online) Color(0xFF81C784) else Color(0xFFAEBCC8)