Render kick and ban reason in the timeline when available (#4642)

* Map the reason to RoomMembershipContent

* Create function to create RoomMembershipContent.

* Render reason for kick and ban state event.
This commit is contained in:
Benoit Marty
2025-04-30 18:13:53 +02:00
committed by GitHub
parent 23caebcbc8
commit db6bc7c04f
10 changed files with 164 additions and 78 deletions

View File

@@ -26,6 +26,7 @@ class RoomMembershipContentFormatter @Inject constructor(
val userId = membershipContent.userId
val memberIsYou = matrixClient.isMe(userId)
val userDisplayNameOrId = membershipContent.userDisplayName ?: userId.value
val reason = membershipContent.reason?.takeIf { it.isNotBlank() }
return when (membershipContent.change) {
MembershipChange.JOINED -> if (memberIsYou) {
sp.getString(R.string.state_event_room_join_by_you)
@@ -38,9 +39,17 @@ class RoomMembershipContentFormatter @Inject constructor(
sp.getString(R.string.state_event_room_leave, senderDisambiguatedDisplayName)
}
MembershipChange.BANNED, MembershipChange.KICKED_AND_BANNED -> if (senderIsYou) {
sp.getString(R.string.state_event_room_ban_by_you, userDisplayNameOrId)
if (reason != null) {
sp.getString(R.string.state_event_room_ban_by_you_with_reason, userDisplayNameOrId, reason)
} else {
sp.getString(R.string.state_event_room_ban_by_you, userDisplayNameOrId)
}
} else {
sp.getString(R.string.state_event_room_ban, senderDisambiguatedDisplayName, userDisplayNameOrId)
if (reason != null) {
sp.getString(R.string.state_event_room_ban_with_reason, senderDisambiguatedDisplayName, userDisplayNameOrId, reason)
} else {
sp.getString(R.string.state_event_room_ban, senderDisambiguatedDisplayName, userDisplayNameOrId)
}
}
MembershipChange.UNBANNED -> if (senderIsYou) {
sp.getString(R.string.state_event_room_unban_by_you, userDisplayNameOrId)
@@ -48,9 +57,17 @@ class RoomMembershipContentFormatter @Inject constructor(
sp.getString(R.string.state_event_room_unban, senderDisambiguatedDisplayName, userDisplayNameOrId)
}
MembershipChange.KICKED -> if (senderIsYou) {
sp.getString(R.string.state_event_room_remove_by_you, userDisplayNameOrId)
if (reason != null) {
sp.getString(R.string.state_event_room_remove_by_you_with_reason, userDisplayNameOrId, reason)
} else {
sp.getString(R.string.state_event_room_remove_by_you, userDisplayNameOrId)
}
} else {
sp.getString(R.string.state_event_room_remove, senderDisambiguatedDisplayName, userDisplayNameOrId)
if (reason != null) {
sp.getString(R.string.state_event_room_remove_with_reason, senderDisambiguatedDisplayName, userDisplayNameOrId, reason)
} else {
sp.getString(R.string.state_event_room_remove, senderDisambiguatedDisplayName, userDisplayNameOrId)
}
}
MembershipChange.INVITED -> if (senderIsYou) {
sp.getString(R.string.state_event_room_invite_by_you, userDisplayNameOrId)

View File

@@ -30,7 +30,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessage
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
@@ -38,6 +37,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecry
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
import io.element.android.libraries.matrix.test.A_REASON
import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.media.aMediaSource
@@ -47,6 +47,7 @@ import io.element.android.libraries.matrix.test.timeline.aProfileChangeMessageCo
import io.element.android.libraries.matrix.test.timeline.aProfileTimelineDetails
import io.element.android.libraries.matrix.test.timeline.aStickerContent
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
import org.junit.Before
import org.junit.Test
@@ -289,8 +290,8 @@ class DefaultBaseRoomLastMessageFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - joined`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.JOINED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.JOINED)
val youJoinedRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youJoinedRoom = formatter.format(youJoinedRoomEvent, false)
@@ -305,8 +306,8 @@ class DefaultBaseRoomLastMessageFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - left`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.LEFT)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.LEFT)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.LEFT)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.LEFT)
val youLeftRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youLeftRoom = formatter.format(youLeftRoomEvent, false)
@@ -322,10 +323,10 @@ class DefaultBaseRoomLastMessageFormatterTest {
fun `Membership change - banned`() {
val otherName = "Other"
val third = "Someone"
val youContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED)
val youKickedContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED)
val someoneKickedContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED)
val youContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED)
val youKickedContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED)
val someoneKickedContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED)
val youBannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youBanned = formatter.format(youBannedEvent, false)
@@ -344,13 +345,40 @@ class DefaultBaseRoomLastMessageFormatterTest {
assertThat(someoneKickBanned).isEqualTo("$otherName banned $third")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - banned with reason`() {
val otherName = "Other"
val third = "Someone"
val youContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED, A_REASON)
val youKickedContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED, A_REASON)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED, A_REASON)
val someoneKickedContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED, A_REASON)
val youBannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youBanned = formatter.format(youBannedEvent, false)
assertThat(youBanned).isEqualTo("You banned $third: $A_REASON")
val youKickBannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youKickedContent)
val youKickedBanned = formatter.format(youKickBannedEvent, false)
assertThat(youKickedBanned).isEqualTo("You banned $third: $A_REASON")
val someoneBannedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneBanned = formatter.format(someoneBannedEvent, false)
assertThat(someoneBanned).isEqualTo("$otherName banned $third: $A_REASON")
val someoneKickBannedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneKickedContent)
val someoneKickBanned = formatter.format(someoneKickBannedEvent, false)
assertThat(someoneKickBanned).isEqualTo("$otherName banned $third: $A_REASON")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - unban`() {
val otherName = "Other"
val third = "Someone"
val youContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.UNBANNED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.UNBANNED)
val youContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.UNBANNED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.UNBANNED)
val youUnbannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youUnbanned = formatter.format(youUnbannedEvent, false)
@@ -366,8 +394,8 @@ class DefaultBaseRoomLastMessageFormatterTest {
fun `Membership change - kicked`() {
val otherName = "Other"
val third = "Someone"
val youContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED)
val youContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED)
val youKickedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youKicked = formatter.format(youKickedEvent, false)
@@ -378,13 +406,30 @@ class DefaultBaseRoomLastMessageFormatterTest {
assertThat(someoneKicked).isEqualTo("$otherName removed $third")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - kicked with reason`() {
val otherName = "Other"
val third = "Someone"
val youContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED, A_REASON)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED, A_REASON)
val youKickedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youKicked = formatter.format(youKickedEvent, false)
assertThat(youKicked).isEqualTo("You removed $third: $A_REASON")
val someoneKickedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneKicked = formatter.format(someoneKickedEvent, false)
assertThat(someoneKicked).isEqualTo("$otherName removed $third: $A_REASON")
}
@Test
@Config(qualifiers = "en")
fun `Membership change - invited`() {
val otherName = "Other"
val third = "Someone"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.INVITED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.INVITED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITED)
val youWereInvitedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = youContent)
val youWereInvited = formatter.format(youWereInvitedEvent, false)
@@ -403,8 +448,8 @@ class DefaultBaseRoomLastMessageFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - invitation accepted`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.INVITATION_ACCEPTED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_ACCEPTED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.INVITATION_ACCEPTED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_ACCEPTED)
val youAcceptedInviteEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youAcceptedInvite = formatter.format(youAcceptedInviteEvent, false)
@@ -419,8 +464,8 @@ class DefaultBaseRoomLastMessageFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - invitation rejected`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.INVITATION_REJECTED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_REJECTED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.INVITATION_REJECTED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_REJECTED)
val youRejectedInviteEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youRejectedInvite = formatter.format(youRejectedInviteEvent, false)
@@ -436,7 +481,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
fun `Membership change - invitation revoked`() {
val otherName = "Other"
val third = "Someone"
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITATION_REVOKED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITATION_REVOKED)
val youRevokedInviteEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youRevokedInvite = formatter.format(youRevokedInviteEvent, false)
@@ -451,8 +496,8 @@ class DefaultBaseRoomLastMessageFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - knocked`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCKED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.KNOCKED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCKED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.KNOCKED)
val youKnockedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youKnocked = formatter.format(youKnockedEvent, false)
@@ -468,7 +513,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
fun `Membership change - knock accepted`() {
val otherName = "Other"
val third = "Someone"
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KNOCK_ACCEPTED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KNOCK_ACCEPTED)
val youAcceptedKnockEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youAcceptedKnock = formatter.format(youAcceptedKnockEvent, false)
@@ -483,8 +528,8 @@ class DefaultBaseRoomLastMessageFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - knock retracted`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCK_RETRACTED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), null, MembershipChange.KNOCK_RETRACTED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCK_RETRACTED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), null, MembershipChange.KNOCK_RETRACTED)
val youRetractedKnockEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youRetractedKnock = formatter.format(youRetractedKnockEvent, false)
@@ -500,8 +545,8 @@ class DefaultBaseRoomLastMessageFormatterTest {
fun `Membership change - knock denied`() {
val otherName = "Other"
val third = "Someone"
val youContent = RoomMembershipContent(A_USER_ID, third, MembershipChange.KNOCK_DENIED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KNOCK_DENIED)
val youContent = aRoomMembershipContent(A_USER_ID, third, MembershipChange.KNOCK_DENIED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KNOCK_DENIED)
val youDeniedKnockEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youDeniedKnock = formatter.format(youDeniedKnockEvent, false)
@@ -520,8 +565,8 @@ class DefaultBaseRoomLastMessageFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - None`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.NONE)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.NONE)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.NONE)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.NONE)
val youNoneRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youNoneRoom = formatter.format(youNoneRoomEvent, false)
@@ -538,7 +583,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
val otherChanges = arrayOf(MembershipChange.ERROR, MembershipChange.NOT_IMPLEMENTED, null)
val results = otherChanges.map { change ->
val content = RoomMembershipContent(A_USER_ID, null, change)
val content = aRoomMembershipContent(A_USER_ID, null, change)
val event = createRoomEvent(sentByYou = false, senderDisplayName = "Someone", content = content)
val result = formatter.format(event, false)
change to result

View File

@@ -30,7 +30,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessage
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
@@ -47,6 +46,7 @@ import io.element.android.libraries.matrix.test.timeline.aProfileChangeMessageCo
import io.element.android.libraries.matrix.test.timeline.aProfileTimelineDetails
import io.element.android.libraries.matrix.test.timeline.aStickerContent
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
import org.junit.Before
@@ -198,8 +198,8 @@ class DefaultPinnedMessagesBannerFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - joined`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.JOINED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.JOINED)
val youJoinedRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youJoinedRoom = formatter.format(youJoinedRoomEvent)
@@ -214,8 +214,8 @@ class DefaultPinnedMessagesBannerFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - left`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.LEFT)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.LEFT)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.LEFT)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.LEFT)
val youLeftRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youLeftRoom = formatter.format(youLeftRoomEvent)
@@ -231,10 +231,10 @@ class DefaultPinnedMessagesBannerFormatterTest {
fun `Membership change - banned`() {
val otherName = "Other"
val third = "Someone"
val youContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED)
val youKickedContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED)
val someoneKickedContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED)
val youContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED)
val youKickedContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED)
val someoneKickedContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED)
val youBannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youBanned = formatter.format(youBannedEvent)
@@ -258,8 +258,8 @@ class DefaultPinnedMessagesBannerFormatterTest {
fun `Membership change - unban`() {
val otherName = "Other"
val third = "Someone"
val youContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.UNBANNED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.UNBANNED)
val youContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.UNBANNED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.UNBANNED)
val youUnbannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youUnbanned = formatter.format(youUnbannedEvent)
@@ -275,8 +275,8 @@ class DefaultPinnedMessagesBannerFormatterTest {
fun `Membership change - kicked`() {
val otherName = "Other"
val third = "Someone"
val youContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED)
val youContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED)
val youKickedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youKicked = formatter.format(youKickedEvent)
@@ -292,8 +292,8 @@ class DefaultPinnedMessagesBannerFormatterTest {
fun `Membership change - invited`() {
val otherName = "Other"
val third = "Someone"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.INVITED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.INVITED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITED)
val youWereInvitedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = youContent)
val youWereInvited = formatter.format(youWereInvitedEvent)
@@ -312,8 +312,8 @@ class DefaultPinnedMessagesBannerFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - invitation accepted`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.INVITATION_ACCEPTED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_ACCEPTED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.INVITATION_ACCEPTED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_ACCEPTED)
val youAcceptedInviteEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youAcceptedInvite = formatter.format(youAcceptedInviteEvent)
@@ -328,8 +328,8 @@ class DefaultPinnedMessagesBannerFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - invitation rejected`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.INVITATION_REJECTED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_REJECTED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.INVITATION_REJECTED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_REJECTED)
val youRejectedInviteEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youRejectedInvite = formatter.format(youRejectedInviteEvent)
@@ -345,7 +345,7 @@ class DefaultPinnedMessagesBannerFormatterTest {
fun `Membership change - invitation revoked`() {
val otherName = "Other"
val third = "Someone"
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITATION_REVOKED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITATION_REVOKED)
val youRevokedInviteEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youRevokedInvite = formatter.format(youRevokedInviteEvent)
@@ -360,8 +360,8 @@ class DefaultPinnedMessagesBannerFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - knocked`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCKED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.KNOCKED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCKED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.KNOCKED)
val youKnockedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youKnocked = formatter.format(youKnockedEvent)
@@ -377,7 +377,7 @@ class DefaultPinnedMessagesBannerFormatterTest {
fun `Membership change - knock accepted`() {
val otherName = "Other"
val third = "Someone"
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KNOCK_ACCEPTED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KNOCK_ACCEPTED)
val youAcceptedKnockEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youAcceptedKnock = formatter.format(youAcceptedKnockEvent)
@@ -392,8 +392,8 @@ class DefaultPinnedMessagesBannerFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - knock retracted`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCK_RETRACTED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), null, MembershipChange.KNOCK_RETRACTED)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCK_RETRACTED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), null, MembershipChange.KNOCK_RETRACTED)
val youRetractedKnockEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youRetractedKnock = formatter.format(youRetractedKnockEvent)
@@ -409,8 +409,8 @@ class DefaultPinnedMessagesBannerFormatterTest {
fun `Membership change - knock denied`() {
val otherName = "Other"
val third = "Someone"
val youContent = RoomMembershipContent(A_USER_ID, third, MembershipChange.KNOCK_DENIED)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KNOCK_DENIED)
val youContent = aRoomMembershipContent(A_USER_ID, third, MembershipChange.KNOCK_DENIED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KNOCK_DENIED)
val youDeniedKnockEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youDeniedKnock = formatter.format(youDeniedKnockEvent)
@@ -429,8 +429,8 @@ class DefaultPinnedMessagesBannerFormatterTest {
@Config(qualifiers = "en")
fun `Membership change - None`() {
val otherName = "Other"
val youContent = RoomMembershipContent(A_USER_ID, null, MembershipChange.NONE)
val someoneContent = RoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.NONE)
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.NONE)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.NONE)
val youNoneRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youNoneRoom = formatter.format(youNoneRoomEvent)
@@ -447,7 +447,7 @@ class DefaultPinnedMessagesBannerFormatterTest {
val otherChanges = arrayOf(MembershipChange.ERROR, MembershipChange.NOT_IMPLEMENTED, null)
val results = otherChanges.map { change ->
val content = RoomMembershipContent(A_USER_ID, null, change)
val content = aRoomMembershipContent(A_USER_ID, null, change)
val event = createRoomEvent(sentByYou = false, senderDisplayName = "Someone", content = content)
val result = formatter.format(event)
change to result

View File

@@ -70,7 +70,8 @@ data class UnableToDecryptContent(
data class RoomMembershipContent(
val userId: UserId,
val userDisplayName: String?,
val change: MembershipChange?
val change: MembershipChange?,
val reason: String?,
) : EventContent
data class ProfileChangeContent(

View File

@@ -105,7 +105,8 @@ class TimelineEventContentMapper(
RoomMembershipContent(
userId = UserId(it.userId),
userDisplayName = it.userDisplayName,
change = it.change?.map()
change = it.change?.map(),
reason = it.reason,
)
}
is TimelineItemContent.State -> {

View File

@@ -11,13 +11,13 @@ import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.MembershipChange
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.A_USER_ID_2
import io.element.android.libraries.matrix.test.timeline.aMessageContent
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent
internal val timelineStartEvent = MatrixTimelineItem.Virtual(
uniqueId = UniqueId("timeline_start"),
@@ -29,11 +29,11 @@ internal val roomCreateEvent = MatrixTimelineItem.Event(
)
internal val roomCreatorJoinEvent = MatrixTimelineItem.Event(
uniqueId = UniqueId("m.room.member"),
event = anEventTimelineItem(content = RoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED))
event = anEventTimelineItem(content = aRoomMembershipContent(userId = A_USER_ID, change = MembershipChange.JOINED))
)
internal val otherMemberJoinEvent = MatrixTimelineItem.Event(
uniqueId = UniqueId("m.room.member_other"),
event = anEventTimelineItem(content = RoomMembershipContent(A_USER_ID_2, null, MembershipChange.JOINED))
event = anEventTimelineItem(content = aRoomMembershipContent(userId = A_USER_ID_2, change = MembershipChange.JOINED))
)
internal val messageEvent = MatrixTimelineItem.Event(
uniqueId = UniqueId("m.room.message"),

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.test.timeline.item.event
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.event.MembershipChange
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
import io.element.android.libraries.matrix.test.A_USER_ID
fun aRoomMembershipContent(
userId: UserId = A_USER_ID,
userDisplayName: String? = null,
change: MembershipChange? = null,
reason: String? = null,
) = RoomMembershipContent(
userId = userId,
userDisplayName = userDisplayName,
change = change,
reason = reason,
)

View File

@@ -13,12 +13,12 @@ import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
import io.element.android.libraries.matrix.api.timeline.item.event.MembershipChange
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
import io.element.android.libraries.matrix.test.timeline.aProfileTimelineDetails
import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent
import org.junit.Test
class InReplyToDetailTest {
@@ -47,9 +47,8 @@ class InReplyToDetailTest {
eventId = AN_EVENT_ID,
senderId = A_USER_ID,
senderProfile = aProfileTimelineDetails(),
content = RoomMembershipContent(
content = aRoomMembershipContent(
userId = A_USER_ID,
userDisplayName = null,
change = MembershipChange.INVITED,
)
)

View File

@@ -30,7 +30,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
@@ -43,6 +42,7 @@ import io.element.android.libraries.matrix.test.media.aMediaSource
import io.element.android.libraries.matrix.test.timeline.aMessageContent
import io.element.android.libraries.matrix.test.timeline.aPollContent
import io.element.android.libraries.matrix.test.timeline.aProfileTimelineDetails
import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent
import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
@@ -496,7 +496,7 @@ class InReplyToMetadataKtTest {
fun `room membership content`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = RoomMembershipContent(A_USER_ID, null, null)
eventContent = aRoomMembershipContent(userId = A_USER_ID)
).metadata(hideImage = false)
}.test {
awaitItem().let {

View File

@@ -31,7 +31,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessage
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
@@ -47,6 +46,7 @@ import io.element.android.libraries.matrix.test.timeline.aPollContent
import io.element.android.libraries.matrix.test.timeline.aProfileChangeMessageContent
import io.element.android.libraries.matrix.test.timeline.aStickerContent
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent
import io.element.android.libraries.mediaviewer.api.MediaInfo
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation
@@ -67,10 +67,8 @@ class DefaultEventItemFactoryTest {
aPollContent(),
aProfileChangeMessageContent(),
RedactedContent,
RoomMembershipContent(
aRoomMembershipContent(
userId = A_USER_ID,
userDisplayName = null,
change = null,
),
StateContent("", OtherState.RoomCreate),
aStickerContent(