diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomSummaryRow.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomSummaryRow.kt index e2598a9e1c..f541417104 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomSummaryRow.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomSummaryRow.kt @@ -60,6 +60,7 @@ import io.element.android.libraries.designsystem.theme.roomListRoomMessage import io.element.android.libraries.designsystem.theme.roomListRoomMessageDate import io.element.android.libraries.designsystem.theme.roomListRoomName import io.element.android.libraries.designsystem.theme.unreadIndicator +import io.element.android.libraries.matrix.api.notification.CallIntent import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.ui.components.InviteSenderView import io.element.android.libraries.matrix.ui.model.InviteSender @@ -349,6 +350,7 @@ private fun MessagePreviewAndIndicatorRow( if (room.hasRoomCall) { OnGoingCallIcon( color = tint, + isAudio = room.activeCallIntent == CallIntent.AUDIO ) } if (room.userDefinedNotificationMode == RoomNotificationMode.MUTE) { @@ -398,10 +400,11 @@ private fun InviteNameAndIndicatorRow( @Composable private fun OnGoingCallIcon( color: Color, + isAudio: Boolean ) { Icon( modifier = Modifier.size(16.dp), - imageVector = CompoundIcons.VideoCallSolid(), + imageVector = if (isAudio) CompoundIcons.VoiceCallSolid() else CompoundIcons.VideoCallSolid(), contentDescription = stringResource(CommonStrings.a11y_notifications_ongoing_call), tint = color, ) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/datasource/RoomListRoomSummaryFactory.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/datasource/RoomListRoomSummaryFactory.kt index d723d1a424..26054d7e56 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/datasource/RoomListRoomSummaryFactory.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/datasource/RoomListRoomSummaryFactory.kt @@ -17,6 +17,7 @@ import io.element.android.libraries.dateformatter.api.DateFormatter import io.element.android.libraries.dateformatter.api.DateFormatterMode import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.eventformatter.api.RoomLatestEventFormatter +import io.element.android.libraries.matrix.api.room.CallIntentConsensus import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.isDm import io.element.android.libraries.matrix.api.roomlist.LatestEventValue @@ -50,6 +51,11 @@ class RoomListRoomSummaryFactory( avatarData = avatarData, userDefinedNotificationMode = roomInfo.userDefinedNotificationMode, hasRoomCall = roomInfo.hasRoomCall, + activeCallIntent = when (val consensus = roomInfo.activeCallIntentConsensus) { + is CallIntentConsensus.Full -> consensus.callIntent + is CallIntentConsensus.Partial -> consensus.callIntent + CallIntentConsensus.None -> null + }, isDirect = roomInfo.isDirect, isFavorite = roomInfo.isFavorite, inviteSender = roomInfo.inviter?.toInviteSender(), diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/model/RoomListRoomSummary.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/model/RoomListRoomSummary.kt index a59e444455..628d0d0a9b 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/model/RoomListRoomSummary.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/model/RoomListRoomSummary.kt @@ -13,6 +13,7 @@ import io.element.android.features.invite.api.InviteData import io.element.android.libraries.designsystem.components.avatar.AvatarData 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.notification.CallIntent import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.ui.model.InviteSender import kotlinx.collections.immutable.ImmutableList @@ -33,6 +34,7 @@ data class RoomListRoomSummary( val avatarData: AvatarData, val userDefinedNotificationMode: RoomNotificationMode?, val hasRoomCall: Boolean, + val activeCallIntent: CallIntent?, val isDirect: Boolean, val isDm: Boolean, val isFavorite: Boolean, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/model/RoomListRoomSummaryProvider.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/model/RoomListRoomSummaryProvider.kt index 400decff6f..eefb2d6484 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/model/RoomListRoomSummaryProvider.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/model/RoomListRoomSummaryProvider.kt @@ -14,6 +14,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize 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.UserId +import io.element.android.libraries.matrix.api.notification.CallIntent import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.ui.model.InviteSender import kotlinx.collections.immutable.toImmutableList @@ -132,6 +133,14 @@ open class RoomListRoomSummaryProvider : PreviewParameterProvider RoomCallState.StandBy( canStartCall = canJoinCall, @@ -70,3 +71,12 @@ class RoomCallStatePresenter( return callState } } + +fun CallIntentConsensus.isAudio(): Boolean { + val intent = when (this) { + is CallIntentConsensus.Full -> callIntent + is CallIntentConsensus.Partial -> callIntent + is CallIntentConsensus.None -> return false + } + return intent == CallIntent.AUDIO +} diff --git a/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt b/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt index 0a561ad59a..4c6fcf8e59 100644 --- a/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt +++ b/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt @@ -14,6 +14,8 @@ import io.element.android.features.call.api.CurrentCallService import io.element.android.features.call.test.FakeCurrentCallService import io.element.android.features.enterprise.test.FakeSessionEnterpriseService import io.element.android.features.roomcall.api.RoomCallState +import io.element.android.libraries.matrix.api.notification.CallIntent +import io.element.android.libraries.matrix.api.room.CallIntentConsensus import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.test.room.FakeBaseRoom @@ -188,6 +190,100 @@ class RoomCallStatePresenterTest { } } + @Test + fun `present - active call with audio Intent`() = runTest { + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + roomPermissions = roomPermissions(true), + ).apply { + givenRoomInfo( + aRoomInfo( + hasRoomCall = true, + activeCallIntentConsensus = CallIntentConsensus.Full(CallIntent.AUDIO), + activeRoomCallParticipants = emptyList(), + ) + ) + } + ) + val presenter = createRoomCallStatePresenter( + joinedRoom = room, + currentCallService = FakeCurrentCallService(MutableStateFlow(CurrentCall.RoomCall(room.roomId))), + ) + presenter.test { + skipItems(1) + assertThat(awaitItem()).isEqualTo( + RoomCallState.OnGoing( + canJoinCall = true, + isAudioCall = true, + isUserInTheCall = false, + isUserLocallyInTheCall = true, + ) + ) + } + } + + @Test + fun `present - active call with partial audio Intent`() = runTest { + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + roomPermissions = roomPermissions(true), + ).apply { + givenRoomInfo( + aRoomInfo( + hasRoomCall = true, + activeCallIntentConsensus = CallIntentConsensus.Partial(CallIntent.AUDIO, 1, 4), + ) + ) + } + ) + val presenter = createRoomCallStatePresenter( + joinedRoom = room, + currentCallService = FakeCurrentCallService(MutableStateFlow(CurrentCall.RoomCall(room.roomId))), + ) + presenter.test { + skipItems(1) + assertThat(awaitItem()).isEqualTo( + RoomCallState.OnGoing( + canJoinCall = true, + isAudioCall = true, + isUserInTheCall = false, + isUserLocallyInTheCall = true, + ) + ) + } + } + + @Test + fun `present - active call with no intent defaults to Audio`() = runTest { + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + roomPermissions = roomPermissions(true), + ).apply { + givenRoomInfo( + aRoomInfo( + hasRoomCall = true, + activeCallIntentConsensus = CallIntentConsensus.None, + ) + ) + } + ) + val presenter = createRoomCallStatePresenter( + joinedRoom = room, + currentCallService = FakeCurrentCallService(MutableStateFlow(CurrentCall.RoomCall(room.roomId))), + ) + presenter.test { + skipItems(1) + assertThat(awaitItem()).isEqualTo( + RoomCallState.OnGoing( + canJoinCall = true, + isAudioCall = false, + isUserInTheCall = false, + isUserLocallyInTheCall = true, + ) + ) + } + } + @Test fun `present - user leaves the call`() = runTest { val room = FakeJoinedRoom( diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomSummaryRow_Day_38_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomSummaryRow_Day_38_en.png new file mode 100644 index 0000000000..473fd3f275 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomSummaryRow_Day_38_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26071a6b16f4446526f6abf28274580eb0f385bd0e74f4f2b0479da5f5d4f6f2 +size 12914 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomSummaryRow_Night_38_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomSummaryRow_Night_38_en.png new file mode 100644 index 0000000000..14c08f0b62 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomSummaryRow_Night_38_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ddef7c50d6a791c6a32bae8506a999b198bc601b70b6ffb5e5e7a8d5a2f1543 +size 12869