Do not show membership/profile events in public rooms (#6360)
* Filter some membership/profile/topic events in public rooms: don't display join and leave membership events in publicly joinable rooms, and hide display name and avatar url changes in non encrypted and publicly joinable rooms. * Add empty day post-processing to the timeline based on bxdxnn's code, tweaked. --------- Co-authored-by: Jorge Martín <jorgem@element.io>
This commit is contained in:
parent
5277382e6d
commit
b31dad4b26
6 changed files with 339 additions and 8 deletions
|
|
@ -16,6 +16,7 @@ import io.element.android.features.messages.impl.timeline.factories.event.Timeli
|
|||
import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemVirtualFactory
|
||||
import io.element.android.features.messages.impl.timeline.groups.TimelineItemGrouper
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemDaySeparatorModel
|
||||
import io.element.android.libraries.androidutils.diff.DiffCacheUpdater
|
||||
import io.element.android.libraries.androidutils.diff.MutableListDiffCache
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
|
|
@ -96,7 +97,8 @@ class TimelineItemsFactory(
|
|||
}
|
||||
}
|
||||
val result = timelineItemGrouper.group(newTimelineItemStates).toImmutableList()
|
||||
this._timelineItems.emit(result)
|
||||
val filteredResult = filterEmptyDaySeparators(result)
|
||||
this._timelineItems.emit(filteredResult)
|
||||
}
|
||||
|
||||
private suspend fun buildAndCacheItem(
|
||||
|
|
@ -114,3 +116,25 @@ class TimelineItemsFactory(
|
|||
return timelineItem
|
||||
}
|
||||
}
|
||||
|
||||
// Remove day separators for days with no events after the client-side event filtering
|
||||
internal fun filterEmptyDaySeparators(items: List<TimelineItem>): ImmutableList<TimelineItem> {
|
||||
return buildList {
|
||||
var hasEventBefore = false
|
||||
for (item in items) {
|
||||
when (item) {
|
||||
is TimelineItem.Event, is TimelineItem.GroupedEvents -> {
|
||||
hasEventBefore = true
|
||||
add(item)
|
||||
}
|
||||
is TimelineItem.Virtual if item.model is TimelineItemDaySeparatorModel -> {
|
||||
if (hasEventBefore) {
|
||||
add(item)
|
||||
}
|
||||
hasEventBefore = false
|
||||
}
|
||||
else -> add(item)
|
||||
}
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Element Creations 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.features.messages.impl.timeline.factories
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.messages.impl.fixtures.aMessageEvent
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemDebugInfo
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemReactions
|
||||
import io.element.android.features.messages.impl.timeline.model.ReadReceiptData
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItemReadReceipts
|
||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemReadMarkerModel
|
||||
import io.element.android.features.messages.impl.timeline.model.virtual.aTimelineItemDaySeparatorModel
|
||||
import io.element.android.libraries.designsystem.components.avatar.anAvatarData
|
||||
import io.element.android.libraries.matrix.api.core.UniqueId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
|
||||
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.core.FakeSendHandle
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import org.junit.Test
|
||||
|
||||
class TimelineItemsFactoryTest {
|
||||
private val anEvent = TimelineItem.Event(
|
||||
id = UniqueId("event"),
|
||||
eventId = AN_EVENT_ID,
|
||||
senderId = A_USER_ID,
|
||||
senderAvatar = anAvatarData(),
|
||||
senderProfile = ProfileDetails.Ready(displayName = "User", displayNameAmbiguous = false, avatarUrl = null),
|
||||
content = aMessageEvent().content,
|
||||
reactionsState = aTimelineItemReactions(count = 0),
|
||||
readReceiptState = TimelineItemReadReceipts(emptyList<ReadReceiptData>().toImmutableList()),
|
||||
localSendState = LocalEventSendState.Sent(AN_EVENT_ID),
|
||||
isEditable = false,
|
||||
canBeRepliedTo = false,
|
||||
inReplyTo = null,
|
||||
threadInfo = null,
|
||||
origin = null,
|
||||
timelineItemDebugInfoProvider = { aTimelineItemDebugInfo() },
|
||||
messageShieldProvider = { null },
|
||||
sendHandleProvider = { FakeSendHandle() },
|
||||
forwarder = null,
|
||||
forwarderProfile = null,
|
||||
)
|
||||
|
||||
private fun aDaySeparator(date: String) = TimelineItem.Virtual(
|
||||
id = UniqueId("day_$date"),
|
||||
model = aTimelineItemDaySeparatorModel(date)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `filterEmptyDaySeparators keeps day separator with events after it`() {
|
||||
val items = listOf(
|
||||
anEvent,
|
||||
aDaySeparator("Today"),
|
||||
)
|
||||
val result = filterEmptyDaySeparators(items)
|
||||
assertThat(result).hasSize(2)
|
||||
assertThat(result[0]).isEqualTo(anEvent)
|
||||
assertThat(result[1]).isEqualTo(aDaySeparator("Today"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `filterEmptyDaySeparators removes day separator with no events after it`() {
|
||||
val items = listOf(
|
||||
aDaySeparator("Today"),
|
||||
aDaySeparator("Yesterday"),
|
||||
)
|
||||
val result = filterEmptyDaySeparators(items)
|
||||
assertThat(result).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `filterEmptyDaySeparators removes first day separator and keeps second when only second has events`() {
|
||||
val items = listOf(
|
||||
aDaySeparator("Today"),
|
||||
anEvent,
|
||||
aDaySeparator("Yesterday"),
|
||||
)
|
||||
val result = filterEmptyDaySeparators(items)
|
||||
assertThat(result).hasSize(2)
|
||||
assertThat(result[0]).isEqualTo(anEvent)
|
||||
assertThat(result[1]).isEqualTo(aDaySeparator("Yesterday"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `filterEmptyDaySeparators handles multiple day separators in a row with no events`() {
|
||||
val items = listOf(
|
||||
aDaySeparator("Today"),
|
||||
aDaySeparator("Yesterday"),
|
||||
aDaySeparator("Last week"),
|
||||
)
|
||||
val result = filterEmptyDaySeparators(items)
|
||||
assertThat(result).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `filterEmptyDaySeparators keeps all items when no day separators`() {
|
||||
val items = listOf(
|
||||
anEvent,
|
||||
anEvent.copy(id = UniqueId("event2")),
|
||||
)
|
||||
val result = filterEmptyDaySeparators(items)
|
||||
assertThat(result).hasSize(2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `filterEmptyDaySeparators handles grouped events after day separator`() {
|
||||
val groupedEvents = TimelineItem.GroupedEvents(
|
||||
id = UniqueId("grouped"),
|
||||
events = listOf(anEvent).toImmutableList(),
|
||||
aggregatedReadReceipts = emptyList<ReadReceiptData>().toImmutableList(),
|
||||
)
|
||||
val items = listOf(
|
||||
groupedEvents,
|
||||
aDaySeparator("Today"),
|
||||
)
|
||||
val result = filterEmptyDaySeparators(items)
|
||||
assertThat(result).hasSize(2)
|
||||
assertThat(result[0]).isEqualTo(groupedEvents)
|
||||
assertThat(result[1]).isEqualTo(aDaySeparator("Today"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `filterEmptyDaySeparators removes day separator followed by non-event virtual item`() {
|
||||
val readMarker = TimelineItem.Virtual(
|
||||
id = UniqueId("readMarker"),
|
||||
model = TimelineItemReadMarkerModel
|
||||
)
|
||||
val items = listOf(
|
||||
aDaySeparator("Today"),
|
||||
readMarker,
|
||||
)
|
||||
val result = filterEmptyDaySeparators(items)
|
||||
assertThat(result).hasSize(1)
|
||||
assertThat(result[0]).isEqualTo(readMarker)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `filterEmptyDaySeparators keeps day separator when non-event virtual items are between separator and event`() {
|
||||
val readMarker = TimelineItem.Virtual(
|
||||
id = UniqueId("readMarker"),
|
||||
model = TimelineItemReadMarkerModel
|
||||
)
|
||||
val items = listOf(
|
||||
anEvent,
|
||||
readMarker,
|
||||
aDaySeparator("Today"),
|
||||
)
|
||||
val result = filterEmptyDaySeparators(items)
|
||||
assertThat(result).hasSize(3)
|
||||
assertThat(result[2]).isEqualTo(aDaySeparator("Today"))
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import io.element.android.libraries.androidutils.hash.hash
|
|||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.media.AudioInfo
|
||||
import io.element.android.libraries.matrix.api.media.FileInfo
|
||||
import io.element.android.libraries.matrix.api.media.ImageInfo
|
||||
|
|
@ -20,6 +21,7 @@ import io.element.android.libraries.matrix.api.media.VideoInfo
|
|||
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||
import io.element.android.libraries.matrix.api.room.IntentionalMention
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import io.element.android.libraries.matrix.api.timeline.MsgType
|
||||
|
|
@ -43,6 +45,7 @@ import io.element.android.libraries.matrix.impl.timeline.postprocessor.TypingNot
|
|||
import io.element.android.libraries.matrix.impl.timeline.reply.InReplyToMapper
|
||||
import io.element.android.libraries.matrix.impl.util.MessageEventContent
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -121,6 +124,13 @@ class RustTimeline(
|
|||
private val lastForwardIndicatorsPostProcessor = LastForwardIndicatorsPostProcessor(mode)
|
||||
private val typingNotificationPostProcessor = TypingNotificationPostProcessor(mode)
|
||||
|
||||
private data class RoomTimelineInfo(
|
||||
val roomCreators: ImmutableList<UserId>,
|
||||
val isDm: Boolean,
|
||||
val joinRule: JoinRule?,
|
||||
val isEncrypted: Boolean?,
|
||||
)
|
||||
|
||||
override val backwardPaginationStatus = MutableStateFlow(
|
||||
Timeline.PaginationStatus(isPaginating = false, hasMoreToLoad = mode != Timeline.Mode.PinnedEvents)
|
||||
)
|
||||
|
|
@ -220,20 +230,23 @@ class RustTimeline(
|
|||
_timelineItems,
|
||||
backwardPaginationStatus,
|
||||
forwardPaginationStatus,
|
||||
joinedRoom.roomInfoFlow.map { it.creators to it.isDm }.distinctUntilChanged(),
|
||||
joinedRoom.roomInfoFlow.map { RoomTimelineInfo(it.creators, it.isDm, it.joinRule, it.isEncrypted) }.distinctUntilChanged(),
|
||||
) {
|
||||
timelineItems,
|
||||
backwardPaginationStatus,
|
||||
forwardPaginationStatus,
|
||||
(roomCreators, isDm),
|
||||
roomInfo,
|
||||
->
|
||||
withContext(dispatcher) {
|
||||
val (roomCreators, isDm, joinRule, isEncrypted) = roomInfo
|
||||
timelineItems
|
||||
.let { items ->
|
||||
roomBeginningPostProcessor.process(
|
||||
items = items,
|
||||
isDm = isDm,
|
||||
roomCreator = roomCreators.firstOrNull(),
|
||||
joinRule = joinRule,
|
||||
isEncrypted = isEncrypted,
|
||||
hasMoreToLoadBackwards = backwardPaginationStatus.hasMoreToLoad,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,33 +9,49 @@
|
|||
package io.element.android.libraries.matrix.impl.timeline.postprocessor
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
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.ProfileChangeContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
||||
|
||||
/**
|
||||
* This timeline post-processor removes the room creation event and the self-join event from the timeline for DMs
|
||||
* or add the RoomBeginning item.
|
||||
* or add the RoomBeginning item. For rooms that aren't invite-only and aren't encrypted, it also removes join/leave and profile change events.
|
||||
*/
|
||||
class RoomBeginningPostProcessor(private val mode: Timeline.Mode) {
|
||||
fun process(
|
||||
items: List<MatrixTimelineItem>,
|
||||
isDm: Boolean,
|
||||
roomCreator: UserId?,
|
||||
joinRule: JoinRule?,
|
||||
isEncrypted: Boolean?,
|
||||
hasMoreToLoadBackwards: Boolean,
|
||||
): List<MatrixTimelineItem> {
|
||||
return when {
|
||||
items.isEmpty() -> items
|
||||
mode == Timeline.Mode.PinnedEvents -> items
|
||||
joinRule !is JoinRule.Invite && isEncrypted == false -> filterRoomMemberEvents(items)
|
||||
isDm -> processForDM(items, roomCreator)
|
||||
hasMoreToLoadBackwards -> items
|
||||
else -> processForRoom(items)
|
||||
}
|
||||
}
|
||||
|
||||
private fun filterRoomMemberEvents(items: List<MatrixTimelineItem>): List<MatrixTimelineItem> {
|
||||
return items.filter { item ->
|
||||
val eventContent = (item as? MatrixTimelineItem.Event)?.event?.content
|
||||
when (eventContent) {
|
||||
is RoomMembershipContent -> eventContent.change !in listOf(MembershipChange.JOINED, MembershipChange.LEFT)
|
||||
is ProfileChangeContent -> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processForRoom(items: List<MatrixTimelineItem>): List<MatrixTimelineItem> {
|
||||
// No changes needed, timeline start item is already added by the SDK
|
||||
return items
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTime
|
|||
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.aProfileChangeMessageContent
|
||||
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
||||
import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent
|
||||
|
||||
|
|
@ -36,6 +37,14 @@ internal val otherMemberJoinEvent = MatrixTimelineItem.Event(
|
|||
uniqueId = UniqueId("m.room.member_other"),
|
||||
event = anEventTimelineItem(content = aRoomMembershipContent(userId = A_USER_ID_2, change = MembershipChange.JOINED))
|
||||
)
|
||||
internal val otherMemberLeaveEvent = MatrixTimelineItem.Event(
|
||||
uniqueId = UniqueId("m.room.member_leave"),
|
||||
event = anEventTimelineItem(content = aRoomMembershipContent(userId = A_USER_ID_2, change = MembershipChange.LEFT))
|
||||
)
|
||||
internal val profileChangeEvent = MatrixTimelineItem.Event(
|
||||
uniqueId = UniqueId("m.room.member_profile"),
|
||||
event = anEventTimelineItem(content = aProfileChangeMessageContent(displayName = "New Name", prevDisplayName = "Old Name"))
|
||||
)
|
||||
internal val messageEvent = MatrixTimelineItem.Event(
|
||||
uniqueId = UniqueId("m.room.message"),
|
||||
event = anEventTimelineItem(content = aMessageContent("hi"))
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
package io.element.android.libraries.matrix.impl.timeline.postprocessor
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||
import org.junit.Test
|
||||
|
|
@ -21,6 +22,8 @@ class RoomBeginningPostProcessorTest {
|
|||
items = emptyList(),
|
||||
isDm = true,
|
||||
roomCreator = A_USER_ID,
|
||||
joinRule = null,
|
||||
isEncrypted = null,
|
||||
hasMoreToLoadBackwards = false,
|
||||
)
|
||||
assertThat(processedItems).isEmpty()
|
||||
|
|
@ -33,6 +36,8 @@ class RoomBeginningPostProcessorTest {
|
|||
items = listOf(messageEvent),
|
||||
isDm = true,
|
||||
roomCreator = A_USER_ID,
|
||||
joinRule = null,
|
||||
isEncrypted = null,
|
||||
hasMoreToLoadBackwards = false,
|
||||
)
|
||||
assertThat(processedItems).isEqualTo(listOf(messageEvent))
|
||||
|
|
@ -45,6 +50,8 @@ class RoomBeginningPostProcessorTest {
|
|||
items = listOf(messageEvent),
|
||||
isDm = true,
|
||||
roomCreator = null,
|
||||
joinRule = null,
|
||||
isEncrypted = null,
|
||||
hasMoreToLoadBackwards = false,
|
||||
)
|
||||
assertThat(processedItems).isEqualTo(listOf(messageEvent))
|
||||
|
|
@ -62,6 +69,8 @@ class RoomBeginningPostProcessorTest {
|
|||
items = timelineItems,
|
||||
isDm = true,
|
||||
roomCreator = A_USER_ID,
|
||||
joinRule = null,
|
||||
isEncrypted = null,
|
||||
hasMoreToLoadBackwards = false,
|
||||
)
|
||||
assertThat(processedItems).containsExactly(timelineStartEvent)
|
||||
|
|
@ -78,6 +87,8 @@ class RoomBeginningPostProcessorTest {
|
|||
items = timelineItems,
|
||||
isDm = true,
|
||||
roomCreator = A_USER_ID,
|
||||
joinRule = null,
|
||||
isEncrypted = null,
|
||||
hasMoreToLoadBackwards = false,
|
||||
)
|
||||
assertThat(processedItems).isEqualTo(timelineItems)
|
||||
|
|
@ -96,7 +107,14 @@ class RoomBeginningPostProcessorTest {
|
|||
messageEvent,
|
||||
)
|
||||
val processor = RoomBeginningPostProcessor(Timeline.Mode.Live)
|
||||
val processedItems = processor.process(timelineItems, isDm = true, roomCreator = A_USER_ID, hasMoreToLoadBackwards = false)
|
||||
val processedItems = processor.process(
|
||||
timelineItems,
|
||||
isDm = true,
|
||||
roomCreator = A_USER_ID,
|
||||
joinRule = null,
|
||||
isEncrypted = null,
|
||||
hasMoreToLoadBackwards = false
|
||||
)
|
||||
assertThat(processedItems).isEqualTo(expected)
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +125,14 @@ class RoomBeginningPostProcessorTest {
|
|||
roomCreatorJoinEvent,
|
||||
)
|
||||
val processor = RoomBeginningPostProcessor(Timeline.Mode.Live)
|
||||
val processedItems = processor.process(timelineItems, isDm = true, roomCreator = A_USER_ID, hasMoreToLoadBackwards = true)
|
||||
val processedItems = processor.process(
|
||||
timelineItems,
|
||||
isDm = true,
|
||||
roomCreator = A_USER_ID,
|
||||
joinRule = null,
|
||||
isEncrypted = null,
|
||||
hasMoreToLoadBackwards = true
|
||||
)
|
||||
assertThat(processedItems).isEmpty()
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +142,14 @@ class RoomBeginningPostProcessorTest {
|
|||
roomCreatorJoinEvent,
|
||||
)
|
||||
val processor = RoomBeginningPostProcessor(Timeline.Mode.Live)
|
||||
val processedItems = processor.process(timelineItems, isDm = true, roomCreator = A_USER_ID, hasMoreToLoadBackwards = true)
|
||||
val processedItems = processor.process(
|
||||
timelineItems,
|
||||
isDm = true,
|
||||
roomCreator = A_USER_ID,
|
||||
joinRule = null,
|
||||
isEncrypted = null,
|
||||
hasMoreToLoadBackwards = true
|
||||
)
|
||||
assertThat(processedItems).isEmpty()
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +160,84 @@ class RoomBeginningPostProcessorTest {
|
|||
otherMemberJoinEvent,
|
||||
)
|
||||
val processor = RoomBeginningPostProcessor(Timeline.Mode.Live)
|
||||
val processedItems = processor.process(timelineItems, isDm = true, roomCreator = A_USER_ID, hasMoreToLoadBackwards = true)
|
||||
val processedItems = processor.process(
|
||||
timelineItems,
|
||||
isDm = true,
|
||||
roomCreator = A_USER_ID,
|
||||
joinRule = null,
|
||||
isEncrypted = null,
|
||||
hasMoreToLoadBackwards = true
|
||||
)
|
||||
assertThat(processedItems).isEqualTo(listOf(otherMemberJoinEvent))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `processor removes join, leave, and profile events in unencrypted public rooms`() {
|
||||
val timelineItems = listOf(
|
||||
roomCreateEvent,
|
||||
roomCreatorJoinEvent,
|
||||
otherMemberJoinEvent,
|
||||
messageEvent,
|
||||
otherMemberLeaveEvent,
|
||||
profileChangeEvent,
|
||||
)
|
||||
val expected = listOf(
|
||||
roomCreateEvent,
|
||||
messageEvent,
|
||||
)
|
||||
val processor = RoomBeginningPostProcessor(Timeline.Mode.Live)
|
||||
val processedItems = processor.process(
|
||||
timelineItems,
|
||||
isDm = false,
|
||||
roomCreator = A_USER_ID,
|
||||
joinRule = JoinRule.Public,
|
||||
isEncrypted = false,
|
||||
hasMoreToLoadBackwards = false
|
||||
)
|
||||
assertThat(processedItems).isEqualTo(expected)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `processor keeps all events in encrypted public rooms`() {
|
||||
val timelineItems = listOf(
|
||||
roomCreateEvent,
|
||||
roomCreatorJoinEvent,
|
||||
otherMemberJoinEvent,
|
||||
messageEvent,
|
||||
otherMemberLeaveEvent,
|
||||
profileChangeEvent,
|
||||
)
|
||||
val processor = RoomBeginningPostProcessor(Timeline.Mode.Live)
|
||||
val processedItems = processor.process(
|
||||
timelineItems,
|
||||
isDm = false,
|
||||
roomCreator = A_USER_ID,
|
||||
joinRule = JoinRule.Public,
|
||||
isEncrypted = true,
|
||||
hasMoreToLoadBackwards = false
|
||||
)
|
||||
assertThat(processedItems).isEqualTo(timelineItems)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `processor keeps membership events in invite-only rooms`() {
|
||||
val timelineItems = listOf(
|
||||
roomCreateEvent,
|
||||
roomCreatorJoinEvent,
|
||||
otherMemberJoinEvent,
|
||||
messageEvent,
|
||||
otherMemberLeaveEvent,
|
||||
profileChangeEvent,
|
||||
)
|
||||
val processor = RoomBeginningPostProcessor(Timeline.Mode.Live)
|
||||
val processedItems = processor.process(
|
||||
timelineItems,
|
||||
isDm = false,
|
||||
roomCreator = A_USER_ID,
|
||||
joinRule = JoinRule.Invite,
|
||||
isEncrypted = null,
|
||||
hasMoreToLoadBackwards = false
|
||||
)
|
||||
assertThat(processedItems).isEqualTo(timelineItems)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue