Hide Element Call entry point if Element Call service is not available. (#4783)

* Hide Element Call entry point if Element Call service is not available.

* No need to preview the case RoomCallState.Unavailable

* Hide start call action from user profile if Element Call is not available.

* Add mising `use` and cover the problem by a test.

* Update screenshots

* Update enterprise submodule ref.

* Ensure `enterpriseService.isElementCallAvailable()` is not called several times.
And fix unit tests on CI

---------

Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
Benoit Marty 2025-05-27 16:31:05 +02:00 committed by GitHub
parent 730fb684b0
commit 5b9da3c41b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 146 additions and 45 deletions

View file

@ -11,9 +11,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import io.element.android.features.call.api.CurrentCall
import io.element.android.features.call.api.CurrentCallService
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.roomcall.api.RoomCallState
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.room.JoinedRoom
@ -23,9 +25,13 @@ import javax.inject.Inject
class RoomCallStatePresenter @Inject constructor(
private val room: JoinedRoom,
private val currentCallService: CurrentCallService,
private val enterpriseService: EnterpriseService,
) : Presenter<RoomCallState> {
@Composable
override fun present(): RoomCallState {
val isAvailable by produceState(false) {
value = enterpriseService.isElementCallAvailable()
}
val roomInfo by room.roomInfoFlow.collectAsState()
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
val canJoinCall by room.canCall(updateKey = syncUpdateFlow.value)
@ -41,6 +47,7 @@ class RoomCallStatePresenter @Inject constructor(
}
}
val callState = when {
isAvailable.not() -> RoomCallState.Unavailable
roomInfo.hasRoomCall -> RoomCallState.OnGoing(
canJoinCall = canJoinCall,
isUserInTheCall = isUserInTheCall,

View file

@ -11,6 +11,7 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.features.call.api.CurrentCall
import io.element.android.features.call.api.CurrentCallService
import io.element.android.features.call.test.FakeCurrentCallService
import io.element.android.features.enterprise.test.FakeEnterpriseService
import io.element.android.features.roomcall.api.RoomCallState
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
@ -25,12 +26,13 @@ class RoomCallStatePresenterTest {
@Test
fun `present - initial state`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(false) },
)
)
val presenter = createRoomCallStatePresenter(joinedRoom = room)
presenter.test {
skipItems(1)
val initialState = awaitItem()
assertThat(initialState).isEqualTo(
RoomCallState.StandBy(
@ -40,10 +42,29 @@ class RoomCallStatePresenterTest {
}
}
@Test
fun `present - element call not available`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(false) },
)
)
val presenter = createRoomCallStatePresenter(
joinedRoom = room,
isElementCallAvailable = false,
)
presenter.test {
val initialState = awaitItem()
assertThat(initialState).isEqualTo(
RoomCallState.Unavailable
)
}
}
@Test
fun `present - initial state - user can join call`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(true) },
)
)
@ -69,6 +90,7 @@ class RoomCallStatePresenterTest {
)
val presenter = createRoomCallStatePresenter(joinedRoom = room)
presenter.test {
skipItems(1)
assertThat(awaitItem()).isEqualTo(
RoomCallState.OnGoing(
canJoinCall = false,
@ -83,15 +105,15 @@ class RoomCallStatePresenterTest {
fun `present - user has joined the call on another session`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(true) },
).apply {
givenRoomInfo(
aRoomInfo(
hasRoomCall = true,
activeRoomCallParticipants = listOf(sessionId),
canUserJoinCallResult = { Result.success(true) },
).apply {
givenRoomInfo(
aRoomInfo(
hasRoomCall = true,
activeRoomCallParticipants = listOf(sessionId),
)
)
)
}
}
)
val presenter = createRoomCallStatePresenter(joinedRoom = room)
presenter.test {
@ -110,15 +132,15 @@ class RoomCallStatePresenterTest {
fun `present - user has joined the call locally`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(true) },
).apply {
givenRoomInfo(
aRoomInfo(
hasRoomCall = true,
activeRoomCallParticipants = listOf(sessionId),
canUserJoinCallResult = { Result.success(true) },
).apply {
givenRoomInfo(
aRoomInfo(
hasRoomCall = true,
activeRoomCallParticipants = listOf(sessionId),
)
)
)
}
}
)
val presenter = createRoomCallStatePresenter(
joinedRoom = room,
@ -140,15 +162,15 @@ class RoomCallStatePresenterTest {
fun `present - user leaves the call`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(true) },
).apply {
givenRoomInfo(
aRoomInfo(
hasRoomCall = true,
activeRoomCallParticipants = listOf(sessionId),
canUserJoinCallResult = { Result.success(true) },
).apply {
givenRoomInfo(
aRoomInfo(
hasRoomCall = true,
activeRoomCallParticipants = listOf(sessionId),
)
)
)
}
}
)
val currentCall = MutableStateFlow<CurrentCall>(CurrentCall.RoomCall(room.roomId))
val currentCallService = FakeCurrentCallService(currentCall = currentCall)
@ -203,10 +225,14 @@ class RoomCallStatePresenterTest {
private fun createRoomCallStatePresenter(
joinedRoom: JoinedRoom,
currentCallService: CurrentCallService = FakeCurrentCallService(),
isElementCallAvailable: Boolean = true,
): RoomCallStatePresenter {
return RoomCallStatePresenter(
room = joinedRoom,
currentCallService = currentCallService,
enterpriseService = FakeEnterpriseService(
isElementCallAvailableResult = { isElementCallAvailable },
),
)
}
}