diff --git a/vector/src/main/java/im/vector/app/core/ui/views/ActiveConferenceView.kt b/vector/src/main/java/im/vector/app/core/ui/views/ActiveConferenceView.kt
deleted file mode 100644
index 256f2d963e..0000000000
--- a/vector/src/main/java/im/vector/app/core/ui/views/ActiveConferenceView.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2020 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.app.core.ui.views
-
-import android.content.Context
-import android.text.SpannableString
-import android.text.method.LinkMovementMethod
-import android.text.style.ClickableSpan
-import android.util.AttributeSet
-import android.view.View
-import android.widget.RelativeLayout
-import androidx.core.view.isVisible
-import im.vector.app.R
-import im.vector.app.core.utils.tappableMatchingText
-import im.vector.app.databinding.ViewActiveConferenceViewBinding
-import im.vector.app.features.home.room.detail.RoomDetailViewState
-import im.vector.app.features.themes.ThemeUtils
-import org.matrix.android.sdk.api.session.room.model.Membership
-import org.matrix.android.sdk.api.session.widgets.model.Widget
-import org.matrix.android.sdk.api.session.widgets.model.WidgetType
-
-class ActiveConferenceView @JvmOverloads constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0
-) : RelativeLayout(context, attrs, defStyleAttr) {
-
- interface Callback {
- fun onTapJoinAudio(jitsiWidget: Widget)
- fun onTapJoinVideo(jitsiWidget: Widget)
- fun onDelete(jitsiWidget: Widget)
- }
-
- var callback: Callback? = null
- private var jitsiWidget: Widget? = null
-
- private lateinit var views: ViewActiveConferenceViewBinding
-
- init {
- setupView()
- }
-
- private fun setupView() {
- inflate(context, R.layout.view_active_conference_view, this)
- views = ViewActiveConferenceViewBinding.bind(this)
- setBackgroundColor(ThemeUtils.getColor(context, R.attr.colorPrimary))
-
- // "voice" and "video" texts are underlined and clickable
- val voiceString = context.getString(R.string.ongoing_conference_call_voice)
- val videoString = context.getString(R.string.ongoing_conference_call_video)
-
- val fullMessage = context.getString(R.string.ongoing_conference_call, voiceString, videoString)
-
- val styledText = SpannableString(fullMessage)
- styledText.tappableMatchingText(voiceString, object : ClickableSpan() {
- override fun onClick(widget: View) {
- jitsiWidget?.let {
- callback?.onTapJoinAudio(it)
- }
- }
- })
- styledText.tappableMatchingText(videoString, object : ClickableSpan() {
- override fun onClick(widget: View) {
- jitsiWidget?.let {
- callback?.onTapJoinVideo(it)
- }
- }
- })
-
- views.activeConferenceInfo.apply {
- text = styledText
- movementMethod = LinkMovementMethod.getInstance()
- }
-
- views.deleteWidgetButton.setOnClickListener {
- jitsiWidget?.let { callback?.onDelete(it) }
- }
- }
-
- fun render(state: RoomDetailViewState) {
- val summary = state.asyncRoomSummary()
- if (summary?.membership == Membership.JOIN) {
- // We only display banner for 'live' widgets
- jitsiWidget = state.activeRoomWidgets()?.firstOrNull {
- // for now only jitsi?
- it.type == WidgetType.Jitsi
- }
-
- isVisible = jitsiWidget != null
- // if sent by me or if i can moderate?
- views.deleteWidgetButton.isVisible = state.isAllowedToManageWidgets
- } else {
- isVisible = false
- }
- }
-}
diff --git a/vector/src/main/java/im/vector/app/features/call/conference/RemoveJitsiWidgetView.kt b/vector/src/main/java/im/vector/app/features/call/conference/RemoveJitsiWidgetView.kt
new file mode 100644
index 0000000000..cb26d5416b
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/call/conference/RemoveJitsiWidgetView.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.call.conference
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.res.ColorStateList
+import android.util.AttributeSet
+import android.view.MotionEvent
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
+import androidx.core.widget.ImageViewCompat
+import im.vector.app.R
+import im.vector.app.databinding.ViewRemoveJitsiWidgetBinding
+import im.vector.app.features.home.room.detail.RoomDetailViewState
+import org.matrix.android.sdk.api.session.room.model.Membership
+
+@SuppressLint("ClickableViewAccessibility") class RemoveJitsiWidgetView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+) : ConstraintLayout(context, attrs, defStyleAttr) {
+
+ private sealed class State {
+ object Unmount : State()
+ object Idle : State()
+ data class Sliding(val initialX: Float, val translationX: Float, val hasReachedActivationThreshold: Boolean) : State()
+ object Progress : State()
+ }
+
+ private val views: ViewRemoveJitsiWidgetBinding
+ private var state: State = State.Unmount
+ var onCompleteSliding: (() -> Unit)? = null
+
+ init {
+ inflate(context, R.layout.view_remove_jitsi_widget, this)
+ views = ViewRemoveJitsiWidgetBinding.bind(this)
+ views.removeJitsiSlidingContainer.setOnTouchListener { _, event ->
+ val currentState = state
+ return@setOnTouchListener when (event.action) {
+ MotionEvent.ACTION_DOWN -> {
+ if (currentState == State.Idle) {
+ val initialX = views.removeJitsiSlidingContainer.x - event.rawX
+ updateState(State.Sliding(initialX, 0f, false))
+ }
+ true
+ }
+ MotionEvent.ACTION_UP,
+ MotionEvent.ACTION_CANCEL -> {
+ if (currentState is State.Sliding) {
+ if (currentState.hasReachedActivationThreshold) {
+ updateState(State.Progress)
+ } else {
+ updateState(State.Idle)
+ }
+ }
+ true
+ }
+ MotionEvent.ACTION_MOVE -> {
+ if (currentState is State.Sliding) {
+ val translationX = (currentState.initialX + event.rawX).coerceAtLeast(0f)
+ val hasReachedActivationThreshold = views.removeJitsiSlidingContainer.width + translationX >= views.removeJitsiHangupContainer.x
+ updateState(State.Sliding(currentState.initialX, translationX, hasReachedActivationThreshold))
+ }
+ true
+ }
+ else -> false
+ }
+ }
+ renderInternalState(state)
+ }
+
+ fun render(roomDetailViewState: RoomDetailViewState) {
+ val summary = roomDetailViewState.asyncRoomSummary()
+ val newState = if (summary?.membership != Membership.JOIN || !roomDetailViewState.isAllowedToManageWidgets || roomDetailViewState.jitsiState.widgetId == null) {
+ State.Unmount
+ } else if (roomDetailViewState.jitsiState.deleteWidgetInProgress) {
+ State.Progress
+ } else {
+ State.Idle
+ }
+ // Don't force Idle if we are already sliding
+ if (state is State.Sliding && newState is State.Idle) {
+ return
+ } else {
+ updateState(newState)
+ }
+ }
+
+ private fun updateState(newState: State) {
+ if (newState == state) {
+ return
+ }
+ renderInternalState(newState)
+ state = newState
+ if (state == State.Progress) {
+ onCompleteSliding?.invoke()
+ }
+ }
+
+ private fun renderInternalState(state: State) {
+ isVisible = state != State.Unmount
+ when (state) {
+ State.Progress -> {
+ isVisible = true
+ views.updateVisibilities(true)
+ views.updateHangupColors(true)
+ }
+ State.Idle -> {
+ isVisible = true
+ views.updateVisibilities(false)
+ views.removeJitsiSlidingContainer.translationX = 0f
+ views.updateHangupColors(false)
+ }
+ is State.Sliding -> {
+ isVisible = true
+ views.updateVisibilities(false)
+ views.removeJitsiSlidingContainer.translationX = state.translationX
+ views.updateHangupColors(state.hasReachedActivationThreshold)
+ }
+ else -> Unit
+ }
+ }
+
+ private fun ViewRemoveJitsiWidgetBinding.updateVisibilities(isProgress: Boolean) {
+ removeJitsiProgressContainer.isVisible = isProgress
+ removeJitsiHangupContainer.isVisible = !isProgress
+ removeJitsiSlidingContainer.isVisible = !isProgress
+ }
+
+ private fun ViewRemoveJitsiWidgetBinding.updateHangupColors(activated: Boolean) {
+ val iconTintColor: Int
+ val bgColor: Int
+ if (activated) {
+ bgColor = ContextCompat.getColor(context, R.color.palette_vermilion)
+ iconTintColor = ContextCompat.getColor(context, R.color.palette_white)
+ } else {
+ bgColor = ContextCompat.getColor(context, android.R.color.transparent)
+ iconTintColor = ContextCompat.getColor(context, R.color.palette_vermilion)
+ }
+ removeJitsiHangupContainer.setBackgroundColor(bgColor)
+ ImageViewCompat.setImageTintList(removeJitsiHangupIcon, ColorStateList.valueOf(iconTintColor))
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
index 3e55b2b924..224c52b30f 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
@@ -67,7 +67,6 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
-import com.facebook.react.bridge.JavaOnlyMap
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.jakewharton.rxbinding3.view.focusChanges
import com.jakewharton.rxbinding3.widget.textChanges
@@ -90,7 +89,6 @@ import im.vector.app.core.intent.getMimeTypeFromUri
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.platform.showOptimizedSnackbar
import im.vector.app.core.resources.ColorProvider
-import im.vector.app.core.ui.views.ActiveConferenceView
import im.vector.app.core.ui.views.CurrentCallsCardView
import im.vector.app.core.ui.views.FailedMessagesWarningView
import im.vector.app.core.ui.views.NotificationAreaView
@@ -124,7 +122,6 @@ import im.vector.app.features.call.VectorCallActivity
import im.vector.app.features.call.conference.JitsiBroadcastEmitter
import im.vector.app.features.call.conference.JitsiBroadcastEventObserver
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.command.Command
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
@@ -178,7 +175,6 @@ import nl.dionsegijn.konfetti.models.Shape
import nl.dionsegijn.konfetti.models.Size
import org.billcarsonfr.jsonviewer.JSonViewerDialog
import org.commonmark.parser.Parser
-import org.jitsi.meet.sdk.BroadcastEmitter
import org.jitsi.meet.sdk.BroadcastEvent
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
@@ -331,9 +327,10 @@ class RoomDetailFragment @Inject constructor(
setupJumpToReadMarkerView()
setupActiveCallView()
setupJumpToBottomView()
- setupConfBannerView()
setupEmojiPopup()
setupFailedMessagesWarningView()
+ setupRemoveJitsiWidgetView()
+
views.roomToolbarContentView.debouncedClicks {
navigator.openRoomProfile(requireActivity(), roomDetailArgs.roomId)
@@ -397,7 +394,7 @@ class RoomDetailFragment @Inject constructor(
RoomDetailViewEvents.OpenActiveWidgetBottomSheet -> onViewWidgetsClicked()
is RoomDetailViewEvents.ShowInfoOkDialog -> showDialogWithMessage(it.message)
is RoomDetailViewEvents.JoinJitsiConference -> joinJitsiRoom(it.widget, it.withVideo)
- RoomDetailViewEvents.LeaveJitsiConference -> leaveJitsiConference()
+ RoomDetailViewEvents.LeaveJitsiConference -> leaveJitsiConference()
RoomDetailViewEvents.ShowWaitingView -> vectorBaseActivity.showWaitingView()
RoomDetailViewEvents.HideWaitingView -> vectorBaseActivity.hideWaitingView()
is RoomDetailViewEvents.RequestNativeWidgetPermission -> requestNativeWidgetPermission(it)
@@ -420,6 +417,18 @@ class RoomDetailFragment @Inject constructor(
}
}
+ private fun setupRemoveJitsiWidgetView() {
+ views.removeJitsiWidgetView.onCompleteSliding = {
+ withState(roomDetailViewModel) {
+ val jitsiWidgetId = it.jitsiState.widgetId ?: return@withState
+ if (it.jitsiState.hasJoined) {
+ leaveJitsiConference()
+ }
+ roomDetailViewModel.handle(RoomDetailAction.RemoveWidget(jitsiWidgetId))
+ }
+ }
+ }
+
private fun leaveJitsiConference() {
JitsiBroadcastEmitter(vectorBaseActivity).emitConferenceEnded()
}
@@ -530,31 +539,6 @@ class RoomDetailFragment @Inject constructor(
)
}
- private fun setupConfBannerView() {
- views.activeConferenceView.callback = object : ActiveConferenceView.Callback {
- override fun onTapJoinAudio(jitsiWidget: Widget) {
- // need to check if allowed first
- roomDetailViewModel.handle(RoomDetailAction.EnsureNativeWidgetAllowed(
- widget = jitsiWidget,
- userJustAccepted = false,
- grantedEvents = RoomDetailViewEvents.JoinJitsiConference(jitsiWidget, false))
- )
- }
-
- override fun onTapJoinVideo(jitsiWidget: Widget) {
- roomDetailViewModel.handle(RoomDetailAction.EnsureNativeWidgetAllowed(
- widget = jitsiWidget,
- userJustAccepted = false,
- grantedEvents = RoomDetailViewEvents.JoinJitsiConference(jitsiWidget, true))
- )
- }
-
- override fun onDelete(jitsiWidget: Widget) {
- roomDetailViewModel.handle(RoomDetailAction.RemoveWidget(jitsiWidget.widgetId))
- }
- }
- }
-
private fun setupEmojiPopup() {
emojiPopup = EmojiPopup
.Builder
@@ -1261,7 +1245,7 @@ class RoomDetailFragment @Inject constructor(
invalidateOptionsMenu()
val summary = state.asyncRoomSummary()
renderToolbar(summary, state.typingMessage)
- views.activeConferenceView.render(state)
+ views.removeJitsiWidgetView.render(state)
views.failedMessagesWarningView.render(state.hasFailedSending)
val inviter = state.asyncInviter()
if (summary?.membership == Membership.JOIN) {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
index 106c753068..29b50eb77e 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
@@ -60,12 +60,12 @@ import io.reactivex.Observable
import io.reactivex.rxkotlin.subscribeBy
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.commonmark.parser.Parser
import org.commonmark.renderer.html.HtmlRenderer
import org.jitsi.meet.sdk.BroadcastEvent
-import org.jitsi.meet.sdk.JitsiMeet
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.extensions.orFalse
@@ -241,18 +241,25 @@ class RoomDetailViewModel @AssistedInject constructor(
widgets.filter { it.isActive }
}
.execute { widgets ->
- val jitsiWidget = widgets()?.firstOrNull { it.type == WidgetType.Jitsi }
- val jitsiConfId = jitsiWidget?.let {
- jitsiService.extractProperties(it)?.confId
- }
copy(
activeRoomWidgets = widgets,
- jitsiState = jitsiState.copy(
- confId = jitsiConfId,
- widgetId = jitsiWidget?.widgetId
- )
)
}
+
+ asyncSubscribe(RoomDetailViewState::activeRoomWidgets) { widgets ->
+ setState {
+ val jitsiWidget = widgets.firstOrNull { it.type == WidgetType.Jitsi }
+ val jitsiConfId = jitsiWidget?.let {
+ jitsiService.extractProperties(it)?.confId
+ }
+ copy(
+ jitsiState = jitsiState.copy(
+ confId = jitsiConfId,
+ widgetId = jitsiWidget?.widgetId
+ )
+ )
+ }
+ }
}
private fun observeMyRoomMember() {
@@ -318,8 +325,8 @@ class RoomDetailViewModel @AssistedInject constructor(
is RoomDetailAction.ManageIntegrations -> handleManageIntegrations()
is RoomDetailAction.AddJitsiWidget -> handleAddJitsiConference(action)
is RoomDetailAction.UpdateJoinJitsiCallStatus -> handleJitsiCallJoinStatus(action)
- is RoomDetailAction.JoinJitsiCall -> handleJoinJitsiCall()
- is RoomDetailAction.LeaveJitsiCall -> handleLeaveJitsiCall()
+ is RoomDetailAction.JoinJitsiCall -> handleJoinJitsiCall()
+ is RoomDetailAction.LeaveJitsiCall -> handleLeaveJitsiCall()
is RoomDetailAction.RemoveWidget -> handleDeleteWidget(action.widgetId)
is RoomDetailAction.EnsureNativeWidgetAllowed -> handleCheckWidgetAllowed(action)
is RoomDetailAction.CancelSend -> handleCancel(action)
@@ -363,8 +370,8 @@ class RoomDetailViewModel @AssistedInject constructor(
_viewEvents.post(RoomDetailViewEvents.LeaveJitsiConference)
}
- private fun handleJoinJitsiCall() = withState{ state ->
- val jitsiWidget = state.activeRoomWidgets()?.firstOrNull { it.widgetId == state.jitsiState.widgetId} ?: return@withState
+ private fun handleJoinJitsiCall() = withState { state ->
+ val jitsiWidget = state.activeRoomWidgets()?.firstOrNull { it.widgetId == state.jitsiState.widgetId } ?: return@withState
val action = RoomDetailAction.EnsureNativeWidgetAllowed(jitsiWidget, false, RoomDetailViewEvents.JoinJitsiConference(jitsiWidget, true))
handleCheckWidgetAllowed(action)
}
@@ -477,10 +484,15 @@ class RoomDetailViewModel @AssistedInject constructor(
}
}
- private fun handleDeleteWidget(widgetId: String) {
- _viewEvents.post(RoomDetailViewEvents.ShowWaitingView)
+ private fun handleDeleteWidget(widgetId: String) = withState { state ->
+ val isJitsiWidget = state.jitsiState.widgetId == widgetId
viewModelScope.launch(Dispatchers.IO) {
try {
+ if (isJitsiWidget) {
+ setState { copy(jitsiState = jitsiState.copy(deleteWidgetInProgress = true)) }
+ } else {
+ _viewEvents.post(RoomDetailViewEvents.ShowWaitingView)
+ }
session.widgetService().destroyRoomWidget(room.roomId, widgetId)
// local echo
setState {
@@ -496,7 +508,11 @@ class RoomDetailViewModel @AssistedInject constructor(
} catch (failure: Throwable) {
_viewEvents.post(RoomDetailViewEvents.ShowMessage(stringProvider.getString(R.string.failed_to_remove_widget)))
} finally {
- _viewEvents.post(RoomDetailViewEvents.HideWaitingView)
+ if (isJitsiWidget) {
+ setState { copy(jitsiState = jitsiState.copy(deleteWidgetInProgress = false)) }
+ } else {
+ _viewEvents.post(RoomDetailViewEvents.HideWaitingView)
+ }
}
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt
index 75650ed322..f368036b9e 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt
@@ -59,7 +59,8 @@ data class JitsiState(
val hasJoined: Boolean = false,
// Not null if we have an active jitsi widget on the room
val confId: String? = null,
- val widgetId: String? = null
+ val widgetId: String? = null,
+ val deleteWidgetInProgress: Boolean = false
)
data class RoomDetailViewState(
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/WidgetItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/WidgetItemFactory.kt
index 84867e15c6..e856907717 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/WidgetItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/WidgetItemFactory.kt
@@ -38,13 +38,8 @@ class WidgetItemFactory @Inject constructor(
private val avatarSizeProvider: AvatarSizeProvider,
private val messageColorProvider: MessageColorProvider,
private val avatarRenderer: AvatarRenderer,
- private val activeSessionDataSource: ActiveSessionDataSource,
private val roomSummariesHolder: RoomSummariesHolder
) {
- private val currentUserId: String?
- get() = activeSessionDataSource.currentValue?.orNull()?.myUserId
-
- private fun Event.isSentByCurrentUser() = senderId != null && senderId == currentUserId
fun create(params: TimelineItemFactoryParams): VectorEpoxyModel<*>? {
val event = params.event
diff --git a/vector/src/main/res/layout/fragment_room_detail.xml b/vector/src/main/res/layout/fragment_room_detail.xml
index 65da9156c9..3b96146c4d 100644
--- a/vector/src/main/res/layout/fragment_room_detail.xml
+++ b/vector/src/main/res/layout/fragment_room_detail.xml
@@ -100,13 +100,14 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appBarLayout" />
-
+ android:visibility="visible"
+ android:background="?android:colorBackground"
+ android:minHeight="54dp"
+ app:layout_constraintTop_toBottomOf="@id/syncStateView"/>
diff --git a/vector/src/main/res/layout/view_active_conference_view.xml b/vector/src/main/res/layout/view_active_conference_view.xml
deleted file mode 100644
index 9f26ed9a1a..0000000000
--- a/vector/src/main/res/layout/view_active_conference_view.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/vector/src/main/res/layout/view_remove_jitsi_widget.xml b/vector/src/main/res/layout/view_remove_jitsi_widget.xml
new file mode 100644
index 0000000000..0da5493ce9
--- /dev/null
+++ b/vector/src/main/res/layout/view_remove_jitsi_widget.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml
index da7ed473ff..632ecf3409 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -742,6 +742,8 @@
Cannot initialize the camera
call answered elsewhere
+ Ending call…
+
Take a picture or a video"
Cannot record video"
@@ -3247,6 +3249,8 @@
Transfer to %1$s
Unknown person
+ Slide to end the call for everyone
+
Re-Authentication Needed
${app_name} requires you to enter your credentials to perform this action.
@@ -3409,4 +3413,5 @@
"Teammate spaces aren’t quite ready but you can still give them a try"
"At the moment people might not be able to join any private rooms you make.\n\nWe’ll be improving this as part of the beta, but just wanted to let you know."
Sorry, an error occurred while trying to join: %s
+