refactor: make Marmot group members list reactive
Expose the member list as MutableStateFlow<List<GroupMemberInfo>> on MarmotGroupChatroom, populated by MarmotManager.syncMetadataTo alongside the existing memberCount. MarmotGroupInfoScreen and RemoveMemberScreen now observe it via collectAsStateWithLifecycle, so both remote commits (already routed through syncMetadataTo in DecryptAndIndexProcessor) and local mutations refresh the UI without manual re-queries. Account.addMarmotGroupMember and removeMarmotGroupMember now call syncMetadataTo right after the MLS state is mutated, mirroring the pattern already used by updateMarmotGroupMetadata, so the local change is visible immediately without waiting for the relay round-trip.
This commit is contained in:
@@ -2070,6 +2070,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"}"
|
||||
@@ -2270,6 +2277,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)
|
||||
}
|
||||
|
||||
|
||||
+1
-8
@@ -58,7 +58,6 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.marmot.GroupMemberInfo
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
@@ -85,19 +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
|
||||
|
||||
LifecycleResumeEffect(nostrGroupId) {
|
||||
members = accountViewModel.marmotGroupMembers(nostrGroupId)
|
||||
chatroom.memberCount.value = members.size
|
||||
onPauseOrDispose {}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
|
||||
+6
-7
@@ -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
|
||||
|
||||
+3
-1
@@ -437,7 +437,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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user