From 80518c55c9039d5f1c12abff2192149776357456 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 15 Apr 2026 02:46:27 +0000 Subject: [PATCH] feat: render MLS groups inline in the Messages list MLS (Marmot) groups now appear in the regular Messages list alongside DMs and public chats. Each entry shows the group's image (robohash fallback from the nostr group id), name, and last message, marked with an "MLS Group" label rendered in the same style as the existing "Public Chat" badge. Tapping the row navigates to the dedicated MLS group chat screen. Notes are routed to the MLS row by checking for a MarmotGroupChatroom in the note's gatherers, so this works without changing the feed filter that already aggregates marmot newest messages. --- .../chats/rooms/ChatroomHeaderCompose.kt | 36 +++++++++++++++++++ amethyst/src/main/res/values/strings.xml | 1 + 2 files changed, 37 insertions(+) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt index a663c1bb89..8e02c4945d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt @@ -42,6 +42,7 @@ import androidx.compose.ui.text.withStyle import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel +import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User @@ -118,6 +119,12 @@ private fun ChatroomEntry( accountViewModel: AccountViewModel, nav: INav, ) { + val marmotGroup = lastMessage.inGatherers?.firstNotNullOfOrNull { it as? MarmotGroupChatroom } + if (marmotGroup != null) { + MarmotGroupRoomCompose(lastMessage, marmotGroup, accountViewModel, nav) + return + } + val baseNoteEvent = lastMessage.event when (baseNoteEvent) { is ChannelMessageEvent -> { @@ -234,6 +241,35 @@ private fun ChannelRoomCompose( ) } +@Composable +private fun MarmotGroupRoomCompose( + lastMessage: Note, + chatroom: MarmotGroupChatroom, + accountViewModel: AccountViewModel, + nav: INav, +) { + val authorName by observeUserName(lastMessage.author!!, accountViewModel) + val displayName by chatroom.displayName.collectAsStateWithLifecycle() + val unread by chatroom.unreadCount.collectAsStateWithLifecycle() + + val noteEvent = lastMessage.event + val description = noteEvent?.content?.take(200) + + val groupName = displayName?.takeIf { it.isNotBlank() } ?: "Group ${chatroom.nostrGroupId.take(8)}" + + ChannelName( + channelIdHex = chatroom.nostrGroupId, + channelPicture = null, + channelTitle = { modifier -> ChannelTitleWithLabelInfo(groupName, R.string.marmot_group, modifier) }, + channelLastTime = lastMessage.createdAt(), + channelLastContent = "$authorName: $description", + hasNewMessages = unread > 0, + loadProfilePicture = accountViewModel.settings.showProfilePictures(), + loadRobohash = accountViewModel.settings.isNotPerformanceMode(), + onClick = { nav.nav(Route.MarmotGroupChat(chatroom.nostrGroupId)) }, + ) +} + @Composable private fun ChannelTitleWithLabelInfo( channelName: String, diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 4fffe2ae20..67562ab860 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -283,6 +283,7 @@ and thus chat messages disappear over time Public Chat + MLS Group Public Chat Metadata Public chats are visible to everyone on Nostr and anyone can participate on them. They are great for open communities around specific topics.