Jitsi call: add join status for Jitsi in RoomDetailViewState

This commit is contained in:
ganfra 2021-07-05 15:45:01 +02:00
parent 7f74278a73
commit 47d2d31a94
5 changed files with 51 additions and 9 deletions

View file

@ -108,8 +108,7 @@ class JitsiService @Inject constructor(
this.avatar = userAvatar?.let { URL(it) } this.avatar = userAvatar?.let { URL(it) }
} }
val roomName = session.getRoomSummary(roomId)?.displayName val roomName = session.getRoomSummary(roomId)?.displayName
val properties = session.widgetService().getWidgetComputedUrl(jitsiWidget, themeProvider.isLightTheme()) val properties = extractProperties(jitsiWidget) ?: throw IllegalStateException()
?.let { url -> jitsiWidgetPropertiesFactory.create(url) } ?: throw IllegalStateException()
val token = if (jitsiWidget.isOpenIdJWTAuthenticationRequired()) { val token = if (jitsiWidget.isOpenIdJWTAuthenticationRequired()) {
getOpenIdJWTToken(roomId, properties.domain, userDisplayName ?: session.myUserId, userAvatar ?: "") getOpenIdJWTToken(roomId, properties.domain, userDisplayName ?: session.myUserId, userAvatar ?: "")
@ -126,6 +125,11 @@ class JitsiService @Inject constructor(
) )
} }
fun extractProperties(jitsiWidget: Widget): JitsiWidgetProperties? {
return session.widgetService().getWidgetComputedUrl(jitsiWidget, themeProvider.isLightTheme())
?.let { url -> jitsiWidgetPropertiesFactory.create(url) }
}
private fun Widget.isOpenIdJWTAuthenticationRequired(): Boolean { private fun Widget.isOpenIdJWTAuthenticationRequired(): Boolean {
return widgetContent.data[JITSI_AUTH_KEY] == JITSI_OPEN_ID_TOKEN_JWT_AUTH return widgetContent.data[JITSI_AUTH_KEY] == JITSI_OPEN_ID_TOKEN_JWT_AUTH
} }

View file

