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
This commit is contained in:
Claude
2026-04-16 01:55:44 +00:00
parent 3356059d50
commit e168b9dde2
5 changed files with 29 additions and 4 deletions
@@ -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)
@@ -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,
@@ -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
@@ -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<Note>): Set<Note> = 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) {
+1
View File
@@ -1090,6 +1090,7 @@
<string name="new_feature_nip17_activate">Activate</string>
<string name="messages_create_public_chat">Public</string>
<string name="messages_create_group">Group</string>
<string name="messages_create_public_private_chat_description">New Public or Private Group</string>
<string name="messages_relay_based">Relay</string>
<string name="messages_new_message">Private</string>