From e168b9dde27788c24df0150d0820d70e21f2fef9 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Apr 2026 01:55:44 +0000 Subject: [PATCH] feat: replace MLS Groups FAB with Create Group and show marmot messages in notifications Replace the "MLS Groups" FAB button on MessagesScreen with a "Create Group" action that navigates directly to the group creation screen (Route.CreateMarmotGroup) instead of the group list page. This aligns with the plan to merge all marmot groups into the Messages screen's Known and New Requests tabs. Add marmot group messages to the notification screen so they appear alongside regular DMs. This includes: - Including marmot group messages in NotificationFeedFilter.feed() - Accepting marmot group notes in acceptableEvent() via inGatherers check - Converting marmot group notes to MessageSetCard in CardFeedContentState - Routing marmot group notification clicks to the group chat screen https://claude.ai/code/session_012wbykgUYHNVdHVNbDDnMUt --- .../amethyst/ui/navigation/routes/RouteMaker.kt | 7 +++++++ .../loggedIn/chats/rooms/ChannelFabColumn.kt | 4 ++-- .../notifications/CardFeedContentState.kt | 5 ++++- .../notifications/dal/NotificationFeedFilter.kt | 16 +++++++++++++++- amethyst/src/main/res/values/strings.xml | 1 + 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt index 5be6bbd33..c68fb7a63 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.ui.navigation.routes 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.commons.model.nip53LiveActivities.LiveActivitiesChannel import com.vitorpamplona.amethyst.model.Account @@ -61,6 +62,12 @@ fun routeFor( note: Note, loggedIn: Account, ): Route? { + // Marmot group messages should navigate to the group chat + val marmotGroup = note.inGatherers?.firstNotNullOfOrNull { it as? MarmotGroupChatroom } + if (marmotGroup != null) { + return Route.MarmotGroupChat(marmotGroup.nostrGroupId) + } + val noteEvent = note.event ?: return Route.EventRedirect(note.idHex) return routeFor(noteEvent, loggedIn) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChannelFabColumn.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChannelFabColumn.kt index 91dbfaa23..8618fe5ec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChannelFabColumn.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChannelFabColumn.kt @@ -106,7 +106,7 @@ fun ChannelFabColumn(nav: INav) { FloatingActionButton( onClick = { - nav.nav(Route.MarmotGroupList) + nav.nav(Route.CreateMarmotGroup) isOpen = false }, modifier = Size55Modifier, @@ -114,7 +114,7 @@ fun ChannelFabColumn(nav: INav) { containerColor = MaterialTheme.colorScheme.primary, ) { Text( - text = "MLS\nGroups", + text = stringRes(R.string.messages_create_group), color = Color.White, textAlign = TextAlign.Center, fontSize = Font12SP, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt index e2edca451..53c3730a3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt @@ -24,6 +24,7 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.mutableStateOf +import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom import com.vitorpamplona.amethyst.commons.ui.feeds.InvalidatableContent import com.vitorpamplona.amethyst.commons.ui.feeds.LoadedFeedState import com.vitorpamplona.amethyst.commons.ui.notifications.Card @@ -306,7 +307,7 @@ class CardFeedContentState( it.event !is GenericRepostEvent && it.event !is LnZapEvent }.map { - if (it.event is PrivateDmEvent || it.event is NIP17Group) { + if (it.event is PrivateDmEvent || it.event is NIP17Group || it.isInMarmotGroup()) { MessageSetCard(it) } else if (it.event is BadgeAwardEvent) { BadgeCard(it) @@ -475,3 +476,5 @@ data class CombinedZap( fun idHex() = response.idHex } + +private fun Note.isInMarmotGroup(): Boolean = inGatherers?.any { it is MarmotGroupChatroom } == true diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt index 70ee67990..b7f401ed6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt @@ -34,6 +34,7 @@ import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent import com.vitorpamplona.quartz.experimental.forks.IForkableEvent import com.vitorpamplona.quartz.experimental.nipsOnNostr.NipTextEvent import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent +import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser @@ -151,7 +152,14 @@ class NotificationFeedFilter( acceptableEvent(note, filterParams) } - return sort(notifications) + // Include marmot group messages as notifications (like DMs) + val loggedInUserHex = account.userProfile().pubkeyHex + val marmotMessages = + account.marmotGroupList.rooms.mapFlatten { _, chatroom -> + chatroom.messages.filter { it.author?.pubkeyHex != loggedInUserHex } + } + + return sort(notifications + marmotMessages) } override fun applyFilter(newItems: Set): Set = innerApplyFilter(newItems) @@ -168,6 +176,12 @@ class NotificationFeedFilter( ): Boolean { val loggedInUserHex = account.userProfile().pubkeyHex + // Marmot group messages are always acceptable (user is a group member) + val isMarmotGroupMessage = it.inGatherers?.any { g -> g is MarmotGroupChatroom } == true + if (isMarmotGroupMessage) { + return it.author?.pubkeyHex != loggedInUserHex + } + val noteEvent = it.event val notifAuthor = if (noteEvent is LnZapEvent) { diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 07ecc77b2..583f378fd 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -1090,6 +1090,7 @@ Activate Public + Group New Public or Private Group Relay Private