Rework how audio only layout will be handled

This commit is contained in:
Sylvain Berfini 2022-03-31 15:47:15 +02:00
parent 7b933ad76b
commit 291ae367a6
19 changed files with 448 additions and 263 deletions

View file

@ -23,6 +23,7 @@ import android.Manifest
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.activities.voip.ConferenceDisplayMode
import org.linphone.core.* import org.linphone.core.*
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
import org.linphone.utils.AudioRouteUtils import org.linphone.utils.AudioRouteUtils
@ -44,9 +45,7 @@ class ConferenceWaitingRoomViewModel : ViewModel() {
val layoutMenuSelected = MutableLiveData<Boolean>() val layoutMenuSelected = MutableLiveData<Boolean>()
val isActiveSpeakerLayoutSelected = MutableLiveData<Boolean>() val selectedLayout = MutableLiveData<ConferenceDisplayMode>()
val isAudioOnlyLayoutSelected = MutableLiveData<Boolean>()
val isVideoAvailable = MutableLiveData<Boolean>() val isVideoAvailable = MutableLiveData<Boolean>()
@ -101,20 +100,17 @@ class ConferenceWaitingRoomViewModel : ViewModel() {
Log.i("[Conference Waiting Room] Microphone will be ${if (callParams.isMicEnabled) "enabled" else "muted"}") Log.i("[Conference Waiting Room] Microphone will be ${if (callParams.isMicEnabled) "enabled" else "muted"}")
updateMicState() updateMicState()
layoutMenuSelected.value = false callParams.isVideoEnabled = isVideoAvailableInCore()
isActiveSpeakerLayoutSelected.value = false
isAudioOnlyLayoutSelected.value = false
updateLayout()
isVideoAvailable.value = isAudioOnlyLayoutSelected.value == false && (core.isVideoCaptureEnabled || core.isVideoPreviewEnabled)
callParams.isVideoEnabled = isVideoAvailable.value == true
callParams.videoDirection = if (core.videoActivationPolicy.automaticallyInitiate) MediaDirection.SendRecv else MediaDirection.RecvOnly callParams.videoDirection = if (core.videoActivationPolicy.automaticallyInitiate) MediaDirection.SendRecv else MediaDirection.RecvOnly
Log.i("[Conference Waiting Room] Video will be ${if (callParams.isVideoEnabled) "enabled" else "disabled"}") Log.i("[Conference Waiting Room] Video will be ${if (callParams.isVideoEnabled) "enabled" else "disabled"}")
updateVideoState() updateVideoState()
layoutMenuSelected.value = false
updateLayout()
if (AudioRouteUtils.isBluetoothAudioRouteAvailable()) { if (AudioRouteUtils.isBluetoothAudioRouteAvailable()) {
setBluetoothAudioRoute() setBluetoothAudioRoute()
} else if (isVideoAvailable.value == true && isVideoEnabled.value == true) { } else if (isVideoAvailableInCore() && isVideoEnabled.value == true) {
setSpeakerAudioRoute() setSpeakerAudioRoute()
} else { } else {
setEarpieceAudioRoute() setEarpieceAudioRoute()
@ -209,22 +205,31 @@ class ConferenceWaitingRoomViewModel : ViewModel() {
fun setMosaicLayout() { fun setMosaicLayout() {
Log.i("[Conference Waiting Room] Set default layout to Mosaic") Log.i("[Conference Waiting Room] Set default layout to Mosaic")
coreContext.core.defaultConferenceLayout = ConferenceLayout.Grid
callParams.conferenceVideoLayout = ConferenceLayout.Grid
callParams.isVideoEnabled = isVideoAvailableInCore()
updateLayout() updateLayout()
updateVideoState()
layoutMenuSelected.value = false layoutMenuSelected.value = false
} }
fun setActiveSpeakerLayout() { fun setActiveSpeakerLayout() {
Log.i("[Conference Waiting Room] Set default layout to ActiveSpeaker") Log.i("[Conference Waiting Room] Set default layout to ActiveSpeaker")
coreContext.core.defaultConferenceLayout = ConferenceLayout.ActiveSpeaker
callParams.conferenceVideoLayout = ConferenceLayout.ActiveSpeaker
callParams.isVideoEnabled = isVideoAvailableInCore()
updateLayout() updateLayout()
updateVideoState()
layoutMenuSelected.value = false layoutMenuSelected.value = false
} }
fun setAudioOnlyLayout() { fun setAudioOnlyLayout() {
Log.i("[Conference Waiting Room] Set default layout to AudioOnly") Log.i("[Conference Waiting Room] Set default layout to AudioOnly, disabling video in call")
coreContext.core.defaultConferenceLayout = ConferenceLayout.Legacy // TODO: FIXME: Replace Legacy by AudioOnly callParams.isVideoEnabled = false
updateLayout() updateLayout()
updateVideoState()
layoutMenuSelected.value = false layoutMenuSelected.value = false
} }
@ -233,7 +238,7 @@ class ConferenceWaitingRoomViewModel : ViewModel() {
askPermissionEvent.value = Event(Manifest.permission.CAMERA) askPermissionEvent.value = Event(Manifest.permission.CAMERA)
return return
} }
callParams.isVideoEnabled = isVideoAvailable.value == true callParams.isVideoEnabled = isVideoAvailableInCore()
callParams.videoDirection = if (callParams.videoDirection == MediaDirection.SendRecv) MediaDirection.RecvOnly else MediaDirection.SendRecv callParams.videoDirection = if (callParams.videoDirection == MediaDirection.SendRecv) MediaDirection.RecvOnly else MediaDirection.SendRecv
Log.i("[Conference Waiting Room] Video will be ${if (callParams.isVideoEnabled) "enabled" else "disabled"}") Log.i("[Conference Waiting Room] Video will be ${if (callParams.isVideoEnabled) "enabled" else "disabled"}")
updateVideoState() updateVideoState()
@ -241,7 +246,7 @@ class ConferenceWaitingRoomViewModel : ViewModel() {
fun enableVideo() { fun enableVideo() {
Log.i("[Conference Waiting Room] Video will be enabled") Log.i("[Conference Waiting Room] Video will be enabled")
callParams.isVideoEnabled = isVideoAvailable.value == true callParams.isVideoEnabled = isVideoAvailableInCore()
callParams.videoDirection = MediaDirection.SendRecv callParams.videoDirection = MediaDirection.SendRecv
updateVideoState() updateVideoState()
} }
@ -290,20 +295,25 @@ class ConferenceWaitingRoomViewModel : ViewModel() {
} }
private fun updateLayout() { private fun updateLayout() {
val core = coreContext.core if (!callParams.isVideoEnabled) {
val layout = core.defaultConferenceLayout selectedLayout.value = ConferenceDisplayMode.AUDIO_ONLY
isActiveSpeakerLayoutSelected.value = layout == ConferenceLayout.ActiveSpeaker } else {
isAudioOnlyLayoutSelected.value = layout == ConferenceLayout.Legacy // TODO: FIXME: Replace Legacy by AudioOnly selectedLayout.value = when (callParams.conferenceVideoLayout) {
ConferenceLayout.Grid -> ConferenceDisplayMode.GRID
isVideoAvailable.value = isAudioOnlyLayoutSelected.value == false && (core.isVideoCaptureEnabled || core.isVideoPreviewEnabled) else -> ConferenceDisplayMode.ACTIVE_SPEAKER
callParams.isVideoEnabled = isVideoAvailable.value == true && isAudioOnlyLayoutSelected.value == false }
if (isAudioOnlyLayoutSelected.value == true) callParams.videoDirection = MediaDirection.RecvOnly }
updateVideoState()
} }
private fun updateVideoState() { private fun updateVideoState() {
isVideoAvailable.value = callParams.isVideoEnabled
isVideoEnabled.value = callParams.isVideoEnabled && callParams.videoDirection == MediaDirection.SendRecv isVideoEnabled.value = callParams.isVideoEnabled && callParams.videoDirection == MediaDirection.SendRecv
isSwitchCameraAvailable.value = callParams.isVideoEnabled && coreContext.showSwitchCameraButton() isSwitchCameraAvailable.value = callParams.isVideoEnabled && coreContext.showSwitchCameraButton()
coreContext.core.isVideoPreviewEnabled = callParams.isVideoEnabled coreContext.core.isVideoPreviewEnabled = callParams.isVideoEnabled
} }
private fun isVideoAvailableInCore(): Boolean {
val core = coreContext.core
return core.isVideoCaptureEnabled || core.isVideoPreviewEnabled
}
} }

View file

@ -48,9 +48,6 @@ class ConferencesSettingsViewModel : GenericSettingsViewModel() {
labels.add(prefs.getString(R.string.conference_display_mode_mosaic)) labels.add(prefs.getString(R.string.conference_display_mode_mosaic))
layoutValues.add(ConferenceLayout.Grid.toInt()) layoutValues.add(ConferenceLayout.Grid.toInt())
labels.add(prefs.getString(R.string.conference_display_mode_audio_only))
layoutValues.add(ConferenceLayout.Legacy.toInt()) // TODO: FIXME: Use AudioOnly
layoutLabels.value = labels layoutLabels.value = labels
layoutIndex.value = layoutValues.indexOf(core.defaultConferenceLayout.toInt()) layoutIndex.value = layoutValues.indexOf(core.defaultConferenceLayout.toInt())
} }

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2010-2022 Belledonne Communications SARL.
*
* This file is part of linphone-android
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.linphone.activities.voip
enum class ConferenceDisplayMode {
GRID,
ACTIVE_SPEAKER,
AUDIO_ONLY
}

