From 801eecfe8d38747ed4af1307072fbbb70519c511 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 13 Mar 2023 20:18:16 +0100 Subject: [PATCH] [MatrixSDK] finish mapping timeline and makes it compile --- app/build.gradle.kts | 1 + .../io/element/android/appnav/RootFlowNode.kt | 17 +++-- .../android/appnav/di/MatrixClientsHolder.kt | 11 ++- .../impl/changeserver/ChangeServerView.kt | 2 +- .../login/impl/error/ErrorFormatter.kt | 2 +- .../login/impl/root/LoginRootPresenter.kt | 18 ++--- .../impl/timeline/TimelineStateProvider.kt | 3 +- .../event/TimelineItemEncryptedView.kt | 4 +- .../event/TimelineItemContentFactory.kt | 38 ++++++---- ...eItemContentFailedToParseMessageFactory.kt | 4 +- ...ineItemContentFailedToParseStateFactory.kt | 4 +- .../TimelineItemContentMessageFactory.kt | 41 +++++----- ...TimelineItemContentProfileChangeFactory.kt | 4 +- .../TimelineItemContentRedactedFactory.kt | 4 +- ...imelineItemContentRoomMembershipFactory.kt | 4 +- .../event/TimelineItemContentStateFactory.kt | 4 +- .../TimelineItemContentStickerFactory.kt | 4 +- .../event/TimelineItemContentUTDFactory.kt | 8 +- .../event/TimelineItemEventFactory.kt | 22 +++--- .../virtual/TimelineItemVirtualFactory.kt | 9 +-- .../impl/timeline/model/TimelineItem.kt | 7 +- .../event/TimelineItemEncryptedContent.kt | 4 +- .../event/TimelineItemEventContentProvider.kt | 4 +- .../impl/timeline/util/toHtmlDocument.kt | 4 +- .../libraries/core/extensions/Result.kt | 27 +++++++ libraries/matrix/api/build.gradle.kts | 2 - .../libraries/matrix/api/MatrixClient.kt | 8 +- .../matrix/api/auth/AuthErrorCode.kt | 2 - .../api/auth/AuthenticationException.kt | 25 +++++++ .../api/auth/MatrixAuthenticationService.kt | 6 +- .../api/auth/MatrixHomeServerDetails.kt | 9 +-- .../item/event/TimelineEventContent.kt | 74 +++++++++---------- libraries/matrix/impl/build.gradle.kts | 2 +- .../libraries/matrix/impl/RustMatrixClient.kt | 23 ++++-- .../impl/auth/AuthenticationException.kt | 31 ++++++++ .../matrix/impl/auth/HomeserverDetails.kt | 28 +++++++ .../auth/RustMatrixAuthenticationService.kt | 52 ++++++------- .../matrix/impl/media/RustMediaResolver.kt | 14 +--- .../timeline/item/event/EventMessageMapper.kt | 40 +++++----- .../item/event/TimelineEventContentMapper.kt | 30 +++++--- .../libraries/matrix/test/FakeMatrixClient.kt | 5 +- .../test/auth/FakeAuthenticationService.kt | 12 +-- samples/minimal/build.gradle.kts | 1 + .../android/samples/minimal/MainActivity.kt | 2 +- 44 files changed, 372 insertions(+), 244 deletions(-) create mode 100644 libraries/core/src/main/kotlin/io/element/android/libraries/core/extensions/Result.kt create mode 100644 libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthenticationException.kt create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationException.kt create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetails.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e1bddd561b..e71b20a051 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -219,6 +219,7 @@ dependencies { implementation(libs.androidx.activity.compose) implementation(libs.androidx.startup) implementation(libs.coil) + implementation(libs.matrix.sdk) implementation(libs.dagger) kapt(libs.dagger.compiler) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt index 87263b86f4..8251584308 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -119,14 +119,15 @@ class RootFlowNode @AssistedInject constructor( onSuccess(latestKnownUserId) return } - val matrixClient = authenticationService.restoreSession(UserId(latestKnownUserId.value)) - if (matrixClient == null) { - Timber.v("Failed to restore session...") - onFailure() - } else { - matrixClientsHolder.add(matrixClient) - onSuccess(matrixClient.sessionId) - } + authenticationService.restoreSession(UserId(latestKnownUserId.value)) + .onSuccess { matrixClient -> + matrixClientsHolder.add(matrixClient) + onSuccess(matrixClient.sessionId) + } + .onFailure { + Timber.v("Failed to restore session...") + onFailure() + } } private fun onOpenBugReport() { diff --git a/appnav/src/main/kotlin/io/element/android/appnav/di/MatrixClientsHolder.kt b/appnav/src/main/kotlin/io/element/android/appnav/di/MatrixClientsHolder.kt index 2e929b07e5..092cffd630 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/di/MatrixClientsHolder.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/di/MatrixClientsHolder.kt @@ -64,10 +64,13 @@ class MatrixClientsHolder @Inject constructor(private val authenticationService: runBlocking { userIds.forEach { userId -> Timber.v("Restore matrix session: $userId") - val matrixClient = authenticationService.restoreSession(userId) - if (matrixClient != null) { - add(matrixClient) - } + authenticationService.restoreSession(userId) + .onSuccess { matrixClient -> + add(matrixClient) + } + .onFailure { + Timber.e("Fail to restore session") + } } } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt index ef8f4d76b3..2e238c7b50 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt @@ -80,9 +80,9 @@ import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TextField import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.components.onTabOrEnterKeyFocusNext +import io.element.android.libraries.matrix.api.auth.AuthenticationException import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag -import org.matrix.rustcomponents.sdk.AuthenticationException import io.element.android.libraries.ui.strings.R as StringR @OptIn(ExperimentalMaterial3Api::class, ExperimentalTextApi::class) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/error/ErrorFormatter.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/error/ErrorFormatter.kt index 1e83fcbc66..6c652a29c1 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/error/ErrorFormatter.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/error/ErrorFormatter.kt @@ -17,8 +17,8 @@ package io.element.android.features.login.impl.error import io.element.android.libraries.matrix.api.auth.AuthErrorCode +import io.element.android.libraries.matrix.api.auth.AuthenticationException import io.element.android.libraries.matrix.api.auth.errorCode -import org.matrix.rustcomponents.sdk.AuthenticationException import io.element.android.libraries.ui.strings.R.string as StringR fun loginError( diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/root/LoginRootPresenter.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/root/LoginRootPresenter.kt index a76f197b4a..46a42ad24c 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/root/LoginRootPresenter.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/root/LoginRootPresenter.kt @@ -25,7 +25,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import io.element.android.features.login.impl.util.LoginConstants import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails import kotlinx.coroutines.CoroutineScope @@ -71,15 +70,14 @@ class LoginRootPresenter @Inject constructor(private val authenticationService: private fun CoroutineScope.submit(homeserver: String, formState: LoginFormState, loggedInState: MutableState) = launch { loggedInState.value = LoggedInState.LoggingIn //TODO rework the setHomeserver flow - tryOrNull { - authenticationService.setHomeserver(homeserver) - } - try { - val sessionId = authenticationService.login(formState.login.trim(), formState.password.trim()) - loggedInState.value = LoggedInState.LoggedIn(sessionId) - } catch (failure: Throwable) { - loggedInState.value = LoggedInState.ErrorLoggingIn(failure) - } + authenticationService.setHomeserver(homeserver) + authenticationService.login(formState.login.trim(), formState.password.trim()) + .onSuccess { sessionId -> + loggedInState.value = LoggedInState.LoggedIn(sessionId) + } + .onFailure { failure -> + loggedInState.value = LoggedInState.ErrorLoggingIn(failure) + } } private fun updateFormState(formState: MutableState, updateLambda: LoginFormState.() -> LoginFormState) { 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 bb487845f7..df222911b0 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 @@ -24,6 +24,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent 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.UserId import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -81,7 +82,7 @@ internal fun aTimelineItemEvent( return TimelineItem.Event( id = randomId, eventId = EventId(randomId), - senderId = "@senderId", + senderId = UserId("@senderId"), senderAvatar = AvatarData("@senderId", "sender"), content = content, reactionsState = TimelineItemReactions( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEncryptedView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEncryptedView.kt index 2d98005eba..4d65c1ebcd 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEncryptedView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEncryptedView.kt @@ -24,7 +24,7 @@ import androidx.compose.ui.tooling.preview.Preview import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewLight -import org.matrix.rustcomponents.sdk.EncryptedMessage +import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent @Composable fun TimelineItemEncryptedView( @@ -53,7 +53,7 @@ internal fun TimelineItemEncryptedViewDarkPreview() = private fun ContentToPreview() { TimelineItemEncryptedView( content = TimelineItemEncryptedContent( - encryptedMessage = EncryptedMessage.Unknown, + data = UnableToDecryptContent.Data.Unknown ) ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt index c3417bc3c9..262ef31d2e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt @@ -17,11 +17,20 @@ package io.element.android.features.messages.impl.timeline.factories.event import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent -import org.matrix.rustcomponents.sdk.TimelineItemContentKind +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent +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.MessageContent +import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent +import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent +import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent +import io.element.android.libraries.matrix.api.timeline.item.event.StateContent +import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent +import io.element.android.libraries.matrix.api.timeline.item.event.TimelineEventContent +import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent +import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent import javax.inject.Inject -typealias RustTimelineItemContent = org.matrix.rustcomponents.sdk.TimelineItemContent - class TimelineItemContentFactory @Inject constructor( private val messageFactory: TimelineItemContentMessageFactory, private val redactedMessageFactory: TimelineItemContentRedactedFactory, @@ -34,17 +43,18 @@ class TimelineItemContentFactory @Inject constructor( private val failedToParseStateFactory: TimelineItemContentFailedToParseStateFactory ) { - fun create(itemContent: RustTimelineItemContent): TimelineItemEventContent { - return when (val kind = itemContent.kind()) { - is TimelineItemContentKind.Message -> messageFactory.create(itemContent.asMessage()) - is TimelineItemContentKind.RedactedMessage -> redactedMessageFactory.create(kind) - is TimelineItemContentKind.Sticker -> stickerFactory.create(kind) - is TimelineItemContentKind.UnableToDecrypt -> utdFactory.create(kind) - is TimelineItemContentKind.RoomMembership -> roomMembershipFactory.create(kind) - is TimelineItemContentKind.ProfileChange -> profileChangeFactory.create(kind) - is TimelineItemContentKind.State -> stateFactory.create(kind) - is TimelineItemContentKind.FailedToParseMessageLike -> failedToParseMessageFactory.create(kind) - is TimelineItemContentKind.FailedToParseState -> failedToParseStateFactory.create(kind) + fun create(itemContent: TimelineEventContent): TimelineItemEventContent { + return when (itemContent) { + is FailedToParseMessageLikeContent -> failedToParseMessageFactory.create(itemContent) + is FailedToParseStateContent -> failedToParseStateFactory.create(itemContent) + is MessageContent -> messageFactory.create(itemContent) + is ProfileChangeContent -> profileChangeFactory.create(itemContent) + is RedactedContent -> redactedMessageFactory.create(itemContent) + is RoomMembershipContent -> roomMembershipFactory.create(itemContent) + is StateContent -> stateFactory.create(itemContent) + is StickerContent -> stickerFactory.create(itemContent) + is UnableToDecryptContent -> utdFactory.create(itemContent) + is UnknownContent -> TimelineItemUnknownContent } } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFailedToParseMessageFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFailedToParseMessageFactory.kt index f5923e34af..4dacb76523 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFailedToParseMessageFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFailedToParseMessageFactory.kt @@ -18,12 +18,12 @@ package io.element.android.features.messages.impl.timeline.factories.event import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent -import org.matrix.rustcomponents.sdk.TimelineItemContentKind +import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent import javax.inject.Inject class TimelineItemContentFailedToParseMessageFactory @Inject constructor() { - fun create(kind: TimelineItemContentKind.FailedToParseMessageLike): TimelineItemEventContent { + fun create(failedToParseMessageLike: FailedToParseMessageLikeContent): TimelineItemEventContent { return TimelineItemUnknownContent } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFailedToParseStateFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFailedToParseStateFactory.kt index 7ef7bfecab..7e2bf90050 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFailedToParseStateFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFailedToParseStateFactory.kt @@ -18,12 +18,12 @@ package io.element.android.features.messages.impl.timeline.factories.event import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent -import org.matrix.rustcomponents.sdk.TimelineItemContentKind +import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent import javax.inject.Inject class TimelineItemContentFailedToParseStateFactory @Inject constructor() { - fun create(kind: TimelineItemContentKind.FailedToParseState): TimelineItemEventContent { + fun create(failedToParseState: FailedToParseStateContent): TimelineItemEventContent { return TimelineItemUnknownContent } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt index 3146d24a10..c0b4a4f5cc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt @@ -24,43 +24,46 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent import io.element.android.features.messages.impl.timeline.util.toHtmlDocument import io.element.android.libraries.matrix.api.media.MediaResolver -import org.matrix.rustcomponents.sdk.Message -import org.matrix.rustcomponents.sdk.MessageType +import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent +import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType import javax.inject.Inject class TimelineItemContentMessageFactory @Inject constructor() { - fun create(contentAsMessage: Message?): TimelineItemEventContent { - return when (val messageType = contentAsMessage?.msgtype()) { - is MessageType.Emote -> TimelineItemEmoteContent( - body = messageType.content.body, - htmlDocument = messageType.content.formatted?.toHtmlDocument() + fun create(content: MessageContent): TimelineItemEventContent { + return when (val messageType = content.type) { + is EmoteMessageType -> TimelineItemEmoteContent( + body = messageType.body, + htmlDocument = messageType.formatted?.toHtmlDocument() ) - is MessageType.Image -> { - val height = messageType.content.info?.height?.toFloat() - val width = messageType.content.info?.width?.toFloat() + is ImageMessageType -> { + val height = messageType.info?.height?.toFloat() + val width = messageType.info?.width?.toFloat() val aspectRatio = if (height != null && width != null) { width / height } else { 0.7f } TimelineItemImageContent( - body = messageType.content.body, + body = messageType.body, imageMeta = MediaResolver.Meta( - url = messageType.content.source, + url = messageType.url, kind = MediaResolver.Kind.Content ), - blurhash = messageType.content.info?.blurhash, + blurhash = messageType.info?.blurhash, aspectRatio = aspectRatio ) } - is MessageType.Notice -> TimelineItemNoticeContent( - body = messageType.content.body, - htmlDocument = messageType.content.formatted?.toHtmlDocument() + is NoticeMessageType -> TimelineItemNoticeContent( + body = messageType.body, + htmlDocument = messageType.formatted?.toHtmlDocument() ) - is MessageType.Text -> TimelineItemTextContent( - body = messageType.content.body, - htmlDocument = messageType.content.formatted?.toHtmlDocument() + is TextMessageType -> TimelineItemTextContent( + body = messageType.body, + htmlDocument = messageType.formatted?.toHtmlDocument() ) else -> TimelineItemUnknownContent } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentProfileChangeFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentProfileChangeFactory.kt index 8e7683d51d..689bbcbaa1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentProfileChangeFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentProfileChangeFactory.kt @@ -18,12 +18,12 @@ package io.element.android.features.messages.impl.timeline.factories.event import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent -import org.matrix.rustcomponents.sdk.TimelineItemContentKind +import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent import javax.inject.Inject class TimelineItemContentProfileChangeFactory @Inject constructor() { - fun create(kind: TimelineItemContentKind.ProfileChange): TimelineItemEventContent { + fun create(content: ProfileChangeContent): TimelineItemEventContent { return TimelineItemUnknownContent } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRedactedFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRedactedFactory.kt index 968c51070c..dfbbd233c7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRedactedFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRedactedFactory.kt @@ -18,12 +18,12 @@ package io.element.android.features.messages.impl.timeline.factories.event import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent -import org.matrix.rustcomponents.sdk.TimelineItemContentKind +import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent import javax.inject.Inject class TimelineItemContentRedactedFactory @Inject constructor() { - fun create(kind: TimelineItemContentKind.RedactedMessage): TimelineItemEventContent { + fun create(content: RedactedContent): TimelineItemEventContent { return TimelineItemRedactedContent } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRoomMembershipFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRoomMembershipFactory.kt index 037338cbbe..808e0d3b70 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRoomMembershipFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentRoomMembershipFactory.kt @@ -18,12 +18,12 @@ package io.element.android.features.messages.impl.timeline.factories.event import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent -import org.matrix.rustcomponents.sdk.TimelineItemContentKind +import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent import javax.inject.Inject class TimelineItemContentRoomMembershipFactory @Inject constructor() { - fun create(kind: TimelineItemContentKind.RoomMembership): TimelineItemEventContent { + fun create(content: RoomMembershipContent): TimelineItemEventContent { return TimelineItemUnknownContent } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStateFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStateFactory.kt index e2dcec5a8c..1680006bc1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStateFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStateFactory.kt @@ -18,12 +18,12 @@ package io.element.android.features.messages.impl.timeline.factories.event import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent -import org.matrix.rustcomponents.sdk.TimelineItemContentKind +import io.element.android.libraries.matrix.api.timeline.item.event.StateContent import javax.inject.Inject class TimelineItemContentStateFactory @Inject constructor() { - fun create(kind: TimelineItemContentKind.State): TimelineItemEventContent { + fun create(content: StateContent): TimelineItemEventContent { return TimelineItemUnknownContent } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStickerFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStickerFactory.kt index de7ad74ef5..b823791912 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStickerFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentStickerFactory.kt @@ -18,12 +18,12 @@ package io.element.android.features.messages.impl.timeline.factories.event import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent -import org.matrix.rustcomponents.sdk.TimelineItemContentKind +import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent import javax.inject.Inject class TimelineItemContentStickerFactory @Inject constructor() { - fun create(kind: TimelineItemContentKind.Sticker): TimelineItemEventContent { + fun create(content: StickerContent): TimelineItemEventContent { return TimelineItemUnknownContent } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentUTDFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentUTDFactory.kt index 495059be73..3281f6dd9b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentUTDFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentUTDFactory.kt @@ -16,14 +16,14 @@ package io.element.android.features.messages.impl.timeline.factories.event -import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent -import org.matrix.rustcomponents.sdk.TimelineItemContentKind +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent +import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent import javax.inject.Inject class TimelineItemContentUTDFactory @Inject constructor() { - fun create(kind: TimelineItemContentKind.UnableToDecrypt): TimelineItemEventContent { - return TimelineItemEncryptedContent(kind.msg) + fun create(content: UnableToDecryptContent): TimelineItemEventContent { + return TimelineItemEncryptedContent(content.data) } } 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 39c8719db4..c21622b50f 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 @@ -23,8 +23,8 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItemReac import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import kotlinx.collections.immutable.toImmutableList -import org.matrix.rustcomponents.sdk.ProfileTimelineDetails import javax.inject.Inject class TimelineItemEventFactory @Inject constructor( @@ -36,13 +36,13 @@ class TimelineItemEventFactory @Inject constructor( index: Int, timelineItems: List, ): TimelineItem.Event { - val currentSender = currentTimelineItem.event.sender() + val currentSender = currentTimelineItem.event.sender val groupPosition = computeGroupPosition(currentTimelineItem, timelineItems, index) val senderDisplayName: String? val senderAvatarUrl: String? - when (val senderProfile = currentTimelineItem.event.senderProfile()) { + when (val senderProfile = currentTimelineItem.event.senderProfile) { ProfileTimelineDetails.Unavailable, ProfileTimelineDetails.Pending, is ProfileTimelineDetails.Error -> { @@ -56,8 +56,8 @@ class TimelineItemEventFactory @Inject constructor( } val senderAvatarData = AvatarData( - id = currentSender, - name = senderDisplayName ?: currentSender, + id = currentSender.value, + name = senderDisplayName ?: currentSender.value, url = senderAvatarUrl, size = AvatarSize.SMALL ) @@ -67,15 +67,15 @@ class TimelineItemEventFactory @Inject constructor( senderId = currentSender, senderDisplayName = senderDisplayName, senderAvatar = senderAvatarData, - content = contentFactory.create(currentTimelineItem.event.content()), - isMine = currentTimelineItem.event.isOwn(), + content = contentFactory.create(currentTimelineItem.event.content), + isMine = currentTimelineItem.event.isOwn, groupPosition = groupPosition, reactionsState = currentTimelineItem.computeReactionsState() ) } private fun MatrixTimelineItem.Event.computeReactionsState(): TimelineItemReactions { - val aggregatedReactions = event.reactions().orEmpty().map { + val aggregatedReactions = event.reactions.map { AggregatedReaction(key = it.key, count = it.count.toString(), isHighlighted = false) } return TimelineItemReactions(aggregatedReactions.toImmutableList()) @@ -90,9 +90,9 @@ class TimelineItemEventFactory @Inject constructor( timelineItems.getOrNull(index - 1) as? MatrixTimelineItem.Event val nextTimelineItem = timelineItems.getOrNull(index + 1) as? MatrixTimelineItem.Event - val currentSender = currentTimelineItem.event.sender() - val previousSender = prevTimelineItem?.event?.sender() - val nextSender = nextTimelineItem?.event?.sender() + val currentSender = currentTimelineItem.event.sender + val previousSender = prevTimelineItem?.event?.sender + val nextSender = nextTimelineItem?.event?.sender return when { previousSender != currentSender && nextSender == currentSender -> TimelineItemGroupPosition.First diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/virtual/TimelineItemVirtualFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/virtual/TimelineItemVirtualFactory.kt index a6ee1de9b2..100917a05f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/virtual/TimelineItemVirtualFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/virtual/TimelineItemVirtualFactory.kt @@ -23,7 +23,6 @@ import io.element.android.features.messages.impl.timeline.model.virtual.Timeline import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemVirtualModel import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem -import org.matrix.rustcomponents.sdk.VirtualTimelineItem import javax.inject.Inject class TimelineItemVirtualFactory @Inject constructor( @@ -43,10 +42,10 @@ class TimelineItemVirtualFactory @Inject constructor( private fun MatrixTimelineItem.Virtual.computeModel(index: Int): TimelineItemVirtualModel { return when (val inner = virtual) { - is io.element.android.libraries.matrix.api.timeline.item.virtual.TimelineItemVirtual.VirtualTimelineItem.DayDivider -> daySeparatorFactory.create(inner) - is io.element.android.libraries.matrix.api.timeline.item.virtual.TimelineItemVirtual.VirtualTimelineItem.ReadMarker -> TimelineItemReadMarkerModel - is io.element.android.libraries.matrix.api.timeline.item.virtual.TimelineItemVirtual.VirtualTimelineItem.LoadingIndicator -> TimelineItemLoadingModel - is io.element.android.libraries.matrix.api.timeline.item.virtual.TimelineItemVirtual.VirtualTimelineItem.TimelineStart -> TimelineItemReadMarkerModel + is VirtualTimelineItem.DayDivider -> daySeparatorFactory.create(inner) + is VirtualTimelineItem.ReadMarker -> TimelineItemReadMarkerModel + is VirtualTimelineItem.LoadingIndicator -> TimelineItemLoadingModel + is VirtualTimelineItem.TimelineStart -> TimelineItemReadMarkerModel else -> TimelineItemUnknownVirtualModel } } 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 fbadbf79af..ced4ce1d10 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 @@ -21,11 +21,12 @@ 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.UserId @Immutable sealed interface TimelineItem { - fun identifier(): String = when(this){ + fun identifier(): String = when (this) { is Event -> id is Virtual -> id } @@ -40,7 +41,7 @@ sealed interface TimelineItem { data class Event( val id: String, val eventId: EventId? = null, - val senderId: String, + val senderId: UserId, val senderDisplayName: String?, val senderAvatar: AvatarData, val content: TimelineItemEventContent, @@ -52,6 +53,6 @@ sealed interface TimelineItem { val showSenderInformation = groupPosition.isNew() && !isMine - val safeSenderName: String = senderDisplayName ?: senderId + val safeSenderName: String = senderDisplayName ?: senderId.value } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEncryptedContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEncryptedContent.kt index cdb9b1a274..b42c2ac535 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEncryptedContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEncryptedContent.kt @@ -16,8 +16,8 @@ package io.element.android.features.messages.impl.timeline.model.event -import org.matrix.rustcomponents.sdk.EncryptedMessage +import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent data class TimelineItemEncryptedContent( - val encryptedMessage: EncryptedMessage + val data: UnableToDecryptContent.Data ) : TimelineItemEventContent diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContentProvider.kt index e8df9d9639..7e4be1bbd1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContentProvider.kt @@ -17,8 +17,8 @@ package io.element.android.features.messages.impl.timeline.model.event import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent import org.jsoup.Jsoup -import org.matrix.rustcomponents.sdk.EncryptedMessage class TimelineItemEventContentProvider : PreviewParameterProvider { override val values = sequenceOf( @@ -49,7 +49,7 @@ fun aTimelineItemEmoteContent() = TimelineItemEmoteContent( ) fun aTimelineItemEncryptedContent() = TimelineItemEncryptedContent( - encryptedMessage = EncryptedMessage.Unknown + data = UnableToDecryptContent.Data.Unknown ) fun aTimelineItemNoticeContent() = TimelineItemNoticeContent( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/util/toHtmlDocument.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/util/toHtmlDocument.kt index 5a9a51796a..8031e77a4d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/util/toHtmlDocument.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/util/toHtmlDocument.kt @@ -16,10 +16,10 @@ package io.element.android.features.messages.impl.timeline.util +import io.element.android.libraries.matrix.api.timeline.item.event.FormattedBody +import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat import org.jsoup.Jsoup import org.jsoup.nodes.Document -import org.matrix.rustcomponents.sdk.FormattedBody -import org.matrix.rustcomponents.sdk.MessageFormat fun FormattedBody.toHtmlDocument(): Document? { return takeIf { it.format == MessageFormat.HTML }?.body?.let { formattedBody -> diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/extensions/Result.kt b/libraries/core/src/main/kotlin/io/element/android/libraries/core/extensions/Result.kt new file mode 100644 index 0000000000..b63efa781d --- /dev/null +++ b/libraries/core/src/main/kotlin/io/element/android/libraries/core/extensions/Result.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.core.extensions + +/** + * Can be used to transform some Throwable into some other + */ +inline fun Result.mapFailure(transform: (exception: Throwable) -> Throwable): Result { + return when (val exception = exceptionOrNull()) { + null -> this + else -> Result.failure(transform(exception)) + } +} diff --git a/libraries/matrix/api/build.gradle.kts b/libraries/matrix/api/build.gradle.kts index 26b133e9ff..3a2fd2472a 100644 --- a/libraries/matrix/api/build.gradle.kts +++ b/libraries/matrix/api/build.gradle.kts @@ -32,8 +32,6 @@ anvil { } dependencies { - // api(projects.libraries.rustsdk) - api(libs.matrix.sdk) implementation(projects.libraries.di) implementation(libs.dagger) implementation(projects.libraries.core) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt index 52ea513ff2..a0f6a472e8 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt @@ -21,8 +21,6 @@ import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.media.MediaResolver import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource -import org.matrix.rustcomponents.sdk.MediaSource -import java.io.Closeable interface MatrixClient { val sessionId: SessionId @@ -34,9 +32,9 @@ interface MatrixClient { suspend fun logout() suspend fun loadUserDisplayName(): Result suspend fun loadUserAvatarURLString(): Result - suspend fun loadMediaContentForSource(source: MediaSource): Result - suspend fun loadMediaThumbnailForSource( - source: MediaSource, + suspend fun loadMediaContent(url: String): Result + suspend fun loadMediaThumbnail( + url: String, width: Long, height: Long ): Result diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthErrorCode.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthErrorCode.kt index 18dc3a6605..dfc88e6110 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthErrorCode.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthErrorCode.kt @@ -16,8 +16,6 @@ package io.element.android.libraries.matrix.api.auth -import org.matrix.rustcomponents.sdk.AuthenticationException - enum class AuthErrorCode(val value: String) { UNKNOWN("M_UNKNOWN"), USER_DEACTIVATED("M_USER_DEACTIVATED"), diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthenticationException.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthenticationException.kt new file mode 100644 index 0000000000..4c943db0d6 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthenticationException.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.api.auth + +sealed class AuthenticationException(message: String) : Exception(message) { + class ClientMissing(message: String) : AuthenticationException(message) + class InvalidServerName(message: String) : AuthenticationException(message) + class SlidingSyncNotAvailable(message: String) : AuthenticationException(message) + class SessionMissing(message: String) : AuthenticationException(message) + class Generic(message: String) : AuthenticationException(message) +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt index 80ee68e6de..3414c4fb6e 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt @@ -24,8 +24,8 @@ import kotlinx.coroutines.flow.StateFlow interface MatrixAuthenticationService { fun isLoggedIn(): Flow suspend fun getLatestSessionId(): SessionId? - suspend fun restoreSession(sessionId: SessionId): MatrixClient? + suspend fun restoreSession(sessionId: SessionId): Result fun getHomeserverDetails(): StateFlow - suspend fun setHomeserver(homeserver: String) - suspend fun login(username: String, password: String): SessionId + suspend fun setHomeserver(homeserver: String): Result + suspend fun login(username: String, password: String): Result } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetails.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetails.kt index 430029642e..7f2b074c67 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetails.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetails.kt @@ -18,17 +18,10 @@ package io.element.android.libraries.matrix.api.auth import android.os.Parcelable import kotlinx.parcelize.Parcelize -import org.matrix.rustcomponents.sdk.HomeserverLoginDetails @Parcelize data class MatrixHomeServerDetails( val url: String, val supportsPasswordLogin: Boolean, val authenticationIssuer: String? -): Parcelable { - constructor(homeserverLoginDetails: HomeserverLoginDetails) : this( - homeserverLoginDetails.url(), - homeserverLoginDetails.supportsPasswordLogin(), - homeserverLoginDetails.authenticationIssuer() - ) -} +): Parcelable diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/TimelineEventContent.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/TimelineEventContent.kt index 4fc2f437f7..12bd98568a 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/TimelineEventContent.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/TimelineEventContent.kt @@ -24,11 +24,11 @@ import io.element.android.libraries.matrix.api.media.VideoInfo sealed interface TimelineEventContent -data class TimelineEventMessageContent( +data class MessageContent( val body: String, val inReplyTo: UserId?, val isEdited: Boolean, - val content: MessageContent? + val type: MessageType? ) : TimelineEventContent object RedactedContent : TimelineEventContent @@ -39,45 +39,45 @@ data class StickerContent( val url: String ) : TimelineEventContent -sealed interface EncryptedMessage { - data class OlmV1Curve25519AesSha2( - val senderKey: String - ) : EncryptedMessage - - data class MegolmV1AesSha2( - val sessionId: String - ) : EncryptedMessage - - object Unknown : EncryptedMessage -} - data class UnableToDecryptContent( - val message: EncryptedMessage -) : TimelineEventContent + val data: Data +) : TimelineEventContent { + sealed interface Data { + data class OlmV1Curve25519AesSha2( + val senderKey: String + ) : Data + + data class MegolmV1AesSha2( + val sessionId: String + ) : Data + + object Unknown : Data + } +} -data class RoomMembership( +data class RoomMembershipContent( val userId: UserId, val change: MembershipChange? ) : TimelineEventContent -data class ProfileChange( +data class ProfileChangeContent( val displayName: String?, val prevDisplayName: String?, val avatarUrl: String?, val prevAvatarUrl: String? ) : TimelineEventContent -data class State( +data class StateContent( val stateKey: String, val content: OtherState ) : TimelineEventContent -data class FailedToParseMessageLike( +data class FailedToParseMessageLikeContent( val eventType: String, val error: String ) : TimelineEventContent -data class FailedToParseState( +data class FailedToParseStateContent( val eventType: String, val stateKey: String, val error: String @@ -85,9 +85,9 @@ data class FailedToParseState( object UnknownContent : TimelineEventContent -sealed interface MessageContent +sealed interface MessageType -object UnknownMessageContent : MessageContent +object UnknownMessageType : MessageType enum class MessageFormat { HTML, UNKNOWN @@ -98,44 +98,44 @@ data class FormattedBody( val body: String ) -data class EmoteMessageContent( +data class EmoteMessageType( val body: String, val formatted: FormattedBody? -) : MessageContent +) : MessageType -data class ImageMessageContent( +data class ImageMessageType( val body: String, val url: String, val info: ImageInfo? -) : MessageContent +) : MessageType -data class AudioMessageContent( +data class AudioMessageType( var body: String, var url: String, var info: AudioInfo? -) : MessageContent +) : MessageType -data class VideoMessageContent( +data class VideoMessageType( val body: String, val url: String, val info: VideoInfo? -) : MessageContent +) : MessageType -data class FileMessageContent( +data class FileMessageType( val body: String, val url: String, val info: FileInfo? -) : MessageContent +) : MessageType -data class NoticeMessageContent( +data class NoticeMessageType( val body: String, val formatted: FormattedBody? -) : MessageContent +) : MessageType -data class TextMessageContent( +data class TextMessageType( val body: String, val formatted: FormattedBody? -) : MessageContent +) : MessageType enum class MembershipChange { NONE, diff --git a/libraries/matrix/impl/build.gradle.kts b/libraries/matrix/impl/build.gradle.kts index 49f18be870..4c0e4c6402 100644 --- a/libraries/matrix/impl/build.gradle.kts +++ b/libraries/matrix/impl/build.gradle.kts @@ -32,7 +32,7 @@ anvil { dependencies { // api(projects.libraries.rustsdk) - api(libs.matrix.sdk) + implementation(libs.matrix.sdk) implementation(projects.libraries.di) implementation(projects.libraries.matrix.api) implementation(libs.dagger) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 2539df41e4..5cda9a9f8d 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -32,12 +32,12 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.Client import org.matrix.rustcomponents.sdk.ClientDelegate -import org.matrix.rustcomponents.sdk.MediaSource import org.matrix.rustcomponents.sdk.RequiredState import org.matrix.rustcomponents.sdk.SlidingSyncMode import org.matrix.rustcomponents.sdk.SlidingSyncRequestListFilters import org.matrix.rustcomponents.sdk.SlidingSyncViewBuilder import org.matrix.rustcomponents.sdk.TaskHandle +import org.matrix.rustcomponents.sdk.mediaSourceFromUrl import org.matrix.rustcomponents.sdk.use import timber.log.Timber import java.io.File @@ -181,9 +181,9 @@ class RustMatrixClient constructor( } catch (failure: Throwable) { Timber.e(failure, "Fail to call logout on HS. Still delete local files.") } - client.destroy() baseDirectory.deleteSessionDirectory(userID = client.userId()) sessionStore.removeSession(client.userId()) + client.destroy() } override suspend fun loadUserDisplayName(): Result = withContext(dispatchers.io) { @@ -199,23 +199,30 @@ class RustMatrixClient constructor( } @OptIn(ExperimentalUnsignedTypes::class) - override suspend fun loadMediaContentForSource(source: MediaSource): Result = + override suspend fun loadMediaContent(url: String): Result = withContext(dispatchers.io) { runCatching { - client.getMediaContent(source).toUByteArray().toByteArray() + mediaSourceFromUrl(url).use { source -> + client.getMediaContent(source).toUByteArray().toByteArray() + } } } @OptIn(ExperimentalUnsignedTypes::class) - override suspend fun loadMediaThumbnailForSource( - source: MediaSource, + override suspend fun loadMediaThumbnail( + url: String, width: Long, height: Long ): Result = withContext(dispatchers.io) { runCatching { - client.getMediaThumbnail(source, width.toULong(), height.toULong()).toUByteArray() - .toByteArray() + mediaSourceFromUrl(url).use { source -> + client.getMediaThumbnail( + source = source, + width = width.toULong(), + height = height.toULong() + ).toUByteArray().toByteArray() + } } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationException.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationException.kt new file mode 100644 index 0000000000..96e3a367cb --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationException.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.impl.auth + +import io.element.android.libraries.matrix.api.auth.AuthenticationException +import org.matrix.rustcomponents.sdk.AuthenticationException as RustAuthenticationException + +fun Throwable.mapAuthenticationException(): Throwable { + return when (this) { + is RustAuthenticationException.ClientMissing -> AuthenticationException.ClientMissing(this.message!!) + is RustAuthenticationException.Generic -> AuthenticationException.Generic(this.message!!) + is RustAuthenticationException.InvalidServerName -> AuthenticationException.InvalidServerName(this.message!!) + is RustAuthenticationException.SessionMissing -> AuthenticationException.SessionMissing(this.message!!) + is RustAuthenticationException.SlidingSyncNotAvailable -> AuthenticationException.SlidingSyncNotAvailable(this.message!!) + else -> this + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetails.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetails.kt new file mode 100644 index 0000000000..e2f3cfe676 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetails.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.impl.auth + +import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails +import org.matrix.rustcomponents.sdk.HomeserverLoginDetails + +fun HomeserverLoginDetails.map(): MatrixHomeServerDetails = use { + MatrixHomeServerDetails( + url = url(), + supportsPasswordLogin = supportsPasswordLogin(), + authenticationIssuer = authenticationIssuer() + ) +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt index 6a52217899..55361be4b4 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt @@ -18,6 +18,7 @@ package io.element.android.libraries.matrix.impl.auth import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.core.extensions.mapFailure import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SingleIn import io.element.android.libraries.matrix.api.MatrixClient @@ -26,7 +27,6 @@ import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.impl.RustMatrixClient -import io.element.android.libraries.matrix.impl.util.logError import io.element.android.libraries.sessionstorage.api.SessionData import io.element.android.libraries.sessionstorage.api.SessionStore import kotlinx.coroutines.CoroutineScope @@ -39,7 +39,6 @@ import org.matrix.rustcomponents.sdk.Client import org.matrix.rustcomponents.sdk.ClientBuilder import org.matrix.rustcomponents.sdk.Session import org.matrix.rustcomponents.sdk.use -import timber.log.Timber import java.io.File import javax.inject.Inject @@ -63,10 +62,10 @@ class RustMatrixAuthenticationService @Inject constructor( sessionStore.getLatestSession()?.userId?.let { UserId(it) } } - override suspend fun restoreSession(sessionId: SessionId) = withContext(coroutineDispatchers.io) { - val sessionData = sessionStore.getSession(sessionId.value) - if (sessionData != null) { - try { + override suspend fun restoreSession(sessionId: SessionId): Result = withContext(coroutineDispatchers.io) { + runCatching { + val sessionData = sessionStore.getSession(sessionId.value) + if (sessionData != null) { val client = ClientBuilder() .basePath(baseDirectory.absolutePath) .homeserverUrl(sessionData.homeserverUrl) @@ -74,36 +73,39 @@ class RustMatrixAuthenticationService @Inject constructor( .use { it.build() } client.restoreSession(sessionData.toSession()) createMatrixClient(client) - } catch (throwable: Throwable) { - logError(throwable) - null + } else { + throw IllegalStateException("No session to restore with id $sessionId") } - } else null + }.mapFailure { failure -> + failure.mapAuthenticationException() + } } override fun getHomeserverDetails(): StateFlow = currentHomeserver - override suspend fun setHomeserver(homeserver: String) { + override suspend fun setHomeserver(homeserver: String): Result = withContext(coroutineDispatchers.io) { - authService.configureHomeserver(homeserver) - val homeServerDetails = authService.homeserverDetails()?.use { MatrixHomeServerDetails(it) } - if (homeServerDetails != null) { - currentHomeserver.value = homeServerDetails.copy(url = homeserver) + runCatching { + authService.configureHomeserver(homeserver) + val homeServerDetails = authService.homeserverDetails()?.map() + if (homeServerDetails != null) { + currentHomeserver.value = homeServerDetails.copy(url = homeserver) + } } + }.mapFailure { failure -> + failure.mapAuthenticationException() } - } - override suspend fun login(username: String, password: String): SessionId = + override suspend fun login(username: String, password: String): Result = withContext(coroutineDispatchers.io) { - val client = try { - authService.login(username, password, "ElementX Android", null) - } catch (failure: Throwable) { - Timber.e(failure, "Fail login") - throw failure + runCatching { + val client = authService.login(username, password, "ElementX Android", null) + val sessionData = client.use { it.session().toSessionData() } + sessionStore.storeData(sessionData) + SessionId(sessionData.userId) } - val sessionData = client.use { it.session().toSessionData() } - sessionStore.storeData(sessionData) - SessionId(sessionData.userId) + }.mapFailure { failure -> + failure.mapAuthenticationException() } private fun createMatrixClient(client: Client): MatrixClient { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaResolver.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaResolver.kt index 8b16b8e551..68ed48350e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaResolver.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaResolver.kt @@ -18,23 +18,15 @@ package io.element.android.libraries.matrix.impl.media import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.media.MediaResolver -import org.matrix.rustcomponents.sdk.MediaSource -import org.matrix.rustcomponents.sdk.mediaSourceFromUrl internal class RustMediaResolver(private val client: MatrixClient) : MediaResolver { override suspend fun resolve(url: String?, kind: MediaResolver.Kind): ByteArray? { if (url.isNullOrEmpty()) return null - return mediaSourceFromUrl(url).use { mediaSource -> - resolve(mediaSource, kind) - } - } - - private suspend fun resolve(mediaSource: MediaSource, kind: MediaResolver.Kind): ByteArray? { return when (kind) { - is MediaResolver.Kind.Content -> client.loadMediaContentForSource(mediaSource) - is MediaResolver.Kind.Thumbnail -> client.loadMediaThumbnailForSource( - mediaSource, + is MediaResolver.Kind.Content -> client.loadMediaContent(url) + is MediaResolver.Kind.Thumbnail -> client.loadMediaThumbnail( + url, kind.width.toLong(), kind.height.toLong() ) 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 6cf2e7878f..801060171c 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 @@ -17,17 +17,17 @@ package io.element.android.libraries.matrix.impl.timeline.item.event import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageContent -import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageContent -import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageContent +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.FileMessageType import io.element.android.libraries.matrix.api.timeline.item.event.FormattedBody -import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageContent +import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat -import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageContent -import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageContent -import io.element.android.libraries.matrix.api.timeline.item.event.TimelineEventMessageContent -import io.element.android.libraries.matrix.api.timeline.item.event.UnknownMessageContent -import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageContent +import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent +import io.element.android.libraries.matrix.api.timeline.item.event.UnknownMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType import io.element.android.libraries.matrix.impl.media.map import io.element.android.libraries.matrix.impl.media.useUrl import org.matrix.rustcomponents.sdk.Message @@ -38,40 +38,40 @@ import org.matrix.rustcomponents.sdk.MessageFormat as RustMessageFormat class EventMessageMapper { - fun map(message: Message): TimelineEventMessageContent = message.use { + fun map(message: Message): MessageContent = message.use { val content = message.msgtype().use { type -> when (type) { is MessageType.Audio -> { - AudioMessageContent(type.content.body, type.content.source.useUrl(), type.content.info?.map()) + AudioMessageType(type.content.body, type.content.source.useUrl(), type.content.info?.map()) } is MessageType.File -> { - FileMessageContent(type.content.body, type.content.source.useUrl(), type.content.info?.map()) + FileMessageType(type.content.body, type.content.source.useUrl(), type.content.info?.map()) } is MessageType.Image -> { - ImageMessageContent(type.content.body, type.content.source.useUrl(), type.content.info?.map()) + ImageMessageType(type.content.body, type.content.source.useUrl(), type.content.info?.map()) } is MessageType.Notice -> { - NoticeMessageContent(type.content.body, type.content.formatted?.map()) + NoticeMessageType(type.content.body, type.content.formatted?.map()) } is MessageType.Text -> { - TextMessageContent(type.content.body, type.content.formatted?.map()) + TextMessageType(type.content.body, type.content.formatted?.map()) } is MessageType.Emote -> { - EmoteMessageContent(type.content.body, type.content.formatted?.map()) + EmoteMessageType(type.content.body, type.content.formatted?.map()) } is MessageType.Video -> { - VideoMessageContent(type.content.body, type.content.source.useUrl(), type.content.info?.map()) + VideoMessageType(type.content.body, type.content.source.useUrl(), type.content.info?.map()) } null -> { - UnknownMessageContent + UnknownMessageType } } } - TimelineEventMessageContent( + MessageContent( body = message.body(), inReplyTo = message.inReplyTo()?.let { UserId(it) }, isEdited = message.isEdited(), - content = content + type = content ) } } 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 e40e7f82d5..08a09c602f 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 @@ -17,31 +17,33 @@ package io.element.android.libraries.matrix.impl.timeline.item.event import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLike -import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseState +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.MembershipChange -import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChange +import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent -import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembership +import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent import io.element.android.libraries.matrix.api.timeline.item.event.TimelineEventContent +import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent import io.element.android.libraries.matrix.impl.media.map import org.matrix.rustcomponents.sdk.TimelineItemContent import org.matrix.rustcomponents.sdk.TimelineItemContentKind +import org.matrix.rustcomponents.sdk.EncryptedMessage as RustEncryptedMessage class TimelineEventContentMapper(private val eventMessageMapper: EventMessageMapper = EventMessageMapper()) { fun map(content: TimelineItemContent): TimelineEventContent = content.use { when (val kind = content.kind()) { is TimelineItemContentKind.FailedToParseMessageLike -> { - FailedToParseMessageLike( + FailedToParseMessageLikeContent( eventType = kind.eventType, error = kind.error ) } is TimelineItemContentKind.FailedToParseState -> { - FailedToParseState( + FailedToParseStateContent( eventType = kind.eventType, stateKey = kind.stateKey, error = kind.error @@ -56,7 +58,7 @@ class TimelineEventContentMapper(private val eventMessageMapper: EventMessageMap } } is TimelineItemContentKind.ProfileChange -> { - ProfileChange( + ProfileChangeContent( displayName = kind.displayName, prevDisplayName = kind.prevDisplayName, avatarUrl = kind.avatarUrl, @@ -67,7 +69,7 @@ class TimelineEventContentMapper(private val eventMessageMapper: EventMessageMap RedactedContent } is TimelineItemContentKind.RoomMembership -> { - RoomMembership( + RoomMembershipContent( UserId(kind.userId), MembershipChange.JOINED ) @@ -83,8 +85,18 @@ class TimelineEventContentMapper(private val eventMessageMapper: EventMessageMap ) } is TimelineItemContentKind.UnableToDecrypt -> { - UnknownContent + UnableToDecryptContent( + data = kind.msg.map() + ) } } } } + +private fun RustEncryptedMessage.map(): UnableToDecryptContent.Data { + return when (this) { + is RustEncryptedMessage.MegolmV1AesSha2 -> UnableToDecryptContent.Data.MegolmV1AesSha2(sessionId) + is RustEncryptedMessage.OlmV1Curve25519AesSha2 -> UnableToDecryptContent.Data.OlmV1Curve25519AesSha2(senderKey) + RustEncryptedMessage.Unknown -> UnableToDecryptContent.Data.Unknown + } +} diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index 7bdaec6c0b..eb1010df87 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -26,7 +26,6 @@ import io.element.android.libraries.matrix.test.media.FakeMediaResolver import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.FakeRoomSummaryDataSource import kotlinx.coroutines.delay -import org.matrix.rustcomponents.sdk.MediaSource class FakeMatrixClient( override val sessionId: SessionId = A_SESSION_ID, @@ -66,11 +65,11 @@ class FakeMatrixClient( return userAvatarURLString } - override suspend fun loadMediaContentForSource(source: MediaSource): Result { + override suspend fun loadMediaContent(url: String): Result { return Result.success(ByteArray(0)) } - override suspend fun loadMediaThumbnailForSource(source: MediaSource, width: Long, height: Long): Result { + override suspend fun loadMediaThumbnail(url: String, width: Long, height: Long): Result { return Result.success(ByteArray(0)) } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt index 102ec2d868..e6a6be8012 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt @@ -20,7 +20,6 @@ import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.matrix.test.A_HOMESERVER import io.element.android.libraries.matrix.test.A_USER_ID import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow @@ -41,8 +40,8 @@ class FakeAuthenticationService : MatrixAuthenticationService { return null } - override suspend fun restoreSession(sessionId: SessionId): MatrixClient? { - return null + override suspend fun restoreSession(sessionId: SessionId): Result { + return Result.failure(IllegalStateException()) } override fun getHomeserverDetails(): StateFlow { @@ -53,15 +52,16 @@ class FakeAuthenticationService : MatrixAuthenticationService { this.homeserver.value = homeserver } - override suspend fun setHomeserver(homeserver: String) { + override suspend fun setHomeserver(homeserver: String): Result { changeServerError?.let { throw it } delay(100) + return Result.success(Unit) } - override suspend fun login(username: String, password: String): SessionId { + override suspend fun login(username: String, password: String): Result { delay(100) loginError?.let { throw it } - return A_USER_ID + return Result.success(A_USER_ID) } fun givenLoginError(throwable: Throwable?) { diff --git a/samples/minimal/build.gradle.kts b/samples/minimal/build.gradle.kts index 47f5675a07..6e2a1ff5aa 100644 --- a/samples/minimal/build.gradle.kts +++ b/samples/minimal/build.gradle.kts @@ -57,5 +57,6 @@ dependencies { implementation(projects.features.roomlist.impl) implementation(projects.features.login.impl) implementation(libs.coroutines.core) + implementation(libs.matrix.sdk) coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.2") } diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt index 4ba66c51d6..53d4999934 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt @@ -72,7 +72,7 @@ class MainActivity : ComponentActivity() { } else { val matrixClient = runBlocking { val sessionId = matrixAuthenticationService.getLatestSessionId()!! - matrixAuthenticationService.restoreSession(sessionId) + matrixAuthenticationService.restoreSession(sessionId).getOrNull() } RoomListScreen(matrixClient = matrixClient!!).Content(modifier) }