CallScreenEvents -> CallScreenEvent

This commit is contained in:
Benoit Marty 2026-04-27 17:04:12 +02:00
parent ba3f24cbed
commit 38f09aac95
7 changed files with 25 additions and 25 deletions

View file

@ -10,8 +10,8 @@ package io.element.android.features.call.impl.ui
import io.element.android.features.call.impl.utils.WidgetMessageInterceptor import io.element.android.features.call.impl.utils.WidgetMessageInterceptor
sealed interface CallScreenEvents { sealed interface CallScreenEvent {
data object Hangup : CallScreenEvents data object Hangup : CallScreenEvent
data class SetupMessageChannels(val widgetMessageInterceptor: WidgetMessageInterceptor) : CallScreenEvents data class SetupMessageChannels(val widgetMessageInterceptor: WidgetMessageInterceptor) : CallScreenEvent
data class OnWebViewError(val description: String?) : CallScreenEvents data class OnWebViewError(val description: String?) : CallScreenEvent
} }

View file

@ -152,9 +152,9 @@ class CallScreenPresenter(
} }
} }
fun handleEvent(event: CallScreenEvents) { fun handleEvent(event: CallScreenEvent) {
when (event) { when (event) {
is CallScreenEvents.Hangup -> { is CallScreenEvent.Hangup -> {
val widgetId = callWidgetDriver.value?.id val widgetId = callWidgetDriver.value?.id
val interceptor = messageInterceptor.value val interceptor = messageInterceptor.value
if (widgetId != null && interceptor != null && isWidgetLoaded) { if (widgetId != null && interceptor != null && isWidgetLoaded) {
@ -174,10 +174,10 @@ class CallScreenPresenter(
} }
} }
} }
is CallScreenEvents.SetupMessageChannels -> { is CallScreenEvent.SetupMessageChannels -> {
messageInterceptor.value = event.widgetMessageInterceptor messageInterceptor.value = event.widgetMessageInterceptor
} }
is CallScreenEvents.OnWebViewError -> { is CallScreenEvent.OnWebViewError -> {
if (!ignoreWebViewError) { if (!ignoreWebViewError) {
webViewError = event.description.orEmpty() webViewError = event.description.orEmpty()
} }

View file

@ -15,5 +15,5 @@ data class CallScreenState(
val webViewError: String?, val webViewError: String?,
val userAgent: String, val userAgent: String,
val isCallActive: Boolean, val isCallActive: Boolean,
val eventSink: (CallScreenEvents) -> Unit, val eventSink: (CallScreenEvent) -> Unit,
) )

View file

@ -26,7 +26,7 @@ internal fun aCallScreenState(
webViewError: String? = null, webViewError: String? = null,
userAgent: String = "", userAgent: String = "",
isCallActive: Boolean = true, isCallActive: Boolean = true,
eventSink: (CallScreenEvents) -> Unit = {}, eventSink: (CallScreenEvent) -> Unit = {},
): CallScreenState { ): CallScreenState {
return CallScreenState( return CallScreenState(
urlState = urlState, urlState = urlState,

View file

@ -68,7 +68,7 @@ internal fun CallScreenView(
if (pipState.supportPip) { if (pipState.supportPip) {
pipState.eventSink.invoke(PictureInPictureEvents.EnterPictureInPicture) pipState.eventSink.invoke(PictureInPictureEvents.EnterPictureInPicture)
} else { } else {
state.eventSink(CallScreenEvents.Hangup) state.eventSink(CallScreenEvent.Hangup)
} }
} }
@ -84,7 +84,7 @@ internal fun CallScreenView(
append(stringResource(CommonStrings.error_unknown)) append(stringResource(CommonStrings.error_unknown))
state.webViewError.takeIf { it.isNotEmpty() }?.let { append("\n\n").append(it) } state.webViewError.takeIf { it.isNotEmpty() }?.let { append("\n\n").append(it) }
}, },
onSubmit = { state.eventSink(CallScreenEvents.Hangup) }, onSubmit = { state.eventSink(CallScreenEvent.Hangup) },
) )
} else { } else {
var webViewAudioManager by remember { mutableStateOf<WebViewAudioManager?>(null) } var webViewAudioManager by remember { mutableStateOf<WebViewAudioManager?>(null) }
@ -123,14 +123,14 @@ internal fun CallScreenView(
Timber.d("Can't start in-call audio mode since the app is already in it.") Timber.d("Can't start in-call audio mode since the app is already in it.")
} }
}, },
onError = { state.eventSink(CallScreenEvents.OnWebViewError(it)) }, onError = { state.eventSink(CallScreenEvent.OnWebViewError(it)) },
) )
webViewAudioManager = WebViewAudioManager( webViewAudioManager = WebViewAudioManager(
webView = webView, webView = webView,
coroutineScope = coroutineScope, coroutineScope = coroutineScope,
onInvalidAudioDeviceAdded = { invalidAudioDeviceReason = it }, onInvalidAudioDeviceAdded = { invalidAudioDeviceReason = it },
) )
state.eventSink(CallScreenEvents.SetupMessageChannels(interceptor)) state.eventSink(CallScreenEvent.SetupMessageChannels(interceptor))
val pipController = WebViewPipController(webView) val pipController = WebViewPipController(webView)
pipState.eventSink(PictureInPictureEvents.SetPipController(pipController)) pipState.eventSink(PictureInPictureEvents.SetPipController(pipController))
}, },
@ -147,7 +147,7 @@ internal fun CallScreenView(
Timber.e(state.urlState.error, "WebView failed to load URL: ${state.urlState.error.message}") Timber.e(state.urlState.error, "WebView failed to load URL: ${state.urlState.error.message}")
ErrorDialog( ErrorDialog(
content = state.urlState.error.message.orEmpty(), content = state.urlState.error.message.orEmpty(),
onSubmit = { state.eventSink(CallScreenEvents.Hangup) }, onSubmit = { state.eventSink(CallScreenEvent.Hangup) },
) )
} }
is AsyncData.Success -> Unit is AsyncData.Success -> Unit