View file

@ -113,7 +113,6 @@ open class CallData(val call: Call) : GenericContactData(call.remoteAddress) {
displayableAddress.value = clone.asStringUriOnly() displayableAddress.value = clone.asStringUriOnly()
update() update()
// initChatRoom()
val conferenceInfo = coreContext.core.findConferenceInformationFromUri(call.remoteAddress) val conferenceInfo = coreContext.core.findConferenceInformationFromUri(call.remoteAddress)
if (conferenceInfo != null) { if (conferenceInfo != null) {
@ -167,6 +166,10 @@ open class CallData(val call: Call) : GenericContactData(call.remoteAddress) {
contextMenuClickListener?.onShowContextMenu(anchor, this) contextMenuClickListener?.onShowContextMenu(anchor, this)
} }
fun isActiveAndNotInConference(): Boolean {
return isPaused.value == false && isRemotelyPaused.value == false && isInRemoteConference.value == false
}
private fun isCallPaused(): Boolean { private fun isCallPaused(): Boolean {
return when (call.state) { return when (call.state) {
Call.State.Paused, Call.State.Pausing -> true Call.State.Paused, Call.State.Pausing -> true

View file

@ -39,6 +39,7 @@ import org.linphone.activities.main.MainActivity
import org.linphone.activities.navigateToCallsList import org.linphone.activities.navigateToCallsList
import org.linphone.activities.navigateToConferenceLayout import org.linphone.activities.navigateToConferenceLayout
import org.linphone.activities.navigateToConferenceParticipants import org.linphone.activities.navigateToConferenceParticipants
import org.linphone.activities.voip.ConferenceDisplayMode
import org.linphone.activities.voip.viewmodels.CallsViewModel import org.linphone.activities.voip.viewmodels.CallsViewModel
import org.linphone.activities.voip.viewmodels.ConferenceViewModel import org.linphone.activities.voip.viewmodels.ConferenceViewModel
import org.linphone.activities.voip.viewmodels.ControlsViewModel import org.linphone.activities.voip.viewmodels.ControlsViewModel
@ -79,20 +80,11 @@ class ConferenceCallFragment : GenericFragment<VoipConferenceCallFragmentBinding
binding.statsViewModel = statsViewModel binding.statsViewModel = statsViewModel
conferenceViewModel.conferenceMosaicDisplayMode.observe( conferenceViewModel.conferenceDisplayMode.observe(
viewLifecycleOwner viewLifecycleOwner
) { ) { displayMode ->
if (it) { startTimer(R.id.active_conference_timer)
startTimer(R.id.active_conference_timer) if (displayMode == ConferenceDisplayMode.ACTIVE_SPEAKER) {
}
}
conferenceViewModel.conferenceActiveSpeakerDisplayMode.observe(
viewLifecycleOwner
) {
if (it) {
startTimer(R.id.active_conference_timer)
if (conferenceViewModel.conferenceExists.value == true) { if (conferenceViewModel.conferenceExists.value == true) {
Log.i("[Conference Call] Local participant is in conference and current layout is active speaker, updating Core's native window id") Log.i("[Conference Call] Local participant is in conference and current layout is active speaker, updating Core's native window id")
val layout = val layout =
@ -107,14 +99,6 @@ class ConferenceCallFragment : GenericFragment<VoipConferenceCallFragmentBinding
} }
} }
conferenceViewModel.conferenceAudioOnlyDisplayMode.observe(
viewLifecycleOwner
) {
if (it) {
startTimer(R.id.active_conference_timer)
}
}
conferenceViewModel.conferenceParticipantDevices.observe( conferenceViewModel.conferenceParticipantDevices.observe(
viewLifecycleOwner viewLifecycleOwner
) { ) {
@ -138,6 +122,20 @@ class ConferenceCallFragment : GenericFragment<VoipConferenceCallFragmentBinding
} }
} }
conferenceViewModel.conferenceDisplayMode.observe(
viewLifecycleOwner
) { layout ->
when (layout) {
ConferenceDisplayMode.AUDIO_ONLY -> {
controlsViewModel.fullScreenMode.value = false
}
else -> {
val conference = conferenceViewModel.conference.value
if (conference != null) switchToFullScreenIfPossible(conference)
}
}
}
controlsViewModel.goToConferenceParticipantsListEvent.observe( controlsViewModel.goToConferenceParticipantsListEvent.observe(
viewLifecycleOwner viewLifecycleOwner
) { ) {

View file

@ -26,6 +26,7 @@ import androidx.navigation.navGraphViewModels
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R import org.linphone.R
import org.linphone.activities.GenericFragment import org.linphone.activities.GenericFragment
import org.linphone.activities.voip.ConferenceDisplayMode
import org.linphone.activities.voip.viewmodels.ConferenceViewModel import org.linphone.activities.voip.viewmodels.ConferenceViewModel
import org.linphone.databinding.VoipConferenceLayoutFragmentBinding import org.linphone.databinding.VoipConferenceLayoutFragmentBinding
@ -53,6 +54,16 @@ class ConferenceLayoutFragment : GenericFragment<VoipConferenceLayoutFragmentBin
} }
} }
conferenceViewModel.conferenceDisplayMode.observe(
viewLifecycleOwner
) {
binding.localPreviewVideoSurface.visibility = if (it == ConferenceDisplayMode.AUDIO_ONLY) {
View.GONE
} else {
View.VISIBLE
}
}
binding.setDismissDialogClickListener { binding.setDismissDialogClickListener {
val dialog = binding.root.findViewById<LinearLayout>(R.id.too_many_participants_dialog) val dialog = binding.root.findViewById<LinearLayout>(R.id.too_many_participants_dialog)
dialog?.visibility = View.GONE dialog?.visibility = View.GONE

View file

@ -73,6 +73,7 @@ class CallsViewModel : ViewModel() {
} }
override fun onLastCallEnded(core: Core) { override fun onLastCallEnded(core: Core) {
Log.i("[Calls] Last call ended")
currentCallData.value?.destroy() currentCallData.value?.destroy()
noMoreCallEvent.value = Event(true) noMoreCallEvent.value = Event(true)
} }

View file

@ -24,6 +24,7 @@ import androidx.lifecycle.ViewModel
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R import org.linphone.R
import org.linphone.activities.voip.ConferenceDisplayMode
import org.linphone.activities.voip.data.ConferenceParticipantData import org.linphone.activities.voip.data.ConferenceParticipantData
import org.linphone.activities.voip.data.ConferenceParticipantDeviceData import org.linphone.activities.voip.data.ConferenceParticipantDeviceData
import org.linphone.core.* import org.linphone.core.*
@ -43,9 +44,7 @@ class ConferenceViewModel : ViewModel() {
val conferenceCreationPending = MutableLiveData<Boolean>() val conferenceCreationPending = MutableLiveData<Boolean>()
val conferenceParticipants = MutableLiveData<List<ConferenceParticipantData>>() val conferenceParticipants = MutableLiveData<List<ConferenceParticipantData>>()
val conferenceParticipantDevices = MutableLiveData<List<ConferenceParticipantDeviceData>>() val conferenceParticipantDevices = MutableLiveData<List<ConferenceParticipantDeviceData>>()
val conferenceMosaicDisplayMode = MutableLiveData<Boolean>() val conferenceDisplayMode = MutableLiveData<ConferenceDisplayMode>()
val conferenceActiveSpeakerDisplayMode = MutableLiveData<Boolean>()
val conferenceAudioOnlyDisplayMode = MutableLiveData<Boolean>()
val isRecording = MutableLiveData<Boolean>() val isRecording = MutableLiveData<Boolean>()
val isRemotelyRecorded = MutableLiveData<Boolean>() val isRemotelyRecorded = MutableLiveData<Boolean>()
@ -64,10 +63,9 @@ class ConferenceViewModel : ViewModel() {
updateParticipantsList(conference) updateParticipantsList(conference)
val count = conferenceParticipants.value.orEmpty().size val count = conferenceParticipants.value.orEmpty().size
if (count > maxParticipantsForMosaicLayout && conferenceMosaicDisplayMode.value == true) { if (count > maxParticipantsForMosaicLayout && conferenceDisplayMode.value == ConferenceDisplayMode.GRID) {
Log.w("[Conference] More than $maxParticipantsForMosaicLayout participants ($count), forcing active speaker layout") Log.w("[Conference] More than $maxParticipantsForMosaicLayout participants ($count), forcing active speaker layout")
conferenceMosaicDisplayMode.value = false conferenceDisplayMode.value = ConferenceDisplayMode.ACTIVE_SPEAKER
conferenceActiveSpeakerDisplayMode.value = true
} }
} }
@ -181,9 +179,6 @@ class ConferenceViewModel : ViewModel() {
conferenceParticipants.value = arrayListOf() conferenceParticipants.value = arrayListOf()
conferenceParticipantDevices.value = arrayListOf() conferenceParticipantDevices.value = arrayListOf()
conferenceMosaicDisplayMode.value = false
conferenceActiveSpeakerDisplayMode.value = false
conferenceAudioOnlyDisplayMode.value = false
subject.value = AppUtils.getString(R.string.conference_default_title) subject.value = AppUtils.getString(R.string.conference_default_title)
@ -290,27 +285,57 @@ class ConferenceViewModel : ViewModel() {
} }
} }
fun changeLayout(layout: ConferenceLayout) { fun changeLayout(layout: ConferenceDisplayMode) {
Log.i("[Conference] Trying to change conference layout to $layout") Log.i("[Conference] Trying to change conference layout to $layout")
val conference = conference.value val conference = conference.value
if (conference != null) { if (conference != null) {
conference.layout = layout val call = conference.call
updateConferenceLayout(conference) if (call != null) {
val params = call.core.createCallParams(call)
if (params == null) {
Log.e("[Conference] Failed to create call params from conference call!")
return
}
params.isVideoEnabled = layout != ConferenceDisplayMode.AUDIO_ONLY
params.conferenceVideoLayout = when (layout) {
ConferenceDisplayMode.GRID -> ConferenceLayout.Grid
else -> ConferenceLayout.ActiveSpeaker
}
call.update(params)
conferenceDisplayMode.value = layout
val list = sortDevicesDataList(conferenceParticipantDevices.value.orEmpty())
conferenceParticipantDevices.value = list
} else {
Log.e("[Conference] Failed to get call from conference!")
}
} else { } else {
Log.e("[Conference] Conference is null in ConferenceViewModel") Log.e("[Conference] Conference is null in ConferenceViewModel")
} }
} }
private fun updateConferenceLayout(conference: Conference) { private fun updateConferenceLayout(conference: Conference) {
val layout = conference.layout val call = conference.call
conferenceMosaicDisplayMode.value = layout == ConferenceLayout.Grid if (call == null) {
conferenceActiveSpeakerDisplayMode.value = layout == ConferenceLayout.ActiveSpeaker Log.e("[Conference] Conference call is null!")
conferenceAudioOnlyDisplayMode.value = layout == ConferenceLayout.Legacy // TODO: FIXME: Use AudioOnly layout return
}
val params = call.params
conferenceDisplayMode.value = if (!params.isVideoEnabled) {
ConferenceDisplayMode.AUDIO_ONLY
} else {
when (params.conferenceVideoLayout) {
ConferenceLayout.Grid -> ConferenceDisplayMode.GRID
else -> ConferenceDisplayMode.ACTIVE_SPEAKER
}
}
val list = sortDevicesDataList(conferenceParticipantDevices.value.orEmpty()) val list = sortDevicesDataList(conferenceParticipantDevices.value.orEmpty())
conferenceParticipantDevices.value = list conferenceParticipantDevices.value = list
Log.i("[Conference] Conference current layout is: $layout") Log.i("[Conference] Conference current layout is: ${conferenceDisplayMode.value}")
} }
private fun terminateConference(conference: Conference) { private fun terminateConference(conference: Conference) {
@ -422,7 +447,7 @@ class ConferenceViewModel : ViewModel() {
} }
if (meDeviceData != null) { if (meDeviceData != null) {
val index = sortedList.indexOf(meDeviceData) val index = sortedList.indexOf(meDeviceData)
val expectedIndex = if (conferenceActiveSpeakerDisplayMode.value == true) { val expectedIndex = if (conferenceDisplayMode.value == ConferenceDisplayMode.ACTIVE_SPEAKER) {
0 0
} else { } else {
sortedList.size - 1 sortedList.size - 1

View file

@ -353,9 +353,6 @@ class CoreContext(val context: Context, coreConfig: Config) {
core.isVibrationOnIncomingCallEnabled = true core.isVibrationOnIncomingCallEnabled = true
core.config.setBool("app", "incoming_call_vibration", false) core.config.setBool("app", "incoming_call_vibration", false)
} }
if (core.defaultConferenceLayout == ConferenceLayout.Legacy) {
core.defaultConferenceLayout = ConferenceLayout.ActiveSpeaker
}
initUserCertificates() initUserCertificates()

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="6.7dp" />
<solid android:color="?attr/voipParticipantBackgroundColor"/>
</shape>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<stroke android:width="2dp" android:color="?attr/colorPrimary"/>
<corners android:radius="6.7dp"/>
</shape>

View file

@ -3,7 +3,11 @@
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<data> <data>
<import type="android.view.View" /> <import type="android.view.View" />
<import type="org.linphone.activities.voip.ConferenceDisplayMode" />
<variable <variable
name="viewModel" name="viewModel"
type="org.linphone.activities.main.conference.viewmodels.ConferenceWaitingRoomViewModel" /> type="org.linphone.activities.main.conference.viewmodels.ConferenceWaitingRoomViewModel" />
@ -21,20 +25,19 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:layout_margin="20dp" android:layout_margin="20dp"
android:maxLines="1"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1"
android:text="@{viewModel.subject, default=`Conference subject`}" /> android:text="@{viewModel.subject, default=`Conference subject`}" />
<TextView <TextView
style="@style/conference_waiting_room_no_video_font" style="@style/conference_waiting_room_no_video_font"
android:visibility="@{viewModel.isVideoEnabled ? View.GONE : View.VISIBLE}"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:text="@string/conference_waiting_room_video_disabled"/> android:text="@string/conference_waiting_room_video_disabled"
android:visibility="@{viewModel.isVideoEnabled ? View.GONE : View.VISIBLE}" />
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:visibility="@{viewModel.isVideoEnabled ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_above="@id/conference_controls" android:layout_above="@id/conference_controls"
@ -42,7 +45,8 @@
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
android:layout_marginBottom="20dp" android:layout_marginBottom="20dp"
android:background="@drawable/shape_remote_video_background"> android:background="@drawable/shape_remote_video_background"
android:visibility="@{viewModel.isVideoEnabled ? View.VISIBLE : View.GONE, default=gone}">
<org.linphone.activities.voip.views.RoundCornersTextureView <org.linphone.activities.voip.views.RoundCornersTextureView
android:id="@+id/local_preview_video_surface" android:id="@+id/local_preview_video_surface"
@ -73,131 +77,131 @@
android:id="@+id/conference_controls" android:id="@+id/conference_controls"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_above="@id/buttons" android:layout_above="@id/buttons"
android:layout_marginBottom="20dp"> android:layout_marginBottom="20dp"
android:orientation="horizontal">
<TextView <TextView
android:onClick="@{() -> viewModel.cancel()}" style="@style/big_orange_button_font"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingLeft="20dp"
android:paddingTop="8dp"
android:paddingRight="20dp"
android:paddingBottom="8dp"
android:layout_marginStart="20dp" android:layout_marginStart="20dp"
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
android:gravity="center"
android:background="@drawable/shape_rect_gray_button"
android:text="@string/conference_waiting_room_cancel_call"
style="@style/big_orange_button_font"/>
<TextView
android:onClick="@{() -> viewModel.start()}"
android:enabled="@{!viewModel.joinInProgress}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:background="@drawable/shape_rect_gray_button"
android:gravity="center"
android:onClick="@{() -> viewModel.cancel()}"
android:paddingLeft="20dp" android:paddingLeft="20dp"
android:paddingTop="8dp" android:paddingTop="8dp"
android:paddingRight="20dp" android:paddingRight="20dp"
android:paddingBottom="8dp" android:paddingBottom="8dp"
android:text="@string/conference_waiting_room_cancel_call" />
<TextView
style="@style/big_orange_button_bold_font"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:gravity="center" android:layout_weight="1"
android:background="@drawable/shape_rect_orange_button" android:background="@drawable/shape_rect_orange_button"
android:text="@string/conference_waiting_room_start_call" android:enabled="@{!viewModel.joinInProgress}"
style="@style/big_orange_button_bold_font"/> android:gravity="center"
android:onClick="@{() -> viewModel.start()}"
android:paddingLeft="20dp"
android:paddingTop="8dp"
android:paddingRight="20dp"
android:paddingBottom="8dp"
android:text="@string/conference_waiting_room_start_call" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:visibility="@{viewModel.audioRoutesSelected ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_above="@id/buttons" android:layout_above="@id/buttons"
android:background="@drawable/shape_audio_routes_background"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:orientation="vertical"> android:background="@drawable/shape_audio_routes_background"
android:orientation="vertical"
android:visibility="@{viewModel.audioRoutesSelected ? View.VISIBLE : View.GONE, default=gone}">
<ImageView <ImageView
android:selected="@{viewModel.isBluetoothHeadsetSelected}"
android:onClick="@{() -> viewModel.setBluetoothAudioRoute()}"
android:contentDescription="@string/content_description_use_bluetooth_headset"
android:layout_width="@dimen/voip_call_button_size" android:layout_width="@dimen/voip_call_button_size"
android:layout_height="@dimen/voip_call_button_size" android:layout_height="@dimen/voip_call_button_size"
android:background="@drawable/button_toggle_background_reverse"
android:layout_margin="5dp" android:layout_margin="5dp"
android:background="@drawable/button_toggle_background_reverse"
android:contentDescription="@string/content_description_use_bluetooth_headset"
android:onClick="@{() -> viewModel.setBluetoothAudioRoute()}"
android:selected="@{viewModel.isBluetoothHeadsetSelected}"
android:src="@drawable/icon_bluetooth" /> android:src="@drawable/icon_bluetooth" />
<ImageView <ImageView
android:selected="@{!viewModel.isSpeakerSelected &amp;&amp; !viewModel.isBluetoothHeadsetSelected}"
android:onClick="@{() -> viewModel.setEarpieceAudioRoute()}"
android:contentDescription="@string/content_description_use_earpiece"
android:layout_width="@dimen/voip_call_button_size" android:layout_width="@dimen/voip_call_button_size"
android:layout_height="@dimen/voip_call_button_size" android:layout_height="@dimen/voip_call_button_size"
android:background="@drawable/button_toggle_background_reverse"
android:layout_margin="5dp" android:layout_margin="5dp"
android:background="@drawable/button_toggle_background_reverse"
android:contentDescription="@string/content_description_use_earpiece"
android:onClick="@{() -> viewModel.setEarpieceAudioRoute()}"
android:selected="@{!viewModel.isSpeakerSelected &amp;&amp; !viewModel.isBluetoothHeadsetSelected}"
android:src="@drawable/icon_earpiece" /> android:src="@drawable/icon_earpiece" />
<ImageView <ImageView
android:selected="@{viewModel.isSpeakerSelected}"
android:onClick="@{() -> viewModel.setSpeakerAudioRoute()}"
android:contentDescription="@string/content_description_use_speaker"
android:layout_width="@dimen/voip_call_button_size" android:layout_width="@dimen/voip_call_button_size"
android:layout_height="@dimen/voip_call_button_size" android:layout_height="@dimen/voip_call_button_size"
android:background="@drawable/button_toggle_background_reverse"
android:layout_margin="5dp" android:layout_margin="5dp"
android:background="@drawable/button_toggle_background_reverse"
android:contentDescription="@string/content_description_use_speaker"
android:onClick="@{() -> viewModel.setSpeakerAudioRoute()}"
android:selected="@{viewModel.isSpeakerSelected}"
android:src="@drawable/icon_speaker" /> android:src="@drawable/icon_speaker" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:visibility="@{viewModel.layoutMenuSelected ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_above="@id/buttons" android:layout_above="@id/buttons"
android:background="@drawable/shape_audio_routes_background"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_marginBottom="10dp"
android:layout_marginEnd="15dp" android:layout_marginEnd="15dp"
android:orientation="vertical"> android:layout_marginBottom="10dp"
android:background="@drawable/shape_audio_routes_background"
android:orientation="vertical"
android:visibility="@{viewModel.layoutMenuSelected ? View.VISIBLE : View.GONE, default=gone}">
<ImageView <ImageView
android:selected="@{!viewModel.isActiveSpeakerLayoutSelected &amp;&amp; !viewModel.isAudioOnlyLayoutSelected}"
android:onClick="@{() -> viewModel.setMosaicLayout()}"
android:contentDescription="@string/conference_display_mode_mosaic"
android:layout_width="@dimen/voip_call_button_size" android:layout_width="@dimen/voip_call_button_size"
android:layout_height="@dimen/voip_call_button_size" android:layout_height="@dimen/voip_call_button_size"
android:background="@drawable/button_toggle_background_reverse"
android:layout_margin="5dp" android:layout_margin="5dp"
android:background="@drawable/button_toggle_background_reverse"
android:contentDescription="@string/conference_display_mode_mosaic"
android:onClick="@{() -> viewModel.setMosaicLayout()}"
android:padding="5dp" android:padding="5dp"
android:selected="@{viewModel.selectedLayout == ConferenceDisplayMode.GRID}"
android:src="@drawable/icon_conference_layout_grid" android:src="@drawable/icon_conference_layout_grid"
app:tint="@color/white_color" /> app:tint="@color/white_color" />
<ImageView <ImageView
android:selected="@{viewModel.isActiveSpeakerLayoutSelected}"
android:onClick="@{() -> viewModel.setActiveSpeakerLayout()}"
android:contentDescription="@string/conference_display_mode_active_speaker"
android:layout_width="@dimen/voip_call_button_size" android:layout_width="@dimen/voip_call_button_size"
android:layout_height="@dimen/voip_call_button_size" android:layout_height="@dimen/voip_call_button_size"
android:background="@drawable/button_toggle_background_reverse"
android:layout_margin="5dp" android:layout_margin="5dp"
android:background="@drawable/button_toggle_background_reverse"
android:contentDescription="@string/conference_display_mode_active_speaker"
android:onClick="@{() -> viewModel.setActiveSpeakerLayout()}"
android:padding="5dp" android:padding="5dp"
android:selected="@{viewModel.selectedLayout == ConferenceDisplayMode.ACTIVE_SPEAKER}"
android:src="@drawable/icon_conference_layout_active_speaker" android:src="@drawable/icon_conference_layout_active_speaker"
app:tint="@color/white_color"/> app:tint="@color/white_color" />
<ImageView <ImageView
android:selected="@{viewModel.isAudioOnlyLayoutSelected}"
android:onClick="@{() -> viewModel.setAudioOnlyLayout()}"
android:contentDescription="@string/conference_display_mode_audio_only"
android:layout_width="@dimen/voip_call_button_size" android:layout_width="@dimen/voip_call_button_size"
android:layout_height="@dimen/voip_call_button_size" android:layout_height="@dimen/voip_call_button_size"
android:background="@drawable/button_toggle_background_reverse"
android:layout_margin="5dp" android:layout_margin="5dp"
android:background="@drawable/button_toggle_background_reverse"
android:contentDescription="@string/conference_display_mode_audio_only"
android:onClick="@{() -> viewModel.setAudioOnlyLayout()}"
android:padding="5dp" android:padding="5dp"
android:selected="@{viewModel.selectedLayout == ConferenceDisplayMode.AUDIO_ONLY}"
android:src="@drawable/icon_conference_layout_audio_only" android:src="@drawable/icon_conference_layout_audio_only"
app:tint="@color/white_color" /> app:tint="@color/white_color" />
@ -211,14 +215,14 @@
android:layout_marginBottom="10dp"> android:layout_marginBottom="10dp">
<ImageView <ImageView
android:contentDescription="@{viewModel.isMicrophoneMuted ? @string/content_description_disable_mic_mute : @string/content_description_enable_mic_mute}"
android:onClick="@{() -> viewModel.toggleMuteMicrophone()}"
android:selected="@{viewModel.isMicrophoneMuted}"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginEnd="5dp" android:layout_marginEnd="5dp"
android:background="@drawable/button_background_reverse" android:background="@drawable/button_background_reverse"
android:contentDescription="@{viewModel.isMicrophoneMuted ? @string/content_description_disable_mic_mute : @string/content_description_enable_mic_mute}"
android:onClick="@{() -> viewModel.toggleMuteMicrophone()}"
android:padding="5dp" android:padding="5dp"
android:selected="@{viewModel.isMicrophoneMuted}"
android:src="@drawable/icon_toggle_mic" android:src="@drawable/icon_toggle_mic"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="W,1:1" app:layout_constraintDimensionRatio="W,1:1"
@ -245,46 +249,46 @@
android:visibility="@{viewModel.audioRoutesEnabled ? View.GONE : View.VISIBLE}" /> android:visibility="@{viewModel.audioRoutesEnabled ? View.GONE : View.VISIBLE}" />
<ImageView <ImageView
android:onClick="@{() -> viewModel.toggleAudioRoutesMenu()}"
android:selected="@{viewModel.audioRoutesSelected}"
android:visibility="@{viewModel.audioRoutesEnabled ? View.VISIBLE : View.GONE, default=gone}"
android:layout_height="match_parent"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/button_toggle_background_reverse" android:background="@drawable/button_toggle_background_reverse"
android:src="@drawable/icon_audio_routes" android:contentDescription="@string/content_description_toggle_audio_menu"
android:onClick="@{() -> viewModel.toggleAudioRoutesMenu()}"
android:padding="5dp" android:padding="5dp"
android:contentDescription="@string/content_description_toggle_audio_menu"/> android:selected="@{viewModel.audioRoutesSelected}"
android:src="@drawable/icon_audio_routes"
android:visibility="@{viewModel.audioRoutesEnabled ? View.VISIBLE : View.GONE, default=gone}" />
</RelativeLayout> </RelativeLayout>
<ImageView <ImageView
android:contentDescription="@{viewModel.isVideoEnabled ? @string/content_description_disable_video : @string/content_description_enable_video}"
android:enabled="@{viewModel.isVideoAvailable}"
android:onClick="@{() -> viewModel.toggleVideo()}"
android:selected="@{viewModel.isVideoEnabled}"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:background="@drawable/button_background_reverse" android:background="@drawable/button_background_reverse"
android:contentDescription="@{viewModel.isVideoEnabled ? @string/content_description_disable_video : @string/content_description_enable_video}"
android:enabled="@{viewModel.isVideoAvailable}"
android:onClick="@{() -> viewModel.toggleVideo()}"
android:padding="5dp" android:padding="5dp"
android:selected="@{viewModel.isVideoEnabled}"
android:src="@drawable/icon_toggle_camera" android:src="@drawable/icon_toggle_camera"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="W,1:1" app:layout_constraintDimensionRatio="W,1:1"
app:layout_constraintStart_toEndOf="@id/speaker" /> app:layout_constraintStart_toEndOf="@id/speaker" />
<ImageView <ImageView
android:onClick="@{() -> viewModel.toggleLayoutMenu()}"
android:selected="@{viewModel.layoutMenuSelected}"
android:layout_height="match_parent"
android:layout_width="0dp" android:layout_width="0dp"
android:background="@drawable/button_toggle_background_reverse" android:layout_height="match_parent"
android:src="@{viewModel.isActiveSpeakerLayoutSelected ? @drawable/icon_conference_layout_active_speaker : viewModel.isAudioOnlyLayoutSelected ? @drawable/icon_conference_layout_audio_only : @drawable/icon_conference_layout_grid, default=@drawable/icon_conference_layout_grid}"
android:padding="10dp"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:background="@drawable/button_toggle_background_reverse"
android:contentDescription="@string/content_description_toggle_layout_menu" android:contentDescription="@string/content_description_toggle_layout_menu"
app:layout_constraintDimensionRatio="W,1:1" android:onClick="@{() -> viewModel.toggleLayoutMenu()}"
android:padding="10dp"
android:selected="@{viewModel.layoutMenuSelected}"
android:src="@{viewModel.selectedLayout == ConferenceDisplayMode.ACTIVE_SPEAKER ? @drawable/icon_conference_layout_active_speaker : viewModel.selectedLayout == ConferenceDisplayMode.AUDIO_ONLY ? @drawable/icon_conference_layout_audio_only : @drawable/icon_conference_layout_grid, default=@drawable/icon_conference_layout_grid}"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"/> app:layout_constraintDimensionRatio="W,1:1"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -3,13 +3,22 @@
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<data> <data>
<import type="android.view.View" /> <import type="android.view.View" />
<import type="org.linphone.activities.voip.ConferenceDisplayMode" />
<variable <variable
name="controlsViewModel" name="controlsViewModel"
type="org.linphone.activities.voip.viewmodels.ControlsViewModel" /> type="org.linphone.activities.voip.viewmodels.ControlsViewModel" />
<variable <variable
name="callsViewModel" name="callsViewModel"
type="org.linphone.activities.voip.viewmodels.CallsViewModel" /> type="org.linphone.activities.voip.viewmodels.CallsViewModel" />
<variable
name="conferenceViewModel"
type="org.linphone.activities.voip.viewmodels.ConferenceViewModel" />
</data> </data>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@ -86,7 +95,7 @@
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:background="@drawable/button_background_reverse" android:background="@drawable/button_background_reverse"
android:contentDescription="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.isVideoSendReceive ? @string/content_description_disable_video : @string/content_description_enable_video}" android:contentDescription="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.isVideoSendReceive ? @string/content_description_disable_video : @string/content_description_enable_video}"
android:enabled="@{controlsViewModel.isVideoAvailable &amp;&amp; !controlsViewModel.isVideoUpdateInProgress}" android:enabled="@{controlsViewModel.isVideoAvailable &amp;&amp; !controlsViewModel.isVideoUpdateInProgress &amp;&amp; conferenceViewModel.conferenceDisplayMode != ConferenceDisplayMode.AUDIO_ONLY}}"
android:onClick="@{() -> controlsViewModel.toggleVideo()}" android:onClick="@{() -> controlsViewModel.toggleVideo()}"
android:padding="5dp" android:padding="5dp"
android:selected="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.isVideoSendReceive}" android:selected="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.isVideoSendReceive}"
@ -128,7 +137,7 @@
android:translationY="@{controlsViewModel.bouncyCounterTranslateY}" android:translationY="@{controlsViewModel.bouncyCounterTranslateY}"
android:visibility="@{callsViewModel.chatAndCallsCount == 0 ? View.GONE : View.VISIBLE}" android:visibility="@{callsViewModel.chatAndCallsCount == 0 ? View.GONE : View.VISIBLE}"
app:layout_constraintEnd_toEndOf="@id/more" app:layout_constraintEnd_toEndOf="@id/more"
app:layout_constraintTop_toTopOf="@id/more"/> app:layout_constraintTop_toTopOf="@id/more" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -4,13 +4,19 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<data> <data>
<import type="android.view.View" /> <import type="android.view.View" />
<import type="org.linphone.activities.voip.ConferenceDisplayMode" />
<variable <variable
name="controlsViewModel" name="controlsViewModel"
type="org.linphone.activities.voip.viewmodels.ControlsViewModel" /> type="org.linphone.activities.voip.viewmodels.ControlsViewModel" />
<variable <variable
name="callsViewModel" name="callsViewModel"
type="org.linphone.activities.voip.viewmodels.CallsViewModel" /> type="org.linphone.activities.voip.viewmodels.CallsViewModel" />
<variable <variable
name="conferenceViewModel" name="conferenceViewModel"
type="org.linphone.activities.voip.viewmodels.ConferenceViewModel" /> type="org.linphone.activities.voip.viewmodels.ConferenceViewModel" />
@ -37,7 +43,7 @@
app:layout_constraintEnd_toStartOf="@id/call_stats" app:layout_constraintEnd_toStartOf="@id/call_stats"
app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/chat"/> app:layout_constraintTop_toTopOf="@id/chat" />
<TextView <TextView
android:id="@+id/call_stats" android:id="@+id/call_stats"
@ -91,7 +97,7 @@
app:layout_constraintBottom_toBottomOf="@id/chat" app:layout_constraintBottom_toBottomOf="@id/chat"
app:layout_constraintEnd_toEndOf="@id/chat" app:layout_constraintEnd_toEndOf="@id/chat"
app:layout_constraintStart_toStartOf="@id/chat" app:layout_constraintStart_toStartOf="@id/chat"
app:layout_constraintTop_toTopOf="@id/chat"/> app:layout_constraintTop_toTopOf="@id/chat" />
<TextView <TextView
android:id="@+id/transfer_call" android:id="@+id/transfer_call"
@ -107,7 +113,7 @@
app:layout_constraintEnd_toStartOf="@id/conference_participants" app:layout_constraintEnd_toStartOf="@id/conference_participants"
app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/numpad"/> app:layout_constraintTop_toBottomOf="@id/numpad" />
<TextView <TextView
android:id="@+id/conference_participants" android:id="@+id/conference_participants"
@ -123,7 +129,7 @@
app:layout_constraintEnd_toStartOf="@id/add_call" app:layout_constraintEnd_toStartOf="@id/add_call"
app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toEndOf="@id/transfer_call" app:layout_constraintStart_toEndOf="@id/transfer_call"
app:layout_constraintTop_toTopOf="@id/calls"/> app:layout_constraintTop_toTopOf="@id/calls" />
<TextView <TextView
android:id="@+id/add_call" android:id="@+id/add_call"
@ -138,14 +144,14 @@
app:layout_constraintBottom_toBottomOf="@id/calls" app:layout_constraintBottom_toBottomOf="@id/calls"
app:layout_constraintEnd_toStartOf="@id/conference_layout" app:layout_constraintEnd_toStartOf="@id/conference_layout"
app:layout_constraintStart_toEndOf="@id/conference_participants" app:layout_constraintStart_toEndOf="@id/conference_participants"
app:layout_constraintTop_toTopOf="@id/calls"/> app:layout_constraintTop_toTopOf="@id/calls" />
<TextView <TextView
android:id="@+id/conference_layout" android:id="@+id/conference_layout"
style="@style/call_options_font" style="@style/call_options_font"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:drawableTop="@{conferenceViewModel.conferenceActiveSpeakerDisplayMode ? @drawable/icon_conference_layout_active_speaker : conferenceViewModel.conferenceAudioOnlyDisplayMode ? @drawable/icon_conference_layout_audio_only : @drawable/icon_conference_layout_grid, default=@drawable/icon_conference_layout_grid}" android:drawableTop="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.ACTIVE_SPEAKER ? @drawable/icon_conference_layout_active_speaker : conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.AUDIO_ONLY ? @drawable/icon_conference_layout_audio_only : @drawable/icon_conference_layout_grid, default=@drawable/icon_conference_layout_grid}"
android:enabled="@{conferenceViewModel.isVideoConference}" android:enabled="@{conferenceViewModel.isVideoConference}"
android:gravity="center" android:gravity="center"
android:onClick="@{() -> controlsViewModel.goToConferenceLayout()}" android:onClick="@{() -> controlsViewModel.goToConferenceLayout()}"

View file

@ -26,52 +26,40 @@
android:layout_margin="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? @dimen/voip_remote_margin_full_screen : @dimen/voip_remote_margin, default=@dimen/voip_remote_margin}" android:layout_margin="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? @dimen/voip_remote_margin_full_screen : @dimen/voip_remote_margin, default=@dimen/voip_remote_margin}"
android:visibility="@{inflatedVisibility}"> android:visibility="@{inflatedVisibility}">
<include <LinearLayout
android:id="@+id/header"
layout="@layout/voip_conference_header"
android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}"
app:conferenceViewModel="@{conferenceViewModel}" />
<include
android:id="@+id/remote_recording"
layout="@layout/voip_remote_recording"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/header"
android:layout_margin="10dp"
android:visibility="@{conferenceViewModel.isRemotelyRecorded ? View.VISIBLE : View.GONE, default=gone}" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_above="@id/miniatures" android:gravity="center"
android:layout_below="@id/remote_recording" android:orientation="vertical">
android:layout_marginTop="10dp"
android:background="@drawable/shape_remote_background">
<include <include
layout="@layout/voip_contact_avatar" android:id="@+id/header"
android:layout_width="0dp" layout="@layout/voip_conference_header"
android:layout_height="0dp" android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}"
android:layout_margin="10dp" app:conferenceViewModel="@{conferenceViewModel}" />
app:data="@{conferenceViewModel.speakingParticipant}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_max="200dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView <include
style="@style/call_remote_name_font" android:id="@+id/remote_recording"
android:layout_width="wrap_content" layout="@layout/voip_remote_recording"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="10dp" android:visibility="@{conferenceViewModel.isRemotelyRecorded ? View.VISIBLE : View.GONE, default=gone}" />
android:layout_marginBottom="10dp"
android:text="@{conferenceViewModel.speakingParticipant.contact.fullName ?? conferenceViewModel.speakingParticipant.displayName}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> <androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:entries="@{conferenceViewModel.conferenceParticipantDevices}"
app:layout="@{@layout/voip_conference_participant_remote_audio_only}" />
</androidx.core.widget.NestedScrollView>
</LinearLayout>
</RelativeLayout> </RelativeLayout>

View file

@ -4,17 +4,25 @@
xmlns:bind="http://schemas.android.com/tools"> xmlns:bind="http://schemas.android.com/tools">
<data> <data>
<import type="android.view.View" /> <import type="android.view.View" />
<import type="org.linphone.activities.voip.ConferenceDisplayMode" />
<import type="com.google.android.flexbox.FlexDirection" /> <import type="com.google.android.flexbox.FlexDirection" />
<variable <variable
name="controlsViewModel" name="controlsViewModel"
type="org.linphone.activities.voip.viewmodels.ControlsViewModel" /> type="org.linphone.activities.voip.viewmodels.ControlsViewModel" />
<variable <variable
name="callsViewModel" name="callsViewModel"
type="org.linphone.activities.voip.viewmodels.CallsViewModel" /> type="org.linphone.activities.voip.viewmodels.CallsViewModel" />
<variable <variable
name="conferenceViewModel" name="conferenceViewModel"
type="org.linphone.activities.voip.viewmodels.ConferenceViewModel" /> type="org.linphone.activities.voip.viewmodels.ConferenceViewModel" />
<variable <variable
name="statsViewModel" name="statsViewModel"
type="org.linphone.activities.voip.viewmodels.StatisticsListViewModel" /> type="org.linphone.activities.voip.viewmodels.StatisticsListViewModel" />
@ -33,129 +41,130 @@
<ViewStub <ViewStub
android:id="@+id/stubbed_conference_active_speaker_layout" android:id="@+id/stubbed_conference_active_speaker_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:inflatedId="@+id/conference_active_speaker_layout" android:inflatedId="@+id/conference_active_speaker_layout"
android:layout="@layout/voip_conference_active_speaker" android:layout="@layout/voip_conference_active_speaker"
android:visibility="@{conferenceViewModel.conferenceActiveSpeakerDisplayMode ? View.VISIBLE : View.GONE, default=gone}" android:visibility="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.ACTIVE_SPEAKER &amp;&amp; conferenceViewModel.conferenceExists &amp;&amp; !callsViewModel.currentCallData.isActiveAndNotInConference ? View.VISIBLE : View.GONE, default=gone}"
app:inflatedVisibility="@{conferenceViewModel.conferenceActiveSpeakerDisplayMode ? View.VISIBLE : View.GONE}"
android:layout_width="match_parent"
app:conferenceViewModel="@{conferenceViewModel}" app:conferenceViewModel="@{conferenceViewModel}"
app:controlsViewModel="@{controlsViewModel}" app:controlsViewModel="@{controlsViewModel}"
android:layout_height="0dp" app:inflatedVisibility="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.ACTIVE_SPEAKER &amp;&amp; conferenceViewModel.conferenceExists &amp;&amp; !callsViewModel.currentCallData.isActiveAndNotInConference ? View.VISIBLE : View.GONE}"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@id/primary_buttons"
app:layout_constraintBottom_toTopOf="@id/primary_buttons" /> app:layout_constraintTop_toTopOf="parent" />
<ViewStub <ViewStub
android:id="@+id/stubbed_conference_grid_layout" android:id="@+id/stubbed_conference_grid_layout"
android:layout="@layout/voip_conference_grid"
android:visibility="@{conferenceViewModel.conferenceMosaicDisplayMode ? View.VISIBLE : View.GONE, default=gone}"
app:inflatedVisibility="@{conferenceViewModel.conferenceMosaicDisplayMode ? View.VISIBLE : View.GONE}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp"
android:layout="@layout/voip_conference_grid"
android:visibility="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.GRID &amp;&amp; conferenceViewModel.conferenceExists &amp;&amp; !callsViewModel.currentCallData.isActiveAndNotInConference ? View.VISIBLE : View.GONE, default=gone}"
app:conferenceViewModel="@{conferenceViewModel}" app:conferenceViewModel="@{conferenceViewModel}"
app:controlsViewModel="@{controlsViewModel}" app:controlsViewModel="@{controlsViewModel}"
android:layout_height="0dp" app:inflatedVisibility="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.GRID &amp;&amp; conferenceViewModel.conferenceExists &amp;&amp; !callsViewModel.currentCallData.isActiveAndNotInConference ? View.VISIBLE : View.GONE}"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@id/primary_buttons"
app:layout_constraintBottom_toTopOf="@id/primary_buttons" /> app:layout_constraintTop_toTopOf="parent" />
<ViewStub <ViewStub
android:id="@+id/stubbed_conference_audio_only_layout" android:id="@+id/stubbed_conference_audio_only_layout"
android:layout="@layout/voip_conference_audio_only"
android:visibility="@{conferenceViewModel.conferenceAudioOnlyDisplayMode ? View.VISIBLE : View.GONE, default=gone}"
app:inflatedVisibility="@{conferenceViewModel.conferenceAudioOnlyDisplayMode ? View.VISIBLE : View.GONE}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp"
android:layout="@layout/voip_conference_audio_only"
android:visibility="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.AUDIO_ONLY &amp;&amp; conferenceViewModel.conferenceExists &amp;&amp; !callsViewModel.currentCallData.isActiveAndNotInConference ? View.VISIBLE : View.GONE, default=gone}"
app:conferenceViewModel="@{conferenceViewModel}" app:conferenceViewModel="@{conferenceViewModel}"
app:controlsViewModel="@{controlsViewModel}" app:controlsViewModel="@{controlsViewModel}"
android:layout_height="0dp" app:inflatedVisibility="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.AUDIO_ONLY &amp;&amp; conferenceViewModel.conferenceExists &amp;&amp; !callsViewModel.currentCallData.isActiveAndNotInConference ? View.VISIBLE : View.GONE}"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@id/primary_buttons"
app:layout_constraintBottom_toTopOf="@id/primary_buttons" /> app:layout_constraintTop_toTopOf="parent" />
<ViewStub <ViewStub
android:id="@+id/stubbed_audio_routes" android:id="@+id/stubbed_audio_routes"
android:layout="@layout/voip_buttons_audio_routes"
android:visibility="@{controlsViewModel.audioRoutesEnabled ? View.VISIBLE : View.GONE}"
app:inflatedVisibility="@{controlsViewModel.audioRoutesEnabled ? View.VISIBLE : View.GONE}"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginStart="12dp" android:layout_marginStart="12dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginBottom="10dp"
app:layout_constraintEnd_toEndOf="parent" android:layout="@layout/voip_buttons_audio_routes"
android:visibility="@{controlsViewModel.audioRoutesEnabled ? View.VISIBLE : View.GONE}"
app:controlsViewModel="@{controlsViewModel}"
app:inflatedVisibility="@{controlsViewModel.audioRoutesEnabled ? View.VISIBLE : View.GONE}"
app:layout_constraintBottom_toTopOf="@id/primary_buttons" app:layout_constraintBottom_toTopOf="@id/primary_buttons"
app:controlsViewModel="@{controlsViewModel}"/> app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<include <include
android:id="@+id/primary_buttons" android:id="@+id/primary_buttons"
android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}"
layout="@layout/voip_buttons" layout="@layout/voip_buttons"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="@dimen/voip_buttons_fragment_size" android:layout_height="@dimen/voip_buttons_fragment_size"
android:layout_marginBottom="10dp"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginBottom="10dp"
app:layout_constraintEnd_toEndOf="parent" android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}"
app:layout_constraintBottom_toBottomOf="parent" app:callsViewModel="@{callsViewModel}"
app:layout_constraintWidth_max="@dimen/voip_buttons_max_width" app:conferenceViewModel="@{conferenceViewModel}"
app:controlsViewModel="@{controlsViewModel}" app:controlsViewModel="@{controlsViewModel}"
app:callsViewModel="@{callsViewModel}" /> app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintWidth_max="@dimen/voip_buttons_max_width" />
<ViewStub <ViewStub
android:id="@+id/stubbed_paused_conference" android:id="@+id/stubbed_paused_conference"
android:layout="@layout/voip_conference_paused"
android:visibility="@{conferenceViewModel.isConferenceLocallyPaused ? View.VISIBLE : View.GONE, default=gone}"
app:inflatedVisibility="@{conferenceViewModel.isConferenceLocallyPaused ? View.VISIBLE : View.GONE}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginBottom="5dp" android:layout_marginBottom="5dp"
app:layout_constraintTop_toTopOf="parent" android:layout="@layout/voip_conference_paused"
android:visibility="@{conferenceViewModel.isConferenceLocallyPaused ? View.VISIBLE : View.GONE, default=gone}"
app:conferenceViewModel="@{conferenceViewModel}"
app:inflatedVisibility="@{conferenceViewModel.isConferenceLocallyPaused ? View.VISIBLE : View.GONE}"
app:layout_constraintBottom_toTopOf="@id/primary_buttons" app:layout_constraintBottom_toTopOf="@id/primary_buttons"
app:conferenceViewModel="@{conferenceViewModel}" /> app:layout_constraintTop_toTopOf="parent" />
<LinearLayout <LinearLayout
android:onClick="@{() -> controlsViewModel.hideExtraButtons(false)}"
android:visibility="@{controlsViewModel.showExtras ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/voip_translucent_popup_background" /> android:background="@color/voip_translucent_popup_background"
android:onClick="@{() -> controlsViewModel.hideExtraButtons(false)}"
android:visibility="@{controlsViewModel.showExtras ? View.VISIBLE : View.GONE, default=gone}" />
<include <include
layout="@layout/voip_buttons_extra" layout="@layout/voip_buttons_extra"
android:translationY="@{controlsViewModel.extraButtonsMenuTranslateY, default=@dimen/voip_call_extra_buttons_translate_y}"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="@dimen/voip_call_extra_buttons_height" android:layout_height="@dimen/voip_call_extra_buttons_height"
android:layout_marginStart="15dp" android:layout_marginStart="15dp"
android:layout_marginEnd="15dp" android:layout_marginEnd="15dp"
app:layout_constraintStart_toStartOf="parent" android:translationY="@{controlsViewModel.extraButtonsMenuTranslateY, default=@dimen/voip_call_extra_buttons_translate_y}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintWidth_max="@dimen/voip_extra_menu_max_width"
app:controlsViewModel="@{controlsViewModel}"
app:callsViewModel="@{callsViewModel}" app:callsViewModel="@{callsViewModel}"
app:conferenceViewModel="@{conferenceViewModel}"/> app:conferenceViewModel="@{conferenceViewModel}"
app:controlsViewModel="@{controlsViewModel}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintWidth_max="@dimen/voip_extra_menu_max_width" />
<ViewStub <ViewStub
android:id="@+id/stubbed_call_stats" android:id="@+id/stubbed_call_stats"
android:layout="@layout/voip_call_stats"
android:visibility="@{controlsViewModel.callStatsVisible ? View.VISIBLE : View.GONE, default=gone}"
app:inflatedVisibility="@{controlsViewModel.callStatsVisible ? View.VISIBLE : View.GONE}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:statsViewModel="@{statsViewModel}" android:layout="@layout/voip_call_stats"
app:controlsViewModel="@{controlsViewModel}"/> android:visibility="@{controlsViewModel.callStatsVisible ? View.VISIBLE : View.GONE, default=gone}"
app:controlsViewModel="@{controlsViewModel}"
app:inflatedVisibility="@{controlsViewModel.callStatsVisible ? View.VISIBLE : View.GONE}"
app:statsViewModel="@{statsViewModel}" />
<ViewStub <ViewStub
android:id="@+id/stubbed_numpad" android:id="@+id/stubbed_numpad"
android:layout="@layout/voip_numpad"
android:visibility="@{controlsViewModel.numpadVisible ? View.VISIBLE : View.GONE, default=gone}"
app:inflatedVisibility="@{controlsViewModel.numpadVisible ? View.VISIBLE : View.GONE}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:controlsViewModel="@{controlsViewModel}"/> android:layout="@layout/voip_numpad"
android:visibility="@{controlsViewModel.numpadVisible ? View.VISIBLE : View.GONE, default=gone}"
app:controlsViewModel="@{controlsViewModel}"
app:inflatedVisibility="@{controlsViewModel.numpadVisible ? View.VISIBLE : View.GONE}" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
<include <include
layout="@layout/voip_conference_creation_pending_wait_layout" layout="@layout/voip_conference_creation_pending_wait_layout"
bind:visibility="@{conferenceViewModel.conferenceCreationPending}"/> bind:visibility="@{conferenceViewModel.conferenceCreationPending}" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -6,7 +6,7 @@
<import type="android.view.View" /> <import type="android.view.View" />
<import type="org.linphone.core.ConferenceLayout" /> <import type="org.linphone.activities.voip.ConferenceDisplayMode" />
<variable <variable
name="cancelClickListener" name="cancelClickListener"
@ -71,11 +71,11 @@
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:checked="@{conferenceViewModel.conferenceMosaicDisplayMode}" android:checked="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.GRID}"
android:drawableEnd="@drawable/icon_conference_layout_grid" android:drawableEnd="@drawable/icon_conference_layout_grid"
android:drawableTint="?attr/voipDrawableColor" android:drawableTint="?attr/voipDrawableColor"
android:enabled="@{conferenceViewModel.conferenceParticipantDevices.size() > conferenceViewModel.maxParticipantsForMosaicLayout ? false : true}" android:enabled="@{conferenceViewModel.conferenceParticipantDevices.size() > conferenceViewModel.maxParticipantsForMosaicLayout ? false : true}"
android:onClickListener="@{() -> conferenceViewModel.changeLayout(ConferenceLayout.Grid)}" android:onClickListener="@{() -> conferenceViewModel.changeLayout(ConferenceDisplayMode.GRID)}"
android:text="@string/conference_display_mode_mosaic" /> android:text="@string/conference_display_mode_mosaic" />
<View <View
@ -90,11 +90,11 @@
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:checked="@{conferenceViewModel.conferenceActiveSpeakerDisplayMode}" android:checked="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.ACTIVE_SPEAKER}"
android:drawableEnd="@drawable/icon_conference_layout_active_speaker" android:drawableEnd="@drawable/icon_conference_layout_active_speaker"
android:drawableTint="?attr/voipDrawableColor" android:drawableTint="?attr/voipDrawableColor"
android:enabled="@{conferenceViewModel.conferenceParticipantDevices.size() > conferenceViewModel.maxParticipantsForMosaicLayout ? false : true}" android:enabled="@{conferenceViewModel.conferenceParticipantDevices.size() > conferenceViewModel.maxParticipantsForMosaicLayout ? false : true}"
android:onClickListener="@{() -> conferenceViewModel.changeLayout(ConferenceLayout.ActiveSpeaker)}" android:onClickListener="@{() -> conferenceViewModel.changeLayout(ConferenceDisplayMode.ACTIVE_SPEAKER)}"
android:text="@string/conference_display_mode_active_speaker" /> android:text="@string/conference_display_mode_active_speaker" />
<View <View
@ -102,7 +102,6 @@
android:layout_height="1dp" android:layout_height="1dp"
android:background="?attr/dividerColor" /> android:background="?attr/dividerColor" />
<!-- TODO: FIXME: Use AudioOnly layout -->
<RadioButton <RadioButton
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -110,10 +109,10 @@
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:checked="@{conferenceViewModel.conferenceAudioOnlyDisplayMode}" android:checked="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.AUDIO_ONLY}"
android:drawableEnd="@drawable/icon_conference_layout_audio_only" android:drawableEnd="@drawable/icon_conference_layout_audio_only"
android:drawableTint="?attr/voipDrawableColor" android:drawableTint="?attr/voipDrawableColor"
android:onClickListener="@{() -> conferenceViewModel.changeLayout(ConferenceLayout.Legacy)}" android:onClickListener="@{() -> conferenceViewModel.changeLayout(ConferenceDisplayMode.AUDIO_ONLY)}"
android:text="@string/conference_display_mode_audio_only" /> android:text="@string/conference_display_mode_audio_only" />
<View <View

View file

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View" />
<variable
name="data"
type="org.linphone.activities.voip.data.ConferenceParticipantDeviceData" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="@dimen/voip_conference_audio_only_participant_cell_height">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="5dp"
android:background="@drawable/shape_audio_only_remote_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<include
android:id="@+id/participant_avatar"
layout="@layout/voip_contact_avatar"
android:layout_width="@dimen/voip_conference_audio_only_participant_avatar_size"
android:layout_height="@dimen/voip_conference_audio_only_participant_avatar_size"
android:layout_marginStart="10dp"
app:data="@{data}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHeight_max="200dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/participant_name"
style="@style/call_remote_name_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="@{data.contact.fullName ?? data.displayName, default=`Merry Brandybuck`}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/participant_avatar"
app:layout_constraintTop_toTopOf="parent" />
<TextView
style="@style/call_remote_name_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/conference_participant_paused"
android:visibility="@{data.isInConference ? View.GONE : View.VISIBLE, default=gone}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/participant_name"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="5dp"
android:adjustViewBounds="true"
android:contentDescription="@null"
android:src="@drawable/shape_conference_audio_only_border"
android:visibility="@{data.activeSpeaker ? View.VISIBLE : View.GONE, default=gone}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:layout_width="@dimen/voip_conference_participant_mic_muted_icon_size_grid"
android:layout_height="@dimen/voip_conference_participant_mic_muted_icon_size_grid"
android:layout_marginEnd="10dp"
android:background="@drawable/shape_button_disabled_background"
android:contentDescription="@string/content_description_conference_participant_mic_muted"
android:padding="5dp"
android:src="@drawable/icon_mic_muted"
android:visibility="@{data.micMuted ? View.VISIBLE : View.GONE, default=gone}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -61,4 +61,6 @@
<dimen name="voip_dialog_button_max_width">137dp</dimen> <dimen name="voip_dialog_button_max_width">137dp</dimen>
<dimen name="voip_contact_avatar_max_height">200dp</dimen> <dimen name="voip_contact_avatar_max_height">200dp</dimen>
<dimen name="voip_numpad_button_max_size">60dp</dimen> <dimen name="voip_numpad_button_max_size">60dp</dimen>
<dimen name="voip_conference_audio_only_participant_cell_height">60dp</dimen>
<dimen name="voip_conference_audio_only_participant_avatar_size">40dp</dimen>
</resources> </resources>