diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt index e21794b46d..d191915972 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt @@ -47,7 +47,7 @@ open class JoinRoomStateProvider : PreviewParameterProvider { ), aJoinRoomState( contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin), - joinAction = AsyncAction.Failure(ClientException.Generic("Something went wrong")) + joinAction = AsyncAction.Failure(ClientException.Generic("Something went wrong", null)) ), aJoinRoomState( contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited(null)) diff --git a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt index 22f7796a5b..7d151e5530 100644 --- a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt +++ b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt @@ -250,7 +250,7 @@ class JoinRoomPresenterTest { val presenter = createJoinRoomPresenter( roomDescription = Optional.of(roomDescription), joinRoomLambda = { _, _, _ -> - Result.failure(ClientException.MatrixApi(ErrorKind.Forbidden, "403", "Forbidden")) + Result.failure(ClientException.MatrixApi(ErrorKind.Forbidden, "403", "Forbidden", null)) }, ) presenter.test { @@ -742,7 +742,7 @@ class JoinRoomPresenterTest { fun `present - when room is not known RoomPreview is loaded with error Forbidden`() = runTest { val client = FakeMatrixClient( getRoomPreviewResult = { _, _ -> - Result.failure(ClientException.MatrixApi(ErrorKind.Forbidden, "403", "Forbidden")) + Result.failure(ClientException.MatrixApi(ErrorKind.Forbidden, "403", "Forbidden", null)) } ) val presenter = createJoinRoomPresenter( diff --git a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverStateProvider.kt b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverStateProvider.kt index d629089cf8..49786b6436 100644 --- a/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverStateProvider.kt +++ b/features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverStateProvider.kt @@ -18,7 +18,7 @@ open class RoomAliasResolverStateProvider : PreviewParameterProvider { when (this) { - is RustClientException.Generic -> ClientException.Generic(msg) + is RustClientException.Generic -> ClientException.Generic(msg, details) is RustClientException.MatrixApi -> ClientException.MatrixApi( kind = kind.map(), code = code, - message = msg + message = msg, + details = details, ) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt index c4d2d3bc98..3a131e6a19 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt @@ -16,6 +16,7 @@ import io.element.android.libraries.matrix.impl.roomlist.roomOrNull import io.element.android.libraries.matrix.impl.timeline.runWithTimelineListenerRegistered import kotlinx.coroutines.CancellationException import kotlinx.coroutines.withTimeout +import org.matrix.rustcomponents.sdk.MsgLikeKind import org.matrix.rustcomponents.sdk.RoomListService import org.matrix.rustcomponents.sdk.Timeline import org.matrix.rustcomponents.sdk.TimelineItemContent @@ -42,7 +43,10 @@ class RoomContentForwarder( toRoomIds: List, timeoutMs: Long = 5000L ) { - val content = (fromTimeline.getEventTimelineItemByEventId(eventId.value).content as? TimelineItemContent.Message)?.content + val messageLikeContent = (fromTimeline.getEventTimelineItemByEventId(eventId.value).content as? TimelineItemContent.MsgLike)?.content + ?: throw ForwardEventException(toRoomIds) + + val content = (messageLikeContent.kind as? MsgLikeKind.Message)?.content ?: throw ForwardEventException(toRoomIds) val targetSlidingSyncRooms = toRoomIds.mapNotNull { roomId -> roomListService.roomOrNull(roomId.value) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomPreview.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomPreview.kt index 88c2836a06..44c294a707 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomPreview.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomPreview.kt @@ -48,8 +48,8 @@ class RustRoomPreview( override suspend fun membershipDetails(): Result = runCatching { val details = inner.ownMembershipDetails() ?: return@runCatching null RoomMembershipDetails( - currentUserMember = RoomMemberMapper.map(details.ownRoomMember), - senderMember = details.senderRoomMember?.let { RoomMemberMapper.map(it) }, + currentUserMember = RoomMemberMapper.map(details.roomMember), + senderMember = details.senderInfo?.let { RoomMemberMapper.map(it) }, ) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt index 8c2f8645b2..7cd12d0f38 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt @@ -23,24 +23,25 @@ import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageT import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType import io.element.android.libraries.matrix.impl.media.map import io.element.android.libraries.matrix.impl.timeline.reply.InReplyToMapper +import org.matrix.rustcomponents.sdk.InReplyToDetails import org.matrix.rustcomponents.sdk.MessageType +import org.matrix.rustcomponents.sdk.MsgLikeKind import org.matrix.rustcomponents.sdk.use import org.matrix.rustcomponents.sdk.FormattedBody as RustFormattedBody -import org.matrix.rustcomponents.sdk.MessageContent as Message import org.matrix.rustcomponents.sdk.MessageFormat as RustMessageFormat import org.matrix.rustcomponents.sdk.MessageType as RustMessageType class EventMessageMapper { private val inReplyToMapper by lazy { InReplyToMapper(TimelineEventContentMapper()) } - fun map(message: Message): MessageContent = message.use { - val type = it.msgType.use(this::mapMessageType) - val inReplyToEvent: InReplyTo? = it.inReplyTo?.use(inReplyToMapper::map) + fun map(message: MsgLikeKind.Message, inReplyTo: InReplyToDetails?, isThreaded: Boolean): MessageContent = message.use { + val type = it.content.msgType.use(this::mapMessageType) + val inReplyToEvent: InReplyTo? = inReplyTo?.use(inReplyToMapper::map) MessageContent( - body = it.body, + body = it.content.body, inReplyTo = inReplyToEvent, - isEdited = it.isEdited, - isThreaded = it.threadRoot != null, + isEdited = it.content.isEdited, + isThreaded = isThreaded, type = type ) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt index 89661b5888..6d7ca02784 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt @@ -28,6 +28,7 @@ import org.matrix.rustcomponents.sdk.EventOrTransactionId import org.matrix.rustcomponents.sdk.QueueWedgeError import org.matrix.rustcomponents.sdk.Reaction import org.matrix.rustcomponents.sdk.ShieldState +import org.matrix.rustcomponents.sdk.TimelineItemContent import uniffi.matrix_sdk_common.ShieldStateCode import org.matrix.rustcomponents.sdk.EventSendState as RustEventSendState import org.matrix.rustcomponents.sdk.EventTimelineItem as RustEventTimelineItem @@ -48,7 +49,7 @@ class EventTimelineItemMapper( isOwn = isOwn, isRemote = isRemote, localSendState = localSendState?.map(), - reactions = reactions.map(), + reactions = (content as? TimelineItemContent.MsgLike)?.content?.reactions.map(), receipts = readReceipts.map(), sender = UserId(sender), senderProfile = senderProfile.map(), diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt index 4d1de2cbfa..f383df5ccf 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt @@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.impl.media.map import io.element.android.libraries.matrix.impl.poll.map import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableMap +import org.matrix.rustcomponents.sdk.MsgLikeKind import org.matrix.rustcomponents.sdk.TimelineItemContent import org.matrix.rustcomponents.sdk.use import uniffi.matrix_sdk_ui.RoomPinnedEventsChange @@ -54,8 +55,43 @@ class TimelineEventContentMapper( error = it.error ) } - is TimelineItemContent.Message -> { - eventMessageMapper.map(it.content) + is TimelineItemContent.MsgLike -> { + when (val kind = it.content.kind) { + is MsgLikeKind.Message -> { + val inReplyTo = it.content.inReplyTo + val isThreaded = it.content.threadRoot != null + eventMessageMapper.map(kind, inReplyTo, isThreaded) + } + is MsgLikeKind.Redacted -> { + RedactedContent + } + is MsgLikeKind.Poll -> { + PollContent( + question = kind.question, + kind = kind.kind.map(), + maxSelections = kind.maxSelections, + answers = kind.answers.map { answer -> answer.map() }.toImmutableList(), + votes = kind.votes.mapValues { vote -> + vote.value.map { userId -> UserId(userId) }.toImmutableList() + }.toImmutableMap(), + endTime = kind.endTime, + isEdited = kind.hasBeenEdited, + ) + } + is MsgLikeKind.UnableToDecrypt -> { + UnableToDecryptContent( + data = kind.msg.map() + ) + } + is MsgLikeKind.Sticker -> { + StickerContent( + filename = kind.body, + body = null, + info = kind.info.map(), + source = kind.source.map(), + ) + } + } } is TimelineItemContent.ProfileChange -> { ProfileChangeContent( @@ -65,9 +101,6 @@ class TimelineEventContentMapper( prevAvatarUrl = it.prevAvatarUrl ) } - TimelineItemContent.RedactedMessage -> { - RedactedContent - } is TimelineItemContent.RoomMembership -> { RoomMembershipContent( userId = UserId(it.userId), @@ -81,32 +114,6 @@ class TimelineEventContentMapper( content = it.content.map() ) } - is TimelineItemContent.Sticker -> { - StickerContent( - filename = it.body, - body = null, - info = it.info.map(), - source = it.source.map(), - ) - } - is TimelineItemContent.Poll -> { - PollContent( - question = it.question, - kind = it.kind.map(), - maxSelections = it.maxSelections, - answers = it.answers.map { answer -> answer.map() }.toImmutableList(), - votes = it.votes.mapValues { vote -> - vote.value.map { userId -> UserId(userId) }.toImmutableList() - }.toImmutableMap(), - endTime = it.endTime, - isEdited = it.hasBeenEdited, - ) - } - is TimelineItemContent.UnableToDecrypt -> { - UnableToDecryptContent( - data = it.msg.map() - ) - } is TimelineItemContent.CallInvite -> LegacyCallInviteContent is TimelineItemContent.CallNotify -> CallNotifyContent } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/EventTimelineItem.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/EventTimelineItem.kt index ff8fcaa78d..3b59ad903a 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/EventTimelineItem.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/EventTimelineItem.kt @@ -15,7 +15,6 @@ import org.matrix.rustcomponents.sdk.EventSendState import org.matrix.rustcomponents.sdk.EventTimelineItem import org.matrix.rustcomponents.sdk.EventTimelineItemDebugInfo import org.matrix.rustcomponents.sdk.ProfileDetails -import org.matrix.rustcomponents.sdk.Reaction import org.matrix.rustcomponents.sdk.Receipt import org.matrix.rustcomponents.sdk.ShieldState import org.matrix.rustcomponents.sdk.TimelineItemContent @@ -30,7 +29,6 @@ fun aRustEventTimelineItem( isEditable: Boolean = true, content: TimelineItemContent = aRustTimelineItemMessageContent(), timestamp: ULong = 0uL, - reactions: List = emptyList(), debugInfo: EventTimelineItemDebugInfo = anEventTimelineItemDebugInfo(), localSendState: EventSendState? = null, readReceipts: Map = emptyMap(), @@ -49,7 +47,6 @@ fun aRustEventTimelineItem( canBeRepliedTo = canBeRepliedTo, content = content, localSendState = localSendState, - reactions = reactions, readReceipts = readReceipts, origin = origin, localCreatedAt = localCreatedAt, diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/EventTimelineItemContent.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/EventTimelineItemContent.kt index 9fe3a7569a..6e2def8aff 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/EventTimelineItemContent.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/EventTimelineItemContent.kt @@ -9,16 +9,23 @@ package io.element.android.libraries.matrix.impl.fixtures.factories import org.matrix.rustcomponents.sdk.MessageContent import org.matrix.rustcomponents.sdk.MessageType +import org.matrix.rustcomponents.sdk.MsgLikeContent +import org.matrix.rustcomponents.sdk.MsgLikeKind import org.matrix.rustcomponents.sdk.TextMessageContent import org.matrix.rustcomponents.sdk.TimelineItemContent -fun aRustTimelineItemMessageContent(body: String = "Hello") = TimelineItemContent.Message( - content = MessageContent( - msgType = MessageType.Text(content = TextMessageContent(body = body, formatted = null)), - body = body, - inReplyTo = null, +fun aRustTimelineItemMessageContent(body: String = "Hello") = TimelineItemContent.MsgLike( + content = MsgLikeContent( + kind = MsgLikeKind.Message( + content = MessageContent( + msgType = MessageType.Text(content = TextMessageContent(body = body, formatted = null)), + body = body, + isEdited = false, + mentions = null, + ) + ), + reactions = emptyList(), threadRoot = null, - isEdited = false, - mentions = null, - ) + inReplyTo = null, + ), ) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/NotificationItem.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/NotificationItem.kt index ce6b333680..7df10e623c 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/NotificationItem.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/NotificationItem.kt @@ -7,9 +7,11 @@ package io.element.android.libraries.matrix.impl.fixtures.factories +import io.element.android.libraries.matrix.api.core.ThreadId import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustTimelineEvent import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_USER_NAME +import org.matrix.rustcomponents.sdk.JoinRule import org.matrix.rustcomponents.sdk.NotificationEvent import org.matrix.rustcomponents.sdk.NotificationItem import org.matrix.rustcomponents.sdk.NotificationRoomInfo @@ -22,12 +24,14 @@ fun aRustNotificationItem( roomInfo: NotificationRoomInfo = aRustNotificationRoomInfo(), isNoisy: Boolean? = false, hasMention: Boolean? = false, + threadId: ThreadId? = null, ) = NotificationItem( event = event, senderInfo = senderInfo, roomInfo = roomInfo, isNoisy = isNoisy, hasMention = hasMention, + threadId = threadId?.value, ) fun aRustNotificationSenderInfo( @@ -47,6 +51,8 @@ fun aRustNotificationRoomInfo( joinedMembersCount: ULong = 2u, isEncrypted: Boolean? = true, isDirect: Boolean = false, + joinRule: JoinRule? = null, + isPublic: Boolean = true, ) = NotificationRoomInfo( displayName = displayName, avatarUrl = avatarUrl, @@ -54,6 +60,8 @@ fun aRustNotificationRoomInfo( joinedMembersCount = joinedMembersCount, isEncrypted = isEncrypted, isDirect = isDirect, + joinRule = joinRule, + isPublic = isPublic, ) fun aRustNotificationEventTimeline(