Merge branch 'develop' into feature/valere/support_verification_violation_banner

This commit is contained in:
Benoit Marty 2025-02-18 15:42:08 +01:00 committed by GitHub
commit 36d5528904
625 changed files with 6274 additions and 2292 deletions

View file

@ -25,10 +25,9 @@ import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
import io.element.android.libraries.matrix.api.room.PendingRoom
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.RoomPreview
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
@ -55,7 +54,7 @@ interface MatrixClient : Closeable {
val sessionCoroutineScope: CoroutineScope
val ignoredUsersFlow: StateFlow<ImmutableList<UserId>>
suspend fun getRoom(roomId: RoomId): MatrixRoom?
suspend fun getPendingRoom(roomId: RoomId): PendingRoom?
suspend fun getPendingRoom(roomId: RoomId): RoomPreview?
suspend fun findDM(userId: UserId): RoomId?
suspend fun ignoreUser(userId: UserId): Result<Unit>
suspend fun unignoreUser(userId: UserId): Result<Unit>
@ -146,7 +145,11 @@ interface MatrixClient : Closeable {
* Execute generic GET requests through the SDKs internal HTTP client.
*/
suspend fun getUrl(url: String): Result<String>
suspend fun getRoomPreviewInfo(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreviewInfo>
/**
* Get a room preview for a given room ID or alias. This is especially useful for rooms that the user is not a member of, or hasn't joined yet.
*/
suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreview>
/**
* Returns the currently used sliding sync version.

View file

@ -9,6 +9,7 @@ package io.element.android.libraries.matrix.api.exception
sealed class ClientException(message: String) : Exception(message) {
class Generic(message: String) : ClientException(message)
class MatrixApi(val kind: ErrorKind, val code: String, message: String) : ClientException(message)
class Other(message: String) : ClientException(message)
}

View file

@ -0,0 +1,457 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.api.exception
sealed interface ErrorKind {
/**
* M_BAD_ALIAS
*
* One or more room aliases within the m.room.canonical_alias event do
* not point to the room ID for which the state event is to be sent to.
*
* room aliases: https://spec.matrix.org/latest/client-server-api/#room-aliases
*/
data object BadAlias : ErrorKind
/**
* M_BAD_JSON
*
* The request contained valid JSON, but it was malformed in some way, e.g.
* missing required keys, invalid values for keys.
*/
data object BadJson : ErrorKind
/**
* M_BAD_STATE
*
* The state change requested cannot be performed, such as attempting to
* unban a user who is not banned.
*/
data object BadState : ErrorKind
/**
* M_BAD_STATUS
*
* The application service returned a bad status.
*/
data class BadStatus(
/**
* The HTTP status code of the response.
*/
val status: Int?,
/**
* The body of the response.
*/
val body: String?
) : ErrorKind
/**
* M_CANNOT_LEAVE_SERVER_NOTICE_ROOM
*
* The user is unable to reject an invite to join the server notices
* room.
*
* server notices: https://spec.matrix.org/latest/client-server-api/#server-notices
*/
data object CannotLeaveServerNoticeRoom : ErrorKind
/**
* M_CANNOT_OVERWRITE_MEDIA
*
* The create_content_async endpoint was called with a media ID that
* already has content.
*
*/
data object CannotOverwriteMedia : ErrorKind
/**
* M_CAPTCHA_INVALID
*
* The Captcha provided did not match what was expected.
*/
data object CaptchaInvalid : ErrorKind
/**
* M_CAPTCHA_NEEDED
*
* A Captcha is required to complete the request.
*/
data object CaptchaNeeded : ErrorKind
/**
* M_CONNECTION_FAILED
*
* The connection to the application service failed.
*/
data object ConnectionFailed : ErrorKind
/**
* M_CONNECTION_TIMEOUT
*
* The connection to the application service timed out.
*/
data object ConnectionTimeout : ErrorKind
/**
* M_DUPLICATE_ANNOTATION
*
* The request is an attempt to send a duplicate annotation.
*
* duplicate annotation: https://spec.matrix.org/latest/client-server-api/#avoiding-duplicate-annotations
*/
data object DuplicateAnnotation : ErrorKind
/**
* M_EXCLUSIVE
*
* The resource being requested is reserved by an application service, or
* the application service making the request has not created the
* resource.
*/
data object Exclusive : ErrorKind
/**
* M_FORBIDDEN
*
* Forbidden access, e.g. joining a room without permission, failed login.
*/
data object Forbidden : ErrorKind
/**
* M_GUEST_ACCESS_FORBIDDEN
*
* The room or resource does not permit guests to access it.
*
* guests: https://spec.matrix.org/latest/client-server-api/#guest-access
*/
data object GuestAccessForbidden : ErrorKind
/**
* M_INCOMPATIBLE_ROOM_VERSION
*
* The client attempted to join a room that has a version the server does
* not support.
*/
data class IncompatibleRoomVersion(
/**
* The room's version.
*/
val roomVersion: String
) : ErrorKind
/**
* M_INVALID_PARAM
*
* A parameter that was specified has the wrong value. For example, the
* server expected an integer and instead received a string.
*/
data object InvalidParam : ErrorKind
/**
* M_INVALID_ROOM_STATE
*
* The initial state implied by the parameters to the create_room
* request is invalid, e.g. the user's power_level is set below that
* necessary to set the room name.
*
*/
data object InvalidRoomState : ErrorKind
/**
* M_INVALID_USERNAME
*
* The desired user name is not valid.
*/
data object InvalidUsername : ErrorKind
/**
* M_LIMIT_EXCEEDED
*
* The request has been refused due to rate limiting: too many requests
* have been sent in a short period of time.
*
* rate limiting: https://spec.matrix.org/latest/client-server-api/#rate-limiting
*/
data class LimitExceeded(
/**
* How long a client should wait before they can try again.
*/
val retryAfterMs: Long?
) : ErrorKind
/**
* M_MISSING_PARAM
*
* A required parameter was missing from the request.
*/
data object MissingParam : ErrorKind
/**
* M_MISSING_TOKEN
*
* No access token was specified for the request, but one is required.
*
* access token: https://spec.matrix.org/latest/client-server-api/#client-authentication
*/
data object MissingToken : ErrorKind
/**
* M_NOT_FOUND
*
* No resource was found for this request.
*/
data object NotFound : ErrorKind
/**
* M_NOT_JSON
*
* The request did not contain valid JSON.
*/
data object NotJson : ErrorKind
/**
* M_NOT_YET_UPLOADED
*
* An mxc URI generated was used and the content is not yet available.
*
*/
data object NotYetUploaded : ErrorKind
/**
* M_RESOURCE_LIMIT_EXCEEDED
*
* The request cannot be completed because the homeserver has reached a
* resource limit imposed on it. For example, a homeserver held in a
* shared hosting environment may reach a resource limit if it starts
* using too much memory or disk space.
*/
data class ResourceLimitExceeded(
/**
* A URI giving a contact method for the server administrator.
*/
val adminContact: String
) : ErrorKind
/**
* M_ROOM_IN_USE
*
* The room alias specified in the request is already taken.
*
* room alias: https://spec.matrix.org/latest/client-server-api/#room-aliases
*/
data object RoomInUse : ErrorKind
/**
* M_SERVER_NOT_TRUSTED
*
* The client's request used a third-party server, e.g. identity server,
* that this server does not trust.
*/
data object ServerNotTrusted : ErrorKind
/**
* M_THREEPID_AUTH_FAILED
*
* Authentication could not be performed on the third-party identifier.
*
* third-party identifier: https://spec.matrix.org/latest/client-server-api/#adding-account-administrative-contact-information
*/
data object ThreepidAuthFailed : ErrorKind
/**
* M_THREEPID_DENIED
*
* The server does not permit this third-party identifier. This may
* happen if the server only permits, for example, email addresses from
* a particular domain.
*
* third-party identifier: https://spec.matrix.org/latest/client-server-api/#adding-account-administrative-contact-information
*/
data object ThreepidDenied : ErrorKind
/**
* M_THREEPID_IN_USE
*
* The third-party identifier is already in use by another user.
*
* third-party identifier: https://spec.matrix.org/latest/client-server-api/#adding-account-administrative-contact-information
*/
data object ThreepidInUse : ErrorKind
/**
* M_THREEPID_MEDIUM_NOT_SUPPORTED
*
* The homeserver does not support adding a third-party identifier of the
* given medium.
*
* third-party identifier: https://spec.matrix.org/latest/client-server-api/#adding-account-administrative-contact-information
*/
data object ThreepidMediumNotSupported : ErrorKind
/**
* M_THREEPID_NOT_FOUND
*
* No account matching the given third-party identifier could be found.
*
* third-party identifier: https://spec.matrix.org/latest/client-server-api/#adding-account-administrative-contact-information
*/
data object ThreepidNotFound : ErrorKind
/**
* M_TOO_LARGE
*
* The request or entity was too large.
*/
data object TooLarge : ErrorKind
/**
* M_UNABLE_TO_AUTHORISE_JOIN
*
* The room is restricted and none of the conditions can be validated by
* the homeserver. This can happen if the homeserver does not know
* about any of the rooms listed as conditions, for example.
*
* restricted: https://spec.matrix.org/latest/client-server-api/#restricted-rooms
*/
data object UnableToAuthorizeJoin : ErrorKind
/**
* M_UNABLE_TO_GRANT_JOIN
*
* A different server should be attempted for the join. This is typically
* because the resident server can see that the joining user satisfies
* one or more conditions, such as in the case of restricted rooms,
* but the resident server would be unable to meet the authorization
* rules.
*
* restricted rooms: https://spec.matrix.org/latest/client-server-api/#restricted-rooms
*/
data object UnableToGrantJoin : ErrorKind
/**
* M_UNAUTHORIZED
*
* The request was not correctly authorized. Usually due to login failures.
*/
data object Unauthorized : ErrorKind
/**
* M_UNKNOWN
*
* An unknown error has occurred.
*/
data object Unknown : ErrorKind
/**
* M_UNKNOWN_TOKEN
*
* The access or refresh token specified was not recognized.
*
* access or refresh token: https://spec.matrix.org/latest/client-server-api/#client-authentication
*/
data class UnknownToken(
/**
* If this is true, the client is in a "soft logout" state, i.e.
* the server requires re-authentication but the session is not
* invalidated. The client can acquire a new access token by
* specifying the device ID it is already using to the login API.
*
* soft logout: https://spec.matrix.org/latest/client-server-api/#soft-logout
*/
val softLogout: Boolean
) : ErrorKind
/**
* M_UNRECOGNIZED
*
* The server did not understand the request.
*
* This is expected to be returned with a 404 HTTP status code if the
* endpoint is not implemented or a 405 HTTP status code if the
* endpoint is implemented, but the incorrect HTTP method is used.
*/
data object Unrecognized : ErrorKind
/**
* M_UNSUPPORTED_ROOM_VERSION
*
* The request to create_room used a room version that the server does
* not support.
*
*/
data object UnsupportedRoomVersion : ErrorKind
/**
* M_URL_NOT_SET
*
* The application service doesn't have a URL configured.
*/
data object UrlNotSet : ErrorKind
/**
* M_USER_DEACTIVATED
*
* The user ID associated with the request has been deactivated.
*/
data object UserDeactivated : ErrorKind
/**
* M_USER_IN_USE
*
* The desired user ID is already taken.
*/
data object UserInUse : ErrorKind
/**
* M_USER_LOCKED
*
* The account has been locked and cannot be used at this time.
*
* locked: https://spec.matrix.org/latest/client-server-api/#account-locking
*/
data object UserLocked : ErrorKind
/**
* M_USER_SUSPENDED
*
* The account has been suspended and can only be used for limited
* actions at this time.
*
* suspended: https://spec.matrix.org/latest/client-server-api/#account-suspension
*/
data object UserSuspended : ErrorKind
/**
* M_WEAK_PASSWORD
*
* The password was rejected by the server for being too weak.
*
* rejected: https://spec.matrix.org/latest/client-server-api/#notes-on-password-management
*/
data object WeakPassword : ErrorKind
/**
* M_WRONG_ROOM_KEYS_VERSION
*
* The version of the room keys backup provided in the request does not
* match the current backup version.
*
* room keys backup: https://spec.matrix.org/latest/client-server-api/#server-side-key-backups
*/
data class WrongRoomKeysVersion(
/**
* The currently active backup version.
*/
val currentVersion: String?
) : ErrorKind
/**
* A custom API error.
*/
data class Custom(val errcode: String) : ErrorKind
}

View file

@ -28,7 +28,6 @@ data class MatrixRoomInfo(
val topic: String?,
val avatarUrl: String?,
val isDirect: Boolean,
val isPublic: Boolean,
val joinRule: JoinRule?,
val isSpace: Boolean,
val isTombstoned: Boolean,

View file

@ -1,20 +0,0 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.api.room
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
/** A reference to a room the current user has knocked to or has been invited to, with the ability to leave the room. */
interface PendingRoom : AutoCloseable {
val sessionId: SessionId
val roomId: RoomId
/** Leave the room ie.decline invite or cancel knock. */
suspend fun leave(): Result<Unit>
}

View file

@ -20,6 +20,7 @@ data class RoomMember(
val normalizedPowerLevel: Long,
val isIgnored: Boolean,
val role: Role,
val membershipChangeReason: String?,
) {
/**
* Role of the RoomMember, based on its [powerLevel].

View file

@ -0,0 +1,20 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.api.room
/**
* Room membership details for the current user and the sender of the membership event.
*
* It also includes the reason the current user's membership changed, if any.
*/
data class RoomMembershipDetails(
val currentUserMember: RoomMember,
val senderMember: RoomMember?,
) {
val membershipChangeReason: String? = currentUserMember.membershipChangeReason
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.api.room
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
/** A reference to a room either invited, knocked or banned. */
interface RoomPreview : AutoCloseable {
val sessionId: SessionId
val info: RoomPreviewInfo
/** Leave the room ie.decline invite or cancel knock. */
suspend fun leave(): Result<Unit>
/**
* Forget the room if we had access to it, and it was left or banned.
*/
suspend fun forget(): Result<Unit>
/**
* Get the membership details of the user in the room, as well as from the user who sent the `m.room.member` event.
*/
suspend fun membershipDetails(): Result<RoomMembershipDetails?>
}

View file

@ -9,7 +9,9 @@ package io.element.android.libraries.matrix.api.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.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRule
data class RoomPreviewInfo(
/** The room id for this room. */
@ -28,12 +30,8 @@ data class RoomPreviewInfo(
val roomType: RoomType,
/** Is the history world-readable for this room? */
val isHistoryWorldReadable: Boolean,
/** Is the room joined by the current user? */
val isJoined: Boolean,
/** Is the current user invited to this room? */
val isInvited: Boolean,
/** is the join rule public for this room? */
val isPublic: Boolean,
/** Can we knock (or restricted-knock) to this room? */
val canKnock: Boolean,
/** the membership of the current user. */
val membership: CurrentUserMembership?,
/** The room's join rule. */
val joinRule: JoinRule,
)

View file

@ -13,6 +13,7 @@ import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.coroutine.childScope
import io.element.android.libraries.core.data.tryOrNull
import io.element.android.libraries.core.extensions.mapFailure
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.DeviceId
@ -32,12 +33,11 @@ import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.PendingRoom
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.RoomPreview
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
import io.element.android.libraries.matrix.api.roomlist.RoomListService
@ -50,6 +50,7 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.impl.core.toProgressWatcher
import io.element.android.libraries.matrix.impl.encryption.RustEncryptionService
import io.element.android.libraries.matrix.impl.exception.mapClientException
import io.element.android.libraries.matrix.impl.media.RustMediaLoader
import io.element.android.libraries.matrix.impl.notification.RustNotificationService
import io.element.android.libraries.matrix.impl.notificationsettings.RustNotificationSettingsService
@ -58,9 +59,9 @@ import io.element.android.libraries.matrix.impl.pushers.RustPushersService
import io.element.android.libraries.matrix.impl.room.RoomContentForwarder
import io.element.android.libraries.matrix.impl.room.RoomSyncSubscriber
import io.element.android.libraries.matrix.impl.room.RustRoomFactory
import io.element.android.libraries.matrix.impl.room.RustRoomPreview
import io.element.android.libraries.matrix.impl.room.TimelineEventTypeFilterFactory
import io.element.android.libraries.matrix.impl.room.join.map
import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewInfoMapper
import io.element.android.libraries.matrix.impl.roomdirectory.RustRoomDirectoryService
import io.element.android.libraries.matrix.impl.roomdirectory.map
import io.element.android.libraries.matrix.impl.roomlist.RoomListFactory
@ -261,8 +262,8 @@ class RustMatrixClient(
return roomFactory.create(roomId)
}
override suspend fun getPendingRoom(roomId: RoomId): PendingRoom? {
return roomFactory.createPendingRoom(roomId)
override suspend fun getPendingRoom(roomId: RoomId): RoomPreview? {
return roomFactory.createRoomPreview(roomId)
}
/**
@ -393,7 +394,7 @@ class RustMatrixClient(
null
}
}
}
}.mapFailure { it.mapClientException() }
override suspend fun joinRoomByIdOrAlias(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomSummary?> = withContext(sessionDispatcher) {
runCatching {
@ -407,7 +408,7 @@ class RustMatrixClient(
Timber.e(e, "Timeout waiting for the room to be available in the room list")
null
}
}
}.mapFailure { it.mapClientException() }
}
override suspend fun knockRoom(roomIdOrAlias: RoomIdOrAlias, message: String, serverNames: List<String>): Result<RoomSummary?> = withContext(
@ -421,7 +422,7 @@ class RustMatrixClient(
Timber.e(e, "Timeout waiting for the room to be available in the room list")
null
}
}
}.mapFailure { it.mapClientException() }
}
override suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit> = withContext(sessionDispatcher) {
@ -448,15 +449,14 @@ class RustMatrixClient(
}
}
override suspend fun getRoomPreviewInfo(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreviewInfo> = withContext(sessionDispatcher) {
override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreview> = withContext(sessionDispatcher) {
runCatching {
when (roomIdOrAlias) {
val roomPreview = when (roomIdOrAlias) {
is RoomIdOrAlias.Alias -> innerClient.getRoomPreviewFromRoomAlias(roomIdOrAlias.roomAlias.value)
is RoomIdOrAlias.Id -> innerClient.getRoomPreviewFromRoomId(roomIdOrAlias.roomId.value, serverNames)
}.use { roomPreview ->
RoomPreviewInfoMapper.map(roomPreview.info())
}
}
RustRoomPreview(sessionId, roomPreview, roomMembershipObserver)
}.mapFailure { it.mapClientException() }
}
override fun syncService(): SyncService = rustSyncService
@ -495,6 +495,7 @@ class RustMatrixClient(
override suspend fun logout(userInitiated: Boolean, ignoreSdkError: Boolean): String? {
var result: String? = null
sessionCoroutineScope.cancel()
// Remove current delegate so we don't receive an auth error
clientDelegateTaskHandle?.cancelAndDestroy()
clientDelegateTaskHandle = null

View file

@ -15,6 +15,11 @@ fun Throwable.mapClientException(): ClientException {
is RustClientException -> {
when (this) {
is RustClientException.Generic -> ClientException.Generic(msg)
is RustClientException.MatrixApi -> ClientException.MatrixApi(
kind = kind.map(),
code = code,
message = msg
)
}
}
else -> ClientException.Other(message ?: "Unknown error")

View file

@ -0,0 +1,63 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.exception
import io.element.android.libraries.matrix.api.exception.ErrorKind
import org.matrix.rustcomponents.sdk.ErrorKind as RustErrorKind
fun RustErrorKind.map(): ErrorKind {
return when (this) {
RustErrorKind.BadAlias -> ErrorKind.BadAlias
RustErrorKind.BadJson -> ErrorKind.BadJson
RustErrorKind.BadState -> ErrorKind.BadState
is RustErrorKind.BadStatus -> ErrorKind.BadStatus(status?.toInt(), body)
RustErrorKind.CannotLeaveServerNoticeRoom -> ErrorKind.CannotLeaveServerNoticeRoom
RustErrorKind.CannotOverwriteMedia -> ErrorKind.CannotOverwriteMedia
RustErrorKind.CaptchaInvalid -> ErrorKind.CaptchaInvalid
RustErrorKind.CaptchaNeeded -> ErrorKind.CaptchaNeeded
RustErrorKind.ConnectionFailed -> ErrorKind.ConnectionFailed
RustErrorKind.ConnectionTimeout -> ErrorKind.ConnectionTimeout
is RustErrorKind.Custom -> ErrorKind.Custom(errcode)
RustErrorKind.DuplicateAnnotation -> ErrorKind.DuplicateAnnotation
RustErrorKind.Exclusive -> ErrorKind.Exclusive
RustErrorKind.Forbidden -> ErrorKind.Forbidden
RustErrorKind.GuestAccessForbidden -> ErrorKind.GuestAccessForbidden
is RustErrorKind.IncompatibleRoomVersion -> ErrorKind.IncompatibleRoomVersion(roomVersion)
RustErrorKind.InvalidParam -> ErrorKind.InvalidParam
RustErrorKind.InvalidRoomState -> ErrorKind.InvalidRoomState
RustErrorKind.InvalidUsername -> ErrorKind.InvalidUsername
is RustErrorKind.LimitExceeded -> ErrorKind.LimitExceeded(retryAfterMs?.toLong())
RustErrorKind.MissingParam -> ErrorKind.MissingParam
RustErrorKind.MissingToken -> ErrorKind.MissingToken
RustErrorKind.NotFound -> ErrorKind.NotFound
RustErrorKind.NotJson -> ErrorKind.NotJson
RustErrorKind.NotYetUploaded -> ErrorKind.NotYetUploaded
is RustErrorKind.ResourceLimitExceeded -> ErrorKind.ResourceLimitExceeded(adminContact)
RustErrorKind.RoomInUse -> ErrorKind.RoomInUse
RustErrorKind.ServerNotTrusted -> ErrorKind.ServerNotTrusted
RustErrorKind.ThreepidAuthFailed -> ErrorKind.ThreepidAuthFailed
RustErrorKind.ThreepidDenied -> ErrorKind.ThreepidDenied
RustErrorKind.ThreepidInUse -> ErrorKind.ThreepidInUse
RustErrorKind.ThreepidMediumNotSupported -> ErrorKind.ThreepidMediumNotSupported
RustErrorKind.ThreepidNotFound -> ErrorKind.ThreepidNotFound
RustErrorKind.TooLarge -> ErrorKind.TooLarge
RustErrorKind.UnableToAuthorizeJoin -> ErrorKind.UnableToAuthorizeJoin
RustErrorKind.UnableToGrantJoin -> ErrorKind.UnableToGrantJoin
RustErrorKind.Unauthorized -> ErrorKind.Unauthorized
RustErrorKind.Unknown -> ErrorKind.Unknown
is RustErrorKind.UnknownToken -> ErrorKind.UnknownToken(softLogout)
RustErrorKind.Unrecognized -> ErrorKind.Unrecognized
RustErrorKind.UnsupportedRoomVersion -> ErrorKind.UnsupportedRoomVersion
RustErrorKind.UrlNotSet -> ErrorKind.UrlNotSet
RustErrorKind.UserDeactivated -> ErrorKind.UserDeactivated
RustErrorKind.UserInUse -> ErrorKind.UserInUse
RustErrorKind.UserLocked -> ErrorKind.UserLocked
RustErrorKind.UserSuspended -> ErrorKind.UserSuspended
RustErrorKind.WeakPassword -> ErrorKind.WeakPassword
is RustErrorKind.WrongRoomKeysVersion -> ErrorKind.WrongRoomKeysVersion(currentVersion)
}
}

View file

@ -37,7 +37,6 @@ class MatrixRoomInfoMapper {
topic = it.topic,
avatarUrl = it.avatarUrl,
isDirect = it.isDirect,
isPublic = it.isPublic,
joinRule = it.joinRule?.map(),
isSpace = it.isSpace,
isTombstoned = it.isTombstoned,

View file

@ -1,31 +0,0 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.room
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.room.PendingRoom
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import org.matrix.rustcomponents.sdk.RoomPreview
class RustPendingRoom(
override val sessionId: SessionId,
override val roomId: RoomId,
private val inner: RoomPreview,
private val roomMembershipObserver: RoomMembershipObserver,
) : PendingRoom {
override suspend fun leave(): Result<Unit> = runCatching {
inner.leave()
}.onSuccess {
roomMembershipObserver.notifyUserLeftRoom(roomId)
}
override fun close() {
inner.destroy()
}
}

View file

@ -16,8 +16,8 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.PendingRoom
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.RoomPreview
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.awaitLoaded
import io.element.android.libraries.matrix.impl.roomlist.fullRoomWithTimeline
@ -28,7 +28,6 @@ import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.Membership
import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.RoomListException
import org.matrix.rustcomponents.sdk.RoomListItem
@ -36,7 +35,6 @@ import timber.log.Timber
import org.matrix.rustcomponents.sdk.RoomListService as InnerRoomListService
private const val CACHE_SIZE = 16
private val PENDING_MEMBERSHIPS = setOf(Membership.INVITED, Membership.KNOCKED)
class RustRoomFactory(
private val sessionId: SessionId,
@ -125,7 +123,7 @@ class RustRoomFactory(
}
}
suspend fun createPendingRoom(roomId: RoomId): PendingRoom? = withContext(dispatcher) {
suspend fun createRoomPreview(roomId: RoomId): RoomPreview? = withContext(dispatcher) {
if (isDestroyed) {
Timber.d("Room factory is destroyed, returning null for $roomId")
return@withContext null
@ -135,19 +133,18 @@ class RustRoomFactory(
Timber.d("Room not found for $roomId")
return@withContext null
}
if (roomListItem.membership() !in PENDING_MEMBERSHIPS) {
Timber.d("Room $roomId is not in pending state")
if (roomListItem.membership() !in RustRoomPreview.ALLOWED_MEMBERSHIPS) {
Timber.d("Room $roomId is not in allowed membership")
return@withContext null
}
val innerRoom = try {
roomListItem.previewRoom(via = emptyList())
} catch (e: Exception) {
Timber.e(e, "Failed to get pending room for $roomId")
Timber.e(e, "Failed to get room preview for $roomId")
return@withContext null
}
RustPendingRoom(
RustRoomPreview(
sessionId = sessionId,
roomId = roomId,
inner = innerRoom,
roomMembershipObserver = roomMembershipObserver,
)

View file

@ -0,0 +1,54 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.room
import androidx.compose.runtime.Immutable
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.RoomPreview
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper
import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewInfoMapper
import org.matrix.rustcomponents.sdk.Membership
import org.matrix.rustcomponents.sdk.RoomPreview as InnerRoomPreview
@Immutable
class RustRoomPreview(
override val sessionId: SessionId,
private val inner: InnerRoomPreview,
private val roomMembershipObserver: RoomMembershipObserver?,
) : RoomPreview {
companion object {
val ALLOWED_MEMBERSHIPS = setOf(Membership.INVITED, Membership.KNOCKED, Membership.BANNED)
}
override val info: RoomPreviewInfo = RoomPreviewInfoMapper.map(inner.info())
override suspend fun leave(): Result<Unit> = runCatching {
inner.leave()
}.onSuccess {
roomMembershipObserver?.notifyUserLeftRoom(info.roomId)
}
override suspend fun forget(): Result<Unit> = runCatching {
inner.forget()
}
override suspend fun membershipDetails(): Result<RoomMembershipDetails?> = runCatching {
val details = inner.ownMembershipDetails() ?: return@runCatching null
RoomMembershipDetails(
currentUserMember = RoomMemberMapper.map(details.ownRoomMember),
senderMember = details.senderRoomMember?.let { RoomMemberMapper.map(it) },
)
}
override fun close() {
inner.destroy()
}
}

View file

@ -25,6 +25,7 @@ object RoomMemberMapper {
normalizedPowerLevel = roomMember.normalizedPowerLevel,
isIgnored = roomMember.isIgnored,
role = mapRole(roomMember.suggestedRoleForPowerLevel),
membershipChangeReason = roomMember.membershipChangeReason
)
fun mapRole(role: RoomMemberRole): RoomMember.Role =

View file

@ -11,9 +11,8 @@ import io.element.android.libraries.core.bool.orFalse
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.join.map
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
object RoomPreviewInfoMapper {
@ -27,10 +26,8 @@ object RoomPreviewInfoMapper {
numberOfJoinedMembers = info.numJoinedMembers.toLong(),
roomType = info.roomType.map(),
isHistoryWorldReadable = info.isHistoryWorldReadable.orFalse(),
isJoined = info.membership == Membership.JOINED,
isInvited = info.membership == Membership.INVITED,
isPublic = info.joinRule == JoinRule.Public,
canKnock = info.joinRule == JoinRule.Knock
membership = info.membership?.map(),
joinRule = info.joinRule.map(),
)
}
}

View file

@ -48,6 +48,7 @@ import io.element.android.services.toolbox.api.systemclock.SystemClock
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
@ -296,7 +297,7 @@ class RustTimeline(
htmlBody: String?,
intentionalMentions: List<IntentionalMention>,
): Result<Unit> = withContext(dispatcher) {
runCatching<Unit> {
runCatching {
val editedContent = EditedContent.RoomMessage(
content = MessageEventContent.from(
body = body,
@ -324,10 +325,12 @@ class RustTimeline(
},
mentions = null,
)
inner.edit(
newContent = editedContent,
eventOrTransactionId = eventOrTransactionId.toRustEventOrTransactionId(),
)
withContext(Dispatchers.IO) {
inner.edit(
newContent = editedContent,
eventOrTransactionId = eventOrTransactionId.toRustEventOrTransactionId(),
)
}
}
}
@ -519,7 +522,7 @@ class RustTimeline(
newContent = editedContent,
eventOrTransactionId = RustEventOrTransactionId.EventId(pollStartId.value),
)
}.map { }
}
}
override suspend fun sendPollResponse(

View file

@ -85,7 +85,6 @@ class MatrixRoomInfoMapperTest {
topic = "topic",
avatarUrl = AN_AVATAR_URL,
isDirect = true,
isPublic = false,
isSpace = false,
isTombstoned = false,
isFavorite = false,
@ -167,7 +166,6 @@ class MatrixRoomInfoMapperTest {
topic = null,
avatarUrl = null,
isDirect = false,
isPublic = true,
joinRule = null,
isSpace = false,
isTombstoned = false,

View file

@ -8,14 +8,16 @@
package io.element.android.libraries.matrix.impl.room.preview
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustRoomPreviewInfo
import io.element.android.libraries.matrix.test.A_ROOM_ALIAS
import io.element.android.libraries.matrix.test.A_ROOM_ID
import org.junit.Test
import org.matrix.rustcomponents.sdk.JoinRule
import org.matrix.rustcomponents.sdk.Membership
import org.matrix.rustcomponents.sdk.JoinRule as RustJoinRule
class RoomPreviewInfoMapperTest {
@Test
@ -23,7 +25,7 @@ class RoomPreviewInfoMapperTest {
assertThat(
RoomPreviewInfoMapper.map(
info = aRustRoomPreviewInfo(
membership = null,
membership = Membership.JOINED,
)
)
).isEqualTo(
@ -36,10 +38,8 @@ class RoomPreviewInfoMapperTest {
numberOfJoinedMembers = 1L,
roomType = RoomType.Room,
isHistoryWorldReadable = true,
isJoined = false,
isInvited = false,
isPublic = true,
canKnock = false,
membership = CurrentUserMembership.JOINED,
joinRule = JoinRule.Public,
)
)
}
@ -51,7 +51,7 @@ class RoomPreviewInfoMapperTest {
info = aRustRoomPreviewInfo(
canonicalAlias = null,
membership = Membership.JOINED,
joinRule = JoinRule.Knock,
joinRule = RustJoinRule.Knock,
)
)
).isEqualTo(
@ -64,10 +64,8 @@ class RoomPreviewInfoMapperTest {
numberOfJoinedMembers = 1L,
roomType = RoomType.Room,
isHistoryWorldReadable = true,
isJoined = true,
isInvited = false,
isPublic = false,
canKnock = true,
membership = CurrentUserMembership.JOINED,
joinRule = JoinRule.Knock,
)
)
}

View file

@ -23,10 +23,9 @@ import io.element.android.libraries.matrix.api.notificationsettings.Notification
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.PendingRoom
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.RoomPreview
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
@ -79,7 +78,7 @@ class FakeMatrixClient(
Optional.of(ResolvedRoomAlias(A_ROOM_ID, emptyList()))
)
},
private val getRoomPreviewInfoResult: (RoomIdOrAlias, List<String>) -> Result<RoomPreviewInfo> = { _, _ -> Result.failure(AN_EXCEPTION) },
private val getRoomPreviewResult: (RoomIdOrAlias, List<String>) -> Result<RoomPreview> = { _, _ -> Result.failure(AN_EXCEPTION) },
private val clearCacheLambda: () -> Unit = { lambdaError() },
private val userIdServerNameLambda: () -> String = { lambdaError() },
private val getUrlLambda: (String) -> Result<String> = { lambdaError() },
@ -105,7 +104,6 @@ class FakeMatrixClient(
private var createDmResult: Result<RoomId> = Result.success(A_ROOM_ID)
private var findDmResult: RoomId? = A_ROOM_ID
private val getRoomResults = mutableMapOf<RoomId, MatrixRoom>()
val getPendingRoomResults = mutableMapOf<RoomId, PendingRoom>()
private val searchUserResults = mutableMapOf<String, Result<MatrixSearchUserResults>>()
private val getProfileResults = mutableMapOf<UserId, Result<MatrixUser>>()
private var uploadMediaResult: Result<String> = Result.success(AN_AVATAR_URL)
@ -132,8 +130,8 @@ class FakeMatrixClient(
return getRoomResults[roomId]
}
override suspend fun getPendingRoom(roomId: RoomId): PendingRoom? {
return getPendingRoomResults[roomId]
override suspend fun getPendingRoom(roomId: RoomId): RoomPreview? = simulateLongTask {
getRoomPreviewResult(RoomIdOrAlias.Id(roomId), emptyList()).getOrNull()
}
override suspend fun findDM(userId: UserId): RoomId? {
@ -313,8 +311,8 @@ class FakeMatrixClient(
resolveRoomAliasResult(roomAlias)
}
override suspend fun getRoomPreviewInfo(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreviewInfo> = simulateLongTask {
getRoomPreviewInfoResult(roomIdOrAlias, serverNames)
override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreview> = simulateLongTask {
getRoomPreviewResult(roomIdOrAlias, serverNames)
}
override suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>> {

View file

@ -1,28 +0,0 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.test.room
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.room.PendingRoom
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.simulateLongTask
class FakePendingRoom(
override val sessionId: SessionId = A_SESSION_ID,
override val roomId: RoomId = A_ROOM_ID,
private val declineInviteResult: () -> Result<Unit> = { lambdaError() }
) : PendingRoom {
override suspend fun leave(): Result<Unit> = simulateLongTask {
declineInviteResult()
}
override fun close() = Unit
}

View file

@ -0,0 +1,40 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.test.room
import androidx.compose.runtime.Immutable
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
import io.element.android.libraries.matrix.api.room.RoomPreview
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.simulateLongTask
@Immutable
class FakeRoomPreview(
override val sessionId: SessionId = A_SESSION_ID,
override val info: RoomPreviewInfo = aRoomPreviewInfo(),
private val declineInviteResult: () -> Result<Unit> = { lambdaError() },
private val forgetRoomResult: () -> Result<Unit> = { lambdaError() },
private val roomMembershipDetails: () -> Result<RoomMembershipDetails?> = { lambdaError() },
) : RoomPreview {
override suspend fun leave(): Result<Unit> = simulateLongTask {
declineInviteResult()
}
override suspend fun forget(): Result<Unit> = simulateLongTask {
forgetRoomResult()
}
override suspend fun membershipDetails(): Result<RoomMembershipDetails?> = simulateLongTask {
roomMembershipDetails()
}
override fun close() = Unit
}

View file

@ -34,7 +34,6 @@ fun aRoomInfo(
topic: String? = A_ROOM_TOPIC,
avatarUrl: String? = AN_AVATAR_URL,
isDirect: Boolean = false,
isPublic: Boolean = true,
joinRule: JoinRule? = JoinRule.Public,
isSpace: Boolean = false,
isTombstoned: Boolean = false,
@ -43,8 +42,8 @@ fun aRoomInfo(
alternativeAliases: List<RoomAlias> = emptyList(),
currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED,
inviter: RoomMember? = null,
activeMembersCount: Long = 1,
invitedMembersCount: Long = 0,
activeMembersCount: Long = 2,
invitedMembersCount: Long = 1,
joinedMembersCount: Long = 1,
highlightCount: Long = 0,
notificationCount: Long = 0,
@ -67,7 +66,6 @@ fun aRoomInfo(
topic = topic,
avatarUrl = avatarUrl,
isDirect = isDirect,
isPublic = isPublic,
joinRule = joinRule,
isSpace = isSpace,
isTombstoned = isTombstoned,

View file

@ -21,6 +21,7 @@ fun aRoomMember(
normalizedPowerLevel: Long = 0L,
isIgnored: Boolean = false,
role: RoomMember.Role = RoomMember.Role.USER,
membershipChangeReason: String? = null,
) = RoomMember(
userId = userId,
displayName = displayName,
@ -31,4 +32,5 @@ fun aRoomMember(
normalizedPowerLevel = normalizedPowerLevel,
isIgnored = isIgnored,
role = role,
membershipChangeReason = membershipChangeReason,
)

View file

@ -0,0 +1,61 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.test.room
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.SessionId
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.A_ROOM_TOPIC
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.tests.testutils.lambda.lambdaError
fun aRoomPreview(
sessionId: SessionId = A_SESSION_ID,
info: RoomPreviewInfo = aRoomPreviewInfo(),
declineInviteResult: () -> Result<Unit> = { lambdaError() },
forgetRoomResult: () -> Result<Unit> = { lambdaError() },
roomMembershipDetails: () -> Result<RoomMembershipDetails?> = { lambdaError() },
) = FakeRoomPreview(
sessionId = sessionId,
info = info,
declineInviteResult = declineInviteResult,
forgetRoomResult = forgetRoomResult,
roomMembershipDetails = roomMembershipDetails,
)
fun aRoomPreviewInfo(
roomId: RoomId = A_ROOM_ID,
name: String? = A_ROOM_NAME,
topic: String? = A_ROOM_TOPIC,
avatarUrl: String? = AN_AVATAR_URL,
joinRule: JoinRule = JoinRule.Public,
isSpace: Boolean = false,
canonicalAlias: RoomAlias? = null,
currentUserMembership: CurrentUserMembership? = null,
numberOfJoinedMembers: Long = 1,
isHistoryWorldReadable: Boolean = true,
) = RoomPreviewInfo(
roomId = roomId,
name = name,
topic = topic,
avatarUrl = avatarUrl,
joinRule = joinRule,
canonicalAlias = canonicalAlias,
numberOfJoinedMembers = numberOfJoinedMembers,
roomType = if (isSpace) RoomType.Space else RoomType.Room,
isHistoryWorldReadable = isHistoryWorldReadable,
membership = currentUserMembership,
)

View file

@ -47,7 +47,6 @@ fun aRoomSummary(
topic: String? = A_ROOM_TOPIC,
avatarUrl: String? = null,
isDirect: Boolean = false,
isPublic: Boolean = true,
joinRule: JoinRule? = JoinRule.Public,
isSpace: Boolean = false,
isTombstoned: Boolean = false,
@ -82,7 +81,6 @@ fun aRoomSummary(
topic = topic,
avatarUrl = avatarUrl,
isDirect = isDirect,
isPublic = isPublic,
joinRule = joinRule,
isSpace = isSpace,
isTombstoned = isTombstoned,