misc : use new_latest_event api (+ some renaming)

This commit is contained in:
ganfra 2025-11-17 20:53:55 +01:00
parent 43152fc073
commit ca526580fd
42 changed files with 352 additions and 290 deletions

View file

@ -277,7 +277,7 @@ private fun MessagePreviewAndIndicatorRow(
val messagePreview = if (room.isTombstoned) { val messagePreview = if (room.isTombstoned) {
stringResource(R.string.screen_roomlist_tombstoned_room_description) stringResource(R.string.screen_roomlist_tombstoned_room_description)
} else { } else {
room.lastMessage.orEmpty() room.latestEvent.orEmpty()
} }
val annotatedMessagePreview = messagePreview as? AnnotatedString ?: AnnotatedString(text = messagePreview.toString()) val annotatedMessagePreview = messagePreview as? AnnotatedString ?: AnnotatedString(text = messagePreview.toString())
Text( Text(

View file

@ -15,7 +15,7 @@ import io.element.android.libraries.core.extensions.orEmpty
import io.element.android.libraries.dateformatter.api.DateFormatter import io.element.android.libraries.dateformatter.api.DateFormatter
import io.element.android.libraries.dateformatter.api.DateFormatterMode import io.element.android.libraries.dateformatter.api.DateFormatterMode
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter import io.element.android.libraries.eventformatter.api.RoomLatestEventFormatter
import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.isDm import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.api.roomlist.RoomSummary
@ -26,7 +26,7 @@ import kotlinx.collections.immutable.toImmutableList
@Inject @Inject
class RoomListRoomSummaryFactory( class RoomListRoomSummaryFactory(
private val dateFormatter: DateFormatter, private val dateFormatter: DateFormatter,
private val roomLastMessageFormatter: RoomLastMessageFormatter, private val roomLatestEventFormatter: RoomLatestEventFormatter,
) { ) {
fun create(roomSummary: RoomSummary): RoomListRoomSummary { fun create(roomSummary: RoomSummary): RoomListRoomSummary {
val roomInfo = roomSummary.info val roomInfo = roomSummary.info
@ -40,13 +40,11 @@ class RoomListRoomSummaryFactory(
numberOfUnreadNotifications = roomInfo.numUnreadNotifications, numberOfUnreadNotifications = roomInfo.numUnreadNotifications,
isMarkedUnread = roomInfo.isMarkedUnread, isMarkedUnread = roomInfo.isMarkedUnread,
timestamp = dateFormatter.format( timestamp = dateFormatter.format(
timestamp = roomSummary.lastMessageTimestamp, timestamp = roomSummary.latestEventTimestamp,
mode = DateFormatterMode.TimeOrDate, mode = DateFormatterMode.TimeOrDate,
useRelative = true, useRelative = true,
), ),
lastMessage = roomSummary.lastMessage?.let { message -> latestEvent = roomLatestEventFormatter.format(roomSummary.latestEvent, roomInfo.isDm).orEmpty(),
roomLastMessageFormatter.format(message.event, roomInfo.isDm)
}.orEmpty(),
avatarData = avatarData, avatarData = avatarData,
userDefinedNotificationMode = roomInfo.userDefinedNotificationMode, userDefinedNotificationMode = roomInfo.userDefinedNotificationMode,
hasRoomCall = roomInfo.hasRoomCall, hasRoomCall = roomInfo.hasRoomCall,

View file

@ -29,7 +29,7 @@ data class RoomListRoomSummary(
val numberOfUnreadNotifications: Long, val numberOfUnreadNotifications: Long,
val isMarkedUnread: Boolean, val isMarkedUnread: Boolean,
val timestamp: String?, val timestamp: String?,
val lastMessage: CharSequence?, val latestEvent: CharSequence?,
val avatarData: AvatarData, val avatarData: AvatarData,
val userDefinedNotificationMode: RoomNotificationMode?, val userDefinedNotificationMode: RoomNotificationMode?,
val hasRoomCall: Boolean, val hasRoomCall: Boolean,

View file

@ -171,7 +171,7 @@ internal fun aRoomListRoomSummary(
numberOfUnreadNotifications = numberOfUnreadNotifications, numberOfUnreadNotifications = numberOfUnreadNotifications,
isMarkedUnread = isMarkedUnread, isMarkedUnread = isMarkedUnread,
timestamp = timestamp, timestamp = timestamp,
lastMessage = lastMessage, latestEvent = lastMessage,
avatarData = avatarData, avatarData = avatarData,
userDefinedNotificationMode = notificationMode, userDefinedNotificationMode = notificationMode,
hasRoomCall = hasRoomCall, hasRoomCall = hasRoomCall,

View file

@ -10,12 +10,12 @@ package io.element.android.features.home.impl.datasource
import io.element.android.libraries.dateformatter.api.DateFormatter import io.element.android.libraries.dateformatter.api.DateFormatter
import io.element.android.libraries.dateformatter.test.FakeDateFormatter import io.element.android.libraries.dateformatter.test.FakeDateFormatter
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter import io.element.android.libraries.eventformatter.api.RoomLatestEventFormatter
fun aRoomListRoomSummaryFactory( fun aRoomListRoomSummaryFactory(
dateFormatter: DateFormatter = FakeDateFormatter { _, _, _ -> "Today" }, dateFormatter: DateFormatter = FakeDateFormatter { _, _, _ -> "Today" },
roomLastMessageFormatter: RoomLastMessageFormatter = RoomLastMessageFormatter { _, _ -> "Hey" } roomLatestEventFormatter: RoomLatestEventFormatter = RoomLatestEventFormatter { _, _ -> "Hey" }
) = RoomListRoomSummaryFactory( ) = RoomListRoomSummaryFactory(
dateFormatter = dateFormatter, dateFormatter = dateFormatter,
roomLastMessageFormatter = roomLastMessageFormatter roomLatestEventFormatter = roomLatestEventFormatter
) )

View file

@ -96,7 +96,7 @@ internal fun createRoomListRoomSummary(
numberOfUnreadNotifications = numberOfUnreadNotifications, numberOfUnreadNotifications = numberOfUnreadNotifications,
isMarkedUnread = isMarkedUnread, isMarkedUnread = isMarkedUnread,
timestamp = timestamp, timestamp = timestamp,
lastMessage = "", latestEvent = "",
avatarData = AvatarData(id = A_ROOM_ID.value, name = A_ROOM_NAME, size = AvatarSize.RoomListItem), avatarData = AvatarData(id = A_ROOM_ID.value, name = A_ROOM_NAME, size = AvatarSize.RoomListItem),
displayType = displayType, displayType = displayType,
userDefinedNotificationMode = userDefinedNotificationMode, userDefinedNotificationMode = userDefinedNotificationMode,

View file

@ -35,8 +35,8 @@ import io.element.android.features.rageshake.test.logs.FakeAnnouncementService
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.dateformatter.api.DateFormatter import io.element.android.libraries.dateformatter.api.DateFormatter
import io.element.android.libraries.dateformatter.test.FakeDateFormatter import io.element.android.libraries.dateformatter.test.FakeDateFormatter
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter import io.element.android.libraries.eventformatter.api.RoomLatestEventFormatter
import io.element.android.libraries.eventformatter.test.FakeRoomLastMessageFormatter import io.element.android.libraries.eventformatter.test.FakeRoomLatestEventFormatter
import io.element.android.libraries.fullscreenintent.api.aFullScreenIntentPermissionsState import io.element.android.libraries.fullscreenintent.api.aFullScreenIntentPermissionsState
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
@ -638,7 +638,7 @@ class RoomListPresenterTest {
client: MatrixClient = FakeMatrixClient(), client: MatrixClient = FakeMatrixClient(),
leaveRoomState: LeaveRoomState = aLeaveRoomState(), leaveRoomState: LeaveRoomState = aLeaveRoomState(),
dateFormatter: DateFormatter = FakeDateFormatter(), dateFormatter: DateFormatter = FakeDateFormatter(),
roomLastMessageFormatter: RoomLastMessageFormatter = FakeRoomLastMessageFormatter(), roomLatestEventFormatter: RoomLatestEventFormatter = FakeRoomLatestEventFormatter(),
sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(), sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(),
analyticsService: AnalyticsService = FakeAnalyticsService(), analyticsService: AnalyticsService = FakeAnalyticsService(),
filtersPresenter: Presenter<RoomListFiltersState> = Presenter { aRoomListFiltersState() }, filtersPresenter: Presenter<RoomListFiltersState> = Presenter { aRoomListFiltersState() },
@ -655,7 +655,7 @@ class RoomListPresenterTest {
roomListService = client.roomListService, roomListService = client.roomListService,
roomListRoomSummaryFactory = aRoomListRoomSummaryFactory( roomListRoomSummaryFactory = aRoomListRoomSummaryFactory(
dateFormatter = dateFormatter, dateFormatter = dateFormatter,
roomLastMessageFormatter = roomLastMessageFormatter, roomLatestEventFormatter = roomLatestEventFormatter,
), ),
coroutineDispatchers = testCoroutineDispatchers(), coroutineDispatchers = testCoroutineDispatchers(),
notificationSettingsService = client.notificationSettingsService, notificationSettingsService = client.notificationSettingsService,

View file

@ -170,7 +170,7 @@ class RoomListViewTest {
// Remove automatic initial events // Remove automatic initial events
eventsRecorder.clear() eventsRecorder.clear()
rule.onNodeWithText(room0.lastMessage!!.toString()).performClick() rule.onNodeWithText(room0.latestEvent!!.toString()).performClick()
} }
eventsRecorder.assertEmpty() eventsRecorder.assertEmpty()
@ -192,7 +192,7 @@ class RoomListViewTest {
) )
// Remove automatic initial events // Remove automatic initial events
eventsRecorder.clear() eventsRecorder.clear()
rule.onNodeWithText(room0.lastMessage!!.toString()) rule.onNodeWithText(room0.latestEvent!!.toString())
.performClick() .performClick()
.performClick() .performClick()
} }
@ -214,7 +214,7 @@ class RoomListViewTest {
// Remove automatic initial events // Remove automatic initial events
eventsRecorder.clear() eventsRecorder.clear()
rule.onNodeWithText(room0.lastMessage!!.toString()).performTouchInput { longClick() } rule.onNodeWithText(room0.latestEvent!!.toString()).performTouchInput { longClick() }
eventsRecorder.assertSingle(RoomListEvents.ShowContextMenu(room0)) eventsRecorder.assertSingle(RoomListEvents.ShowContextMenu(room0))
} }

View file

@ -14,7 +14,7 @@ import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.features.home.impl.datasource.aRoomListRoomSummaryFactory import io.element.android.features.home.impl.datasource.aRoomListRoomSummaryFactory
import io.element.android.libraries.dateformatter.test.FakeDateFormatter import io.element.android.libraries.dateformatter.test.FakeDateFormatter
import io.element.android.libraries.eventformatter.test.FakeRoomLastMessageFormatter import io.element.android.libraries.eventformatter.test.FakeRoomLatestEventFormatter
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.test.room.aRoomSummary import io.element.android.libraries.matrix.test.room.aRoomSummary
@ -126,7 +126,7 @@ fun TestScope.createRoomListSearchPresenter(
roomListService = roomListService, roomListService = roomListService,
roomSummaryFactory = aRoomListRoomSummaryFactory( roomSummaryFactory = aRoomListRoomSummaryFactory(
dateFormatter = FakeDateFormatter(), dateFormatter = FakeDateFormatter(),
roomLastMessageFormatter = FakeRoomLastMessageFormatter(), roomLatestEventFormatter = FakeRoomLatestEventFormatter(),
), ),
coroutineDispatchers = testCoroutineDispatchers(), coroutineDispatchers = testCoroutineDispatchers(),
), ),

View file

@ -103,7 +103,7 @@ import io.element.android.libraries.matrix.api.timeline.item.EmbeddedEventInfo
import io.element.android.libraries.matrix.api.timeline.item.ThreadSummary import io.element.android.libraries.matrix.api.timeline.item.ThreadSummary
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.getAvatarUrl import io.element.android.libraries.matrix.api.timeline.item.event.getAvatarUrl
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
@ -542,7 +542,7 @@ private fun TimelineItemEventRowContent(
@Composable @Composable
private fun MessageSenderInformation( private fun MessageSenderInformation(
senderId: UserId, senderId: UserId,
senderProfile: ProfileTimelineDetails, senderProfile: ProfileDetails,
senderAvatar: AvatarData, senderAvatar: AvatarData,
onClick: () -> Unit, onClick: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
@ -844,7 +844,7 @@ internal fun TimelineItemEventRowWithThreadSummaryPreview() = ElementPreview {
type = TextMessageType("This is the latest message in the thread", null) type = TextMessageType("This is the latest message in the thread", null)
), ),
senderId = UserId("@user:id"), senderId = UserId("@user:id"),
senderProfile = ProfileTimelineDetails.Ready( senderProfile = ProfileDetails.Ready(
displayName = "Alice", displayName = "Alice",
avatarUrl = null, avatarUrl = null,
displayNameAmbiguous = false, displayNameAmbiguous = false,
@ -877,7 +877,7 @@ internal fun ThreadSummaryViewPreview() {
type = TextMessageType(body, null) type = TextMessageType(body, null)
), ),
senderId = UserId("@user:id"), senderId = UserId("@user:id"),
senderProfile = ProfileTimelineDetails.Ready( senderProfile = ProfileDetails.Ready(
displayName = "Alice", displayName = "Alice",
avatarUrl = null, avatarUrl = null,
displayNameAmbiguous = true, displayNameAmbiguous = true,

View file

@ -25,7 +25,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.LegacyCallInv
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent 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.ProfileDetails
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent 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.RoomMembershipContent
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
@ -63,7 +63,7 @@ class TimelineItemContentFactory(
eventId: EventId?, eventId: EventId?,
isEditable: Boolean, isEditable: Boolean,
sender: UserId, sender: UserId,
senderProfile: ProfileTimelineDetails, senderProfile: ProfileDetails,
): TimelineItemEventContent { ): TimelineItemEventContent {
val isOutgoing = sessionId == sender val isOutgoing = sessionId == sender
return when (itemContent) { return when (itemContent) {

View file

@ -28,7 +28,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransa
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShieldProvider import io.element.android.libraries.matrix.api.timeline.item.event.MessageShieldProvider
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
import io.element.android.libraries.matrix.api.timeline.item.event.SendHandleProvider import io.element.android.libraries.matrix.api.timeline.item.event.SendHandleProvider
import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemDebugInfoProvider import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemDebugInfoProvider
import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin
@ -69,7 +69,7 @@ sealed interface TimelineItem {
val eventId: EventId? = null, val eventId: EventId? = null,
val transactionId: TransactionId? = null, val transactionId: TransactionId? = null,
val senderId: UserId, val senderId: UserId,
val senderProfile: ProfileTimelineDetails, val senderProfile: ProfileDetails,
val senderAvatar: AvatarData, val senderAvatar: AvatarData,
val content: TimelineItemEventContent, val content: TimelineItemEventContent,
val sentTimeMillis: Long = 0L, val sentTimeMillis: Long = 0L,

View file

@ -15,7 +15,7 @@ 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.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
@ -86,7 +86,7 @@ fun aRedactedMatrixTimeline(eventId: EventId) = listOf<MatrixTimelineItem>(
reactions = persistentListOf(), reactions = persistentListOf(),
receipts = persistentListOf(), receipts = persistentListOf(),
sender = A_USER_ID, sender = A_USER_ID,
senderProfile = ProfileTimelineDetails.Unavailable, senderProfile = ProfileDetails.Unavailable,
timestamp = 9442, timestamp = 9442,
content = RedactedContent, content = RedactedContent,
origin = null, origin = null,

View file

@ -8,8 +8,8 @@
package io.element.android.libraries.eventformatter.api package io.element.android.libraries.eventformatter.api
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem import io.element.android.libraries.matrix.api.roomlist.LatestEventValue
fun interface RoomLastMessageFormatter { fun interface RoomLatestEventFormatter {
fun format(event: EventTimelineItem, isDmRoom: Boolean): CharSequence? fun format(latestEvent: LatestEventValue, isDmRoom: Boolean): CharSequence?
} }

View file

@ -10,13 +10,15 @@ package io.element.android.libraries.eventformatter.impl
import dev.zacsweers.metro.ContributesBinding import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter import io.element.android.libraries.eventformatter.api.RoomLatestEventFormatter
import io.element.android.libraries.eventformatter.impl.mode.RenderingMode import io.element.android.libraries.eventformatter.impl.mode.RenderingMode
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.permalink.PermalinkParser import io.element.android.libraries.matrix.api.permalink.PermalinkParser
import io.element.android.libraries.matrix.api.roomlist.LatestEventValue
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.CallNotifyContent import io.element.android.libraries.matrix.api.timeline.item.event.CallNotifyContent
import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType
@ -45,22 +47,46 @@ import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.services.toolbox.api.strings.StringProvider import io.element.android.services.toolbox.api.strings.StringProvider
@ContributesBinding(SessionScope::class) @ContributesBinding(SessionScope::class)
class DefaultRoomLastMessageFormatter( class DefaultRoomLatestEventFormatter(
private val sp: StringProvider, private val sp: StringProvider,
private val roomMembershipContentFormatter: RoomMembershipContentFormatter, private val roomMembershipContentFormatter: RoomMembershipContentFormatter,
private val profileChangeContentFormatter: ProfileChangeContentFormatter, private val profileChangeContentFormatter: ProfileChangeContentFormatter,
private val stateContentFormatter: StateContentFormatter, private val stateContentFormatter: StateContentFormatter,
private val permalinkParser: PermalinkParser private val permalinkParser: PermalinkParser,
) : RoomLastMessageFormatter { ) : RoomLatestEventFormatter {
companion object { companion object {
// Max characters to display in the last message. This works around https://github.com/element-hq/element-x-android/issues/2105 // Max characters to display in the last message. This works around https://github.com/element-hq/element-x-android/issues/2105
private const val MAX_SAFE_LENGTH = 500 private const val MAX_SAFE_LENGTH = 500
} }
override fun format(event: EventTimelineItem, isDmRoom: Boolean): CharSequence? { override fun format(latestEvent: LatestEventValue, isDmRoom: Boolean): CharSequence? {
val isOutgoing = event.isOwn return when (latestEvent) {
val senderDisambiguatedDisplayName = event.senderProfile.getDisambiguatedDisplayName(event.sender) LatestEventValue.None -> null
return when (val content = event.content) { is LatestEventValue.Local -> formatContent(
content = latestEvent.content,
isDmRoom = isDmRoom,
isOutgoing = true,
senderId = latestEvent.senderId,
senderDisambiguatedDisplayName = latestEvent.senderProfile.getDisambiguatedDisplayName(latestEvent.senderId)
)
is LatestEventValue.Remote -> formatContent(
content = latestEvent.content,
isDmRoom = isDmRoom,
isOutgoing = latestEvent.isOwn,
senderId = latestEvent.senderId,
senderDisambiguatedDisplayName = latestEvent.senderProfile.getDisambiguatedDisplayName(latestEvent.senderId)
)
}
}
private fun formatContent(
content: EventContent,
isDmRoom: Boolean,
isOutgoing: Boolean,
senderId: UserId,
senderDisambiguatedDisplayName: String
): CharSequence? {
return when (content) {
is MessageContent -> content.process(senderDisambiguatedDisplayName, isDmRoom, isOutgoing) is MessageContent -> content.process(senderDisambiguatedDisplayName, isDmRoom, isOutgoing)
RedactedContent -> { RedactedContent -> {
val message = sp.getString(CommonStrings.common_message_removed) val message = sp.getString(CommonStrings.common_message_removed)
@ -78,7 +104,7 @@ class DefaultRoomLastMessageFormatter(
roomMembershipContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing) roomMembershipContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing)
} }
is ProfileChangeContent -> { is ProfileChangeContent -> {
profileChangeContentFormatter.format(content, event.sender, senderDisambiguatedDisplayName, isOutgoing) profileChangeContentFormatter.format(content, senderId, senderDisambiguatedDisplayName, isOutgoing)
} }
is StateContent -> { is StateContent -> {
stateContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing, RenderingMode.RoomList) stateContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing, RenderingMode.RoomList)

View file

@ -44,7 +44,7 @@ import io.element.android.libraries.matrix.test.media.aMediaSource
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
import io.element.android.libraries.matrix.test.timeline.aPollContent 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.aProfileChangeMessageContent
import io.element.android.libraries.matrix.test.timeline.aProfileTimelineDetails import io.element.android.libraries.matrix.test.timeline.aProfileDetails
import io.element.android.libraries.matrix.test.timeline.aStickerContent 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.anEventTimelineItem
import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent
@ -778,7 +778,7 @@ class DefaultPinnedMessagesBannerFormatterTest {
content: EventContent, content: EventContent,
): EventTimelineItem { ): EventTimelineItem {
val sender = if (sentByYou) A_USER_ID else someoneElseId val sender = if (sentByYou) A_USER_ID else someoneElseId
val profile = aProfileTimelineDetails(senderDisplayName) val profile = aProfileDetails(senderDisplayName)
return anEventTimelineItem( return anEventTimelineItem(
content = content, content = content,
senderProfile = profile, senderProfile = profile,

View file

@ -15,10 +15,10 @@ import com.google.common.truth.Truth.assertWithMessage
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.ImageInfo
import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.api.roomlist.LatestEventValue
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType
@ -43,11 +43,11 @@ 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.FakeMatrixClient
import io.element.android.libraries.matrix.test.media.aMediaSource import io.element.android.libraries.matrix.test.media.aMediaSource
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
import io.element.android.libraries.matrix.test.room.aRemoteLatestEvent
import io.element.android.libraries.matrix.test.timeline.aPollContent 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.aProfileChangeMessageContent
import io.element.android.libraries.matrix.test.timeline.aProfileTimelineDetails import io.element.android.libraries.matrix.test.timeline.aProfileDetails
import io.element.android.libraries.matrix.test.timeline.aStickerContent 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.matrix.test.timeline.item.event.aRoomMembershipContent
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
import org.junit.Before import org.junit.Before
@ -59,17 +59,17 @@ import org.robolectric.annotation.Config
@Suppress("LargeClass") @Suppress("LargeClass")
@RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class)
class DefaultBaseRoomLastMessageFormatterTest { class DefaultRoomLatestEventFormatterTest {
private lateinit var context: Context private lateinit var context: Context
private lateinit var fakeMatrixClient: FakeMatrixClient private lateinit var fakeMatrixClient: FakeMatrixClient
private lateinit var formatter: DefaultRoomLastMessageFormatter private lateinit var formatter: DefaultRoomLatestEventFormatter
@Before @Before
fun setup() { fun setup() {
context = RuntimeEnvironment.getApplication() as Context context = RuntimeEnvironment.getApplication() as Context
fakeMatrixClient = FakeMatrixClient() fakeMatrixClient = FakeMatrixClient()
val stringProvider = AndroidStringProvider(context.resources) val stringProvider = AndroidStringProvider(context.resources)
formatter = DefaultRoomLastMessageFormatter( formatter = DefaultRoomLatestEventFormatter(
sp = AndroidStringProvider(context.resources), sp = AndroidStringProvider(context.resources),
roomMembershipContentFormatter = RoomMembershipContentFormatter(fakeMatrixClient, stringProvider), roomMembershipContentFormatter = RoomMembershipContentFormatter(fakeMatrixClient, stringProvider),
profileChangeContentFormatter = ProfileChangeContentFormatter(stringProvider), profileChangeContentFormatter = ProfileChangeContentFormatter(stringProvider),
@ -84,7 +84,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
val expected = "Message removed" val expected = "Message removed"
val senderName = "Someone" val senderName = "Someone"
sequenceOf(false, true).forEach { isDm -> sequenceOf(false, true).forEach { isDm ->
val message = createRoomEvent(false, senderName, RedactedContent) val message = createLatestEvent(false, senderName, RedactedContent)
val result = formatter.format(message, isDm) val result = formatter.format(message, isDm)
if (isDm) { if (isDm) {
assertThat(result).isEqualTo(expected) assertThat(result).isEqualTo(expected)
@ -100,7 +100,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
fun `Sticker content`() { fun `Sticker content`() {
val body = "a sticker body" val body = "a sticker body"
val info = ImageInfo(null, null, null, null, null, null, null) val info = ImageInfo(null, null, null, null, null, null, null)
val message = createRoomEvent(false, null, aStickerContent(body, info, aMediaSource(url = "url"))) val message = createLatestEvent(false, null, aStickerContent(body, info, aMediaSource(url = "url")))
val result = formatter.format(message, false) val result = formatter.format(message, false)
val expectedBody = someoneElseId.value + ": Sticker (a sticker body)" val expectedBody = someoneElseId.value + ": Sticker (a sticker body)"
assertThat(result.toString()).isEqualTo(expectedBody) assertThat(result.toString()).isEqualTo(expectedBody)
@ -112,7 +112,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
val expected = "Waiting for this message" val expected = "Waiting for this message"
val senderName = "Someone" val senderName = "Someone"
sequenceOf(false, true).forEach { isDm -> sequenceOf(false, true).forEach { isDm ->
val message = createRoomEvent(false, senderName, UnableToDecryptContent(UnableToDecryptContent.Data.Unknown)) val message = createLatestEvent(false, senderName, UnableToDecryptContent(UnableToDecryptContent.Data.Unknown))
val result = formatter.format(message, isDm) val result = formatter.format(message, isDm)
if (isDm) { if (isDm) {
assertThat(result).isEqualTo(expected) assertThat(result).isEqualTo(expected)
@ -134,7 +134,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
FailedToParseStateContent("", "", ""), FailedToParseStateContent("", "", ""),
UnknownContent, UnknownContent,
).forEach { type -> ).forEach { type ->
val message = createRoomEvent(false, senderName, type) val message = createLatestEvent(false, senderName, type)
val result = formatter.format(message, isDm) val result = formatter.format(message, isDm)
if (isDm) { if (isDm) {
assertWithMessage("$type was not properly handled").that(result).isEqualTo(expected) assertWithMessage("$type was not properly handled").that(result).isEqualTo(expected)
@ -198,7 +198,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
sequenceOf(false, true).forEach { isDm -> sequenceOf(false, true).forEach { isDm ->
sharedContentMessagesTypes.forEach { type -> sharedContentMessagesTypes.forEach { type ->
val content = createMessageContent(type) val content = createMessageContent(type)
val message = createRoomEvent(sentByYou = sentByYou, senderDisplayName = senderName, content = content) val message = createLatestEvent(sentByYou = sentByYou, senderDisplayName = senderName, content = content)
val result = formatter.format(message, isDmRoom = isDm) val result = formatter.format(message, isDmRoom = isDm)
if (isDm) { if (isDm) {
resultsInDm.add(type to result) resultsInDm.add(type to result)
@ -294,11 +294,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED) val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.JOINED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.JOINED) val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.JOINED)
val youJoinedRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youJoinedRoomEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youJoinedRoom = formatter.format(youJoinedRoomEvent, false) val youJoinedRoom = formatter.format(youJoinedRoomEvent, false)
assertThat(youJoinedRoom).isEqualTo("You joined the room") assertThat(youJoinedRoom).isEqualTo("You joined the room")
val someoneJoinedRoomEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneJoinedRoomEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneJoinedRoom = formatter.format(someoneJoinedRoomEvent, false) val someoneJoinedRoom = formatter.format(someoneJoinedRoomEvent, false)
assertThat(someoneJoinedRoom).isEqualTo("$otherName joined the room") assertThat(someoneJoinedRoom).isEqualTo("$otherName joined the room")
} }
@ -310,11 +310,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.LEFT) val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.LEFT)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.LEFT) val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.LEFT)
val youLeftRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youLeftRoomEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youLeftRoom = formatter.format(youLeftRoomEvent, false) val youLeftRoom = formatter.format(youLeftRoomEvent, false)
assertThat(youLeftRoom).isEqualTo("You left the room") assertThat(youLeftRoom).isEqualTo("You left the room")
val someoneLeftRoomEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneLeftRoomEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneLeftRoom = formatter.format(someoneLeftRoomEvent, false) val someoneLeftRoom = formatter.format(someoneLeftRoomEvent, false)
assertThat(someoneLeftRoom).isEqualTo("$otherName left the room") assertThat(someoneLeftRoom).isEqualTo("$otherName left the room")
} }
@ -329,19 +329,19 @@ class DefaultBaseRoomLastMessageFormatterTest {
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED) val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.BANNED)
val someoneKickedContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED) val someoneKickedContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED)
val youBannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youBannedEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youBanned = formatter.format(youBannedEvent, false) val youBanned = formatter.format(youBannedEvent, false)
assertThat(youBanned).isEqualTo("You banned $third") assertThat(youBanned).isEqualTo("You banned $third")
val youKickBannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youKickedContent) val youKickBannedEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youKickedContent)
val youKickedBanned = formatter.format(youKickBannedEvent, false) val youKickedBanned = formatter.format(youKickBannedEvent, false)
assertThat(youKickedBanned).isEqualTo("You banned $third") assertThat(youKickedBanned).isEqualTo("You banned $third")
val someoneBannedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneBannedEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneBanned = formatter.format(someoneBannedEvent, false) val someoneBanned = formatter.format(someoneBannedEvent, false)
assertThat(someoneBanned).isEqualTo("$otherName banned $third") assertThat(someoneBanned).isEqualTo("$otherName banned $third")
val someoneKickBannedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneKickedContent) val someoneKickBannedEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneKickedContent)
val someoneKickBanned = formatter.format(someoneKickBannedEvent, false) val someoneKickBanned = formatter.format(someoneKickBannedEvent, false)
assertThat(someoneKickBanned).isEqualTo("$otherName banned $third") assertThat(someoneKickBanned).isEqualTo("$otherName banned $third")
} }
@ -356,19 +356,19 @@ class DefaultBaseRoomLastMessageFormatterTest {
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.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 someoneKickedContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED_AND_BANNED, A_REASON)
val youBannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youBannedEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youBanned = formatter.format(youBannedEvent, false) val youBanned = formatter.format(youBannedEvent, false)
assertThat(youBanned).isEqualTo("You banned $third: $A_REASON") assertThat(youBanned).isEqualTo("You banned $third: $A_REASON")
val youKickBannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youKickedContent) val youKickBannedEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youKickedContent)
val youKickedBanned = formatter.format(youKickBannedEvent, false) val youKickedBanned = formatter.format(youKickBannedEvent, false)
assertThat(youKickedBanned).isEqualTo("You banned $third: $A_REASON") assertThat(youKickedBanned).isEqualTo("You banned $third: $A_REASON")
val someoneBannedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneBannedEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneBanned = formatter.format(someoneBannedEvent, false) val someoneBanned = formatter.format(someoneBannedEvent, false)
assertThat(someoneBanned).isEqualTo("$otherName banned $third: $A_REASON") assertThat(someoneBanned).isEqualTo("$otherName banned $third: $A_REASON")
val someoneKickBannedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneKickedContent) val someoneKickBannedEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneKickedContent)
val someoneKickBanned = formatter.format(someoneKickBannedEvent, false) val someoneKickBanned = formatter.format(someoneKickBannedEvent, false)
assertThat(someoneKickBanned).isEqualTo("$otherName banned $third: $A_REASON") assertThat(someoneKickBanned).isEqualTo("$otherName banned $third: $A_REASON")
} }
@ -381,11 +381,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(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 someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.UNBANNED)
val youUnbannedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youUnbannedEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youUnbanned = formatter.format(youUnbannedEvent, false) val youUnbanned = formatter.format(youUnbannedEvent, false)
assertThat(youUnbanned).isEqualTo("You unbanned $third") assertThat(youUnbanned).isEqualTo("You unbanned $third")
val someoneUnbannedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneUnbannedEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneUnbanned = formatter.format(someoneUnbannedEvent, false) val someoneUnbanned = formatter.format(someoneUnbannedEvent, false)
assertThat(someoneUnbanned).isEqualTo("$otherName unbanned $third") assertThat(someoneUnbanned).isEqualTo("$otherName unbanned $third")
} }
@ -398,11 +398,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(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 someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED)
val youKickedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youKickedEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youKicked = formatter.format(youKickedEvent, false) val youKicked = formatter.format(youKickedEvent, false)
assertThat(youKicked).isEqualTo("You removed $third") assertThat(youKicked).isEqualTo("You removed $third")
val someoneKickedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneKickedEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneKicked = formatter.format(someoneKickedEvent, false) val someoneKicked = formatter.format(someoneKickedEvent, false)
assertThat(someoneKicked).isEqualTo("$otherName removed $third") assertThat(someoneKicked).isEqualTo("$otherName removed $third")
} }
@ -415,11 +415,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED, A_REASON) 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 someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KICKED, A_REASON)
val youKickedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youKickedEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youKicked = formatter.format(youKickedEvent, false) val youKicked = formatter.format(youKickedEvent, false)
assertThat(youKicked).isEqualTo("You removed $third: $A_REASON") assertThat(youKicked).isEqualTo("You removed $third: $A_REASON")
val someoneKickedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneKickedEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneKicked = formatter.format(someoneKickedEvent, false) val someoneKicked = formatter.format(someoneKickedEvent, false)
assertThat(someoneKicked).isEqualTo("$otherName removed $third: $A_REASON") assertThat(someoneKicked).isEqualTo("$otherName removed $third: $A_REASON")
} }
@ -432,15 +432,15 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.INVITED) val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.INVITED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITED) val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.INVITED)
val youWereInvitedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = youContent) val youWereInvitedEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = youContent)
val youWereInvited = formatter.format(youWereInvitedEvent, false) val youWereInvited = formatter.format(youWereInvitedEvent, false)
assertThat(youWereInvited).isEqualTo("$otherName invited you") assertThat(youWereInvited).isEqualTo("$otherName invited you")
val youInvitedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent) val youInvitedEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youInvited = formatter.format(youInvitedEvent, false) val youInvited = formatter.format(youInvitedEvent, false)
assertThat(youInvited).isEqualTo("You invited $third") assertThat(youInvited).isEqualTo("You invited $third")
val someoneInvitedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneInvitedEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneInvited = formatter.format(someoneInvitedEvent, false) val someoneInvited = formatter.format(someoneInvitedEvent, false)
assertThat(someoneInvited).isEqualTo("$otherName invited $third") assertThat(someoneInvited).isEqualTo("$otherName invited $third")
} }
@ -452,11 +452,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(A_USER_ID, null, 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 someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_ACCEPTED)
val youAcceptedInviteEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youAcceptedInviteEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youAcceptedInvite = formatter.format(youAcceptedInviteEvent, false) val youAcceptedInvite = formatter.format(youAcceptedInviteEvent, false)
assertThat(youAcceptedInvite).isEqualTo("You accepted the invite") assertThat(youAcceptedInvite).isEqualTo("You accepted the invite")
val someoneAcceptedInviteEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneAcceptedInviteEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneAcceptedInvite = formatter.format(someoneAcceptedInviteEvent, false) val someoneAcceptedInvite = formatter.format(someoneAcceptedInviteEvent, false)
assertThat(someoneAcceptedInvite).isEqualTo("$otherName accepted the invite") assertThat(someoneAcceptedInvite).isEqualTo("$otherName accepted the invite")
} }
@ -468,11 +468,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(A_USER_ID, null, 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 someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.INVITATION_REJECTED)
val youRejectedInviteEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youRejectedInviteEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youRejectedInvite = formatter.format(youRejectedInviteEvent, false) val youRejectedInvite = formatter.format(youRejectedInviteEvent, false)
assertThat(youRejectedInvite).isEqualTo("You rejected the invitation") assertThat(youRejectedInvite).isEqualTo("You rejected the invitation")
val someoneRejectedInviteEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneRejectedInviteEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneRejectedInvite = formatter.format(someoneRejectedInviteEvent, false) val someoneRejectedInvite = formatter.format(someoneRejectedInviteEvent, false)
assertThat(someoneRejectedInvite).isEqualTo("$otherName rejected the invitation") assertThat(someoneRejectedInvite).isEqualTo("$otherName rejected the invitation")
} }
@ -484,11 +484,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val third = "Someone" val third = "Someone"
val someoneContent = aRoomMembershipContent(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 youRevokedInviteEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youRevokedInvite = formatter.format(youRevokedInviteEvent, false) val youRevokedInvite = formatter.format(youRevokedInviteEvent, false)
assertThat(youRevokedInvite).isEqualTo("You revoked the invitation for $third to join the room") assertThat(youRevokedInvite).isEqualTo("You revoked the invitation for $third to join the room")
val someoneRevokedInviteEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneRevokedInviteEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneRevokedInvite = formatter.format(someoneRevokedInviteEvent, false) val someoneRevokedInvite = formatter.format(someoneRevokedInviteEvent, false)
assertThat(someoneRevokedInvite).isEqualTo("$otherName revoked the invitation for $third to join the room") assertThat(someoneRevokedInvite).isEqualTo("$otherName revoked the invitation for $third to join the room")
} }
@ -500,11 +500,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCKED) val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.KNOCKED)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.KNOCKED) val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.KNOCKED)
val youKnockedEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youKnockedEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youKnocked = formatter.format(youKnockedEvent, false) val youKnocked = formatter.format(youKnockedEvent, false)
assertThat(youKnocked).isEqualTo("You requested to join") assertThat(youKnocked).isEqualTo("You requested to join")
val someoneKnockedEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneKnockedEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneKnocked = formatter.format(someoneKnockedEvent, false) val someoneKnocked = formatter.format(someoneKnockedEvent, false)
assertThat(someoneKnocked).isEqualTo("$otherName is requesting to join") assertThat(someoneKnocked).isEqualTo("$otherName is requesting to join")
} }
@ -516,11 +516,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val third = "Someone" val third = "Someone"
val someoneContent = aRoomMembershipContent(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 youAcceptedKnockEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youAcceptedKnock = formatter.format(youAcceptedKnockEvent, false) val youAcceptedKnock = formatter.format(youAcceptedKnockEvent, false)
assertThat(youAcceptedKnock).isEqualTo("You allowed $third to join") assertThat(youAcceptedKnock).isEqualTo("You allowed $third to join")
val someoneAcceptedKnockEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneAcceptedKnockEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneAcceptedKnock = formatter.format(someoneAcceptedKnockEvent, false) val someoneAcceptedKnock = formatter.format(someoneAcceptedKnockEvent, false)
assertThat(someoneAcceptedKnock).isEqualTo("$otherName granted access to $third") assertThat(someoneAcceptedKnock).isEqualTo("$otherName granted access to $third")
} }
@ -532,11 +532,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(A_USER_ID, 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 someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), null, MembershipChange.KNOCK_RETRACTED)
val youRetractedKnockEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youRetractedKnockEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youRetractedKnock = formatter.format(youRetractedKnockEvent, false) val youRetractedKnock = formatter.format(youRetractedKnockEvent, false)
assertThat(youRetractedKnock).isEqualTo("You cancelled your request to join") assertThat(youRetractedKnock).isEqualTo("You cancelled your request to join")
val someoneRetractedKnockEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneRetractedKnockEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneRetractedKnock = formatter.format(someoneRetractedKnockEvent, false) val someoneRetractedKnock = formatter.format(someoneRetractedKnockEvent, false)
assertThat(someoneRetractedKnock).isEqualTo("$otherName is no longer interested in joining") assertThat(someoneRetractedKnock).isEqualTo("$otherName is no longer interested in joining")
} }
@ -549,15 +549,15 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(A_USER_ID, 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 someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), third, MembershipChange.KNOCK_DENIED)
val youDeniedKnockEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = someoneContent) val youDeniedKnockEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = someoneContent)
val youDeniedKnock = formatter.format(youDeniedKnockEvent, false) val youDeniedKnock = formatter.format(youDeniedKnockEvent, false)
assertThat(youDeniedKnock).isEqualTo("You rejected $third's request to join") assertThat(youDeniedKnock).isEqualTo("You rejected $third's request to join")
val someoneDeniedKnockEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneDeniedKnockEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneDeniedKnock = formatter.format(someoneDeniedKnockEvent, false) val someoneDeniedKnock = formatter.format(someoneDeniedKnockEvent, false)
assertThat(someoneDeniedKnock).isEqualTo("$otherName rejected $third's request to join") assertThat(someoneDeniedKnock).isEqualTo("$otherName rejected $third's request to join")
val someoneDeniedYourKnockEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = youContent) val someoneDeniedYourKnockEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = youContent)
val someoneDeniedYourKnock = formatter.format(someoneDeniedYourKnockEvent, false) val someoneDeniedYourKnock = formatter.format(someoneDeniedYourKnockEvent, false)
assertThat(someoneDeniedYourKnock).isEqualTo("$otherName rejected your request to join") assertThat(someoneDeniedYourKnock).isEqualTo("$otherName rejected your request to join")
} }
@ -569,11 +569,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.NONE) val youContent = aRoomMembershipContent(A_USER_ID, null, MembershipChange.NONE)
val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.NONE) val someoneContent = aRoomMembershipContent(UserId("@someone_else:domain"), otherName, MembershipChange.NONE)
val youNoneRoomEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = youContent) val youNoneRoomEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = youContent)
val youNoneRoom = formatter.format(youNoneRoomEvent, false) val youNoneRoom = formatter.format(youNoneRoomEvent, false)
assertThat(youNoneRoom).isEqualTo("You made no changes") assertThat(youNoneRoom).isEqualTo("You made no changes")
val someoneNoneRoomEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent) val someoneNoneRoomEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = someoneContent)
val someoneNoneRoom = formatter.format(someoneNoneRoomEvent, false) val someoneNoneRoom = formatter.format(someoneNoneRoomEvent, false)
assertThat(someoneNoneRoom).isEqualTo("$otherName made no changes") assertThat(someoneNoneRoom).isEqualTo("$otherName made no changes")
} }
@ -585,7 +585,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
val results = otherChanges.map { change -> val results = otherChanges.map { change ->
val content = aRoomMembershipContent(A_USER_ID, null, change) val content = aRoomMembershipContent(A_USER_ID, null, change)
val event = createRoomEvent(sentByYou = false, senderDisplayName = "Someone", content = content) val event = createLatestEvent(sentByYou = false, senderDisplayName = "Someone", content = content)
val result = formatter.format(event, false) val result = formatter.format(event, false)
change to result change to result
} }
@ -604,19 +604,19 @@ class DefaultBaseRoomLastMessageFormatterTest {
val changedContent = StateContent("", OtherState.RoomAvatar("new_avatar")) val changedContent = StateContent("", OtherState.RoomAvatar("new_avatar"))
val removedContent = StateContent("", OtherState.RoomAvatar(null)) val removedContent = StateContent("", OtherState.RoomAvatar(null))
val youChangedRoomAvatarEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = changedContent) val youChangedRoomAvatarEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = changedContent)
val youChangedRoomAvatar = formatter.format(youChangedRoomAvatarEvent, false) val youChangedRoomAvatar = formatter.format(youChangedRoomAvatarEvent, false)
assertThat(youChangedRoomAvatar).isEqualTo("You changed the room avatar") assertThat(youChangedRoomAvatar).isEqualTo("You changed the room avatar")
val someoneChangedRoomAvatarEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent) val someoneChangedRoomAvatarEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent)
val someoneChangedRoomAvatar = formatter.format(someoneChangedRoomAvatarEvent, false) val someoneChangedRoomAvatar = formatter.format(someoneChangedRoomAvatarEvent, false)
assertThat(someoneChangedRoomAvatar).isEqualTo("$otherName changed the room avatar") assertThat(someoneChangedRoomAvatar).isEqualTo("$otherName changed the room avatar")
val youRemovedRoomAvatarEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = removedContent) val youRemovedRoomAvatarEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = removedContent)
val youRemovedRoomAvatar = formatter.format(youRemovedRoomAvatarEvent, false) val youRemovedRoomAvatar = formatter.format(youRemovedRoomAvatarEvent, false)
assertThat(youRemovedRoomAvatar).isEqualTo("You removed the room avatar") assertThat(youRemovedRoomAvatar).isEqualTo("You removed the room avatar")
val someoneRemovedRoomAvatarEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent) val someoneRemovedRoomAvatarEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent)
val someoneRemovedRoomAvatar = formatter.format(someoneRemovedRoomAvatarEvent, false) val someoneRemovedRoomAvatar = formatter.format(someoneRemovedRoomAvatarEvent, false)
assertThat(someoneRemovedRoomAvatar).isEqualTo("$otherName removed the room avatar") assertThat(someoneRemovedRoomAvatar).isEqualTo("$otherName removed the room avatar")
} }
@ -627,11 +627,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val otherName = "Other" val otherName = "Other"
val content = StateContent("", OtherState.RoomCreate) val content = StateContent("", OtherState.RoomCreate)
val youCreatedRoomMessage = createRoomEvent(sentByYou = true, senderDisplayName = null, content = content) val youCreatedRoomMessage = createLatestEvent(sentByYou = true, senderDisplayName = null, content = content)
val youCreatedRoom = formatter.format(youCreatedRoomMessage, false) val youCreatedRoom = formatter.format(youCreatedRoomMessage, false)
assertThat(youCreatedRoom).isEqualTo("You created the room") assertThat(youCreatedRoom).isEqualTo("You created the room")
val someoneCreatedRoomEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = content) val someoneCreatedRoomEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = content)
val someoneCreatedRoom = formatter.format(someoneCreatedRoomEvent, false) val someoneCreatedRoom = formatter.format(someoneCreatedRoomEvent, false)
assertThat(someoneCreatedRoom).isEqualTo("$otherName created the room") assertThat(someoneCreatedRoom).isEqualTo("$otherName created the room")
} }
@ -642,11 +642,11 @@ class DefaultBaseRoomLastMessageFormatterTest {
val otherName = "Other" val otherName = "Other"
val content = StateContent("", OtherState.RoomEncryption) val content = StateContent("", OtherState.RoomEncryption)
val youCreatedRoomMessage = createRoomEvent(sentByYou = true, senderDisplayName = null, content = content) val youCreatedRoomMessage = createLatestEvent(sentByYou = true, senderDisplayName = null, content = content)
val youCreatedRoom = formatter.format(youCreatedRoomMessage, false) val youCreatedRoom = formatter.format(youCreatedRoomMessage, false)
assertThat(youCreatedRoom).isEqualTo("Encryption enabled") assertThat(youCreatedRoom).isEqualTo("Encryption enabled")
val someoneCreatedRoomEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = content) val someoneCreatedRoomEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = content)
val someoneCreatedRoom = formatter.format(someoneCreatedRoomEvent, false) val someoneCreatedRoom = formatter.format(someoneCreatedRoomEvent, false)
assertThat(someoneCreatedRoom).isEqualTo("Encryption enabled") assertThat(someoneCreatedRoom).isEqualTo("Encryption enabled")
} }
@ -659,19 +659,19 @@ class DefaultBaseRoomLastMessageFormatterTest {
val changedContent = StateContent("", OtherState.RoomName(newName)) val changedContent = StateContent("", OtherState.RoomName(newName))
val removedContent = StateContent("", OtherState.RoomName(null)) val removedContent = StateContent("", OtherState.RoomName(null))
val youChangedRoomNameEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = changedContent) val youChangedRoomNameEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = changedContent)
val youChangedRoomName = formatter.format(youChangedRoomNameEvent, false) val youChangedRoomName = formatter.format(youChangedRoomNameEvent, false)
assertThat(youChangedRoomName).isEqualTo("You changed the room name to: $newName") assertThat(youChangedRoomName).isEqualTo("You changed the room name to: $newName")
val someoneChangedRoomNameEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent) val someoneChangedRoomNameEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent)
val someoneChangedRoomName = formatter.format(someoneChangedRoomNameEvent, false) val someoneChangedRoomName = formatter.format(someoneChangedRoomNameEvent, false)
assertThat(someoneChangedRoomName).isEqualTo("$otherName changed the room name to: $newName") assertThat(someoneChangedRoomName).isEqualTo("$otherName changed the room name to: $newName")
val youRemovedRoomNameEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = removedContent) val youRemovedRoomNameEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = removedContent)
val youRemovedRoomName = formatter.format(youRemovedRoomNameEvent, false) val youRemovedRoomName = formatter.format(youRemovedRoomNameEvent, false)
assertThat(youRemovedRoomName).isEqualTo("You removed the room name") assertThat(youRemovedRoomName).isEqualTo("You removed the room name")
val someoneRemovedRoomNameEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent) val someoneRemovedRoomNameEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent)
val someoneRemovedRoomName = formatter.format(someoneRemovedRoomNameEvent, false) val someoneRemovedRoomName = formatter.format(someoneRemovedRoomNameEvent, false)
assertThat(someoneRemovedRoomName).isEqualTo("$otherName removed the room name") assertThat(someoneRemovedRoomName).isEqualTo("$otherName removed the room name")
} }
@ -684,19 +684,19 @@ class DefaultBaseRoomLastMessageFormatterTest {
val changedContent = StateContent("", OtherState.RoomThirdPartyInvite(inviteeName)) val changedContent = StateContent("", OtherState.RoomThirdPartyInvite(inviteeName))
val removedContent = StateContent("", OtherState.RoomThirdPartyInvite(null)) val removedContent = StateContent("", OtherState.RoomThirdPartyInvite(null))
val youInvitedSomeoneEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = changedContent) val youInvitedSomeoneEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = changedContent)
val youInvitedSomeone = formatter.format(youInvitedSomeoneEvent, false) val youInvitedSomeone = formatter.format(youInvitedSomeoneEvent, false)
assertThat(youInvitedSomeone).isEqualTo("You sent an invitation to $inviteeName to join the room") assertThat(youInvitedSomeone).isEqualTo("You sent an invitation to $inviteeName to join the room")
val someoneInvitedSomeoneEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent) val someoneInvitedSomeoneEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent)
val someoneInvitedSomeone = formatter.format(someoneInvitedSomeoneEvent, false) val someoneInvitedSomeone = formatter.format(someoneInvitedSomeoneEvent, false)
assertThat(someoneInvitedSomeone).isEqualTo("$otherName sent an invitation to $inviteeName to join the room") assertThat(someoneInvitedSomeone).isEqualTo("$otherName sent an invitation to $inviteeName to join the room")
val youInvitedNoOneEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = removedContent) val youInvitedNoOneEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = removedContent)
val youInvitedNoOne = formatter.format(youInvitedNoOneEvent, false) val youInvitedNoOne = formatter.format(youInvitedNoOneEvent, false)
assertThat(youInvitedNoOne).isNull() assertThat(youInvitedNoOne).isNull()
val someoneInvitedNoOneEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent) val someoneInvitedNoOneEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent)
val someoneInvitedNoOne = formatter.format(someoneInvitedNoOneEvent, false) val someoneInvitedNoOne = formatter.format(someoneInvitedNoOneEvent, false)
assertThat(someoneInvitedNoOne).isNull() assertThat(someoneInvitedNoOne).isNull()
} }
@ -710,27 +710,27 @@ class DefaultBaseRoomLastMessageFormatterTest {
val removedContent = StateContent("", OtherState.RoomTopic(null)) val removedContent = StateContent("", OtherState.RoomTopic(null))
val blankContent = StateContent("", OtherState.RoomTopic("")) val blankContent = StateContent("", OtherState.RoomTopic(""))
val youChangedRoomTopicEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = changedContent) val youChangedRoomTopicEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = changedContent)
val youChangedRoomTopic = formatter.format(youChangedRoomTopicEvent, false) val youChangedRoomTopic = formatter.format(youChangedRoomTopicEvent, false)
assertThat(youChangedRoomTopic).isEqualTo("You changed the topic to: $roomTopic") assertThat(youChangedRoomTopic).isEqualTo("You changed the topic to: $roomTopic")
val someoneChangedRoomTopicEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent) val someoneChangedRoomTopicEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent)
val someoneChangedRoomTopic = formatter.format(someoneChangedRoomTopicEvent, false) val someoneChangedRoomTopic = formatter.format(someoneChangedRoomTopicEvent, false)
assertThat(someoneChangedRoomTopic).isEqualTo("$otherName changed the topic to: $roomTopic") assertThat(someoneChangedRoomTopic).isEqualTo("$otherName changed the topic to: $roomTopic")
val youRemovedRoomTopicEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = removedContent) val youRemovedRoomTopicEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = removedContent)
val youRemovedRoomTopic = formatter.format(youRemovedRoomTopicEvent, false) val youRemovedRoomTopic = formatter.format(youRemovedRoomTopicEvent, false)
assertThat(youRemovedRoomTopic).isEqualTo("You removed the room topic") assertThat(youRemovedRoomTopic).isEqualTo("You removed the room topic")
val someoneRemovedRoomTopicEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent) val someoneRemovedRoomTopicEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent)
val someoneRemovedRoomTopic = formatter.format(someoneRemovedRoomTopicEvent, false) val someoneRemovedRoomTopic = formatter.format(someoneRemovedRoomTopicEvent, false)
assertThat(someoneRemovedRoomTopic).isEqualTo("$otherName removed the room topic") assertThat(someoneRemovedRoomTopic).isEqualTo("$otherName removed the room topic")
val youSetBlankRoomTopicEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = blankContent) val youSetBlankRoomTopicEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = blankContent)
val youSetBlankRoomTopic = formatter.format(youSetBlankRoomTopicEvent, false) val youSetBlankRoomTopic = formatter.format(youSetBlankRoomTopicEvent, false)
assertThat(youSetBlankRoomTopic).isEqualTo("You removed the room topic") assertThat(youSetBlankRoomTopic).isEqualTo("You removed the room topic")
val someoneSetBlankRoomTopicEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = blankContent) val someoneSetBlankRoomTopicEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = blankContent)
val someoneSetBlankRoomTopic = formatter.format(someoneSetBlankRoomTopicEvent, false) val someoneSetBlankRoomTopic = formatter.format(someoneSetBlankRoomTopicEvent, false)
assertThat(someoneSetBlankRoomTopic).isEqualTo("$otherName removed the room topic") assertThat(someoneSetBlankRoomTopic).isEqualTo("$otherName removed the room topic")
} }
@ -758,7 +758,7 @@ class DefaultBaseRoomLastMessageFormatterTest {
val results = otherStates.map { state -> val results = otherStates.map { state ->
val content = StateContent("", state) val content = StateContent("", state)
val event = createRoomEvent(sentByYou = false, senderDisplayName = "Someone", content = content) val event = createLatestEvent(sentByYou = false, senderDisplayName = "Someone", content = content)
val result = formatter.format(event, false) val result = formatter.format(event, false)
state to result state to result
} }
@ -780,35 +780,35 @@ class DefaultBaseRoomLastMessageFormatterTest {
val invalidContent = aProfileChangeMessageContent(avatarUrl = null, prevAvatarUrl = null) val invalidContent = aProfileChangeMessageContent(avatarUrl = null, prevAvatarUrl = null)
val sameContent = aProfileChangeMessageContent(avatarUrl = "same_avatar_url", prevAvatarUrl = "same_avatar_url") val sameContent = aProfileChangeMessageContent(avatarUrl = "same_avatar_url", prevAvatarUrl = "same_avatar_url")
val youChangedAvatarEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = changedContent) val youChangedAvatarEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = changedContent)
val youChangedAvatar = formatter.format(youChangedAvatarEvent, false) val youChangedAvatar = formatter.format(youChangedAvatarEvent, false)
assertThat(youChangedAvatar).isEqualTo("You changed your avatar") assertThat(youChangedAvatar).isEqualTo("You changed your avatar")
val someoneChangeAvatarEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent) val someoneChangeAvatarEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent)
val someoneChangeAvatar = formatter.format(someoneChangeAvatarEvent, false) val someoneChangeAvatar = formatter.format(someoneChangeAvatarEvent, false)
assertThat(someoneChangeAvatar).isEqualTo("$otherName changed their avatar") assertThat(someoneChangeAvatar).isEqualTo("$otherName changed their avatar")
val youSetAvatarEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = setContent) val youSetAvatarEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = setContent)
val youSetAvatar = formatter.format(youSetAvatarEvent, false) val youSetAvatar = formatter.format(youSetAvatarEvent, false)
assertThat(youSetAvatar).isEqualTo("You changed your avatar") assertThat(youSetAvatar).isEqualTo("You changed your avatar")
val someoneSetAvatarEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = setContent) val someoneSetAvatarEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = setContent)
val someoneSetAvatar = formatter.format(someoneSetAvatarEvent, false) val someoneSetAvatar = formatter.format(someoneSetAvatarEvent, false)
assertThat(someoneSetAvatar).isEqualTo("$otherName changed their avatar") assertThat(someoneSetAvatar).isEqualTo("$otherName changed their avatar")
val youRemovedAvatarEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = removedContent) val youRemovedAvatarEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = removedContent)
val youRemovedAvatar = formatter.format(youRemovedAvatarEvent, false) val youRemovedAvatar = formatter.format(youRemovedAvatarEvent, false)
assertThat(youRemovedAvatar).isEqualTo("You changed your avatar") assertThat(youRemovedAvatar).isEqualTo("You changed your avatar")
val someoneRemovedAvatarEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent) val someoneRemovedAvatarEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent)
val someoneRemovedAvatar = formatter.format(someoneRemovedAvatarEvent, false) val someoneRemovedAvatar = formatter.format(someoneRemovedAvatarEvent, false)
assertThat(someoneRemovedAvatar).isEqualTo("$otherName changed their avatar") assertThat(someoneRemovedAvatar).isEqualTo("$otherName changed their avatar")
val unchangedEvent = createRoomEvent(sentByYou = true, senderDisplayName = otherName, content = sameContent) val unchangedEvent = createLatestEvent(sentByYou = true, senderDisplayName = otherName, content = sameContent)
val unchangedResult = formatter.format(unchangedEvent, false) val unchangedResult = formatter.format(unchangedEvent, false)
assertThat(unchangedResult).isNull() assertThat(unchangedResult).isNull()
val invalidEvent = createRoomEvent(sentByYou = true, senderDisplayName = otherName, content = invalidContent) val invalidEvent = createLatestEvent(sentByYou = true, senderDisplayName = otherName, content = invalidContent)
val invalidResult = formatter.format(invalidEvent, false) val invalidResult = formatter.format(invalidEvent, false)
assertThat(invalidResult).isNull() assertThat(invalidResult).isNull()
} }
@ -825,35 +825,35 @@ class DefaultBaseRoomLastMessageFormatterTest {
val sameContent = aProfileChangeMessageContent(displayName = newDisplayName, prevDisplayName = newDisplayName) val sameContent = aProfileChangeMessageContent(displayName = newDisplayName, prevDisplayName = newDisplayName)
val invalidContent = aProfileChangeMessageContent(displayName = null, prevDisplayName = null) val invalidContent = aProfileChangeMessageContent(displayName = null, prevDisplayName = null)
val youChangedDisplayNameEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = changedContent) val youChangedDisplayNameEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = changedContent)
val youChangedDisplayName = formatter.format(youChangedDisplayNameEvent, false) val youChangedDisplayName = formatter.format(youChangedDisplayNameEvent, false)
assertThat(youChangedDisplayName).isEqualTo("You changed your display name from $oldDisplayName to $newDisplayName") assertThat(youChangedDisplayName).isEqualTo("You changed your display name from $oldDisplayName to $newDisplayName")
val someoneChangedDisplayNameEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent) val someoneChangedDisplayNameEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = changedContent)
val someoneChangedDisplayName = formatter.format(someoneChangedDisplayNameEvent, false) val someoneChangedDisplayName = formatter.format(someoneChangedDisplayNameEvent, false)
assertThat(someoneChangedDisplayName).isEqualTo("$someoneElseId changed their display name from $oldDisplayName to $newDisplayName") assertThat(someoneChangedDisplayName).isEqualTo("$someoneElseId changed their display name from $oldDisplayName to $newDisplayName")
val youSetDisplayNameEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = setContent) val youSetDisplayNameEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = setContent)
val youSetDisplayName = formatter.format(youSetDisplayNameEvent, false) val youSetDisplayName = formatter.format(youSetDisplayNameEvent, false)
assertThat(youSetDisplayName).isEqualTo("You set your display name to $newDisplayName") assertThat(youSetDisplayName).isEqualTo("You set your display name to $newDisplayName")
val someoneSetDisplayNameEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = setContent) val someoneSetDisplayNameEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = setContent)
val someoneSetDisplayName = formatter.format(someoneSetDisplayNameEvent, false) val someoneSetDisplayName = formatter.format(someoneSetDisplayNameEvent, false)
assertThat(someoneSetDisplayName).isEqualTo("$someoneElseId set their display name to $newDisplayName") assertThat(someoneSetDisplayName).isEqualTo("$someoneElseId set their display name to $newDisplayName")
val youRemovedDisplayNameEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = removedContent) val youRemovedDisplayNameEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = removedContent)
val youRemovedDisplayName = formatter.format(youRemovedDisplayNameEvent, false) val youRemovedDisplayName = formatter.format(youRemovedDisplayNameEvent, false)
assertThat(youRemovedDisplayName).isEqualTo("You removed your display name (it was $oldDisplayName)") assertThat(youRemovedDisplayName).isEqualTo("You removed your display name (it was $oldDisplayName)")
val someoneRemovedDisplayNameEvent = createRoomEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent) val someoneRemovedDisplayNameEvent = createLatestEvent(sentByYou = false, senderDisplayName = otherName, content = removedContent)
val someoneRemovedDisplayName = formatter.format(someoneRemovedDisplayNameEvent, false) val someoneRemovedDisplayName = formatter.format(someoneRemovedDisplayNameEvent, false)
assertThat(someoneRemovedDisplayName).isEqualTo("$someoneElseId removed their display name (it was $oldDisplayName)") assertThat(someoneRemovedDisplayName).isEqualTo("$someoneElseId removed their display name (it was $oldDisplayName)")
val unchangedEvent = createRoomEvent(sentByYou = true, senderDisplayName = otherName, content = sameContent) val unchangedEvent = createLatestEvent(sentByYou = true, senderDisplayName = otherName, content = sameContent)
val unchangedResult = formatter.format(unchangedEvent, false) val unchangedResult = formatter.format(unchangedEvent, false)
assertThat(unchangedResult).isNull() assertThat(unchangedResult).isNull()
val invalidEvent = createRoomEvent(sentByYou = true, senderDisplayName = otherName, content = invalidContent) val invalidEvent = createLatestEvent(sentByYou = true, senderDisplayName = otherName, content = invalidContent)
val invalidResult = formatter.format(invalidEvent, false) val invalidResult = formatter.format(invalidEvent, false)
assertThat(invalidResult).isNull() assertThat(invalidResult).isNull()
} }
@ -882,15 +882,15 @@ class DefaultBaseRoomLastMessageFormatterTest {
prevAvatarUrl = "same_avatar_url", prevAvatarUrl = "same_avatar_url",
) )
val youChangedBothEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = changedContent) val youChangedBothEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = changedContent)
val youChangedBoth = formatter.format(youChangedBothEvent, false) val youChangedBoth = formatter.format(youChangedBothEvent, false)
assertThat(youChangedBoth).isEqualTo("You changed your display name from $oldDisplayName to $newDisplayName\n(avatar was changed too)") assertThat(youChangedBoth).isEqualTo("You changed your display name from $oldDisplayName to $newDisplayName\n(avatar was changed too)")
val invalidContentEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = invalidContent) val invalidContentEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = invalidContent)
val invalidMessage = formatter.format(invalidContentEvent, false) val invalidMessage = formatter.format(invalidContentEvent, false)
assertThat(invalidMessage).isNull() assertThat(invalidMessage).isNull()
val sameContentEvent = createRoomEvent(sentByYou = true, senderDisplayName = null, content = sameContent) val sameContentEvent = createLatestEvent(sentByYou = true, senderDisplayName = null, content = sameContent)
val sameMessage = formatter.format(sameContentEvent, false) val sameMessage = formatter.format(sameContentEvent, false)
assertThat(sameMessage).isNull() assertThat(sameMessage).isNull()
} }
@ -904,10 +904,10 @@ class DefaultBaseRoomLastMessageFormatterTest {
fun `Computes last message for poll in DM`() { fun `Computes last message for poll in DM`() {
val pollContent = aPollContent() val pollContent = aPollContent()
val mineContentEvent = createRoomEvent(sentByYou = true, senderDisplayName = "Alice", content = pollContent) val mineContentEvent = createLatestEvent(sentByYou = true, senderDisplayName = "Alice", content = pollContent)
assertThat(formatter.format(mineContentEvent, true)).isEqualTo("Poll: Do you like polls?") assertThat(formatter.format(mineContentEvent, true)).isEqualTo("Poll: Do you like polls?")
val contentEvent = createRoomEvent(sentByYou = false, senderDisplayName = "Bob", content = pollContent) val contentEvent = createLatestEvent(sentByYou = false, senderDisplayName = "Bob", content = pollContent)
assertThat(formatter.format(contentEvent, true)).isEqualTo("Poll: Do you like polls?") assertThat(formatter.format(contentEvent, true)).isEqualTo("Poll: Do you like polls?")
} }
@ -916,26 +916,26 @@ class DefaultBaseRoomLastMessageFormatterTest {
fun `Computes last message for poll in room`() { fun `Computes last message for poll in room`() {
val pollContent = aPollContent() val pollContent = aPollContent()
val mineContentEvent = createRoomEvent(sentByYou = true, senderDisplayName = "Alice", content = pollContent) val mineContentEvent = createLatestEvent(sentByYou = true, senderDisplayName = "Alice", content = pollContent)
assertThat(formatter.format(mineContentEvent, false).toString()).isEqualTo("You: Poll: Do you like polls?") assertThat(formatter.format(mineContentEvent, false).toString()).isEqualTo("You: Poll: Do you like polls?")
val contentEvent = createRoomEvent(sentByYou = false, senderDisplayName = "Bob", content = pollContent) val contentEvent = createLatestEvent(sentByYou = false, senderDisplayName = "Bob", content = pollContent)
assertThat(formatter.format(contentEvent, false).toString()).isEqualTo("Bob: Poll: Do you like polls?") assertThat(formatter.format(contentEvent, false).toString()).isEqualTo("Bob: Poll: Do you like polls?")
} }
// endregion // endregion
private fun createRoomEvent( private fun createLatestEvent(
sentByYou: Boolean, sentByYou: Boolean,
senderDisplayName: String?, senderDisplayName: String?,
content: EventContent, content: EventContent,
): EventTimelineItem { ): LatestEventValue {
val sender = if (sentByYou) A_USER_ID else someoneElseId val sender = if (sentByYou) A_USER_ID else someoneElseId
val profile = aProfileTimelineDetails(senderDisplayName) val profile = aProfileDetails(senderDisplayName)
return anEventTimelineItem( return aRemoteLatestEvent(
content = content, senderId = sender,
senderProfile = profile, senderProfile = profile,
sender = sender, content = content,
isOwn = sentByYou, isOwn = sentByYou,
) )
} }

View file

@ -8,13 +8,13 @@
package io.element.android.libraries.eventformatter.test package io.element.android.libraries.eventformatter.test
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter import io.element.android.libraries.eventformatter.api.RoomLatestEventFormatter
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem import io.element.android.libraries.matrix.api.roomlist.LatestEventValue
class FakeRoomLastMessageFormatter : RoomLastMessageFormatter { class FakeRoomLatestEventFormatter : RoomLatestEventFormatter {
private var result: CharSequence? = null private var result: CharSequence? = null
override fun format(event: EventTimelineItem, isDmRoom: Boolean): CharSequence? { override fun format(latestEvent: LatestEventValue, isDmRoom: Boolean): CharSequence? {
return result return result
} }

View file

@ -1,20 +0,0 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.api.room.message
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
data class RoomMessage(
val eventId: EventId,
val event: EventTimelineItem,
val sender: UserId,
val originServerTs: Long,
)

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2025 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.libraries.matrix.api.roomlist
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
sealed interface LatestEventValue {
data object None : LatestEventValue
data class Remote(
val timestamp: Long,
val content: EventContent,
val senderId: UserId,
val senderProfile: ProfileDetails,
val isOwn: Boolean,
) : LatestEventValue
data class Local(
val timestamp: Long,
val content: EventContent,
val senderId: UserId,
val senderProfile: ProfileDetails,
val isSending: Boolean,
) : LatestEventValue
}

View file

@ -9,13 +9,16 @@
package io.element.android.libraries.matrix.api.roomlist package io.element.android.libraries.matrix.api.roomlist
import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.RoomInfo
import io.element.android.libraries.matrix.api.room.message.RoomMessage
data class RoomSummary( data class RoomSummary(
val info: RoomInfo, val info: RoomInfo,
val lastMessage: RoomMessage?, val latestEvent: LatestEventValue,
) { ) {
val roomId = info.id val roomId = info.id
val lastMessageTimestamp = lastMessage?.originServerTs val latestEventTimestamp = when (latestEvent) {
is LatestEventValue.None -> null
is LatestEventValue.Local -> latestEvent.timestamp
is LatestEventValue.Remote -> latestEvent.timestamp
}
val isOneToOne get() = info.activeMembersCount == 2L val isOneToOne get() = info.activeMembersCount == 2L
} }

View file

@ -13,7 +13,7 @@ import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
sealed interface EventThreadInfo { sealed interface EventThreadInfo {
data class ThreadRoot(val summary: ThreadSummary) : EventThreadInfo data class ThreadRoot(val summary: ThreadSummary) : EventThreadInfo
@ -29,6 +29,6 @@ data class EmbeddedEventInfo(
val eventOrTransactionId: EventOrTransactionId, val eventOrTransactionId: EventOrTransactionId,
val content: EventContent, val content: EventContent,
val senderId: UserId, val senderId: UserId,
val senderProfile: ProfileTimelineDetails, val senderProfile: ProfileDetails,
val timestamp: Long, val timestamp: Long,
) )

View file

@ -27,7 +27,7 @@ data class EventTimelineItem(
val reactions: ImmutableList<EventReaction>, val reactions: ImmutableList<EventReaction>,
val receipts: ImmutableList<Receipt>, val receipts: ImmutableList<Receipt>,
val sender: UserId, val sender: UserId,
val senderProfile: ProfileTimelineDetails, val senderProfile: ProfileDetails,
val timestamp: Long, val timestamp: Long,
val content: EventContent, val content: EventContent,
val origin: TimelineItemEventOrigin?, val origin: TimelineItemEventOrigin?,

View file

@ -25,7 +25,7 @@ sealed interface InReplyTo {
val eventId: EventId, val eventId: EventId,
val content: EventContent, val content: EventContent,
val senderId: UserId, val senderId: UserId,
val senderProfile: ProfileTimelineDetails, val senderProfile: ProfileDetails,
) : InReplyTo ) : InReplyTo
/** /**

View file

@ -12,20 +12,20 @@ import androidx.compose.runtime.Immutable
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
@Immutable @Immutable
sealed interface ProfileTimelineDetails { sealed interface ProfileDetails {
data object Unavailable : ProfileTimelineDetails data object Unavailable : ProfileDetails
data object Pending : ProfileTimelineDetails data object Pending : ProfileDetails
data class Ready( data class Ready(
val displayName: String?, val displayName: String?,
val displayNameAmbiguous: Boolean, val displayNameAmbiguous: Boolean,
val avatarUrl: String? val avatarUrl: String?
) : ProfileTimelineDetails ) : ProfileDetails
data class Error( data class Error(
val message: String val message: String
) : ProfileTimelineDetails ) : ProfileDetails
} }
/** /**
@ -34,9 +34,9 @@ sealed interface ProfileTimelineDetails {
* If the display name is ambiguous, the user ID is appended in parentheses. * If the display name is ambiguous, the user ID is appended in parentheses.
* Otherwise, the display name is returned. * Otherwise, the display name is returned.
*/ */
fun ProfileTimelineDetails.getDisambiguatedDisplayName(userId: UserId): String { fun ProfileDetails.getDisambiguatedDisplayName(userId: UserId): String {
return when (this) { return when (this) {
is ProfileTimelineDetails.Ready -> when { is ProfileDetails.Ready -> when {
displayName == null -> userId.value displayName == null -> userId.value
displayNameAmbiguous -> "$displayName ($userId)" displayNameAmbiguous -> "$displayName ($userId)"
else -> displayName else -> displayName
@ -45,16 +45,16 @@ fun ProfileTimelineDetails.getDisambiguatedDisplayName(userId: UserId): String {
} }
} }
fun ProfileTimelineDetails.getDisplayName(): String? { fun ProfileDetails.getDisplayName(): String? {
return when (this) { return when (this) {
is ProfileTimelineDetails.Ready -> displayName is ProfileDetails.Ready -> displayName
else -> null else -> null
} }
} }
fun ProfileTimelineDetails.getAvatarUrl(): String? { fun ProfileDetails.getAvatarUrl(): String? {
return when (this) { return when (this) {
is ProfileTimelineDetails.Ready -> avatarUrl is ProfileDetails.Ready -> avatarUrl
else -> null else -> null
} }
} }

View file

@ -18,23 +18,23 @@ private val aUserId = UserId(A_USER_ID)
class ProfileTimelineDetailsTest { class ProfileTimelineDetailsTest {
@Test @Test
fun `getDisambiguatedDisplayName of Unavailable should be equal to userId`() { fun `getDisambiguatedDisplayName of Unavailable should be equal to userId`() {
assertThat(ProfileTimelineDetails.Unavailable.getDisambiguatedDisplayName(aUserId)).isEqualTo(A_USER_ID) assertThat(ProfileDetails.Unavailable.getDisambiguatedDisplayName(aUserId)).isEqualTo(A_USER_ID)
} }
@Test @Test
fun `getDisambiguatedDisplayName of Error should be equal to userId`() { fun `getDisambiguatedDisplayName of Error should be equal to userId`() {
assertThat(ProfileTimelineDetails.Error("An error").getDisambiguatedDisplayName(aUserId)).isEqualTo(A_USER_ID) assertThat(ProfileDetails.Error("An error").getDisambiguatedDisplayName(aUserId)).isEqualTo(A_USER_ID)
} }
@Test @Test
fun `getDisambiguatedDisplayName of Pending should be equal to userId`() { fun `getDisambiguatedDisplayName of Pending should be equal to userId`() {
assertThat(ProfileTimelineDetails.Pending.getDisambiguatedDisplayName(aUserId)).isEqualTo(A_USER_ID) assertThat(ProfileDetails.Pending.getDisambiguatedDisplayName(aUserId)).isEqualTo(A_USER_ID)
} }
@Test @Test
fun `getDisambiguatedDisplayName of Ready without display name should be equal to userId`() { fun `getDisambiguatedDisplayName of Ready without display name should be equal to userId`() {
assertThat( assertThat(
ProfileTimelineDetails.Ready( ProfileDetails.Ready(
displayName = null, displayName = null,
displayNameAmbiguous = false, displayNameAmbiguous = false,
avatarUrl = null, avatarUrl = null,
@ -45,7 +45,7 @@ class ProfileTimelineDetailsTest {
@Test @Test
fun `getDisambiguatedDisplayName of Ready with display name should be equal to display name`() { fun `getDisambiguatedDisplayName of Ready with display name should be equal to display name`() {
assertThat( assertThat(
ProfileTimelineDetails.Ready( ProfileDetails.Ready(
displayName = "Alice", displayName = "Alice",
displayNameAmbiguous = false, displayNameAmbiguous = false,
avatarUrl = null, avatarUrl = null,
@ -56,7 +56,7 @@ class ProfileTimelineDetailsTest {
@Test @Test
fun `getDisambiguatedDisplayName of Ready with display name and ambiguous should be equal to display name with user id`() { fun `getDisambiguatedDisplayName of Ready with display name and ambiguous should be equal to display name with user id`() {
assertThat( assertThat(
ProfileTimelineDetails.Ready( ProfileDetails.Ready(
displayName = "Alice", displayName = "Alice",
displayNameAmbiguous = true, displayNameAmbiguous = true,
avatarUrl = null, avatarUrl = null,

View file

@ -1,28 +0,0 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.impl.room.message
import io.element.android.libraries.matrix.api.room.message.RoomMessage
import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper
import org.matrix.rustcomponents.sdk.EventTimelineItem as RustEventTimelineItem
class RoomMessageFactory(
private val eventTimelineItemMapper: EventTimelineItemMapper = EventTimelineItemMapper(),
) {
fun create(eventTimelineItem: RustEventTimelineItem?): RoomMessage? {
eventTimelineItem ?: return null
val mappedTimelineItem = eventTimelineItemMapper.map(eventTimelineItem)
return RoomMessage(
eventId = mappedTimelineItem.eventId ?: return null,
event = mappedTimelineItem,
sender = mappedTimelineItem.sender,
originServerTs = mappedTimelineItem.timestamp,
)
}
}

View file

@ -40,7 +40,7 @@ internal class RoomListFactory(
private val sessionCoroutineScope: CoroutineScope, private val sessionCoroutineScope: CoroutineScope,
private val analyticsService: AnalyticsService, private val analyticsService: AnalyticsService,
) { ) {
private val roomSummaryDetailsFactory: RoomSummaryFactory = RoomSummaryFactory() private val roomSummaryFactory: RoomSummaryFactory = RoomSummaryFactory()
/** /**
* Creates a room list that can be used to load more rooms and filter them dynamically. * Creates a room list that can be used to load more rooms and filter them dynamically.
@ -55,7 +55,7 @@ internal class RoomListFactory(
val loadingStateFlow: MutableStateFlow<RoomList.LoadingState> = MutableStateFlow(RoomList.LoadingState.NotLoaded) val loadingStateFlow: MutableStateFlow<RoomList.LoadingState> = MutableStateFlow(RoomList.LoadingState.NotLoaded)
val filteredSummariesFlow = MutableSharedFlow<List<RoomSummary>>(replay = 1, extraBufferCapacity = 1) val filteredSummariesFlow = MutableSharedFlow<List<RoomSummary>>(replay = 1, extraBufferCapacity = 1)
val summariesFlow = MutableSharedFlow<List<RoomSummary>>(replay = 1, extraBufferCapacity = 1) val summariesFlow = MutableSharedFlow<List<RoomSummary>>(replay = 1, extraBufferCapacity = 1)
val processor = RoomSummaryListProcessor(summariesFlow, innerRoomListService, coroutineContext, roomSummaryDetailsFactory) val processor = RoomSummaryListProcessor(summariesFlow, innerRoomListService, coroutineContext, roomSummaryFactory)
// Makes sure we don't miss any events // Makes sure we don't miss any events
val dynamicEvents = MutableSharedFlow<RoomListDynamicEvents>(replay = 100) val dynamicEvents = MutableSharedFlow<RoomListDynamicEvents>(replay = 100)
val currentFilter = MutableStateFlow(initialFilter) val currentFilter = MutableStateFlow(initialFilter)

View file

@ -8,24 +8,44 @@
package io.element.android.libraries.matrix.impl.roomlist package io.element.android.libraries.matrix.impl.roomlist
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.roomlist.LatestEventValue
import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.impl.room.RoomInfoMapper import io.element.android.libraries.matrix.impl.room.RoomInfoMapper
import io.element.android.libraries.matrix.impl.room.message.RoomMessageFactory import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper
import io.element.android.libraries.matrix.impl.timeline.item.event.map
import org.matrix.rustcomponents.sdk.Room import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.use import org.matrix.rustcomponents.sdk.use
import org.matrix.rustcomponents.sdk.LatestEventValue as RustLatestEventValue
class RoomSummaryFactory( class RoomSummaryFactory(
private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory(), private val contentMapper: TimelineEventContentMapper = TimelineEventContentMapper(),
private val roomInfoMapper: RoomInfoMapper = RoomInfoMapper(), private val roomInfoMapper: RoomInfoMapper = RoomInfoMapper(),
) { ) {
suspend fun create(room: Room): RoomSummary { suspend fun create(room: Room): RoomSummary {
val roomInfo = room.roomInfo().let(roomInfoMapper::map) val roomInfo = room.roomInfo().let(roomInfoMapper::map)
val latestRoomMessage = room.latestEvent().use { event -> val latestEvent = room.newLatestEvent().use { event ->
roomMessageFactory.create(event) when (event) {
is RustLatestEventValue.None -> LatestEventValue.None
is RustLatestEventValue.Local -> LatestEventValue.Local(
timestamp = event.timestamp.toLong(),
content = contentMapper.map(event.content),
isSending = event.isSending,
senderId = UserId(event.sender),
senderProfile = event.profile.map(),
)
is RustLatestEventValue.Remote -> LatestEventValue.Remote(
timestamp = event.timestamp.toLong(),
content = contentMapper.map(event.content),
senderId = UserId(event.sender),
senderProfile = event.profile.map(),
isOwn = event.isOwn,
)
}
} }
return RoomSummary( return RoomSummary(
info = roomInfo, info = roomInfo,
lastMessage = latestRoomMessage, latestEvent = latestEvent,
) )
} }
} }

View file

@ -24,7 +24,7 @@ class RoomSummaryListProcessor(
private val roomSummaries: MutableSharedFlow<List<RoomSummary>>, private val roomSummaries: MutableSharedFlow<List<RoomSummary>>,
private val roomListService: RoomListServiceInterface, private val roomListService: RoomListServiceInterface,
private val coroutineContext: CoroutineContext, private val coroutineContext: CoroutineContext,
private val roomSummaryDetailsFactory: RoomSummaryFactory = RoomSummaryFactory(), private val roomSummaryFactory: RoomSummaryFactory,
) { ) {
private val mutex = Mutex() private val mutex = Mutex()
@ -103,7 +103,7 @@ class RoomSummaryListProcessor(
} }
private suspend fun buildSummaryForRoomListEntry(entry: Room): RoomSummary { private suspend fun buildSummaryForRoomListEntry(entry: Room): RoomSummary {
return entry.use { roomSummaryDetailsFactory.create(room = it) } return entry.use { roomSummaryFactory.create(room = it) }
} }
private suspend fun buildRoomSummaryForIdentifier(identifier: String): RoomSummary? { private suspend fun buildRoomSummaryForIdentifier(identifier: String): RoomSummary? {

View file

@ -17,7 +17,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
import io.element.android.libraries.matrix.api.timeline.item.event.ReactionSender import io.element.android.libraries.matrix.api.timeline.item.event.ReactionSender
import io.element.android.libraries.matrix.api.timeline.item.event.Receipt import io.element.android.libraries.matrix.api.timeline.item.event.Receipt
import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin
@ -64,12 +64,12 @@ class EventTimelineItemMapper(
} }
} }
fun RustProfileDetails.map(): ProfileTimelineDetails { fun RustProfileDetails.map(): ProfileDetails {
return when (this) { return when (this) {
RustProfileDetails.Pending -> ProfileTimelineDetails.Pending RustProfileDetails.Pending -> ProfileDetails.Pending
RustProfileDetails.Unavailable -> ProfileTimelineDetails.Unavailable RustProfileDetails.Unavailable -> ProfileDetails.Unavailable
is RustProfileDetails.Error -> ProfileTimelineDetails.Error(message) is RustProfileDetails.Error -> ProfileDetails.Error(message)
is RustProfileDetails.Ready -> ProfileTimelineDetails.Ready( is RustProfileDetails.Ready -> ProfileDetails.Ready(
displayName = displayName, displayName = displayName,
displayNameAmbiguous = displayNameAmbiguous, displayNameAmbiguous = displayNameAmbiguous,
avatarUrl = avatarUrl avatarUrl = avatarUrl

View file

@ -192,6 +192,6 @@ class RoomSummaryListProcessorTest {
summaries, summaries,
FakeFfiRoomListService(), FakeFfiRoomListService(),
coroutineContext = StandardTestDispatcher(testScheduler), coroutineContext = StandardTestDispatcher(testScheduler),
roomSummaryDetailsFactory = RoomSummaryFactory(), roomSummaryFactory = RoomSummaryFactory(),
) )
} }

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2025 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.libraries.matrix.test.room
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.roomlist.LatestEventValue
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.timeline.aMessageContent
import io.element.android.libraries.matrix.test.timeline.aProfileDetails
fun aRemoteLatestEvent(
content: EventContent = aMessageContent(),
timestamp: Long = 0L,
isOwn: Boolean = false,
senderId: UserId = A_USER_ID,
senderProfile: ProfileDetails = aProfileDetails(),
): LatestEventValue.Remote {
return LatestEventValue.Remote(
timestamp = timestamp,
content = content,
senderId = senderId,
senderProfile = senderProfile,
isOwn = isOwn,
)
}
fun aLocalLatestEvent(
content: EventContent = aMessageContent(),
timestamp: Long = 0L,
isSending: Boolean = false,
senderId: UserId = A_USER_ID,
senderProfile: ProfileDetails = aProfileDetails(),
): LatestEventValue.Local {
return LatestEventValue.Local(
timestamp = timestamp,
content = content,
senderId = senderId,
senderProfile = senderProfile,
isSending = isSending,
)
}

View file

@ -18,28 +18,24 @@ import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.room.message.RoomMessage
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
import io.element.android.libraries.matrix.api.roomlist.LatestEventValue
import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.A_ROOM_RAW_NAME import io.element.android.libraries.matrix.test.A_ROOM_RAW_NAME
import io.element.android.libraries.matrix.test.A_ROOM_TOPIC import io.element.android.libraries.matrix.test.A_ROOM_TOPIC
import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
fun aRoomSummary( fun aRoomSummary(
info: RoomInfo = aRoomInfo(), info: RoomInfo = aRoomInfo(),
lastMessage: RoomMessage? = aRoomMessage(), latestEventValue: LatestEventValue = aRemoteLatestEvent(),
) = RoomSummary( ) = RoomSummary(
info = info, info = info,
lastMessage = lastMessage, latestEvent = latestEventValue,
) )
fun aRoomSummary( fun aRoomSummary(
@ -79,7 +75,7 @@ fun aRoomSummary(
numUnreadNotifications: Long = 0, numUnreadNotifications: Long = 0,
numUnreadMentions: Long = 0, numUnreadMentions: Long = 0,
historyVisibility: RoomHistoryVisibility = RoomHistoryVisibility.Joined, historyVisibility: RoomHistoryVisibility = RoomHistoryVisibility.Joined,
lastMessage: RoomMessage? = aRoomMessage(), latestEvent: LatestEventValue = aRemoteLatestEvent(),
roomVersion: String? = "11", roomVersion: String? = "11",
privilegedCreatorRole: Boolean = false, privilegedCreatorRole: Boolean = false,
) = RoomSummary( ) = RoomSummary(
@ -120,17 +116,5 @@ fun aRoomSummary(
roomVersion = roomVersion, roomVersion = roomVersion,
privilegedCreatorRole = privilegedCreatorRole, privilegedCreatorRole = privilegedCreatorRole,
), ),
lastMessage = lastMessage, latestEvent = latestEvent,
)
fun aRoomMessage(
eventId: EventId = AN_EVENT_ID,
event: EventTimelineItem = anEventTimelineItem(),
userId: UserId = A_USER_ID,
timestamp: Long = 0L,
) = RoomMessage(
eventId = eventId,
event = event,
sender = userId,
originServerTs = timestamp,
) )

View file

@ -27,7 +27,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield
import io.element.android.libraries.matrix.api.timeline.item.event.MessageType import io.element.android.libraries.matrix.api.timeline.item.event.MessageType
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent 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.ProfileDetails
import io.element.android.libraries.matrix.api.timeline.item.event.Receipt import io.element.android.libraries.matrix.api.timeline.item.event.Receipt
import io.element.android.libraries.matrix.api.timeline.item.event.SendHandleProvider import io.element.android.libraries.matrix.api.timeline.item.event.SendHandleProvider
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
@ -53,7 +53,7 @@ fun anEventTimelineItem(
reactions: ImmutableList<EventReaction> = persistentListOf(), reactions: ImmutableList<EventReaction> = persistentListOf(),
receipts: ImmutableList<Receipt> = persistentListOf(), receipts: ImmutableList<Receipt> = persistentListOf(),
sender: UserId = A_USER_ID, sender: UserId = A_USER_ID,
senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(), senderProfile: ProfileDetails = aProfileDetails(),
timestamp: Long = 0L, timestamp: Long = 0L,
content: EventContent = aProfileChangeMessageContent(), content: EventContent = aProfileChangeMessageContent(),
debugInfoProvider: TimelineItemDebugInfoProvider = TimelineItemDebugInfoProvider { aTimelineItemDebugInfo() }, debugInfoProvider: TimelineItemDebugInfoProvider = TimelineItemDebugInfoProvider { aTimelineItemDebugInfo() },
@ -79,11 +79,11 @@ fun anEventTimelineItem(
sendHandleProvider = sendHandleProvider, sendHandleProvider = sendHandleProvider,
) )
fun aProfileTimelineDetails( fun aProfileDetails(
displayName: String? = A_USER_NAME, displayName: String? = A_USER_NAME,
displayNameAmbiguous: Boolean = false, displayNameAmbiguous: Boolean = false,
avatarUrl: String? = null avatarUrl: String? = null
): ProfileTimelineDetails = ProfileTimelineDetails.Ready( ): ProfileDetails = ProfileDetails.Ready(
displayName = displayName, displayName = displayName,
displayNameAmbiguous = displayNameAmbiguous, displayNameAmbiguous = displayNameAmbiguous,
avatarUrl = avatarUrl, avatarUrl = avatarUrl,

View file

@ -15,7 +15,7 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkParser
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
import io.element.android.libraries.matrix.ui.messages.toPlainText import io.element.android.libraries.matrix.ui.messages.toPlainText
@ -25,7 +25,7 @@ sealed interface InReplyToDetails {
data class Ready( data class Ready(
val eventId: EventId, val eventId: EventId,
val senderId: UserId, val senderId: UserId,
val senderProfile: ProfileTimelineDetails, val senderProfile: ProfileDetails,
val eventContent: EventContent?, val eventContent: EventContent?,
val textContent: String?, val textContent: String?,
) : InReplyToDetails ) : InReplyToDetails

View file

@ -24,7 +24,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.MessageConten
import io.element.android.libraries.matrix.api.timeline.item.event.MessageType import io.element.android.libraries.matrix.api.timeline.item.event.MessageType
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
@ -161,7 +161,7 @@ fun aProfileTimelineDetailsReady(
displayName: String? = "Sender", displayName: String? = "Sender",
displayNameAmbiguous: Boolean = false, displayNameAmbiguous: Boolean = false,
avatarUrl: String? = null, avatarUrl: String? = null,
) = ProfileTimelineDetails.Ready( ) = ProfileDetails.Ready(
displayName = displayName, displayName = displayName,
displayNameAmbiguous = displayNameAmbiguous, displayNameAmbiguous = displayNameAmbiguous,
avatarUrl = avatarUrl, avatarUrl = avatarUrl,

View file

@ -42,7 +42,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnail import io.element.android.libraries.matrix.ui.components.AttachmentThumbnail
import io.element.android.libraries.matrix.ui.messages.sender.SenderName import io.element.android.libraries.matrix.ui.messages.sender.SenderName
@ -74,7 +74,7 @@ fun InReplyToView(
@Composable @Composable
private fun ReplyToReadyContent( private fun ReplyToReadyContent(
senderId: UserId, senderId: UserId,
senderProfile: ProfileTimelineDetails, senderProfile: ProfileDetails,
metadata: InReplyToMetadata?, metadata: InReplyToMetadata?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {

View file

@ -23,13 +23,13 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
// https://www.figma.com/file/Ni6Ii8YKtmXCKYNE90cC67/Timeline-(new)?type=design&node-id=917-80169&mode=design&t=A0CJCBbMqR8NOwUQ-0 // https://www.figma.com/file/Ni6Ii8YKtmXCKYNE90cC67/Timeline-(new)?type=design&node-id=917-80169&mode=design&t=A0CJCBbMqR8NOwUQ-0
@Composable @Composable
fun SenderName( fun SenderName(
senderId: UserId, senderId: UserId,
senderProfile: ProfileTimelineDetails, senderProfile: ProfileDetails,
senderNameMode: SenderNameMode, senderNameMode: SenderNameMode,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@ -39,12 +39,12 @@ fun SenderName(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
when (senderProfile) { when (senderProfile) {
is ProfileTimelineDetails.Error, is ProfileDetails.Error,
ProfileTimelineDetails.Pending, ProfileDetails.Pending,
ProfileTimelineDetails.Unavailable -> { ProfileDetails.Unavailable -> {
MainText(text = senderId.value, mode = senderNameMode) MainText(text = senderId.value, mode = senderNameMode)
} }
is ProfileTimelineDetails.Ready -> { is ProfileDetails.Ready -> {
val displayName = senderProfile.displayName val displayName = senderProfile.displayName
if (displayName.isNullOrEmpty()) { if (displayName.isNullOrEmpty()) {
MainText(text = senderId.value, mode = senderNameMode) MainText(text = senderId.value, mode = senderNameMode)
@ -121,7 +121,7 @@ internal fun SenderNamePreview(
) = ElementPreview { ) = ElementPreview {
SenderName( SenderName(
senderId = senderNameData.userId, senderId = senderNameData.userId,
senderProfile = senderNameData.profileTimelineDetails, senderProfile = senderNameData.profileDetails,
senderNameMode = senderNameData.senderNameMode, senderNameMode = senderNameData.senderNameMode,
) )
} }

View file

@ -11,11 +11,11 @@ package io.element.android.libraries.matrix.ui.messages.sender
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
data class SenderNameData( data class SenderNameData(
val userId: UserId, val userId: UserId,
val profileTimelineDetails: ProfileTimelineDetails, val profileDetails: ProfileDetails,
val senderNameMode: SenderNameMode, val senderNameMode: SenderNameMode,
) )
@ -38,7 +38,7 @@ open class SenderNameDataProvider : PreviewParameterProvider<SenderNameData> {
SenderNameData( SenderNameData(
senderNameMode = senderNameMode, senderNameMode = senderNameMode,
userId = UserId("@alice:${senderNameMode.javaClass.simpleName.lowercase()}"), userId = UserId("@alice:${senderNameMode.javaClass.simpleName.lowercase()}"),
profileTimelineDetails = ProfileTimelineDetails.Unavailable, profileDetails = ProfileDetails.Unavailable,
), ),
) )
} }
@ -49,7 +49,7 @@ private fun aSenderNameData(
displayNameAmbiguous: Boolean = false, displayNameAmbiguous: Boolean = false,
) = SenderNameData( ) = SenderNameData(
userId = UserId("@alice:${senderNameMode.javaClass.simpleName.lowercase()}"), userId = UserId("@alice:${senderNameMode.javaClass.simpleName.lowercase()}"),
profileTimelineDetails = ProfileTimelineDetails.Ready( profileDetails = ProfileDetails.Ready(
displayName = "Alice ${senderNameMode.javaClass.simpleName}", displayName = "Alice ${senderNameMode.javaClass.simpleName}",
displayNameAmbiguous = displayNameAmbiguous, displayNameAmbiguous = displayNameAmbiguous,
avatarUrl = null avatarUrl = null

View file

@ -18,7 +18,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageTy
import io.element.android.libraries.matrix.test.AN_EVENT_ID 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.A_USER_ID
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser 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.aProfileDetails
import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent
import org.junit.Test import org.junit.Test
@ -47,7 +47,7 @@ class InReplyToDetailTest {
val inReplyTo = InReplyTo.Ready( val inReplyTo = InReplyTo.Ready(
eventId = AN_EVENT_ID, eventId = AN_EVENT_ID,
senderId = A_USER_ID, senderId = A_USER_ID,
senderProfile = aProfileTimelineDetails(), senderProfile = aProfileDetails(),
content = aRoomMembershipContent( content = aRoomMembershipContent(
userId = A_USER_ID, userId = A_USER_ID,
change = MembershipChange.INVITED, change = MembershipChange.INVITED,
@ -65,7 +65,7 @@ class InReplyToDetailTest {
val inReplyTo = InReplyTo.Ready( val inReplyTo = InReplyTo.Ready(
eventId = AN_EVENT_ID, eventId = AN_EVENT_ID,
senderId = A_USER_ID, senderId = A_USER_ID,
senderProfile = aProfileTimelineDetails(), senderProfile = aProfileDetails(),
content = MessageContent( content = MessageContent(
body = "**Hello!**", body = "**Hello!**",
inReplyTo = null, inReplyTo = null,
@ -90,7 +90,7 @@ class InReplyToDetailTest {
val inReplyTo = InReplyTo.Ready( val inReplyTo = InReplyTo.Ready(
eventId = AN_EVENT_ID, eventId = AN_EVENT_ID,
senderId = A_USER_ID, senderId = A_USER_ID,
senderProfile = aProfileTimelineDetails(), senderProfile = aProfileDetails(),
content = MessageContent( content = MessageContent(
body = "**Hello!**", body = "**Hello!**",
inReplyTo = null, inReplyTo = null,

View file

@ -29,7 +29,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageT
import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState 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.ProfileChangeContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent 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.StickerContent
@ -42,7 +42,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.media.aMediaSource 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.aMessageContent
import io.element.android.libraries.matrix.test.timeline.aPollContent 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.aProfileDetails
import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent 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.A_BLUR_HASH
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
@ -549,7 +549,7 @@ class InReplyToMetadataKtTest {
private fun anInReplyToDetailsReady( private fun anInReplyToDetailsReady(
eventId: EventId = AN_EVENT_ID, eventId: EventId = AN_EVENT_ID,
senderId: UserId = A_USER_ID, senderId: UserId = A_USER_ID,
senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(), senderProfile: ProfileDetails = aProfileDetails(),
eventContent: EventContent? = aMessageContent(), eventContent: EventContent? = aMessageContent(),
textContent: String? = "textContent", textContent: String? = "textContent",
) = InReplyToDetails.Ready( ) = InReplyToDetails.Ready(