Display error dialog if Element Call can't be joined (#4919)
This commit is contained in:
parent
668d91062c
commit
b500d135b0
3 changed files with 55 additions and 15 deletions
|
|
@ -30,6 +30,9 @@ data class WidgetMessage(
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
enum class Action {
|
enum class Action {
|
||||||
|
@SerialName("io.element.join")
|
||||||
|
Join,
|
||||||
|
|
||||||
@SerialName("im.vector.hangup")
|
@SerialName("im.vector.hangup")
|
||||||
HangUp,
|
HangUp,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,6 @@ import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.json.contentOrNull
|
|
||||||
import kotlinx.serialization.json.jsonObject
|
|
||||||
import kotlinx.serialization.json.jsonPrimitive
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
@ -91,6 +88,7 @@ class CallScreenPresenter @AssistedInject constructor(
|
||||||
var webViewError by remember { mutableStateOf<String?>(null) }
|
var webViewError by remember { mutableStateOf<String?>(null) }
|
||||||
val languageTag = languageTagProvider.provideLanguageTag()
|
val languageTag = languageTagProvider.provideLanguageTag()
|
||||||
val theme = if (ElementTheme.isLightTheme) "light" else "dark"
|
val theme = if (ElementTheme.isLightTheme) "light" else "dark"
|
||||||
|
|
||||||
DisposableEffect(Unit) {
|
DisposableEffect(Unit) {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
// Sets the call as joined
|
// Sets the call as joined
|
||||||
|
|
@ -145,17 +143,25 @@ class CallScreenPresenter @AssistedInject constructor(
|
||||||
if (parsedMessage?.direction == WidgetMessage.Direction.FromWidget) {
|
if (parsedMessage?.direction == WidgetMessage.Direction.FromWidget) {
|
||||||
if (parsedMessage.action == WidgetMessage.Action.Close) {
|
if (parsedMessage.action == WidgetMessage.Action.Close) {
|
||||||
close(callWidgetDriver.value, navigator)
|
close(callWidgetDriver.value, navigator)
|
||||||
} else if (parsedMessage.action == WidgetMessage.Action.SendEvent) {
|
} else if (parsedMessage.action == WidgetMessage.Action.Join) {
|
||||||
// This event is received when a member joins the call, the first one will be the current one
|
isJoinedCall = true
|
||||||
val type = parsedMessage.data?.jsonObject?.get("type")?.jsonPrimitive?.contentOrNull
|
|
||||||
if (type == "org.matrix.msc3401.call.member") {
|
|
||||||
isJoinedCall = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(this)
|
.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) {
|
fun handleEvents(event: CallScreenEvents) {
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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 navigator = FakeCallScreenNavigator()
|
||||||
val widgetDriver = FakeMatrixWidgetDriver()
|
val widgetDriver = FakeMatrixWidgetDriver()
|
||||||
val presenter = createCallScreenPresenter(
|
val presenter = createCallScreenPresenter(
|
||||||
|
|
@ -248,13 +248,10 @@ import kotlin.time.Duration.Companion.seconds
|
||||||
messageInterceptor.givenInterceptedMessage(
|
messageInterceptor.givenInterceptedMessage(
|
||||||
"""
|
"""
|
||||||
{
|
{
|
||||||
"action":"send_event",
|
"action":"io.element.join",
|
||||||
"api":"fromWidget",
|
"api":"fromWidget",
|
||||||
"widgetId":"1",
|
"widgetId":"1",
|
||||||
"requestId":"1",
|
"requestId":"1"
|
||||||
"data":{
|
|
||||||
"type":"org.matrix.msc3401.call.member"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".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
|
@Test
|
||||||
fun `present - automatically sets the isInCall state when starting the call and disposing the screen`() = runTest {
|
fun `present - automatically sets the isInCall state when starting the call and disposing the screen`() = runTest {
|
||||||
val navigator = FakeCallScreenNavigator()
|
val navigator = FakeCallScreenNavigator()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue