Browse Source

Join Room : makes sure we can join by alias

pull/3241/head
ganfra 2 months ago
parent
commit
aebcc52309
  1. 3
      features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt
  2. 14
      features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt
  3. 4
      features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt
  4. 13
      features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt
  5. 8
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt
  6. 4
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/join/JoinRoom.kt
  7. 3
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt
  8. 53
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt
  9. 33
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoom.kt
  10. 1
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt
  11. 60
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt
  12. 22
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt
  13. 2
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt
  14. 8
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/join/FakeJoinRoom.kt
  15. 2
      libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/RoomSummaryDetailsProvider.kt
  16. 5
      libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandlerTest.kt

3
features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt

@ -33,6 +33,7 @@ import io.element.android.libraries.architecture.runCatchingUpdatingState @@ -33,6 +33,7 @@ import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.architecture.runUpdatingState
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.push.api.notifications.NotificationCleaner
import kotlinx.coroutines.CoroutineScope
@ -107,7 +108,7 @@ class AcceptDeclineInvitePresenter @Inject constructor( @@ -107,7 +108,7 @@ class AcceptDeclineInvitePresenter @Inject constructor(
) = launch {
acceptedAction.runUpdatingState {
joinRoom(
roomId = roomId,
roomIdOrAlias = roomId.toRoomIdOrAlias(),
serverNames = emptyList(),
trigger = JoinedRoom.Trigger.Invite,
)

14
features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt

@ -23,7 +23,9 @@ import io.element.android.features.invite.api.response.InviteData @@ -23,7 +23,9 @@ import io.element.android.features.invite.api.response.InviteData
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
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_SESSION_ID
@ -178,8 +180,8 @@ class AcceptDeclineInvitePresenterTest { @@ -178,8 +180,8 @@ class AcceptDeclineInvitePresenterTest {
@Test
fun `present - accepting invite error flow`() = runTest {
val joinRoomFailure = lambdaRecorder { roomId: RoomId, _: List<String>, _: JoinedRoom.Trigger ->
Result.failure<Unit>(RuntimeException("Failed to join room $roomId"))
val joinRoomFailure = lambdaRecorder { roomIdOrAlias: RoomIdOrAlias, _: List<String>, _: JoinedRoom.Trigger ->
Result.failure<Unit>(RuntimeException("Failed to join room $roomIdOrAlias"))
}
val presenter = createAcceptDeclineInvitePresenter(joinRoomLambda = joinRoomFailure)
presenter.test {
@ -208,7 +210,7 @@ class AcceptDeclineInvitePresenterTest { @@ -208,7 +210,7 @@ class AcceptDeclineInvitePresenterTest {
assert(joinRoomFailure)
.isCalledOnce()
.with(
value(A_ROOM_ID),
value(A_ROOM_ID.toRoomIdOrAlias()),
value(emptyList<String>()),
value(JoinedRoom.Trigger.Invite)
)
@ -222,7 +224,7 @@ class AcceptDeclineInvitePresenterTest { @@ -222,7 +224,7 @@ class AcceptDeclineInvitePresenterTest {
val fakeNotificationCleaner = FakeNotificationCleaner(
clearMembershipNotificationForRoomLambda = clearMembershipNotificationForRoomLambda
)
val joinRoomSuccess = lambdaRecorder { _: RoomId, _: List<String>, _: JoinedRoom.Trigger ->
val joinRoomSuccess = lambdaRecorder { _: RoomIdOrAlias, _: List<String>, _: JoinedRoom.Trigger ->
Result.success(Unit)
}
val presenter = createAcceptDeclineInvitePresenter(
@ -248,7 +250,7 @@ class AcceptDeclineInvitePresenterTest { @@ -248,7 +250,7 @@ class AcceptDeclineInvitePresenterTest {
assert(joinRoomSuccess)
.isCalledOnce()
.with(
value(A_ROOM_ID),
value(A_ROOM_ID.toRoomIdOrAlias()),
value(emptyList<String>()),
value(JoinedRoom.Trigger.Invite)
)
@ -271,7 +273,7 @@ class AcceptDeclineInvitePresenterTest { @@ -271,7 +273,7 @@ class AcceptDeclineInvitePresenterTest {
private fun createAcceptDeclineInvitePresenter(
client: MatrixClient = FakeMatrixClient(),
joinRoomLambda: (RoomId, List<String>, JoinedRoom.Trigger) -> Result<Unit> = { _, _, _ ->
joinRoomLambda: (RoomIdOrAlias, List<String>, JoinedRoom.Trigger) -> Result<Unit> = { _, _, _ ->
Result.success(Unit)
},
notificationCleaner: NotificationCleaner = FakeNotificationCleaner(),

4
features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt

@ -96,7 +96,7 @@ class JoinRoomPresenter @AssistedInject constructor( @@ -96,7 +96,7 @@ class JoinRoomPresenter @AssistedInject constructor(
}
else -> {
value = ContentState.Loading(roomIdOrAlias)
val result = matrixClient.getRoomPreviewFromRoomId(roomId, serverNames)
val result = matrixClient.getRoomPreview(roomIdOrAlias, serverNames)
value = result.fold(
onSuccess = { roomPreview ->
roomPreview.toContentState()
@ -153,7 +153,7 @@ class JoinRoomPresenter @AssistedInject constructor( @@ -153,7 +153,7 @@ class JoinRoomPresenter @AssistedInject constructor(
private fun CoroutineScope.joinRoom(joinAction: MutableState<AsyncAction<Unit>>) = launch {
joinAction.runUpdatingState {
joinRoom.invoke(
roomId = roomId,
roomIdOrAlias = roomIdOrAlias,
serverNames = serverNames,
trigger = trigger
)

13
features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt

@ -29,6 +29,7 @@ import io.element.android.libraries.core.meta.BuildMeta @@ -29,6 +29,7 @@ import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.matrix.api.MatrixClient
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.RoomIdOrAlias
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
@ -180,7 +181,7 @@ class JoinRoomPresenterTest { @@ -180,7 +181,7 @@ class JoinRoomPresenterTest {
@Test
fun `present - when room is joined with success, all the parameters are provided`() = runTest {
val aTrigger = JoinedRoom.Trigger.MobilePermalink
val joinRoomLambda = lambdaRecorder { _: RoomId, _: List<String>, _: JoinedRoom.Trigger ->
val joinRoomLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String>, _: JoinedRoom.Trigger ->
Result.success(Unit)
}
val presenter = createJoinRoomPresenter(
@ -201,7 +202,7 @@ class JoinRoomPresenterTest { @@ -201,7 +202,7 @@ class JoinRoomPresenterTest {
}
joinRoomLambda.assertions()
.isCalledOnce()
.with(value(A_ROOM_ID), value(A_SERVER_LIST), value(aTrigger))
.with(value(A_ROOM_ID.toRoomIdOrAlias()), value(A_SERVER_LIST), value(aTrigger))
}
}
@ -366,7 +367,7 @@ class JoinRoomPresenterTest { @@ -366,7 +367,7 @@ class JoinRoomPresenterTest {
@Test
fun `present - when room is not known RoomPreview is loaded`() = runTest {
val client = FakeMatrixClient(
getRoomPreviewFromRoomIdResult = { _, _ ->
getRoomPreviewResult = { _, _ ->
Result.success(
RoomPreview(
roomId = A_ROOM_ID,
@ -411,7 +412,7 @@ class JoinRoomPresenterTest { @@ -411,7 +412,7 @@ class JoinRoomPresenterTest {
@Test
fun `present - when room is not known RoomPreview is loaded with error`() = runTest {
val client = FakeMatrixClient(
getRoomPreviewFromRoomIdResult = { _, _ ->
getRoomPreviewResult = { _, _ ->
Result.failure(AN_EXCEPTION)
}
)
@ -449,7 +450,7 @@ class JoinRoomPresenterTest { @@ -449,7 +450,7 @@ class JoinRoomPresenterTest {
@Test
fun `present - when room is not known RoomPreview is loaded with error 403`() = runTest {
val client = FakeMatrixClient(
getRoomPreviewFromRoomIdResult = { _, _ ->
getRoomPreviewResult = { _, _ ->
Result.failure(Exception("403"))
}
)
@ -474,7 +475,7 @@ class JoinRoomPresenterTest { @@ -474,7 +475,7 @@ class JoinRoomPresenterTest {
serverNames: List<String> = emptyList(),
trigger: JoinedRoom.Trigger = JoinedRoom.Trigger.Invite,
matrixClient: MatrixClient = FakeMatrixClient(),
joinRoomLambda: (RoomId, List<String>, JoinedRoom.Trigger) -> Result<Unit> = { _, _, _ ->
joinRoomLambda: (RoomIdOrAlias, List<String>, JoinedRoom.Trigger) -> Result<Unit> = { _, _, _ ->
Result.success(Unit)
},
knockRoom: KnockRoom = FakeKnockRoom(),

8
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt

@ -19,6 +19,7 @@ package io.element.android.libraries.matrix.api @@ -19,6 +19,7 @@ package io.element.android.libraries.matrix.api
import io.element.android.libraries.matrix.api.core.ProgressCallback
import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
@ -35,6 +36,7 @@ import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias @@ -35,6 +36,7 @@ import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
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
import io.element.android.libraries.matrix.api.sync.SyncService
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
import io.element.android.libraries.matrix.api.user.MatrixUser
@ -65,8 +67,8 @@ interface MatrixClient : Closeable { @@ -65,8 +67,8 @@ interface MatrixClient : Closeable {
suspend fun setDisplayName(displayName: String): Result<Unit>
suspend fun uploadAvatar(mimeType: String, data: ByteArray): Result<Unit>
suspend fun removeAvatar(): Result<Unit>
suspend fun joinRoom(roomId: RoomId): Result<Unit>
suspend fun joinRoomByIdOrAlias(roomId: RoomId, serverNames: List<String>): Result<Unit>
suspend fun joinRoom(roomId: RoomId): Result<RoomSummary?>
suspend fun joinRoomByIdOrAlias(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomSummary?>
suspend fun knockRoom(roomId: RoomId): Result<Unit>
fun syncService(): SyncService
fun sessionVerificationService(): SessionVerificationService
@ -104,7 +106,6 @@ interface MatrixClient : Closeable { @@ -104,7 +106,6 @@ interface MatrixClient : Closeable {
suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit>
suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>>
suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result<ResolvedRoomAlias>
suspend fun getRoomPreviewFromRoomId(roomId: RoomId, serverNames: List<String>): Result<RoomPreview>
/**
* Enables or disables the sending queue, according to the given parameter.
@ -132,4 +133,5 @@ interface MatrixClient : Closeable { @@ -132,4 +133,5 @@ interface MatrixClient : Closeable {
* Execute generic GET requests through the SDKs internal HTTP client.
*/
suspend fun getUrl(url: String): Result<String>
suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreview>
}

4
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/join/JoinRoom.kt

@ -17,11 +17,11 @@ @@ -17,11 +17,11 @@
package io.element.android.libraries.matrix.api.room.join
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
interface JoinRoom {
suspend operator fun invoke(
roomId: RoomId,
roomIdOrAlias: RoomIdOrAlias,
serverNames: List<String>,
trigger: JoinedRoom.Trigger,
): Result<Unit>

3
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt

@ -28,6 +28,7 @@ data class RoomSummary( @@ -28,6 +28,7 @@ data class RoomSummary(
val roomId: RoomId,
val name: String?,
val canonicalAlias: RoomAlias?,
val alternativeAliases: List<RoomAlias>,
val isDirect: Boolean,
val avatarUrl: String?,
val lastMessage: RoomMessage?,
@ -44,4 +45,6 @@ data class RoomSummary( @@ -44,4 +45,6 @@ data class RoomSummary(
val heroes: List<MatrixUser>,
) {
val lastMessageTimestamp = lastMessage?.originServerTs
val aliases: List<RoomAlias>
get() = listOfNotNull(canonicalAlias) + alternativeAliases
}

53
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt

@ -24,7 +24,9 @@ import io.element.android.libraries.matrix.api.MatrixClient @@ -24,7 +24,9 @@ import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.ProgressCallback
import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
import io.element.android.libraries.matrix.api.createroom.RoomPreset
import io.element.android.libraries.matrix.api.createroom.RoomVisibility
@ -41,6 +43,7 @@ import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias @@ -41,6 +43,7 @@ import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
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
import io.element.android.libraries.matrix.api.sync.SyncService
import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
@ -175,7 +178,7 @@ class RustMatrixClient( @@ -175,7 +178,7 @@ class RustMatrixClient(
val (anonymizedAccessToken, anonymizedRefreshToken) = existingData.anonymizedTokens()
clientLog.d(
"Removing session data with access token '$anonymizedAccessToken' " +
"and refresh token '$anonymizedRefreshToken'."
"and refresh token '$anonymizedRefreshToken'."
)
if (existingData != null) {
// Set isTokenValid to false
@ -320,16 +323,23 @@ class RustMatrixClient( @@ -320,16 +323,23 @@ class RustMatrixClient(
/**
* Wait for the room to be available in the room list.
* @param roomId the room id to wait for
* @param roomIdOrAlias the room id or alias to wait for
* @param timeout the timeout to wait for the room to be available
* @throws TimeoutCancellationException if the room is not available after the timeout
*/
private suspend fun awaitRoom(roomId: RoomId, timeout: Duration) {
withTimeout(timeout) {
private suspend fun awaitRoom(roomIdOrAlias: RoomIdOrAlias, timeout: Duration): RoomSummary {
val predicate: (List<RoomSummary>) -> Boolean = when (roomIdOrAlias) {
is RoomIdOrAlias.Alias -> { roomSummaries: List<RoomSummary> ->
roomSummaries.flatMap { it.aliases }.contains(roomIdOrAlias.roomAlias)
}
is RoomIdOrAlias.Id -> { roomSummaries: List<RoomSummary> ->
roomSummaries.map { it.roomId }.contains(roomIdOrAlias.roomId)
}
}
return withTimeout(timeout) {
roomListService.allRooms.summaries
.filter { roomSummaries ->
roomSummaries.map { it.roomId }.contains(roomId)
}
.filter(predicate)
.first()
.first()
}
}
@ -373,7 +383,7 @@ class RustMatrixClient( @@ -373,7 +383,7 @@ class RustMatrixClient(
val roomId = RoomId(client.createRoom(rustParams))
// Wait to receive the room back from the sync but do not returns failure if it fails.
try {
awaitRoom(roomId, 30.seconds)
awaitRoom(roomId.toRoomIdOrAlias(), 30.seconds)
} catch (e: Exception) {
Timber.e(e, "Timeout waiting for the room to be available in the room list")
}
@ -424,30 +434,29 @@ class RustMatrixClient( @@ -424,30 +434,29 @@ class RustMatrixClient(
runCatching { client.removeAvatar() }
}
override suspend fun joinRoom(roomId: RoomId): Result<Unit> = withContext(sessionDispatcher) {
override suspend fun joinRoom(roomId: RoomId): Result<RoomSummary?> = withContext(sessionDispatcher) {
runCatching {
client.joinRoomById(roomId.value).destroy()
try {
awaitRoom(roomId, 10.seconds)
awaitRoom(roomId.toRoomIdOrAlias(), 10.seconds)
} catch (e: Exception) {
Timber.e(e, "Timeout waiting for the room to be available in the room list")
null
}
}
}
override suspend fun joinRoomByIdOrAlias(
roomId: RoomId,
serverNames: List<String>,
): Result<Unit> = withContext(sessionDispatcher) {
override suspend fun joinRoomByIdOrAlias(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomSummary?> = withContext(sessionDispatcher) {
runCatching {
client.joinRoomByIdOrAlias(
roomIdOrAlias = roomId.value,
roomIdOrAlias = roomIdOrAlias.identifier,
serverNames = serverNames,
).destroy()
try {
awaitRoom(roomId, 10.seconds)
awaitRoom(roomIdOrAlias, 10.seconds)
} catch (e: Exception) {
Timber.e(e, "Timeout waiting for the room to be available in the room list")
null
}
}
}
@ -478,12 +487,12 @@ class RustMatrixClient( @@ -478,12 +487,12 @@ class RustMatrixClient(
}
}
override suspend fun getRoomPreviewFromRoomId(roomId: RoomId, serverNames: List<String>): Result<RoomPreview> = withContext(sessionDispatcher) {
override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreview> = withContext(sessionDispatcher) {
runCatching {
client.getRoomPreviewFromRoomId(
roomId = roomId.value,
viaServers = serverNames,
).let(RoomPreviewMapper::map)
when (roomIdOrAlias) {
is RoomIdOrAlias.Alias -> client.getRoomPreviewFromRoomAlias(roomIdOrAlias.roomAlias.value)
is RoomIdOrAlias.Id -> client.getRoomPreviewFromRoomId(roomIdOrAlias.roomId.value, serverNames)
}.let(RoomPreviewMapper::map)
}
}
@ -581,7 +590,7 @@ class RustMatrixClient( @@ -581,7 +590,7 @@ class RustMatrixClient(
var room = getRoom(roomId)
if (room == null) {
emit(Optional.empty())
awaitRoom(roomId, INFINITE)
awaitRoom(roomId.toRoomIdOrAlias(), INFINITE)
room = getRoom(roomId)
}
room?.use {

33
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoom.kt

@ -20,8 +20,9 @@ import com.squareup.anvil.annotations.ContributesBinding @@ -20,8 +20,9 @@ import com.squareup.anvil.annotations.ContributesBinding
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.impl.analytics.toAnalyticsJoinedRoom
import io.element.android.services.analytics.api.AnalyticsService
import javax.inject.Inject
@ -32,18 +33,30 @@ class DefaultJoinRoom @Inject constructor( @@ -32,18 +33,30 @@ class DefaultJoinRoom @Inject constructor(
private val analyticsService: AnalyticsService,
) : JoinRoom {
override suspend fun invoke(
roomId: RoomId,
roomIdOrAlias: RoomIdOrAlias,
serverNames: List<String>,
trigger: JoinedRoom.Trigger,
trigger: JoinedRoom.Trigger
): Result<Unit> {
return if (serverNames.isEmpty()) {
client.joinRoom(roomId)
} else {
client.joinRoomByIdOrAlias(roomId, serverNames)
}.onSuccess {
client.getRoom(roomId)?.use { room ->
analyticsService.capture(room.toAnalyticsJoinedRoom(trigger))
return when (roomIdOrAlias) {
is RoomIdOrAlias.Id -> {
if (serverNames.isEmpty()) {
client.joinRoom(roomIdOrAlias.roomId)
} else {
client.joinRoomByIdOrAlias(roomIdOrAlias, serverNames)
}
}
is RoomIdOrAlias.Alias -> {
client.joinRoomByIdOrAlias(roomIdOrAlias, serverNames = emptyList())
}
}.onSuccess { roomSummary ->
client.captureJoinedRoomAnalytics(roomSummary, trigger)
}.map { }
}
private suspend fun MatrixClient.captureJoinedRoomAnalytics(roomSummary: RoomSummary?, trigger: JoinedRoom.Trigger) {
if (roomSummary == null) return
getRoom(roomSummary.roomId)?.use { room ->
analyticsService.capture(room.toAnalyticsJoinedRoom(trigger))
}
}
}

1
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt

@ -38,6 +38,7 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto @@ -38,6 +38,7 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto
roomId = RoomId(roomInfo.id),
name = roomInfo.displayName,
canonicalAlias = roomInfo.canonicalAlias?.let(::RoomAlias),
alternativeAliases = roomInfo.alternativeAliases.map(::RoomAlias),
isDirect = roomInfo.isDirect,
avatarUrl = roomInfo.avatarUrl,
numUnreadMentions = roomInfo.numUnreadMentions.toInt(),

60
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt

@ -20,11 +20,15 @@ import com.google.common.truth.Truth.assertThat @@ -20,11 +20,15 @@ import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.impl.analytics.toAnalyticsJoinedRoom
import io.element.android.libraries.matrix.test.A_ROOM_ALIAS
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SERVER_LIST
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.room.aRoomSummaryFilled
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value
@ -33,9 +37,10 @@ import org.junit.Test @@ -33,9 +37,10 @@ import org.junit.Test
class DefaultJoinRoomTest {
@Test
fun `when there is no server names, the classic join room API is used`() = runTest {
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(Unit) }
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomId, _: List<String> -> Result.success(Unit) }
fun `when using roomId and there is no server names, the classic join room API is used`() = runTest {
val roomSummary = aRoomSummaryFilled()
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
val roomResult = FakeMatrixRoom()
val aTrigger = JoinedRoom.Trigger.MobilePermalink
val client: MatrixClient = FakeMatrixClient().also {
@ -51,7 +56,7 @@ class DefaultJoinRoomTest { @@ -51,7 +56,7 @@ class DefaultJoinRoomTest {
client = client,
analyticsService = analyticsService,
)
sut.invoke(A_ROOM_ID, emptyList(), aTrigger)
sut.invoke(A_ROOM_ID.toRoomIdOrAlias(), emptyList(), aTrigger)
joinRoomByIdOrAliasLambda
.assertions()
.isNeverCalled()
@ -67,9 +72,10 @@ class DefaultJoinRoomTest { @@ -67,9 +72,10 @@ class DefaultJoinRoomTest {
}
@Test
fun `when server names are available, joinRoomByIdOrAlias API is used`() = runTest {
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(Unit) }
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomId, _: List<String> -> Result.success(Unit) }
fun `when using roomId and server names are available, joinRoomByIdOrAlias API is used`() = runTest {
val roomSummary = aRoomSummaryFilled()
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
val roomResult = FakeMatrixRoom()
val aTrigger = JoinedRoom.Trigger.MobilePermalink
val client: MatrixClient = FakeMatrixClient().also {
@ -85,12 +91,12 @@ class DefaultJoinRoomTest { @@ -85,12 +91,12 @@ class DefaultJoinRoomTest {
client = client,
analyticsService = analyticsService,
)
sut.invoke(A_ROOM_ID, A_SERVER_LIST, aTrigger)
sut.invoke(A_ROOM_ID.toRoomIdOrAlias(), A_SERVER_LIST, aTrigger)
joinRoomByIdOrAliasLambda
.assertions()
.isCalledOnce()
.with(
value(A_ROOM_ID),
value(A_ROOM_ID.toRoomIdOrAlias()),
value(A_SERVER_LIST)
)
joinRoomLambda
@ -100,4 +106,40 @@ class DefaultJoinRoomTest { @@ -100,4 +106,40 @@ class DefaultJoinRoomTest {
roomResult.toAnalyticsJoinedRoom(aTrigger)
)
}
@Test
fun `when using roomAlias, joinRoomByIdOrAlias API is used`() = runTest {
val roomSummary = aRoomSummaryFilled()
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
val roomResult = FakeMatrixRoom()
val aTrigger = JoinedRoom.Trigger.MobilePermalink
val client: MatrixClient = FakeMatrixClient().also {
it.joinRoomLambda = joinRoomLambda
it.joinRoomByIdOrAliasLambda = joinRoomByIdOrAliasLambda
it.givenGetRoomResult(
roomId = A_ROOM_ID,
result = roomResult
)
}
val analyticsService = FakeAnalyticsService()
val sut = DefaultJoinRoom(
client = client,
analyticsService = analyticsService,
)
sut.invoke(A_ROOM_ALIAS.toRoomIdOrAlias(), A_SERVER_LIST, aTrigger)
joinRoomByIdOrAliasLambda
.assertions()
.isCalledOnce()
.with(
value(A_ROOM_ALIAS.toRoomIdOrAlias()),
value(emptyList<String>())
)
joinRoomLambda
.assertions()
.isNeverCalled()
assertThat(analyticsService.capturedEvents).containsExactly(
roomResult.toAnalyticsJoinedRoom(aTrigger)
)
}
}

22
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt

@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.MatrixClient @@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.ProgressCallback
import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
@ -36,6 +37,7 @@ import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias @@ -36,6 +37,7 @@ import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
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
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
@ -80,7 +82,7 @@ class FakeMatrixClient( @@ -80,7 +82,7 @@ class FakeMatrixClient(
private val roomDirectoryService: RoomDirectoryService = FakeRoomDirectoryService(),
private val accountManagementUrlString: Result<String?> = Result.success(null),
private val resolveRoomAliasResult: (RoomAlias) -> Result<ResolvedRoomAlias> = { Result.success(ResolvedRoomAlias(A_ROOM_ID, emptyList())) },
private val getRoomPreviewFromRoomIdResult: (RoomId, List<String>) -> Result<RoomPreview> = { _, _ -> 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() },
@ -108,11 +110,11 @@ class FakeMatrixClient( @@ -108,11 +110,11 @@ class FakeMatrixClient(
private var setDisplayNameResult: Result<Unit> = Result.success(Unit)
private var uploadAvatarResult: Result<Unit> = Result.success(Unit)
private var removeAvatarResult: Result<Unit> = Result.success(Unit)
var joinRoomLambda: (RoomId) -> Result<Unit> = {
Result.success(Unit)
var joinRoomLambda: (RoomId) -> Result<RoomSummary?> = {
Result.success(null)
}
var joinRoomByIdOrAliasLambda: (RoomId, List<String>) -> Result<Unit> = { _, _ ->
Result.success(Unit)
var joinRoomByIdOrAliasLambda: (RoomIdOrAlias, List<String>) -> Result<RoomSummary?> = { _, _ ->
Result.success(null)
}
var knockRoomLambda: (RoomId) -> Result<Unit> = {
Result.success(Unit)
@ -207,10 +209,10 @@ class FakeMatrixClient( @@ -207,10 +209,10 @@ class FakeMatrixClient(
return removeAvatarResult
}
override suspend fun joinRoom(roomId: RoomId): Result<Unit> = joinRoomLambda(roomId)
override suspend fun joinRoom(roomId: RoomId): Result<RoomSummary?> = joinRoomLambda(roomId)
override suspend fun joinRoomByIdOrAlias(roomId: RoomId, serverNames: List<String>): Result<Unit> {
return joinRoomByIdOrAliasLambda(roomId, serverNames)
override suspend fun joinRoomByIdOrAlias(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomSummary?> {
return joinRoomByIdOrAliasLambda(roomIdOrAlias, serverNames)
}
override suspend fun knockRoom(roomId: RoomId): Result<Unit> = knockRoomLambda(roomId)
@ -297,8 +299,8 @@ class FakeMatrixClient( @@ -297,8 +299,8 @@ class FakeMatrixClient(
resolveRoomAliasResult(roomAlias)
}
override suspend fun getRoomPreviewFromRoomId(roomId: RoomId, serverNames: List<String>) = simulateLongTask {
getRoomPreviewFromRoomIdResult(roomId, serverNames)
override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreview> = simulateLongTask {
getRoomPreviewResult(roomIdOrAlias, serverNames)
}
override suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>> {

2
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt

@ -68,6 +68,7 @@ fun aRoomSummary( @@ -68,6 +68,7 @@ fun aRoomSummary(
notificationMode: RoomNotificationMode? = null,
inviter: RoomMember? = null,
canonicalAlias: RoomAlias? = null,
alternativeAliases: List<RoomAlias> = emptyList(),
hasRoomCall: Boolean = false,
isDm: Boolean = false,
isFavorite: Boolean = false,
@ -86,6 +87,7 @@ fun aRoomSummary( @@ -86,6 +87,7 @@ fun aRoomSummary(
userDefinedNotificationMode = notificationMode,
inviter = inviter,
canonicalAlias = canonicalAlias,
alternativeAliases = alternativeAliases,
hasRoomCall = hasRoomCall,
isDm = isDm,
isFavorite = isFavorite,

8
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/join/FakeJoinRoom.kt

@ -17,18 +17,18 @@ @@ -17,18 +17,18 @@
package io.element.android.libraries.matrix.test.room.join
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.tests.testutils.simulateLongTask
class FakeJoinRoom(
var lambda: (RoomId, List<String>, JoinedRoom.Trigger) -> Result<Unit>
var lambda: (RoomIdOrAlias, List<String>, JoinedRoom.Trigger) -> Result<Unit>
) : JoinRoom {
override suspend fun invoke(
roomId: RoomId,
roomIdOrAlias: RoomIdOrAlias,
serverNames: List<String>,
trigger: JoinedRoom.Trigger,
): Result<Unit> = simulateLongTask {
lambda(roomId, serverNames, trigger)
lambda(roomIdOrAlias, serverNames, trigger)
}
}

2
libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/RoomSummaryDetailsProvider.kt

@ -38,6 +38,7 @@ fun aRoomSummaryDetails( @@ -38,6 +38,7 @@ fun aRoomSummaryDetails(
roomId: RoomId = RoomId("!room:domain"),
name: String? = "roomName",
canonicalAlias: RoomAlias? = null,
alternativeAliases: List<RoomAlias> = emptyList(),
isDirect: Boolean = true,
avatarUrl: String? = null,
lastMessage: RoomMessage? = null,
@ -56,6 +57,7 @@ fun aRoomSummaryDetails( @@ -56,6 +57,7 @@ fun aRoomSummaryDetails(
roomId = roomId,
name = name,
canonicalAlias = canonicalAlias,
alternativeAliases = alternativeAliases,
isDirect = isDirect,
avatarUrl = avatarUrl,
lastMessage = lastMessage,

5
libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandlerTest.kt

@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.api.core.SessionId @@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.core.asEventId
import io.element.android.libraries.matrix.api.room.Mention
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.api.timeline.ReceiptType
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_MESSAGE
@ -261,7 +262,7 @@ class NotificationBroadcastReceiverHandlerTest { @@ -261,7 +262,7 @@ class NotificationBroadcastReceiverHandlerTest {
@Test
fun `Test join room`() = runTest {
val joinRoom = lambdaRecorder<RoomId, Result<Unit>> { _ -> Result.success(Unit) }
val joinRoom = lambdaRecorder<RoomId, Result<RoomSummary?>> { _ -> Result.success(null) }
val clearMembershipNotificationForRoomLambda = lambdaRecorder<SessionId, RoomId, Unit> { _, _ -> }
val fakeNotificationCleaner = FakeNotificationCleaner(
clearMembershipNotificationForRoomLambda = clearMembershipNotificationForRoomLambda,
@ -444,7 +445,7 @@ class NotificationBroadcastReceiverHandlerTest { @@ -444,7 +445,7 @@ class NotificationBroadcastReceiverHandlerTest {
private fun TestScope.createNotificationBroadcastReceiverHandler(
matrixRoom: FakeMatrixRoom? = FakeMatrixRoom(),
joinRoom: (RoomId) -> Result<Unit> = { lambdaError() },
joinRoom: (RoomId) -> Result<RoomSummary?> = { lambdaError() },
matrixClient: MatrixClient? = FakeMatrixClient().apply {
givenGetRoomResult(A_ROOM_ID, matrixRoom)
joinRoomLambda = joinRoom

Loading…
Cancel
Save