View file

@ -79,7 +79,7 @@ class ElementCallActivity :
private val webViewTarget = mutableStateOf<CallData?>(null) private val webViewTarget = mutableStateOf<CallData?>(null)
private var eventSink: ((CallScreenEvents) -> Unit)? = null private var eventSink: ((CallScreenEvent) -> Unit)? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -172,7 +172,7 @@ class ElementCallActivity :
pipEventSink(PictureInPictureEvents.OnPictureInPictureModeChanged(isInPictureInPictureMode)) pipEventSink(PictureInPictureEvents.OnPictureInPictureModeChanged(isInPictureInPictureMode))
if (!isInPictureInPictureMode && !lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { if (!isInPictureInPictureMode && !lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
Timber.tag(loggerTag.value).d("Exiting PiP mode: Hangup the call") Timber.tag(loggerTag.value).d("Exiting PiP mode: Hangup the call")
eventSink?.invoke(CallScreenEvents.Hangup) eventSink?.invoke(CallScreenEvent.Hangup)
} }
} }
addOnPictureInPictureModeChangedListener(onPictureInPictureModeChangedListener) addOnPictureInPictureModeChangedListener(onPictureInPictureModeChangedListener)
@ -280,7 +280,7 @@ class ElementCallActivity :
} }
override fun hangUp() { override fun hangUp() {
eventSink?.invoke(CallScreenEvents.Hangup) eventSink?.invoke(CallScreenEvent.Hangup)
} }
} }

View file

@ -14,7 +14,7 @@ import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.analytics.plan.MobileScreen
import io.element.android.features.call.api.CallData import io.element.android.features.call.api.CallData
import io.element.android.features.call.impl.ui.CallScreenEvents import io.element.android.features.call.impl.ui.CallScreenEvent
import io.element.android.features.call.impl.ui.CallScreenNavigator import io.element.android.features.call.impl.ui.CallScreenNavigator
import io.element.android.features.call.impl.ui.CallScreenPresenter import io.element.android.features.call.impl.ui.CallScreenPresenter
import io.element.android.features.call.impl.utils.WidgetMessageSerializer import io.element.android.features.call.impl.utils.WidgetMessageSerializer
@ -109,7 +109,7 @@ class CallScreenPresenterTest {
advanceTimeBy(1.seconds) advanceTimeBy(1.seconds)
val initialState = awaitItem() val initialState = awaitItem()
initialState.eventSink(CallScreenEvents.SetupMessageChannels(messageInterceptor)) initialState.eventSink(CallScreenEvent.SetupMessageChannels(messageInterceptor))
// And incoming message from the Widget Driver is passed to the WebView // And incoming message from the Widget Driver is passed to the WebView
widgetDriver.givenIncomingMessage("A message") widgetDriver.givenIncomingMessage("A message")
@ -143,9 +143,9 @@ class CallScreenPresenterTest {
// Give it time to load the URL and WidgetDriver // Give it time to load the URL and WidgetDriver
advanceTimeBy(1.seconds) advanceTimeBy(1.seconds)
initialState.eventSink(CallScreenEvents.SetupMessageChannels(messageInterceptor)) initialState.eventSink(CallScreenEvent.SetupMessageChannels(messageInterceptor))
initialState.eventSink(CallScreenEvents.Hangup) initialState.eventSink(CallScreenEvent.Hangup)
// Let background coroutines run and the widget drive be received // Let background coroutines run and the widget drive be received
runCurrent() runCurrent()
@ -177,7 +177,7 @@ class CallScreenPresenterTest {
// Give it time to load the URL and WidgetDriver // Give it time to load the URL and WidgetDriver
advanceTimeBy(1.seconds) advanceTimeBy(1.seconds)
initialState.eventSink(CallScreenEvents.SetupMessageChannels(messageInterceptor)) initialState.eventSink(CallScreenEvent.SetupMessageChannels(messageInterceptor))
messageInterceptor.givenInterceptedMessage("""{"action":"io.element.close","api":"fromWidget","widgetId":"1","requestId":"1"}""") messageInterceptor.givenInterceptedMessage("""{"action":"io.element.close","api":"fromWidget","widgetId":"1","requestId":"1"}""")
@ -212,7 +212,7 @@ class CallScreenPresenterTest {
skipItems(2) skipItems(2)
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.isCallActive).isFalse() assertThat(initialState.isCallActive).isFalse()
initialState.eventSink(CallScreenEvents.SetupMessageChannels(messageInterceptor)) initialState.eventSink(CallScreenEvent.SetupMessageChannels(messageInterceptor))
messageInterceptor.givenInterceptedMessage( messageInterceptor.givenInterceptedMessage(
""" """
{ {
@ -249,7 +249,7 @@ class CallScreenPresenterTest {
skipItems(2) skipItems(2)
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.isCallActive).isFalse() assertThat(initialState.isCallActive).isFalse()
initialState.eventSink(CallScreenEvents.SetupMessageChannels(messageInterceptor)) initialState.eventSink(CallScreenEvent.SetupMessageChannels(messageInterceptor))
skipItems(2) skipItems(2)
// Wait for the timeout to trigger // Wait for the timeout to trigger