fix: Make add/remove member events support multiple p tags and add NIP-43 to NoteMaster

Changes memberPubKey() to memberPubKeys() returning a list of all p tags
in RelayAddMemberEvent and RelayRemoveMemberEvent. Updates renderers to
display multiple members. Adds NIP-43 event rendering to ThreadFeedView
(NoteMaster) alongside NoteCompose.

https://claude.ai/code/session_01PRqe4bBCb9u62oPh8u9sHx
This commit is contained in:
Claude
2026-03-29 14:13:41 +00:00
parent c3447e2a05
commit cad0ff3d80
5 changed files with 48 additions and 14 deletions
@@ -77,13 +77,19 @@ fun RenderRelayAddMember(
nav: INav,
) {
val noteEvent = baseNote.event as? RelayAddMemberEvent ?: return
val memberKey = remember(noteEvent) { noteEvent.memberPubKey() }
val memberKeys = remember(noteEvent) { noteEvent.memberPubKeys() }
val title =
if (memberKeys.size == 1) {
stringRes(R.string.relay_member_added)
} else {
stringRes(R.string.relay_members_added, memberKeys.size)
}
val subtitle = remember(memberKeys) { memberKeys.joinToString(", ") { it.take(16) + "..." } }
RelayMemberEventCard(
icon = Icons.Default.PersonAdd,
title = stringRes(R.string.relay_member_added),
subtitle = memberKey?.take(16)?.let { "$it..." },
nav = nav,
title = title,
subtitle = subtitle,
relayPubKey = noteEvent.pubKey,
)
}
@@ -95,13 +101,19 @@ fun RenderRelayRemoveMember(
nav: INav,
) {
val noteEvent = baseNote.event as? RelayRemoveMemberEvent ?: return
val memberKey = remember(noteEvent) { noteEvent.memberPubKey() }
val memberKeys = remember(noteEvent) { noteEvent.memberPubKeys() }
val title =
if (memberKeys.size == 1) {
stringRes(R.string.relay_member_removed)
} else {
stringRes(R.string.relay_members_removed, memberKeys.size)
}
val subtitle = remember(memberKeys) { memberKeys.joinToString(", ") { it.take(16) + "..." } }
RelayMemberEventCard(
icon = Icons.Default.PersonRemove,
title = stringRes(R.string.relay_member_removed),
subtitle = memberKey?.take(16)?.let { "$it..." },
nav = nav,
title = title,
subtitle = subtitle,
relayPubKey = noteEvent.pubKey,
)
}
@@ -165,7 +165,12 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderPoll
import com.vitorpamplona.amethyst.ui.note.types.RenderPostApproval
import com.vitorpamplona.amethyst.ui.note.types.RenderPrivateMessage
import com.vitorpamplona.amethyst.ui.note.types.RenderPublicMessage
import com.vitorpamplona.amethyst.ui.note.types.RenderRelayAddMember
import com.vitorpamplona.amethyst.ui.note.types.RenderRelayDiscovery
import com.vitorpamplona.amethyst.ui.note.types.RenderRelayJoinRequest
import com.vitorpamplona.amethyst.ui.note.types.RenderRelayLeaveRequest
import com.vitorpamplona.amethyst.ui.note.types.RenderRelayMembershipList
import com.vitorpamplona.amethyst.ui.note.types.RenderRelayRemoveMember
import com.vitorpamplona.amethyst.ui.note.types.RenderTextEvent
import com.vitorpamplona.amethyst.ui.note.types.RenderTextModificationEvent
import com.vitorpamplona.amethyst.ui.note.types.RenderTorrent
@@ -231,6 +236,11 @@ import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent
import com.vitorpamplona.quartz.nip35Torrents.TorrentCommentEvent
import com.vitorpamplona.quartz.nip35Torrents.TorrentEvent
import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent
import com.vitorpamplona.quartz.nip43RelayMembers.addMember.RelayAddMemberEvent
import com.vitorpamplona.quartz.nip43RelayMembers.joinRequest.RelayJoinRequestEvent
import com.vitorpamplona.quartz.nip43RelayMembers.leaveRequest.RelayLeaveRequestEvent
import com.vitorpamplona.quartz.nip43RelayMembers.list.RelayMembershipListEvent
import com.vitorpamplona.quartz.nip43RelayMembers.removeMember.RelayRemoveMemberEvent
import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent
import com.vitorpamplona.quartz.nip51Lists.PinListEvent
import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent
@@ -712,6 +722,16 @@ private fun FullBleedNoteCompose(
RenderRepost(baseNote, quotesLeft = 3, backgroundColor, accountViewModel, nav)
} else if (noteEvent is RelayDiscoveryEvent) {
RenderRelayDiscovery(baseNote, accountViewModel, nav)
} else if (noteEvent is RelayMembershipListEvent) {
RenderRelayMembershipList(baseNote, accountViewModel, nav)
} else if (noteEvent is RelayAddMemberEvent) {
RenderRelayAddMember(baseNote, accountViewModel, nav)
} else if (noteEvent is RelayRemoveMemberEvent) {
RenderRelayRemoveMember(baseNote, accountViewModel, nav)
} else if (noteEvent is RelayJoinRequestEvent) {
RenderRelayJoinRequest(baseNote, accountViewModel, nav)
} else if (noteEvent is RelayLeaveRequestEvent) {
RenderRelayLeaveRequest(baseNote, accountViewModel, nav)
} else if (noteEvent is TextNoteModificationEvent) {
RenderTextModificationEvent(
note = baseNote,
+2
View File
@@ -2096,7 +2096,9 @@
<string name="relay_members_you_are_member">You are a member</string>
<string name="relay_membership_list">Relay membership list</string>
<string name="relay_member_added">Member added to relay</string>
<string name="relay_members_added">%1$d members added to relay</string>
<string name="relay_member_removed">Member removed from relay</string>
<string name="relay_members_removed">%1$d members removed from relay</string>
<string name="relay_join_request">Relay join request</string>
<string name="relay_leave_request">Relay leave request</string>
</resources>
@@ -39,20 +39,20 @@ class RelayAddMemberEvent(
content: String,
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
fun memberPubKey() = tags.firstNotNullOfOrNull(PTag::parseKey)
fun memberPubKeys() = tags.mapNotNull(PTag::parseKey)
companion object {
const val KIND = 8000
const val ALT_DESCRIPTION = "Relay member added"
fun build(
memberPubKey: HexKey,
memberPubKeys: List<HexKey>,
createdAt: Long = TimeUtils.now(),
initializer: TagArrayBuilder<RelayAddMemberEvent>.() -> Unit = {},
) = eventTemplate(KIND, "", createdAt) {
alt(ALT_DESCRIPTION)
protect()
add(PTag.assemble(memberPubKey, null))
memberPubKeys.forEach { add(PTag.assemble(it, null)) }
initializer()
}
}
@@ -39,20 +39,20 @@ class RelayRemoveMemberEvent(
content: String,
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
fun memberPubKey() = tags.firstNotNullOfOrNull(PTag::parseKey)
fun memberPubKeys() = tags.mapNotNull(PTag::parseKey)
companion object {
const val KIND = 8001
const val ALT_DESCRIPTION = "Relay member removed"
fun build(
memberPubKey: HexKey,
memberPubKeys: List<HexKey>,
createdAt: Long = TimeUtils.now(),
initializer: TagArrayBuilder<RelayRemoveMemberEvent>.() -> Unit = {},
) = eventTemplate(KIND, "", createdAt) {
alt(ALT_DESCRIPTION)
protect()
add(PTag.assemble(memberPubKey, null))
memberPubKeys.forEach { add(PTag.assemble(it, null)) }
initializer()
}
}