@ -19,6 +19,7 @@ package im.vector.app.features.home.room.detail
import android.net.Uri import android.net.Uri
import android.view.View import android.view.View
import im.vector.app.core.platform.VectorViewModelAction import im.vector.app.core.platform.VectorViewModelAction
import org.jitsi.meet.sdk.BroadcastEvent
import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.content.ContentAttachmentData
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
@ -92,6 +93,7 @@ sealed class RoomDetailAction : VectorViewModelAction {
data class EnsureNativeWidgetAllowed(val widget: Widget, data class EnsureNativeWidgetAllowed(val widget: Widget,
val userJustAccepted: Boolean, val userJustAccepted: Boolean,
val grantedEvents: RoomDetailViewEvents) : RoomDetailAction() val grantedEvents: RoomDetailViewEvents) : RoomDetailAction()
data class UpdateJoinJitsiCallStatus(val broadcastEvent: BroadcastEvent): RoomDetailAction()
data class OpenOrCreateDm(val userId: String) : RoomDetailAction() data class OpenOrCreateDm(val userId: String) : RoomDetailAction()
data class JumpToReadReceipt(val userId: String) : RoomDetailAction() data class JumpToReadReceipt(val userId: String) : RoomDetailAction()
@ -101,6 +103,7 @@ sealed class RoomDetailAction : VectorViewModelAction {
object QuickActionSetTopic : RoomDetailAction() object QuickActionSetTopic : RoomDetailAction()
data class ShowRoomAvatarFullScreen(val matrixItem: MatrixItem?, val transitionView: View?) : RoomDetailAction() data class ShowRoomAvatarFullScreen(val matrixItem: MatrixItem?, val transitionView: View?) : RoomDetailAction()
// Preview URL // Preview URL
data class DoNotShowPreviewUrlFor(val eventId: String, val url: String) : RoomDetailAction() data class DoNotShowPreviewUrlFor(val eventId: String, val url: String) : RoomDetailAction()

View file

@ -120,7 +120,9 @@ import im.vector.app.features.attachments.preview.AttachmentsPreviewArgs
import im.vector.app.features.attachments.toGroupedContentAttachmentData import im.vector.app.features.attachments.toGroupedContentAttachmentData
import im.vector.app.features.call.SharedKnownCallsViewModel import im.vector.app.features.call.SharedKnownCallsViewModel
import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.VectorCallActivity
import im.vector.app.features.call.conference.JitsiBroadcastEventObserver
import im.vector.app.features.call.conference.JitsiCallViewModel import im.vector.app.features.call.conference.JitsiCallViewModel
import im.vector.app.features.call.conference.extractConferenceUrl
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.command.Command import im.vector.app.features.command.Command
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
@ -174,6 +176,7 @@ import nl.dionsegijn.konfetti.models.Shape
import nl.dionsegijn.konfetti.models.Size import nl.dionsegijn.konfetti.models.Size
import org.billcarsonfr.jsonviewer.JSonViewerDialog import org.billcarsonfr.jsonviewer.JSonViewerDialog
import org.commonmark.parser.Parser import org.commonmark.parser.Parser
import org.jitsi.meet.sdk.BroadcastEvent
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.content.ContentAttachmentData
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
@ -301,6 +304,7 @@ class RoomDetailFragment @Inject constructor(
private lateinit var emojiPopup: EmojiPopup private lateinit var emojiPopup: EmojiPopup
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
lifecycle.addObserver(JitsiBroadcastEventObserver(vectorBaseActivity, this::onBroadcastEvent))
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java) sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
knownCallsViewModel = activityViewModelProvider.get(SharedKnownCallsViewModel::class.java) knownCallsViewModel = activityViewModelProvider.get(SharedKnownCallsViewModel::class.java)
@ -412,6 +416,10 @@ class RoomDetailFragment @Inject constructor(
} }
} }
private fun onBroadcastEvent(event: BroadcastEvent) {
roomDetailViewModel.handle(RoomDetailAction.UpdateJoinJitsiCallStatus(event))
}
private fun acceptIncomingCall(event: RoomDetailViewEvents.DisplayAndAcceptCall) { private fun acceptIncomingCall(event: RoomDetailViewEvents.DisplayAndAcceptCall) {
val intent = VectorCallActivity.newIntent( val intent = VectorCallActivity.newIntent(
context = vectorBaseActivity, context = vectorBaseActivity,

View file

@ -39,6 +39,7 @@ import im.vector.app.core.mvrx.runCatchingToAsync
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.call.conference.JitsiService import im.vector.app.features.call.conference.JitsiService
import im.vector.app.features.call.conference.extractConferenceUrl
import im.vector.app.features.call.lookup.CallProtocolsChecker import im.vector.app.features.call.lookup.CallProtocolsChecker
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.command.CommandParser import im.vector.app.features.command.CommandParser
@ -63,8 +64,10 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.commonmark.parser.Parser import org.commonmark.parser.Parser
import org.commonmark.renderer.html.HtmlRenderer import org.commonmark.renderer.html.HtmlRenderer
import org.jitsi.meet.sdk.BroadcastEvent
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
@ -236,8 +239,11 @@ class RoomDetailViewModel @AssistedInject constructor(
.map { widgets -> .map { widgets ->
widgets.filter { it.isActive } widgets.filter { it.isActive }
} }
.execute { .execute { widgets ->
copy(activeRoomWidgets = it) val jitsiConfId = widgets()?.firstOrNull { it.type == WidgetType.Jitsi }?.let { jitsiWidget ->
jitsiService.extractProperties(jitsiWidget)?.confId
}
copy(activeRoomWidgets = widgets, jitsiConfId = jitsiConfId)
} }
} }
@ -303,6 +309,7 @@ class RoomDetailViewModel @AssistedInject constructor(
is RoomDetailAction.EndCall -> handleEndCall() is RoomDetailAction.EndCall -> handleEndCall()
is RoomDetailAction.ManageIntegrations -> handleManageIntegrations() is RoomDetailAction.ManageIntegrations -> handleManageIntegrations()
is RoomDetailAction.AddJitsiWidget -> handleAddJitsiConference(action) is RoomDetailAction.AddJitsiWidget -> handleAddJitsiConference(action)
is RoomDetailAction.UpdateJoinJitsiCallStatus -> handleJitsiCallJoinStatus(action)
is RoomDetailAction.RemoveWidget -> handleDeleteWidget(action.widgetId) is RoomDetailAction.RemoveWidget -> handleDeleteWidget(action.widgetId)
is RoomDetailAction.EnsureNativeWidgetAllowed -> handleCheckWidgetAllowed(action) is RoomDetailAction.EnsureNativeWidgetAllowed -> handleCheckWidgetAllowed(action)
is RoomDetailAction.CancelSend -> handleCancel(action) is RoomDetailAction.CancelSend -> handleCancel(action)
@ -323,6 +330,25 @@ class RoomDetailViewModel @AssistedInject constructor(
}.exhaustive }.exhaustive
} }
private fun handleJitsiCallJoinStatus(action: RoomDetailAction.UpdateJoinJitsiCallStatus) = withState { state ->
if (state.jitsiConfId == null) {
// If jitsi widget is removed while on the call
if (state.hasJoinedActiveJitsiConference) {
setState { copy(hasJoinedActiveJitsiConference = false) }
}
return@withState
}
when (action.broadcastEvent.type) {
BroadcastEvent.Type.CONFERENCE_JOINED,
BroadcastEvent.Type.CONFERENCE_TERMINATED -> {
if (action.broadcastEvent.extractConferenceUrl()?.endsWith(state.jitsiConfId).orFalse()) {
setState { copy(hasJoinedActiveJitsiConference = action.broadcastEvent.type == BroadcastEvent.Type.CONFERENCE_JOINED) }
}
}
else -> Unit
}
}
private fun handleAcceptCall(action: RoomDetailAction.AcceptCall) { private fun handleAcceptCall(action: RoomDetailAction.AcceptCall) {
callManager.getCallById(action.callId)?.also { callManager.getCallById(action.callId)?.also {
_viewEvents.post(RoomDetailViewEvents.DisplayAndAcceptCall(it)) _viewEvents.post(RoomDetailViewEvents.DisplayAndAcceptCall(it))
@ -607,7 +633,7 @@ class RoomDetailViewModel @AssistedInject constructor(
R.id.invite -> state.canInvite R.id.invite -> state.canInvite
R.id.open_matrix_apps -> true R.id.open_matrix_apps -> true
R.id.voice_call -> state.isWebRTCCallOptionAvailable() R.id.voice_call -> state.isWebRTCCallOptionAvailable()
R.id.video_call -> state.isWebRTCCallOptionAvailable() || !state.hasActiveJitsiWidget() R.id.video_call -> true
R.id.search -> true R.id.search -> true
R.id.dev_tools -> vectorPreferences.developerMode() R.id.dev_tools -> vectorPreferences.developerMode()
else -> false else -> false

View file

@ -19,7 +19,6 @@ package im.vector.app.features.home.room.detail
import com.airbnb.mvrx.Async import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
@ -27,7 +26,6 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.sync.SyncState import org.matrix.android.sdk.api.session.sync.SyncState
import org.matrix.android.sdk.api.session.widgets.model.Widget import org.matrix.android.sdk.api.session.widgets.model.Widget
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
/** /**
* Describes the current send mode: * Describes the current send mode:
@ -77,7 +75,10 @@ data class RoomDetailViewState(
val canInvite: Boolean = true, val canInvite: Boolean = true,
val isAllowedToManageWidgets: Boolean = false, val isAllowedToManageWidgets: Boolean = false,
val isAllowedToStartWebRTCCall: Boolean = true, val isAllowedToStartWebRTCCall: Boolean = true,
val hasFailedSending: Boolean = false val hasFailedSending: Boolean = false,
val hasJoinedActiveJitsiConference: Boolean = false,
// Not null if we have an active jitsi widget on the room
val jitsiConfId: String? = null
) : MvRxState { ) : MvRxState {
constructor(args: RoomDetailArgs) : this( constructor(args: RoomDetailArgs) : this(
@ -89,7 +90,7 @@ data class RoomDetailViewState(
fun isWebRTCCallOptionAvailable() = (asyncRoomSummary.invoke()?.joinedMembersCount ?: 0) <= 2 fun isWebRTCCallOptionAvailable() = (asyncRoomSummary.invoke()?.joinedMembersCount ?: 0) <= 2
fun hasActiveJitsiWidget() = activeRoomWidgets()?.any { it.type == WidgetType.Jitsi }.orFalse() fun hasActiveJitsiWidget() =jitsiConfId != null
fun isDm() = asyncRoomSummary()?.isDirect == true fun isDm() = asyncRoomSummary()?.isDirect == true
} }