Display error dialog if Element Call can't be joined (#4919)
This commit is contained in:
committed by
GitHub
parent
668d91062c
commit
b500d135b0
@@ -30,6 +30,9 @@ data class WidgetMessage(
|
||||
|
||||
@Serializable
|
||||
enum class Action {
|
||||
@SerialName("io.element.join")
|
||||
Join,
|
||||
|
||||
@SerialName("im.vector.hangup")
|
||||
HangUp,
|
||||
|
||||
|
||||
@@ -48,9 +48,6 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.json.contentOrNull
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
@@ -91,6 +88,7 @@ class CallScreenPresenter @AssistedInject constructor(
|
||||
var webViewError by remember { mutableStateOf<String?>(null) }
|
||||
val languageTag = languageTagProvider.provideLanguageTag()
|
||||
val theme = if (ElementTheme.isLightTheme) "light" else "dark"
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
coroutineScope.launch {
|
||||
// Sets the call as joined
|
||||
@@ -145,17 +143,25 @@ class CallScreenPresenter @AssistedInject constructor(
|
||||
if (parsedMessage?.direction == WidgetMessage.Direction.FromWidget) {
|
||||
if (parsedMessage.action == WidgetMessage.Action.Close) {
|
||||
close(callWidgetDriver.value, navigator)
|
||||
} else if (parsedMessage.action == WidgetMessage.Action.SendEvent) {
|
||||
// This event is received when a member joins the call, the first one will be the current one
|
||||
val type = parsedMessage.data?.jsonObject?.get("type")?.jsonPrimitive?.contentOrNull
|
||||
if (type == "org.matrix.msc3401.call.member") {
|
||||
isJoinedCall = true
|
||||
}
|
||||
} else if (parsedMessage.action == WidgetMessage.Action.Join) {
|
||||
isJoinedCall = true
|
||||
}
|
||||
}
|
||||
}
|
||||
.launchIn(this)
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
// Wait for the call to be joined, if it takes too long, we display an error
|
||||
delay(10.seconds)
|
||||
|
||||
if (!isJoinedCall) {
|
||||
Timber.w("The call took too long to be joined. Displaying an error before exiting.")
|
||||
|
||||
// This will display a simple 'Sorry, an error occurred' dialog and force the user to exit the call
|
||||
webViewError = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun handleEvents(event: CallScreenEvents) {
|
||||
|
||||
@@ -225,7 +225,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - a received room member message makes the call to be active`() = runTest {
|
||||
fun `present - a received 'joined' action makes the call to be active`() = runTest {
|
||||
val navigator = FakeCallScreenNavigator()
|
||||
val widgetDriver = FakeMatrixWidgetDriver()
|
||||
val presenter = createCallScreenPresenter(
|
||||
@@ -248,13 +248,10 @@ import kotlin.time.Duration.Companion.seconds
|
||||
messageInterceptor.givenInterceptedMessage(
|
||||
"""
|
||||
{
|
||||
"action":"send_event",
|
||||
"action":"io.element.join",
|
||||
"api":"fromWidget",
|
||||
"widgetId":"1",
|
||||
"requestId":"1",
|
||||
"data":{
|
||||
"type":"org.matrix.msc3401.call.member"
|
||||
}
|
||||
"requestId":"1"
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
@@ -264,6 +261,40 @@ import kotlin.time.Duration.Companion.seconds
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - if in room mode and no join action is received an error is displayed`() = runTest {
|
||||
val navigator = FakeCallScreenNavigator()
|
||||
val widgetDriver = FakeMatrixWidgetDriver()
|
||||
val presenter = createCallScreenPresenter(
|
||||
callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID),
|
||||
widgetDriver = widgetDriver,
|
||||
navigator = navigator,
|
||||
dispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true),
|
||||
screenTracker = FakeScreenTracker {},
|
||||
)
|
||||
val messageInterceptor = FakeWidgetMessageInterceptor()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
// Give it time to load the URL and WidgetDriver
|
||||
advanceTimeBy(1.seconds)
|
||||
skipItems(2)
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.isCallActive).isFalse()
|
||||
initialState.eventSink(CallScreenEvents.SetupMessageChannels(messageInterceptor))
|
||||
skipItems(2)
|
||||
|
||||
// Wait for the timeout to trigger
|
||||
advanceTimeBy(10.seconds)
|
||||
|
||||
val finalState = awaitItem()
|
||||
assertThat(finalState.isCallActive).isFalse()
|
||||
// The error dialog that will force the user to leave the call is displayed
|
||||
assertThat(finalState.webViewError).isNotNull()
|
||||
assertThat(finalState.webViewError).isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - automatically sets the isInCall state when starting the call and disposing the screen`() = runTest {
|
||||
val navigator = FakeCallScreenNavigator()
|
||||
|
||||
Reference in New Issue
Block a user