Merge pull request #2457 from vitorpamplona/claude/fix-members-tag-update-OKFvB

Refactor Marmot group members to use reactive state flow
This commit is contained in:
Vitor Pamplona
2026-04-20 12:33:34 -04:00
committed by GitHub
5 changed files with 21 additions and 15 deletions
@@ -2069,6 +2069,13 @@ class Account(
relays = groupRelays,
)
// The MLS commit has already been applied to the local group state —
// surface the new member list in the chatroom now so observers (e.g.
// MarmotGroupInfoScreen) update without waiting for our own commit to
// loop back through the relay.
val chatroom = marmotGroupList.getOrCreateGroup(nostrGroupId)
manager.syncMetadataTo(nostrGroupId, chatroom)
Log.d("MarmotDbg") {
"addMarmotGroupMember: built commit kind=${commitEvent.signedEvent.kind} id=${commitEvent.signedEvent.id.take(8)}" +
"welcomeDelivery=${if (welcomeDelivery != null) "present(giftWrapId=${welcomeDelivery.giftWrapEvent.id.take(8)}…)" else "null"}"
@@ -2259,6 +2266,8 @@ class Account(
if (!isWriteable()) return
val outbound = manager.removeMember(nostrGroupId, targetLeafIndex)
val chatroom = marmotGroupList.getOrCreateGroup(nostrGroupId)
manager.syncMetadataTo(nostrGroupId, chatroom)
client.publish(outbound.signedEvent, groupRelays)
}
@@ -47,7 +47,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -85,18 +84,13 @@ fun MarmotGroupInfoScreen(
val groupDescription by chatroom.description.collectAsStateWithLifecycle()
val adminPubkeys by chatroom.adminPubkeys.collectAsStateWithLifecycle()
val groupRelays by chatroom.relays.collectAsStateWithLifecycle()
var members by remember { mutableStateOf(emptyList<GroupMemberInfo>()) }
val members by chatroom.members.collectAsStateWithLifecycle()
var showLeaveDialog by remember { mutableStateOf(false) }
var isLeaving by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
val myPubkey = accountViewModel.account.signer.pubKey
val context = LocalContext.current
LaunchedEffect(nostrGroupId) {
members = accountViewModel.marmotGroupMembers(nostrGroupId)
chatroom.memberCount.value = members.size
}
Scaffold(
topBar = {
TopAppBar(
@@ -44,7 +44,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -55,6 +54,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.commons.marmot.GroupMemberInfo
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.note.UserPicture
@@ -71,17 +71,17 @@ fun RemoveMemberScreen(
accountViewModel: AccountViewModel,
nav: INav,
) {
var members by remember { mutableStateOf(emptyList<GroupMemberInfo>()) }
val chatroom =
remember(nostrGroupId) {
accountViewModel.account.marmotGroupList.getOrCreateGroup(nostrGroupId)
}
val members by chatroom.members.collectAsStateWithLifecycle()
var memberToRemove by remember { mutableStateOf<GroupMemberInfo?>(null) }
var isRemoving by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
val myPubkey = accountViewModel.account.signer.pubKey
val context = LocalContext.current
LaunchedEffect(nostrGroupId) {
members = accountViewModel.marmotGroupMembers(nostrGroupId)
}
Scaffold(
topBar = {
TopAppBar(
@@ -155,7 +155,6 @@ fun RemoveMemberScreen(
scope.launch(Dispatchers.IO) {
try {
accountViewModel.removeMarmotGroupMember(nostrGroupId, member.leafIndex)
members = accountViewModel.marmotGroupMembers(nostrGroupId)
isRemoving = false
launch(Dispatchers.Main) {
Toast
@@ -432,7 +432,9 @@ class MarmotManager(
chatroom.adminPubkeys.value = metadata.adminPubkeys
chatroom.relays.value = metadata.relays
}
chatroom.memberCount.value = memberCount(nostrGroupId)
val members = memberPubkeys(nostrGroupId)
chatroom.members.value = members
chatroom.memberCount.value = members.size
}
}
@@ -21,6 +21,7 @@
package com.vitorpamplona.amethyst.commons.model.marmotGroups
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.commons.marmot.GroupMemberInfo
import com.vitorpamplona.amethyst.commons.model.Channel.Companion.DefaultFeedOrder
import com.vitorpamplona.amethyst.commons.model.ListChange
import com.vitorpamplona.amethyst.commons.model.Note
@@ -46,6 +47,7 @@ class MarmotGroupChatroom(
var adminPubkeys = MutableStateFlow<List<HexKey>>(emptyList())
var relays = MutableStateFlow<List<String>>(emptyList())
var memberCount = MutableStateFlow(0)
var members = MutableStateFlow<List<GroupMemberInfo>>(emptyList())
var newestMessage: Note? = null
val unreadCount = MutableStateFlow(0)