diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenter.kt index c96e695375..b799de3115 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenter.kt @@ -51,10 +51,12 @@ class ResolveVerifiedUserSendFailurePresenter @Inject constructor( is ResolveVerifiedUserSendFailureEvents.ComputeForMessage -> { val sendState = event.messageEvent.localSendState as? LocalEventSendState.Failed.VerifiedUser val transactionId = event.messageEvent.transactionId - resolver = if (sendState != null && transactionId != null) { + val sendHandle = event.messageEvent.sendhandle + resolver = if (sendState != null && transactionId != null && sendHandle != null) { VerifiedUserSendFailureResolver( room = room, transactionId = transactionId, + sendHandle = sendHandle, iterator = VerifiedUserSendFailureIterator.from(sendState) ) } else { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/VerifiedUserSendFailureResolver.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/VerifiedUserSendFailureResolver.kt index be775ed122..f7e68b6cfb 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/VerifiedUserSendFailureResolver.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/VerifiedUserSendFailureResolver.kt @@ -8,6 +8,7 @@ package io.element.android.features.messages.impl.crypto.sendfailure.resolve import androidx.compose.runtime.mutableStateOf +import io.element.android.libraries.matrix.api.core.SendHandle import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState @@ -22,6 +23,7 @@ import timber.log.Timber class VerifiedUserSendFailureResolver( private val room: MatrixRoom, private val transactionId: TransactionId, + private val sendHandle: SendHandle, private val iterator: VerifiedUserSendFailureIterator, ) { val currentSendFailure = mutableStateOf(null) @@ -33,7 +35,7 @@ class VerifiedUserSendFailureResolver( } suspend fun resend(): Result { - return room.retrySendMessage(transactionId) + return sendHandle.retry() .onSuccess { Timber.d("Succeed to resend message with transactionId: $transactionId") currentSendFailure.value = null @@ -46,10 +48,10 @@ class VerifiedUserSendFailureResolver( suspend fun resolveAndResend(): Result { return when (val failure = currentSendFailure.value) { is LocalEventSendState.Failed.VerifiedUserHasUnsignedDevice -> { - room.ignoreDeviceTrustAndResend(failure.devices, transactionId) + room.ignoreDeviceTrustAndResend(failure.devices, sendHandle) } is LocalEventSendState.Failed.VerifiedUserChangedIdentity -> { - room.withdrawVerificationAndResend(failure.users, transactionId) + room.withdrawVerificationAndResend(failure.users, sendHandle) } else -> { Result.failure(IllegalStateException("Unknown send failure type")) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt index 4d7677560e..bbbd458c7e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt @@ -169,6 +169,7 @@ internal fun aTimelineItemEvent( origin = null, timelineItemDebugInfoProvider = { debugInfo }, messageShieldProvider = { messageShield }, + sendHandleProvider = { null } ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt index 21004fb4ab..d94ca9013a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt @@ -88,6 +88,7 @@ class TimelineItemEventFactory @AssistedInject constructor( origin = currentTimelineItem.event.origin, timelineItemDebugInfoProvider = currentTimelineItem.event.timelineItemDebugInfoProvider, messageShieldProvider = currentTimelineItem.event.messageShieldProvider, + sendHandleProvider = currentTimelineItem.event.sendHandleProvider, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt index e2c81a3794..0a392aac6a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt @@ -16,6 +16,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemVirtualModel import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.SendHandle import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.core.UserId @@ -25,6 +26,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSen 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.ProfileTimelineDetails +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.TimelineItemEventOrigin import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName @@ -82,6 +84,7 @@ sealed interface TimelineItem { val origin: TimelineItemEventOrigin?, val timelineItemDebugInfoProvider: TimelineItemDebugInfoProvider, val messageShieldProvider: MessageShieldProvider, + val sendHandleProvider: SendHandleProvider, ) : TimelineItem { val showSenderInformation = groupPosition.isNew() && !isMine @@ -114,6 +117,8 @@ sealed interface TimelineItem { val debugInfo: TimelineItemDebugInfo get() = timelineItemDebugInfoProvider() + + val sendhandle: SendHandle? get() = sendHandleProvider() } @Immutable diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenterTest.kt index e74ae89b4f..5f5774afb6 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenterTest.kt @@ -111,9 +111,6 @@ class ResolveVerifiedUserSendFailurePresenterTest { userDisplayNameResult = { userId -> Result.success(userId.value) }, - retrySendMessageResult = { - Result.success(Unit) - }, ) val presenter = createResolveVerifiedUserSendFailurePresenter(room) presenter.test { @@ -219,9 +216,6 @@ class ResolveVerifiedUserSendFailurePresenterTest { userDisplayNameResult = { userId -> Result.success(userId.value) }, - retrySendMessageResult = { - Result.success(Unit) - }, ) val presenter = createResolveVerifiedUserSendFailurePresenter(room) presenter.test { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt index 3a4d343203..6050592bd0 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt @@ -19,13 +19,15 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.UniqueId -import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo 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.MessageShieldProvider +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.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_MESSAGE import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_NAME +import io.element.android.libraries.matrix.test.core.FakeSendHandle import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails import io.element.android.libraries.matrix.ui.messages.reply.aProfileTimelineDetailsReady import kotlinx.collections.immutable.toImmutableList @@ -39,9 +41,10 @@ internal fun aMessageEvent( content: TimelineItemEventContent = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, formattedBody = null, isEdited = false), inReplyTo: InReplyToDetails? = null, isThreaded: Boolean = false, - debugInfo: TimelineItemDebugInfo = aTimelineItemDebugInfo(), sendState: LocalEventSendState = LocalEventSendState.Sent(AN_EVENT_ID), - messageShield: MessageShield? = null, + debugInfoProvider: TimelineItemDebugInfoProvider = TimelineItemDebugInfoProvider { aTimelineItemDebugInfo() }, + messageShieldProvider: MessageShieldProvider = MessageShieldProvider { null }, + sendHandleProvider: SendHandleProvider = SendHandleProvider { FakeSendHandle() } ) = TimelineItem.Event( id = UniqueId(eventId?.value.orEmpty()), eventId = eventId, @@ -60,6 +63,7 @@ internal fun aMessageEvent( inReplyTo = inReplyTo, isThreaded = isThreaded, origin = null, - timelineItemDebugInfoProvider = { debugInfo }, - messageShieldProvider = { messageShield }, + timelineItemDebugInfoProvider = debugInfoProvider, + messageShieldProvider = messageShieldProvider, + sendHandleProvider = sendHandleProvider, ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt index a5a806fe5b..53d7c7ad4b 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt @@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_USER_ID +import io.element.android.libraries.matrix.test.core.FakeSendHandle import io.element.android.libraries.matrix.ui.messages.reply.aProfileTimelineDetailsReady import kotlinx.collections.immutable.toImmutableList import org.junit.Test @@ -44,6 +45,7 @@ class TimelineItemGrouperTest { origin = null, timelineItemDebugInfoProvider = { aTimelineItemDebugInfo() }, messageShieldProvider = { null }, + sendHandleProvider = { FakeSendHandle() }, ) private val aNonGroupableItem = aMessageEvent() private val aNonGroupableItemNoEvent = TimelineItem.Virtual(UniqueId("virtual"), aTimelineItemDaySeparatorModel("Today")) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt index a980467add..1b7f101ba0 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt @@ -19,6 +19,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.RedactedConte 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.A_USER_ID +import io.element.android.libraries.matrix.test.core.FakeSendHandle import io.element.android.libraries.mediaplayer.api.MediaPlayer import io.element.android.libraries.mediaplayer.test.FakeMediaPlayer import io.element.android.tests.testutils.testCoroutineDispatchers @@ -96,6 +97,7 @@ fun aRedactedMatrixTimeline(eventId: EventId) = listOf( ) }, messageShieldProvider = { null }, + sendHandleProvider = { FakeSendHandle() }, ), ) ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b809acc763..d4048feeb8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -173,7 +173,7 @@ jsoup = "org.jsoup:jsoup:1.18.1" appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0" timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.61" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.62" matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" } matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" } sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/SendHandle.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/SendHandle.kt new file mode 100644 index 0000000000..e77c10166e --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/SendHandle.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.matrix.api.core + +fun interface SendHandle { + suspend fun retry(): Result +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt index 3bbbf6fdd4..8dd1c5ec5f 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt @@ -12,6 +12,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SendHandle import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.UserId @@ -154,8 +155,6 @@ interface MatrixRoom : Closeable { suspend fun forwardEvent(eventId: EventId, roomIds: List): Result - suspend fun retrySendMessage(transactionId: TransactionId): Result - suspend fun cancelSend(transactionId: TransactionId): Result suspend fun leave(): Result @@ -356,20 +355,20 @@ interface MatrixRoom : Closeable { * Ignore the local trust for the given devices and resend messages that failed to send because said devices are unverified. * * @param devices The map of users identifiers to device identifiers received in the error - * @param transactionId The send queue transaction identifier of the local echo the send error applies to. + * @param sendHandle The send queue handle of the local echo the send error applies to. It can be used to retry the upload. * */ - suspend fun ignoreDeviceTrustAndResend(devices: Map>, transactionId: TransactionId): Result + suspend fun ignoreDeviceTrustAndResend(devices: Map>, sendHandle: SendHandle): Result /** * Remove verification requirements for the given users and * resend messages that failed to send because their identities were no longer verified. * * @param userIds The list of users identifiers received in the error. - * @param transactionId The send queue transaction identifier of the local echo the send error applies to. + * @param sendHandle The send queue handle of the local echo the send error applies to. It can be used to retry the upload. * */ - suspend fun withdrawVerificationAndResend(userIds: List, transactionId: TransactionId): Result + suspend fun withdrawVerificationAndResend(userIds: List, sendHandle: SendHandle): Result override fun close() = destroy() } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt index eb8923d1d6..3683f5f669 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt @@ -8,6 +8,7 @@ package io.element.android.libraries.matrix.api.timeline.item.event import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.SendHandle import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo @@ -30,6 +31,7 @@ data class EventTimelineItem( val origin: TimelineItemEventOrigin?, val timelineItemDebugInfoProvider: TimelineItemDebugInfoProvider, val messageShieldProvider: MessageShieldProvider, + val sendHandleProvider: SendHandleProvider, ) { fun inReplyTo(): InReplyTo? { return (content as? MessageContent)?.inReplyTo @@ -52,3 +54,7 @@ fun interface TimelineItemDebugInfoProvider { fun interface MessageShieldProvider { operator fun invoke(strict: Boolean): MessageShield? } + +fun interface SendHandleProvider { + operator fun invoke(): SendHandle? +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/core/RustSendHandle.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/core/RustSendHandle.kt new file mode 100644 index 0000000000..08b14a80fb --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/core/RustSendHandle.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.core + +import io.element.android.libraries.matrix.api.core.SendHandle + +class RustSendHandle( + val inner: org.matrix.rustcomponents.sdk.SendHandle, +) : SendHandle { + override suspend fun retry(): Result { + return runCatching { + inner.tryResend() + } + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomType.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomType.kt index 91db0d37dd..15a91fcec6 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomType.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomType.kt @@ -8,11 +8,12 @@ package io.element.android.libraries.matrix.impl.room import io.element.android.libraries.matrix.api.room.RoomType +import org.matrix.rustcomponents.sdk.RoomType as RustRoomType -fun String?.toRoomType(): RoomType { +fun RustRoomType.map(): RoomType { return when (this) { - null -> RoomType.Room - "m.space" -> RoomType.Space - else -> RoomType.Other(this) + RustRoomType.Room -> RoomType.Room + RustRoomType.Space -> RoomType.Space + is RustRoomType.Custom -> RoomType.Other(this.value) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt index 8b72282cd5..c12fc17553 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt @@ -16,6 +16,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SendHandle import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.UserId @@ -45,6 +46,7 @@ import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings +import io.element.android.libraries.matrix.impl.core.RustSendHandle import io.element.android.libraries.matrix.impl.mapper.map import io.element.android.libraries.matrix.impl.room.draft.into import io.element.android.libraries.matrix.impl.room.member.RoomMemberListFetcher @@ -481,10 +483,6 @@ class RustMatrixRoom( return liveTimeline.forwardEvent(eventId, roomIds) } - override suspend fun retrySendMessage(transactionId: TransactionId): Result = runCatching { - innerRoom.tryResend(transactionId.value) - } - override suspend fun cancelSend(transactionId: TransactionId): Result { return liveTimeline.cancelSend(transactionId) } @@ -671,19 +669,19 @@ class RustMatrixRoom( innerRoom.clearComposerDraft() } - override suspend fun ignoreDeviceTrustAndResend(devices: Map>, transactionId: TransactionId) = runCatching { + override suspend fun ignoreDeviceTrustAndResend(devices: Map>, sendHandle: SendHandle) = runCatching { innerRoom.ignoreDeviceTrustAndResend( devices = devices.entries.associate { entry -> entry.key.value to entry.value.map { it.value } }, - transactionId = transactionId.value + sendHandle = (sendHandle as RustSendHandle).inner, ) } - override suspend fun withdrawVerificationAndResend(userIds: List, transactionId: TransactionId) = runCatching { + override suspend fun withdrawVerificationAndResend(userIds: List, sendHandle: SendHandle) = runCatching { innerRoom.withdrawVerificationAndResend( userIds = userIds.map { it.value }, - transactionId = transactionId.value + sendHandle = (sendHandle as RustSendHandle).inner, ) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/preview/RoomPreviewInfoMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/preview/RoomPreviewInfoMapper.kt index a1031228a8..3ff3c1b098 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/preview/RoomPreviewInfoMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/preview/RoomPreviewInfoMapper.kt @@ -10,7 +10,7 @@ package io.element.android.libraries.matrix.impl.room.preview import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo -import io.element.android.libraries.matrix.impl.room.toRoomType +import io.element.android.libraries.matrix.impl.room.map import org.matrix.rustcomponents.sdk.JoinRule import org.matrix.rustcomponents.sdk.Membership import org.matrix.rustcomponents.sdk.RoomPreviewInfo as RustRoomPreviewInfo @@ -24,7 +24,7 @@ object RoomPreviewInfoMapper { topic = info.topic, avatarUrl = info.avatarUrl, numberOfJoinedMembers = info.numJoinedMembers.toLong(), - roomType = info.roomType.toRoomType(), + roomType = info.roomType.map(), isHistoryWorldReadable = info.isHistoryWorldReadable, isJoined = info.membership == Membership.JOINED, isInvited = info.membership == Membership.INVITED, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryList.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryList.kt index 576b93d26d..5eb20dc368 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryList.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryList.kt @@ -43,7 +43,7 @@ class RustRoomDirectoryList( override suspend fun filter(filter: String?, batchSize: Int, viaServerName: String?): Result { return execute { - inner.search(filter = filter, batchSize = batchSize.toUInt(), viaServerName = viaServerName) + inner.search(filter = filter, batchSize = batchSize.toUInt(), viaServerName = null) } } 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 f93d3fe982..7e28c93905 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 @@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimeli 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.TimelineItemEventOrigin +import io.element.android.libraries.matrix.impl.core.RustSendHandle import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -56,6 +57,7 @@ class EventTimelineItemMapper( origin = origin?.map(), timelineItemDebugInfoProvider = { lazyProvider.debugInfo().map() }, messageShieldProvider = { strict -> lazyProvider.getShields(strict)?.map() }, + sendHandleProvider = { lazyProvider.getSendHandle()?.let(::RustSendHandle) } ) } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/RoomPreviewInfo.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/RoomPreviewInfo.kt index 0f344d3de0..c2c23fe6d9 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/RoomPreviewInfo.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/RoomPreviewInfo.kt @@ -12,6 +12,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID import org.matrix.rustcomponents.sdk.JoinRule import org.matrix.rustcomponents.sdk.Membership import org.matrix.rustcomponents.sdk.RoomPreviewInfo +import org.matrix.rustcomponents.sdk.RoomType internal fun aRustRoomPreviewInfo( canonicalAlias: String? = A_ROOM_ALIAS.value, @@ -25,7 +26,9 @@ internal fun aRustRoomPreviewInfo( topic = "topic", avatarUrl = "avatarUrl", numJoinedMembers = 1u, - roomType = null, + numActiveMembers = 1u, + isDirect = false, + roomType = RoomType.Room, isHistoryWorldReadable = true, membership = membership, joinRule = joinRule, diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustClientBuilder.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustClientBuilder.kt index abf94edcdd..c22e7adb79 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustClientBuilder.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustClientBuilder.kt @@ -29,7 +29,6 @@ class FakeRustClientBuilder : ClientBuilder(NoPointer) { override fun disableBuiltInRootCertificates() = this override fun roomDecryptionTrustRequirement(trustRequirement: TrustRequirement) = this override fun disableSslVerification() = this - override fun enableCrossProcessRefreshLock(processId: String, sessionDelegate: ClientSessionDelegate) = this override fun homeserverUrl(url: String) = this override fun passphrase(passphrase: String?) = this override fun proxy(url: String) = this diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustLazyTimelineItemProvider.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustLazyTimelineItemProvider.kt index b133ddd0b1..b378668fb6 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustLazyTimelineItemProvider.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustLazyTimelineItemProvider.kt @@ -11,6 +11,7 @@ import io.element.android.libraries.matrix.impl.fixtures.factories.anEventTimeli import org.matrix.rustcomponents.sdk.EventTimelineItemDebugInfo import org.matrix.rustcomponents.sdk.LazyTimelineItemProvider import org.matrix.rustcomponents.sdk.NoPointer +import org.matrix.rustcomponents.sdk.SendHandle import org.matrix.rustcomponents.sdk.ShieldState class FakeRustLazyTimelineItemProvider( @@ -19,4 +20,5 @@ class FakeRustLazyTimelineItemProvider( ) : LazyTimelineItemProvider(NoPointer) { override fun getShields(strict: Boolean) = shieldsState override fun debugInfo() = debugInfo + override fun getSendHandle(): SendHandle? = null } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/RoomTypeKtTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/RoomTypeKtTest.kt index 541598781e..7dc6809d14 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/RoomTypeKtTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/RoomTypeKtTest.kt @@ -8,12 +8,13 @@ package io.element.android.libraries.matrix.impl.room import io.element.android.libraries.matrix.api.room.RoomType import org.junit.Test +import org.matrix.rustcomponents.sdk.RoomType as RustRoomType class RoomTypeKtTest { @Test fun toRoomType() { - assert(null.toRoomType() == RoomType.Room) - assert("m.space".toRoomType() == RoomType.Space) - assert("m.other".toRoomType() == RoomType.Other("m.other")) + assert(RustRoomType.Room.map() == RoomType.Room) + assert(RustRoomType.Space.map() == RoomType.Space) + assert(RustRoomType.Custom("m.other").map() == RoomType.Other("m.other")) } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/core/FakeSendHandle.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/core/FakeSendHandle.kt new file mode 100644 index 0000000000..257cdf6b3e --- /dev/null +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/core/FakeSendHandle.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.matrix.test.core + +import io.element.android.libraries.matrix.api.core.SendHandle +import io.element.android.tests.testutils.simulateLongTask + +class FakeSendHandle( + var retryLambda: () -> Result = { Result.success(Unit) } +) : SendHandle { + override suspend fun retry(): Result = simulateLongTask { + return retryLambda() + } +} diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt index 4a740c0732..9574a2a22c 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt @@ -12,6 +12,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SendHandle import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.UserId @@ -105,7 +106,6 @@ class FakeMatrixRoom( private val sendMessageResult: (String, String?, List) -> Result = { _, _, _ -> lambdaError() }, private val updateUserRoleResult: () -> Result = { lambdaError() }, private val toggleReactionResult: (String, EventOrTransactionId) -> Result = { _, _ -> lambdaError() }, - private val retrySendMessageResult: (TransactionId) -> Result = { lambdaError() }, private val cancelSendResult: (TransactionId) -> Result = { lambdaError() }, private val forwardEventResult: (EventId, List) -> Result = { _, _ -> lambdaError() }, private val reportContentResult: (EventId, String, UserId?) -> Result = { _, _, _ -> lambdaError() }, @@ -138,8 +138,8 @@ class FakeMatrixRoom( private val loadComposerDraftLambda: () -> Result = { Result.success(null) }, private val clearComposerDraftLambda: () -> Result = { Result.success(Unit) }, private val subscribeToSyncLambda: () -> Unit = { lambdaError() }, - private val ignoreDeviceTrustAndResendResult: (Map>, TransactionId) -> Result = { _, _ -> lambdaError() }, - private val withdrawVerificationAndResendResult: (List, TransactionId) -> Result = { _, _ -> lambdaError() }, + private val ignoreDeviceTrustAndResendResult: (Map>, SendHandle) -> Result = { _, _ -> lambdaError() }, + private val withdrawVerificationAndResendResult: (List, SendHandle) -> Result = { _, _ -> lambdaError() }, ) : MatrixRoom { private val _roomInfoFlow: MutableSharedFlow = MutableSharedFlow(replay = 1) override val roomInfoFlow: Flow = _roomInfoFlow @@ -249,10 +249,6 @@ class FakeMatrixRoom( return toggleReactionResult(emoji, eventOrTransactionId) } - override suspend fun retrySendMessage(transactionId: TransactionId): Result = simulateLongTask { - return retrySendMessageResult(transactionId) - } - override suspend fun cancelSend(transactionId: TransactionId): Result { return cancelSendResult(transactionId) } @@ -554,12 +550,12 @@ class FakeMatrixRoom( return getWidgetDriverResult(widgetSettings) } - override suspend fun ignoreDeviceTrustAndResend(devices: Map>, transactionId: TransactionId): Result = simulateLongTask { - return ignoreDeviceTrustAndResendResult(devices, transactionId) + override suspend fun ignoreDeviceTrustAndResend(devices: Map>, sendHandle: SendHandle): Result = simulateLongTask { + return ignoreDeviceTrustAndResendResult(devices, sendHandle) } - override suspend fun withdrawVerificationAndResend(userIds: List, transactionId: TransactionId): Result = simulateLongTask { - return withdrawVerificationAndResendResult(userIds, transactionId) + override suspend fun withdrawVerificationAndResend(userIds: List, sendHandle: SendHandle): Result = simulateLongTask { + return withdrawVerificationAndResendResult(userIds, sendHandle) } fun givenRoomMembersState(state: MatrixRoomMembersState) { diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt index e1c6d9829e..be85bb60b9 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt @@ -21,17 +21,20 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventTimeline import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent -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.MessageType 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.ProfileTimelineDetails 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.StickerContent import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemDebugInfoProvider 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_NAME +import io.element.android.libraries.matrix.test.core.FakeSendHandle import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.persistentListOf @@ -51,8 +54,9 @@ fun anEventTimelineItem( senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(), timestamp: Long = 0L, content: EventContent = aProfileChangeMessageContent(), - debugInfo: TimelineItemDebugInfo = aTimelineItemDebugInfo(), - messageShield: MessageShield? = null, + debugInfoProvider: TimelineItemDebugInfoProvider = TimelineItemDebugInfoProvider { aTimelineItemDebugInfo() }, + messageShieldProvider: MessageShieldProvider = MessageShieldProvider { null }, + sendHandleProvider: SendHandleProvider = SendHandleProvider { FakeSendHandle() } ) = EventTimelineItem( eventId = eventId, transactionId = transactionId, @@ -68,8 +72,9 @@ fun anEventTimelineItem( timestamp = timestamp, content = content, origin = null, - timelineItemDebugInfoProvider = { debugInfo }, - messageShieldProvider = { messageShield }, + timelineItemDebugInfoProvider = debugInfoProvider, + messageShieldProvider = messageShieldProvider, + sendHandleProvider = sendHandleProvider, ) fun aProfileTimelineDetails(