diff --git a/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt b/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt index 15e320c8f8..f57a94bf1e 100644 --- a/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt +++ b/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt @@ -60,10 +60,18 @@ class RoomCallStatePresenter( isUserLocallyInTheCall = isUserLocallyInTheCall, isAudioCall = roomInfo.activeCallIntentConsensus.isAudio(), ) - else -> RoomCallState.StandBy( - canStartCall = canJoinCall, - isDM = roomInfo.isDm - ) + else -> { + // Nobody would ever join a call started in a DM whose other member has left, + // and the call screen has no way out of that state. + // activeMembersCount counts joined and invited members, so a DM whose peer + // has been invited but has not joined yet can still start a call. + // See https://github.com/element-hq/element-x-android/issues/6189 + val isEmptyDm = roomInfo.isDm && roomInfo.activeMembersCount <= 1 + RoomCallState.StandBy( + canStartCall = canJoinCall && !isEmptyDm, + isDM = roomInfo.isDm + ) + } } } } 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 0612adbea1..9a4c3b0af0 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 @@ -49,6 +49,42 @@ class RoomCallStatePresenterTest { } } + @Test + fun `present - a DM with no other member cannot start a call`() = runTest { + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + initialRoomInfo = aRoomInfo(isDm = true, activeMembersCount = 1, joinedMembersCount = 1), + roomPermissions = roomPermissions(true), + ) + ) + val presenter = createRoomCallStatePresenter(joinedRoom = room) + presenter.test { + skipItems(1) + assertThat(awaitItem()).isEqualTo( + RoomCallState.StandBy( + canStartCall = false, + isDM = true + ) + ) + } + } + + @Test + fun `present - a DM becomes callable once the other member is active`() = runTest { + val baseRoom = FakeBaseRoom( + initialRoomInfo = aRoomInfo(isDm = true, activeMembersCount = 1, joinedMembersCount = 1), + roomPermissions = roomPermissions(true), + ) + val room = FakeJoinedRoom(baseRoom = baseRoom) + val presenter = createRoomCallStatePresenter(joinedRoom = room) + presenter.test { + skipItems(1) + assertThat(awaitItem()).isEqualTo(RoomCallState.StandBy(canStartCall = false, isDM = true)) + baseRoom.givenRoomInfo(aRoomInfo(isDm = true, activeMembersCount = 2, joinedMembersCount = 2)) + assertThat(awaitItem()).isEqualTo(RoomCallState.StandBy(canStartCall = true, isDM = true)) + } + } + @Test fun `present - element call not available`() = runTest { val room = FakeJoinedRoom(