diff --git a/app/src/main/java/org/linphone/activities/main/conference/viewmodels/ConferenceWaitingRoomViewModel.kt b/app/src/main/java/org/linphone/activities/main/conference/viewmodels/ConferenceWaitingRoomViewModel.kt index 62de623e0..7f6dc2078 100644 --- a/app/src/main/java/org/linphone/activities/main/conference/viewmodels/ConferenceWaitingRoomViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/conference/viewmodels/ConferenceWaitingRoomViewModel.kt @@ -23,6 +23,7 @@ import android.Manifest import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import org.linphone.LinphoneApplication.Companion.coreContext +import org.linphone.activities.voip.ConferenceDisplayMode import org.linphone.core.* import org.linphone.core.tools.Log import org.linphone.utils.AudioRouteUtils @@ -44,9 +45,7 @@ class ConferenceWaitingRoomViewModel : ViewModel() { val layoutMenuSelected = MutableLiveData() - val isActiveSpeakerLayoutSelected = MutableLiveData() - - val isAudioOnlyLayoutSelected = MutableLiveData() + val selectedLayout = MutableLiveData() val isVideoAvailable = MutableLiveData() @@ -101,20 +100,17 @@ class ConferenceWaitingRoomViewModel : ViewModel() { Log.i("[Conference Waiting Room] Microphone will be ${if (callParams.isMicEnabled) "enabled" else "muted"}") updateMicState() - layoutMenuSelected.value = false - isActiveSpeakerLayoutSelected.value = false - isAudioOnlyLayoutSelected.value = false - updateLayout() - - isVideoAvailable.value = isAudioOnlyLayoutSelected.value == false && (core.isVideoCaptureEnabled || core.isVideoPreviewEnabled) - callParams.isVideoEnabled = isVideoAvailable.value == true + callParams.isVideoEnabled = isVideoAvailableInCore() 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"}") updateVideoState() + layoutMenuSelected.value = false + updateLayout() + if (AudioRouteUtils.isBluetoothAudioRouteAvailable()) { setBluetoothAudioRoute() - } else if (isVideoAvailable.value == true && isVideoEnabled.value == true) { + } else if (isVideoAvailableInCore() && isVideoEnabled.value == true) { setSpeakerAudioRoute() } else { setEarpieceAudioRoute() @@ -209,22 +205,31 @@ class ConferenceWaitingRoomViewModel : ViewModel() { fun setMosaicLayout() { Log.i("[Conference Waiting Room] Set default layout to Mosaic") - coreContext.core.defaultConferenceLayout = ConferenceLayout.Grid + + callParams.conferenceVideoLayout = ConferenceLayout.Grid + callParams.isVideoEnabled = isVideoAvailableInCore() + updateLayout() + updateVideoState() layoutMenuSelected.value = false } fun setActiveSpeakerLayout() { Log.i("[Conference Waiting Room] Set default layout to ActiveSpeaker") - coreContext.core.defaultConferenceLayout = ConferenceLayout.ActiveSpeaker + + callParams.conferenceVideoLayout = ConferenceLayout.ActiveSpeaker + callParams.isVideoEnabled = isVideoAvailableInCore() + updateLayout() + updateVideoState() layoutMenuSelected.value = false } fun setAudioOnlyLayout() { - Log.i("[Conference Waiting Room] Set default layout to AudioOnly") - coreContext.core.defaultConferenceLayout = ConferenceLayout.Legacy // TODO: FIXME: Replace Legacy by AudioOnly + Log.i("[Conference Waiting Room] Set default layout to AudioOnly, disabling video in call") + callParams.isVideoEnabled = false updateLayout() + updateVideoState() layoutMenuSelected.value = false } @@ -233,7 +238,7 @@ class ConferenceWaitingRoomViewModel : ViewModel() { askPermissionEvent.value = Event(Manifest.permission.CAMERA) return } - callParams.isVideoEnabled = isVideoAvailable.value == true + callParams.isVideoEnabled = isVideoAvailableInCore() 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"}") updateVideoState() @@ -241,7 +246,7 @@ class ConferenceWaitingRoomViewModel : ViewModel() { fun enableVideo() { Log.i("[Conference Waiting Room] Video will be enabled") - callParams.isVideoEnabled = isVideoAvailable.value == true + callParams.isVideoEnabled = isVideoAvailableInCore() callParams.videoDirection = MediaDirection.SendRecv updateVideoState() } @@ -290,20 +295,25 @@ class ConferenceWaitingRoomViewModel : ViewModel() { } private fun updateLayout() { - val core = coreContext.core - val layout = core.defaultConferenceLayout - isActiveSpeakerLayoutSelected.value = layout == ConferenceLayout.ActiveSpeaker - isAudioOnlyLayoutSelected.value = layout == ConferenceLayout.Legacy // TODO: FIXME: Replace Legacy by AudioOnly - - isVideoAvailable.value = isAudioOnlyLayoutSelected.value == false && (core.isVideoCaptureEnabled || core.isVideoPreviewEnabled) - callParams.isVideoEnabled = isVideoAvailable.value == true && isAudioOnlyLayoutSelected.value == false - if (isAudioOnlyLayoutSelected.value == true) callParams.videoDirection = MediaDirection.RecvOnly - updateVideoState() + if (!callParams.isVideoEnabled) { + selectedLayout.value = ConferenceDisplayMode.AUDIO_ONLY + } else { + selectedLayout.value = when (callParams.conferenceVideoLayout) { + ConferenceLayout.Grid -> ConferenceDisplayMode.GRID + else -> ConferenceDisplayMode.ACTIVE_SPEAKER + } + } } private fun updateVideoState() { + isVideoAvailable.value = callParams.isVideoEnabled isVideoEnabled.value = callParams.isVideoEnabled && callParams.videoDirection == MediaDirection.SendRecv isSwitchCameraAvailable.value = callParams.isVideoEnabled && coreContext.showSwitchCameraButton() coreContext.core.isVideoPreviewEnabled = callParams.isVideoEnabled } + + private fun isVideoAvailableInCore(): Boolean { + val core = coreContext.core + return core.isVideoCaptureEnabled || core.isVideoPreviewEnabled + } } diff --git a/app/src/main/java/org/linphone/activities/main/settings/viewmodels/ConferencesSettingsViewModel.kt b/app/src/main/java/org/linphone/activities/main/settings/viewmodels/ConferencesSettingsViewModel.kt index 07c593fb0..52d1c005c 100644 --- a/app/src/main/java/org/linphone/activities/main/settings/viewmodels/ConferencesSettingsViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/settings/viewmodels/ConferencesSettingsViewModel.kt @@ -48,9 +48,6 @@ class ConferencesSettingsViewModel : GenericSettingsViewModel() { labels.add(prefs.getString(R.string.conference_display_mode_mosaic)) 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 layoutIndex.value = layoutValues.indexOf(core.defaultConferenceLayout.toInt()) } diff --git a/app/src/main/java/org/linphone/activities/voip/ConferenceDisplayMode.kt b/app/src/main/java/org/linphone/activities/voip/ConferenceDisplayMode.kt new file mode 100644 index 000000000..0e529b351 --- /dev/null +++ b/app/src/main/java/org/linphone/activities/voip/ConferenceDisplayMode.kt @@ -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 . + */ +package org.linphone.activities.voip + +enum class ConferenceDisplayMode { + GRID, + ACTIVE_SPEAKER, + AUDIO_ONLY +} diff --git a/app/src/main/java/org/linphone/activities/voip/data/CallData.kt b/app/src/main/java/org/linphone/activities/voip/data/CallData.kt index dbeaaa29b..5776b8ea1 100644 --- a/app/src/main/java/org/linphone/activities/voip/data/CallData.kt +++ b/app/src/main/java/org/linphone/activities/voip/data/CallData.kt @@ -113,7 +113,6 @@ open class CallData(val call: Call) : GenericContactData(call.remoteAddress) { displayableAddress.value = clone.asStringUriOnly() update() - // initChatRoom() val conferenceInfo = coreContext.core.findConferenceInformationFromUri(call.remoteAddress) if (conferenceInfo != null) { @@ -167,6 +166,10 @@ open class CallData(val call: Call) : GenericContactData(call.remoteAddress) { contextMenuClickListener?.onShowContextMenu(anchor, this) } + fun isActiveAndNotInConference(): Boolean { + return isPaused.value == false && isRemotelyPaused.value == false && isInRemoteConference.value == false + } + private fun isCallPaused(): Boolean { return when (call.state) { Call.State.Paused, Call.State.Pausing -> true diff --git a/app/src/main/java/org/linphone/activities/voip/fragments/ConferenceCallFragment.kt b/app/src/main/java/org/linphone/activities/voip/fragments/ConferenceCallFragment.kt index 2312912aa..516d56480 100644 --- a/app/src/main/java/org/linphone/activities/voip/fragments/ConferenceCallFragment.kt +++ b/app/src/main/java/org/linphone/activities/voip/fragments/ConferenceCallFragment.kt @@ -39,6 +39,7 @@ import org.linphone.activities.main.MainActivity import org.linphone.activities.navigateToCallsList import org.linphone.activities.navigateToConferenceLayout import org.linphone.activities.navigateToConferenceParticipants +import org.linphone.activities.voip.ConferenceDisplayMode import org.linphone.activities.voip.viewmodels.CallsViewModel import org.linphone.activities.voip.viewmodels.ConferenceViewModel import org.linphone.activities.voip.viewmodels.ControlsViewModel @@ -79,20 +80,11 @@ class ConferenceCallFragment : GenericFragment + startTimer(R.id.active_conference_timer) + if (displayMode == ConferenceDisplayMode.ACTIVE_SPEAKER) { 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") val layout = @@ -107,14 +99,6 @@ class ConferenceCallFragment : GenericFragment + when (layout) { + ConferenceDisplayMode.AUDIO_ONLY -> { + controlsViewModel.fullScreenMode.value = false + } + else -> { + val conference = conferenceViewModel.conference.value + if (conference != null) switchToFullScreenIfPossible(conference) + } + } + } + controlsViewModel.goToConferenceParticipantsListEvent.observe( viewLifecycleOwner ) { diff --git a/app/src/main/java/org/linphone/activities/voip/fragments/ConferenceLayoutFragment.kt b/app/src/main/java/org/linphone/activities/voip/fragments/ConferenceLayoutFragment.kt index 3ba59a99b..5b8c9bfa9 100644 --- a/app/src/main/java/org/linphone/activities/voip/fragments/ConferenceLayoutFragment.kt +++ b/app/src/main/java/org/linphone/activities/voip/fragments/ConferenceLayoutFragment.kt @@ -26,6 +26,7 @@ import androidx.navigation.navGraphViewModels import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.R import org.linphone.activities.GenericFragment +import org.linphone.activities.voip.ConferenceDisplayMode import org.linphone.activities.voip.viewmodels.ConferenceViewModel import org.linphone.databinding.VoipConferenceLayoutFragmentBinding @@ -53,6 +54,16 @@ class ConferenceLayoutFragment : GenericFragment(R.id.too_many_participants_dialog) dialog?.visibility = View.GONE diff --git a/app/src/main/java/org/linphone/activities/voip/viewmodels/CallsViewModel.kt b/app/src/main/java/org/linphone/activities/voip/viewmodels/CallsViewModel.kt index bfdf40f48..f1fc5ac6f 100644 --- a/app/src/main/java/org/linphone/activities/voip/viewmodels/CallsViewModel.kt +++ b/app/src/main/java/org/linphone/activities/voip/viewmodels/CallsViewModel.kt @@ -73,6 +73,7 @@ class CallsViewModel : ViewModel() { } override fun onLastCallEnded(core: Core) { + Log.i("[Calls] Last call ended") currentCallData.value?.destroy() noMoreCallEvent.value = Event(true) } diff --git a/app/src/main/java/org/linphone/activities/voip/viewmodels/ConferenceViewModel.kt b/app/src/main/java/org/linphone/activities/voip/viewmodels/ConferenceViewModel.kt index db1610c3a..bd7c8d8f2 100644 --- a/app/src/main/java/org/linphone/activities/voip/viewmodels/ConferenceViewModel.kt +++ b/app/src/main/java/org/linphone/activities/voip/viewmodels/ConferenceViewModel.kt @@ -24,6 +24,7 @@ import androidx.lifecycle.ViewModel import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R +import org.linphone.activities.voip.ConferenceDisplayMode import org.linphone.activities.voip.data.ConferenceParticipantData import org.linphone.activities.voip.data.ConferenceParticipantDeviceData import org.linphone.core.* @@ -43,9 +44,7 @@ class ConferenceViewModel : ViewModel() { val conferenceCreationPending = MutableLiveData() val conferenceParticipants = MutableLiveData>() val conferenceParticipantDevices = MutableLiveData>() - val conferenceMosaicDisplayMode = MutableLiveData() - val conferenceActiveSpeakerDisplayMode = MutableLiveData() - val conferenceAudioOnlyDisplayMode = MutableLiveData() + val conferenceDisplayMode = MutableLiveData() val isRecording = MutableLiveData() val isRemotelyRecorded = MutableLiveData() @@ -64,10 +63,9 @@ class ConferenceViewModel : ViewModel() { updateParticipantsList(conference) 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") - conferenceMosaicDisplayMode.value = false - conferenceActiveSpeakerDisplayMode.value = true + conferenceDisplayMode.value = ConferenceDisplayMode.ACTIVE_SPEAKER } } @@ -181,9 +179,6 @@ class ConferenceViewModel : ViewModel() { conferenceParticipants.value = arrayListOf() conferenceParticipantDevices.value = arrayListOf() - conferenceMosaicDisplayMode.value = false - conferenceActiveSpeakerDisplayMode.value = false - conferenceAudioOnlyDisplayMode.value = false 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") val conference = conference.value if (conference != null) { - conference.layout = layout - updateConferenceLayout(conference) + val call = conference.call + 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 { Log.e("[Conference] Conference is null in ConferenceViewModel") } } private fun updateConferenceLayout(conference: Conference) { - val layout = conference.layout - conferenceMosaicDisplayMode.value = layout == ConferenceLayout.Grid - conferenceActiveSpeakerDisplayMode.value = layout == ConferenceLayout.ActiveSpeaker - conferenceAudioOnlyDisplayMode.value = layout == ConferenceLayout.Legacy // TODO: FIXME: Use AudioOnly layout + val call = conference.call + if (call == null) { + Log.e("[Conference] Conference call is null!") + 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()) 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) { @@ -422,7 +447,7 @@ class ConferenceViewModel : ViewModel() { } if (meDeviceData != null) { val index = sortedList.indexOf(meDeviceData) - val expectedIndex = if (conferenceActiveSpeakerDisplayMode.value == true) { + val expectedIndex = if (conferenceDisplayMode.value == ConferenceDisplayMode.ACTIVE_SPEAKER) { 0 } else { sortedList.size - 1 diff --git a/app/src/main/java/org/linphone/core/CoreContext.kt b/app/src/main/java/org/linphone/core/CoreContext.kt index 5ad8df3a3..975fae9a2 100644 --- a/app/src/main/java/org/linphone/core/CoreContext.kt +++ b/app/src/main/java/org/linphone/core/CoreContext.kt @@ -353,9 +353,6 @@ class CoreContext(val context: Context, coreConfig: Config) { core.isVibrationOnIncomingCallEnabled = true core.config.setBool("app", "incoming_call_vibration", false) } - if (core.defaultConferenceLayout == ConferenceLayout.Legacy) { - core.defaultConferenceLayout = ConferenceLayout.ActiveSpeaker - } initUserCertificates() diff --git a/app/src/main/res/drawable/shape_audio_only_remote_background.xml b/app/src/main/res/drawable/shape_audio_only_remote_background.xml new file mode 100644 index 000000000..ec1d610aa --- /dev/null +++ b/app/src/main/res/drawable/shape_audio_only_remote_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_conference_audio_only_border.xml b/app/src/main/res/drawable/shape_conference_audio_only_border.xml new file mode 100644 index 000000000..d276b1039 --- /dev/null +++ b/app/src/main/res/drawable/shape_conference_audio_only_border.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/conference_waiting_room_fragment.xml b/app/src/main/res/layout/conference_waiting_room_fragment.xml index 5de2ad687..76274b36a 100644 --- a/app/src/main/res/layout/conference_waiting_room_fragment.xml +++ b/app/src/main/res/layout/conference_waiting_room_fragment.xml @@ -3,7 +3,11 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> + + + + @@ -21,20 +25,19 @@ android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_margin="20dp" - android:maxLines="1" android:ellipsize="end" + android:maxLines="1" android:text="@{viewModel.subject, default=`Conference subject`}" /> + android:text="@string/conference_waiting_room_video_disabled" + android:visibility="@{viewModel.isVideoEnabled ? View.GONE : View.VISIBLE}" /> + android:background="@drawable/shape_remote_video_background" + android:visibility="@{viewModel.isVideoEnabled ? View.VISIBLE : View.GONE, default=gone}"> + android:layout_marginBottom="20dp" + android:orientation="horizontal"> - - + + + android:enabled="@{!viewModel.joinInProgress}" + 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" /> + android:background="@drawable/shape_audio_routes_background" + android:orientation="vertical" + android:visibility="@{viewModel.audioRoutesSelected ? View.VISIBLE : View.GONE, default=gone}"> + android:layout_marginBottom="10dp" + android:background="@drawable/shape_audio_routes_background" + android:orientation="vertical" + android:visibility="@{viewModel.layoutMenuSelected ? View.VISIBLE : View.GONE, default=gone}"> + app:tint="@color/white_color" /> @@ -211,14 +215,14 @@ android:layout_marginBottom="10dp"> + android:selected="@{viewModel.audioRoutesSelected}" + android:src="@drawable/icon_audio_routes" + android:visibility="@{viewModel.audioRoutesEnabled ? View.VISIBLE : View.GONE, default=gone}" /> + app:layout_constraintDimensionRatio="W,1:1" + app:layout_constraintEnd_toEndOf="parent" /> diff --git a/app/src/main/res/layout/voip_buttons.xml b/app/src/main/res/layout/voip_buttons.xml index 549380390..928d668a6 100644 --- a/app/src/main/res/layout/voip_buttons.xml +++ b/app/src/main/res/layout/voip_buttons.xml @@ -3,13 +3,22 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> + + + + + + + + app:layout_constraintTop_toTopOf="@id/more" /> diff --git a/app/src/main/res/layout/voip_buttons_extra.xml b/app/src/main/res/layout/voip_buttons_extra.xml index 03e40fbac..6c8433c11 100644 --- a/app/src/main/res/layout/voip_buttons_extra.xml +++ b/app/src/main/res/layout/voip_buttons_extra.xml @@ -4,13 +4,19 @@ xmlns:tools="http://schemas.android.com/tools"> + + + + + + @@ -37,7 +43,7 @@ app:layout_constraintEnd_toStartOf="@id/call_stats" app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="@id/chat"/> + app:layout_constraintTop_toTopOf="@id/chat" /> + app:layout_constraintTop_toTopOf="@id/chat" /> + app:layout_constraintTop_toBottomOf="@id/numpad" /> + app:layout_constraintTop_toTopOf="@id/calls" /> + app:layout_constraintTop_toTopOf="@id/calls" /> - - - - - + android:gravity="center" + android:orientation="vertical"> + android:id="@+id/header" + layout="@layout/voip_conference_header" + android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}" + app:conferenceViewModel="@{conferenceViewModel}" /> - + android:visibility="@{conferenceViewModel.isRemotelyRecorded ? View.VISIBLE : View.GONE, default=gone}" /> - + + + + + + + diff --git a/app/src/main/res/layout/voip_conference_call_fragment.xml b/app/src/main/res/layout/voip_conference_call_fragment.xml index bb9154dbd..58332de3a 100644 --- a/app/src/main/res/layout/voip_conference_call_fragment.xml +++ b/app/src/main/res/layout/voip_conference_call_fragment.xml @@ -4,17 +4,25 @@ xmlns:bind="http://schemas.android.com/tools"> + + + + + + + + @@ -33,129 +41,130 @@ + app:inflatedVisibility="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.ACTIVE_SPEAKER && conferenceViewModel.conferenceExists && !callsViewModel.currentCallData.isActiveAndNotInConference ? View.VISIBLE : View.GONE}" + app:layout_constraintBottom_toTopOf="@id/primary_buttons" + app:layout_constraintTop_toTopOf="parent" /> + app:inflatedVisibility="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.GRID && conferenceViewModel.conferenceExists && !callsViewModel.currentCallData.isActiveAndNotInConference ? View.VISIBLE : View.GONE}" + app:layout_constraintBottom_toTopOf="@id/primary_buttons" + app:layout_constraintTop_toTopOf="parent" /> + app:inflatedVisibility="@{conferenceViewModel.conferenceDisplayMode == ConferenceDisplayMode.AUDIO_ONLY && conferenceViewModel.conferenceExists && !callsViewModel.currentCallData.isActiveAndNotInConference ? View.VISIBLE : View.GONE}" + app:layout_constraintBottom_toTopOf="@id/primary_buttons" + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintWidth_max="@dimen/voip_buttons_max_width" /> + app:layout_constraintTop_toTopOf="parent" /> + android:background="@color/voip_translucent_popup_background" + android:onClick="@{() -> controlsViewModel.hideExtraButtons(false)}" + android:visibility="@{controlsViewModel.showExtras ? View.VISIBLE : View.GONE, default=gone}" /> + 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" /> + android:layout="@layout/voip_call_stats" + android:visibility="@{controlsViewModel.callStatsVisible ? View.VISIBLE : View.GONE, default=gone}" + app:controlsViewModel="@{controlsViewModel}" + app:inflatedVisibility="@{controlsViewModel.callStatsVisible ? View.VISIBLE : View.GONE}" + app:statsViewModel="@{statsViewModel}" /> + 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}" /> + bind:visibility="@{conferenceViewModel.conferenceCreationPending}" /> diff --git a/app/src/main/res/layout/voip_conference_layout_fragment.xml b/app/src/main/res/layout/voip_conference_layout_fragment.xml index e2e7aab80..890da6a72 100644 --- a/app/src/main/res/layout/voip_conference_layout_fragment.xml +++ b/app/src/main/res/layout/voip_conference_layout_fragment.xml @@ -6,7 +6,7 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml index 305109ab1..d9148e09b 100644 --- a/app/src/main/res/values/dimen.xml +++ b/app/src/main/res/values/dimen.xml @@ -61,4 +61,6 @@ 137dp 200dp 60dp + 60dp + 40dp \ No newline at end of file