feat: read MIP-01 group metadata from MLS GroupContext extensions
Implement end-to-end reading of MarmotGroupData (extension 0xF2EE) from the MLS GroupContext.extensions and sync to the UI layer. Quartz (protocol): - MarmotGroupData.decodeTls(): deserialize from TLS wire format (version, nostrGroupId, name, description, admin pubkeys, relays, image fields) - MarmotGroupData.fromExtensions(): find and decode from extension list - MlsGroup.extensions: expose groupContext.extensions publicly Commons (shared logic): - MarmotGroupChatroom: add description, adminPubkeys, relays fields as MutableStateFlow for reactive UI - MarmotManager.groupMetadata(): extract MIP-01 data from group - MarmotManager.syncMetadataTo(): sync metadata + member count to a MarmotGroupChatroom Sync points (amethyst): - Account init: sync metadata after restoreAll() for all restored groups - GiftWrapEventHandler: sync after Welcome processing (group join) - GroupEventHandler: sync after CommitProcessed (epoch advances may update extensions via GroupContextExtensions proposals) UI (GroupInfoScreen): - Display group description from MIP-01 metadata - Display relay URLs from MIP-01 metadata - Mark admin members with "- admin" suffix (from adminPubkeys) https://claude.ai/code/session_0194SxKfAU61PY92eqP4cCXM
This commit is contained in:
+33
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.commons.marmot
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom
|
||||
import com.vitorpamplona.quartz.marmot.GroupEventResult
|
||||
import com.vitorpamplona.quartz.marmot.MarmotInboundProcessor
|
||||
import com.vitorpamplona.quartz.marmot.MarmotOutboundProcessor
|
||||
@@ -31,6 +32,7 @@ import com.vitorpamplona.quartz.marmot.WelcomeResult
|
||||
import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageEvent
|
||||
import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageRotationManager
|
||||
import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageUtils
|
||||
import com.vitorpamplona.quartz.marmot.mip01Groups.MarmotGroupData
|
||||
import com.vitorpamplona.quartz.marmot.mip02Welcome.WelcomeEvent
|
||||
import com.vitorpamplona.quartz.marmot.mip03GroupMessages.GroupEvent
|
||||
import com.vitorpamplona.quartz.marmot.mls.group.MlsGroupManager
|
||||
@@ -287,6 +289,37 @@ class MarmotManager(
|
||||
* Get the current epoch for a group.
|
||||
*/
|
||||
fun groupEpoch(nostrGroupId: HexKey): Long? = groupManager.getGroup(nostrGroupId)?.epoch
|
||||
|
||||
/**
|
||||
* Get the MIP-01 group metadata from the MLS GroupContext extensions.
|
||||
* Returns null if the group doesn't exist or has no MarmotGroupData extension.
|
||||
*/
|
||||
fun groupMetadata(nostrGroupId: HexKey): MarmotGroupData? {
|
||||
val group = groupManager.getGroup(nostrGroupId) ?: return null
|
||||
return MarmotGroupData.fromExtensions(group.extensions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync MIP-01 metadata and member info from the MLS group into a [MarmotGroupChatroom].
|
||||
* Call after joining a group, processing a commit, or restoring from storage.
|
||||
*/
|
||||
fun syncMetadataTo(
|
||||
nostrGroupId: HexKey,
|
||||
chatroom: MarmotGroupChatroom,
|
||||
) {
|
||||
val metadata = groupMetadata(nostrGroupId)
|
||||
if (metadata != null) {
|
||||
if (metadata.name.isNotEmpty()) {
|
||||
chatroom.displayName.value = metadata.name
|
||||
}
|
||||
if (metadata.description.isNotEmpty()) {
|
||||
chatroom.description.value = metadata.description
|
||||
}
|
||||
chatroom.adminPubkeys.value = metadata.adminPubkeys
|
||||
chatroom.relays.value = metadata.relays
|
||||
}
|
||||
chatroom.memberCount.value = memberCount(nostrGroupId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
@@ -42,6 +42,9 @@ class MarmotGroupChatroom(
|
||||
) : NotesGatherer {
|
||||
var messages: Set<Note> = setOf()
|
||||
var displayName = MutableStateFlow<String?>(null)
|
||||
var description = MutableStateFlow<String?>(null)
|
||||
var adminPubkeys = MutableStateFlow<List<HexKey>>(emptyList())
|
||||
var relays = MutableStateFlow<List<String>>(emptyList())
|
||||
var memberCount = MutableStateFlow(0)
|
||||
var newestMessage: Note? = null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user