Changes to reflect new conference API
Should fix various conference UI issues More UI fixes related to conference Fixes & improvements Fixed remove participant button invisible in dark mode API changes Handle conference enter and leave Fixed conference UI issues Small UI improvements Improve logging Improved paused conference cell Use isMe if participant added or removed is focus Update method names after changes to conference API
This commit is contained in:
parent
63205cb33f
commit
b803ae9a61
19 changed files with 506 additions and 371 deletions
|
@ -203,11 +203,17 @@ repositories {
|
||||||
maven {
|
maven {
|
||||||
name "local linphone-sdk maven repository"
|
name "local linphone-sdk maven repository"
|
||||||
url file(LinphoneSdkBuildDir + '/maven_repository/')
|
url file(LinphoneSdkBuildDir + '/maven_repository/')
|
||||||
|
content {
|
||||||
|
includeGroup "org.linphone"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
maven {
|
maven {
|
||||||
name "linphone.org maven repository"
|
name "linphone.org maven repository"
|
||||||
url "https://linphone.org/maven_repository"
|
url "https://linphone.org/maven_repository"
|
||||||
|
content {
|
||||||
|
includeGroup "org.linphone"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ abstract class ProximitySensorActivity : GenericActivity() {
|
||||||
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { }
|
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { }
|
||||||
|
|
||||||
override fun onSensorChanged(event: SensorEvent) {
|
override fun onSensorChanged(event: SensorEvent) {
|
||||||
if (event.timestamp == 0L) return
|
if (event.timestamp == 0L || !proximitySensorEnabled) return
|
||||||
if (isProximitySensorNearby(event)) {
|
if (isProximitySensorNearby(event)) {
|
||||||
if (!proximityWakeLock.isHeld) {
|
if (!proximityWakeLock.isHeld) {
|
||||||
Log.i("[Proximity Sensor Activity] Acquiring proximity wake lock")
|
Log.i("[Proximity Sensor Activity] Acquiring proximity wake lock")
|
||||||
|
@ -89,6 +89,12 @@ abstract class ProximitySensorActivity : GenericActivity() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
enableProximitySensor(false)
|
||||||
|
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
protected fun enableProximitySensor(enable: Boolean) {
|
protected fun enableProximitySensor(enable: Boolean) {
|
||||||
if (!proximitySensorFound) {
|
if (!proximitySensorFound) {
|
||||||
Log.w("[Proximity Sensor Activity] Couldn't find proximity sensor in this device, skipping")
|
Log.w("[Proximity Sensor Activity] Couldn't find proximity sensor in this device, skipping")
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.GenericFragment
|
import org.linphone.activities.GenericFragment
|
||||||
import org.linphone.activities.call.viewmodels.CallsViewModel
|
import org.linphone.activities.call.viewmodels.CallsViewModel
|
||||||
|
import org.linphone.activities.call.viewmodels.ConferenceViewModel
|
||||||
import org.linphone.activities.call.viewmodels.ControlsViewModel
|
import org.linphone.activities.call.viewmodels.ControlsViewModel
|
||||||
import org.linphone.activities.call.viewmodels.SharedCallViewModel
|
import org.linphone.activities.call.viewmodels.SharedCallViewModel
|
||||||
import org.linphone.activities.main.MainActivity
|
import org.linphone.activities.main.MainActivity
|
||||||
|
@ -51,6 +52,7 @@ import org.linphone.utils.PermissionHelper
|
||||||
class ControlsFragment : GenericFragment<CallControlsFragmentBinding>() {
|
class ControlsFragment : GenericFragment<CallControlsFragmentBinding>() {
|
||||||
private lateinit var callsViewModel: CallsViewModel
|
private lateinit var callsViewModel: CallsViewModel
|
||||||
private lateinit var controlsViewModel: ControlsViewModel
|
private lateinit var controlsViewModel: ControlsViewModel
|
||||||
|
private lateinit var conferenceViewModel: ConferenceViewModel
|
||||||
private lateinit var sharedViewModel: SharedCallViewModel
|
private lateinit var sharedViewModel: SharedCallViewModel
|
||||||
|
|
||||||
private var dialog: Dialog? = null
|
private var dialog: Dialog? = null
|
||||||
|
@ -75,6 +77,9 @@ class ControlsFragment : GenericFragment<CallControlsFragmentBinding>() {
|
||||||
controlsViewModel = ViewModelProvider(this).get(ControlsViewModel::class.java)
|
controlsViewModel = ViewModelProvider(this).get(ControlsViewModel::class.java)
|
||||||
binding.controlsViewModel = controlsViewModel
|
binding.controlsViewModel = controlsViewModel
|
||||||
|
|
||||||
|
conferenceViewModel = ViewModelProvider(this).get(ConferenceViewModel::class.java)
|
||||||
|
binding.conferenceViewModel = conferenceViewModel
|
||||||
|
|
||||||
callsViewModel.currentCallViewModel.observe(viewLifecycleOwner, {
|
callsViewModel.currentCallViewModel.observe(viewLifecycleOwner, {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
binding.activeCallTimer.base =
|
binding.activeCallTimer.base =
|
||||||
|
|
|
@ -22,9 +22,8 @@ package org.linphone.activities.call.viewmodels
|
||||||
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.core.Call
|
import org.linphone.core.*
|
||||||
import org.linphone.core.Core
|
import org.linphone.core.tools.Log
|
||||||
import org.linphone.core.CoreListenerStub
|
|
||||||
import org.linphone.utils.Event
|
import org.linphone.utils.Event
|
||||||
import org.linphone.utils.PermissionHelper
|
import org.linphone.utils.PermissionHelper
|
||||||
|
|
||||||
|
@ -35,10 +34,6 @@ class CallsViewModel : ViewModel() {
|
||||||
|
|
||||||
val pausedCalls = MutableLiveData<ArrayList<CallViewModel>>()
|
val pausedCalls = MutableLiveData<ArrayList<CallViewModel>>()
|
||||||
|
|
||||||
val conferenceCalls = MutableLiveData<ArrayList<CallViewModel>>()
|
|
||||||
|
|
||||||
val isConferencePaused = MutableLiveData<Boolean>()
|
|
||||||
|
|
||||||
val noMoreCallEvent: MutableLiveData<Event<Boolean>> by lazy {
|
val noMoreCallEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||||
MutableLiveData<Event<Boolean>>()
|
MutableLiveData<Event<Boolean>>()
|
||||||
}
|
}
|
||||||
|
@ -52,14 +47,9 @@ class CallsViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private val listener = object : CoreListenerStub() {
|
private val listener = object : CoreListenerStub() {
|
||||||
override fun onCallStateChanged(
|
override fun onCallStateChanged(core: Core, call: Call, state: Call.State, message: String) {
|
||||||
core: Core,
|
Log.i("[Calls VM] Call state changed: $state")
|
||||||
call: Call,
|
callPausedByRemote.value = (state == Call.State.PausedByRemote) and (call.conference == null)
|
||||||
state: Call.State,
|
|
||||||
message: String
|
|
||||||
) {
|
|
||||||
callPausedByRemote.value = state == Call.State.PausedByRemote
|
|
||||||
isConferencePaused.value = !coreContext.core.isInConference
|
|
||||||
|
|
||||||
val currentCall = core.currentCall
|
val currentCall = core.currentCall
|
||||||
if (currentCall == null) {
|
if (currentCall == null) {
|
||||||
|
@ -71,14 +61,11 @@ class CallsViewModel : ViewModel() {
|
||||||
if (state == Call.State.End || state == Call.State.Released || state == Call.State.Error) {
|
if (state == Call.State.End || state == Call.State.Released || state == Call.State.Error) {
|
||||||
if (core.callsNb == 0) {
|
if (core.callsNb == 0) {
|
||||||
noMoreCallEvent.value = Event(true)
|
noMoreCallEvent.value = Event(true)
|
||||||
conferenceCalls.value = arrayListOf()
|
|
||||||
} else {
|
} else {
|
||||||
removeCallFromPausedListIfPresent(call)
|
removeCallFromPausedListIfPresent(call)
|
||||||
removeCallFromConferenceIfPresent(call)
|
|
||||||
}
|
}
|
||||||
} else if (state == Call.State.Paused) {
|
} else if (state == Call.State.Paused) {
|
||||||
addCallToPausedList(call)
|
addCallToPausedList(call)
|
||||||
removeCallFromConferenceIfPresent(call)
|
|
||||||
} else if (state == Call.State.Resuming) {
|
} else if (state == Call.State.Resuming) {
|
||||||
removeCallFromPausedListIfPresent(call)
|
removeCallFromPausedListIfPresent(call)
|
||||||
} else if (call.state == Call.State.UpdatedByRemote) {
|
} else if (call.state == Call.State.UpdatedByRemote) {
|
||||||
|
@ -91,17 +78,9 @@ class CallsViewModel : ViewModel() {
|
||||||
call.deferUpdate()
|
call.deferUpdate()
|
||||||
callUpdateEvent.value = Event(call)
|
callUpdateEvent.value = Event(call)
|
||||||
}
|
}
|
||||||
} else {
|
} else if (state == Call.State.StreamsRunning) {
|
||||||
if (state == Call.State.StreamsRunning) {
|
|
||||||
callUpdateEvent.value = Event(call)
|
callUpdateEvent.value = Event(call)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (call.conference != null) {
|
|
||||||
addCallToConferenceListIfNotAlreadyInIt(call)
|
|
||||||
} else {
|
|
||||||
removeCallFromConferenceIfPresent(call)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,21 +91,15 @@ class CallsViewModel : ViewModel() {
|
||||||
if (currentCall != null) {
|
if (currentCall != null) {
|
||||||
currentCallViewModel.value = CallViewModel(currentCall)
|
currentCallViewModel.value = CallViewModel(currentCall)
|
||||||
}
|
}
|
||||||
callPausedByRemote.value = currentCall?.state == Call.State.PausedByRemote
|
|
||||||
isConferencePaused.value = !coreContext.core.isInConference
|
|
||||||
|
|
||||||
val conferenceList = arrayListOf<CallViewModel>()
|
callPausedByRemote.value = currentCall?.state == Call.State.PausedByRemote
|
||||||
|
|
||||||
for (call in coreContext.core.calls) {
|
for (call in coreContext.core.calls) {
|
||||||
if (call.state == Call.State.Paused || call.state == Call.State.Pausing) {
|
if (call.state == Call.State.Paused || call.state == Call.State.Pausing) {
|
||||||
addCallToPausedList(call)
|
addCallToPausedList(call)
|
||||||
} else {
|
|
||||||
if (call.conference != null) {
|
|
||||||
conferenceList.add(CallViewModel(call))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conferenceCalls.value = conferenceList
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
coreContext.core.removeListener(listener)
|
coreContext.core.removeListener(listener)
|
||||||
|
@ -138,20 +111,6 @@ class CallsViewModel : ViewModel() {
|
||||||
coreContext.answerCallVideoUpdateRequest(call, accept)
|
coreContext.answerCallVideoUpdateRequest(call, accept)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pauseConference() {
|
|
||||||
if (coreContext.core.isInConference) {
|
|
||||||
coreContext.core.leaveConference()
|
|
||||||
isConferencePaused.value = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun resumeConference() {
|
|
||||||
if (!coreContext.core.isInConference) {
|
|
||||||
coreContext.core.enterConference()
|
|
||||||
isConferencePaused.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun takeScreenshot() {
|
fun takeScreenshot() {
|
||||||
if (!PermissionHelper.get().hasWriteExternalStorage()) {
|
if (!PermissionHelper.get().hasWriteExternalStorage()) {
|
||||||
askWriteExternalStoragePermissionEvent.value = Event(true)
|
askWriteExternalStoragePermissionEvent.value = Event(true)
|
||||||
|
@ -161,9 +120,17 @@ class CallsViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addCallToPausedList(call: Call) {
|
private fun addCallToPausedList(call: Call) {
|
||||||
|
if (call.conference != null) return // Conference will be displayed as paused, no need to display the call as well
|
||||||
|
|
||||||
val list = arrayListOf<CallViewModel>()
|
val list = arrayListOf<CallViewModel>()
|
||||||
list.addAll(pausedCalls.value.orEmpty())
|
list.addAll(pausedCalls.value.orEmpty())
|
||||||
|
|
||||||
|
for (pausedCallViewModel in list) {
|
||||||
|
if (pausedCallViewModel.call == call) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val viewModel = CallViewModel(call)
|
val viewModel = CallViewModel(call)
|
||||||
list.add(viewModel)
|
list.add(viewModel)
|
||||||
pausedCalls.value = list
|
pausedCalls.value = list
|
||||||
|
@ -182,31 +149,4 @@ class CallsViewModel : ViewModel() {
|
||||||
|
|
||||||
pausedCalls.value = list
|
pausedCalls.value = list
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addCallToConferenceListIfNotAlreadyInIt(call: Call) {
|
|
||||||
val list = arrayListOf<CallViewModel>()
|
|
||||||
list.addAll(conferenceCalls.value.orEmpty())
|
|
||||||
|
|
||||||
for (viewModel in list) {
|
|
||||||
if (viewModel.call == call) return
|
|
||||||
}
|
|
||||||
|
|
||||||
val viewModel = CallViewModel(call)
|
|
||||||
list.add(viewModel)
|
|
||||||
conferenceCalls.value = list
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun removeCallFromConferenceIfPresent(call: Call) {
|
|
||||||
val list = arrayListOf<CallViewModel>()
|
|
||||||
list.addAll(conferenceCalls.value.orEmpty())
|
|
||||||
|
|
||||||
for (viewModel in list) {
|
|
||||||
if (viewModel.call == call) {
|
|
||||||
list.remove(viewModel)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conferenceCalls.value = list
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 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.call.viewmodels
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import org.linphone.contact.GenericContactViewModel
|
||||||
|
import org.linphone.core.Conference
|
||||||
|
import org.linphone.core.Participant
|
||||||
|
import org.linphone.core.tools.Log
|
||||||
|
|
||||||
|
class ConferenceParticipantViewModel(
|
||||||
|
private val conference: Conference,
|
||||||
|
val participant: Participant
|
||||||
|
) :
|
||||||
|
GenericContactViewModel(participant.address) {
|
||||||
|
private val isAdmin = MutableLiveData<Boolean>()
|
||||||
|
val isMeAdmin = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
isAdmin.value = participant.isAdmin
|
||||||
|
isMeAdmin.value = conference.me.isAdmin
|
||||||
|
Log.i("[Conference Participant VM] Participant ${participant.address.asStringUriOnly()} is ${if (participant.isAdmin) "admin" else "not admin"}")
|
||||||
|
Log.i("[Conference Participant VM] Me is ${if (conference.me.isAdmin) "admin" else "not admin"} and is ${if (conference.me.isFocus) "focus" else "not focus"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeFromConference() {
|
||||||
|
Log.i("[Conference Participant VM] Removing participant ${participant.address.asStringUriOnly()} from conference $conference")
|
||||||
|
conference.removeParticipant(participant)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2020 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.call.viewmodels
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
|
import org.linphone.core.*
|
||||||
|
import org.linphone.core.tools.Log
|
||||||
|
|
||||||
|
class ConferenceViewModel : ViewModel() {
|
||||||
|
val isConferencePaused = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val isMeConferenceFocus = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val conferenceAddress = MutableLiveData<Address>()
|
||||||
|
|
||||||
|
val conferenceParticipants = MutableLiveData<List<ConferenceParticipantViewModel>>()
|
||||||
|
|
||||||
|
val isInConference = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
private val conferenceListener = object : ConferenceListenerStub() {
|
||||||
|
override fun onParticipantAdded(conference: Conference, participant: Participant) {
|
||||||
|
if (conference.isMe(participant.address)) {
|
||||||
|
Log.i("[Conference VM] Entered conference")
|
||||||
|
isConferencePaused.value = false
|
||||||
|
} else {
|
||||||
|
Log.i("[Conference VM] Participant added")
|
||||||
|
updateParticipantsList(conference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onParticipantRemoved(conference: Conference, participant: Participant) {
|
||||||
|
if (conference.isMe(participant.address)) {
|
||||||
|
Log.i("[Conference VM] Left conference")
|
||||||
|
isConferencePaused.value = true
|
||||||
|
} else {
|
||||||
|
Log.i("[Conference VM] Participant removed")
|
||||||
|
updateParticipantsList(conference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onParticipantAdminStatusChanged(
|
||||||
|
conference: Conference,
|
||||||
|
participant: Participant
|
||||||
|
) {
|
||||||
|
Log.i("[Conference VM] Participant admin status changed")
|
||||||
|
updateParticipantsList(conference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val listener = object : CoreListenerStub() {
|
||||||
|
override fun onConferenceStateChanged(
|
||||||
|
core: Core,
|
||||||
|
conference: Conference,
|
||||||
|
state: Conference.State
|
||||||
|
) {
|
||||||
|
Log.i("[Conference VM] Conference state changed: $state")
|
||||||
|
isConferencePaused.value = !conference.isIn
|
||||||
|
|
||||||
|
if (state == Conference.State.Instantiated) {
|
||||||
|
conference.addListener(conferenceListener)
|
||||||
|
} else if (state == Conference.State.Created) {
|
||||||
|
updateParticipantsList(conference)
|
||||||
|
isMeConferenceFocus.value = conference.me.isFocus
|
||||||
|
conferenceAddress.value = conference.conferenceAddress
|
||||||
|
} else if (state == Conference.State.Terminated || state == Conference.State.TerminationFailed) {
|
||||||
|
isInConference.value = false
|
||||||
|
conference.removeListener(conferenceListener)
|
||||||
|
conferenceParticipants.value = arrayListOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
coreContext.core.addListener(listener)
|
||||||
|
|
||||||
|
isConferencePaused.value = coreContext.core.conference?.isIn != true
|
||||||
|
isMeConferenceFocus.value = false
|
||||||
|
conferenceParticipants.value = arrayListOf()
|
||||||
|
isInConference.value = false
|
||||||
|
|
||||||
|
val conference = coreContext.core.conference
|
||||||
|
if (conference != null) {
|
||||||
|
conference.addListener(conferenceListener)
|
||||||
|
isMeConferenceFocus.value = conference.me.isFocus
|
||||||
|
updateParticipantsList(conference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
coreContext.core.removeListener(listener)
|
||||||
|
|
||||||
|
super.onCleared()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pauseConference() {
|
||||||
|
val defaultProxyConfig = coreContext.core.defaultProxyConfig
|
||||||
|
val localAddress = defaultProxyConfig?.identityAddress
|
||||||
|
val participants = arrayOf<Address>()
|
||||||
|
val remoteConference = coreContext.core.searchConference(null, localAddress, conferenceAddress.value, participants)
|
||||||
|
val localConference = coreContext.core.searchConference(null, conferenceAddress.value, conferenceAddress.value, participants)
|
||||||
|
val conference = remoteConference ?: localConference
|
||||||
|
|
||||||
|
if (conference != null) {
|
||||||
|
Log.i("[Conference VM] Leaving conference with address ${conferenceAddress.value?.asStringUriOnly()} temporarily")
|
||||||
|
conference.leave()
|
||||||
|
} else {
|
||||||
|
Log.w("[Conference VM] Unable to find conference with address ${conferenceAddress.value?.asStringUriOnly()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resumeConference() {
|
||||||
|
val defaultProxyConfig = coreContext.core.defaultProxyConfig
|
||||||
|
val localAddress = defaultProxyConfig?.identityAddress
|
||||||
|
val participants = arrayOf<Address>()
|
||||||
|
val remoteConference = coreContext.core.searchConference(null, localAddress, conferenceAddress.value, participants)
|
||||||
|
val localConference = coreContext.core.searchConference(null, conferenceAddress.value, conferenceAddress.value, participants)
|
||||||
|
val conference = remoteConference ?: localConference
|
||||||
|
|
||||||
|
if (conference != null) {
|
||||||
|
Log.i("[Conference VM] Entering again conference with address ${conferenceAddress.value?.asStringUriOnly()}")
|
||||||
|
conference.enter()
|
||||||
|
} else {
|
||||||
|
Log.w("[Conference VM] Unable to find conference with address ${conferenceAddress.value?.asStringUriOnly()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateParticipantsList(conference: Conference) {
|
||||||
|
val participants = arrayListOf<ConferenceParticipantViewModel>()
|
||||||
|
for (participant in conference.participantList) {
|
||||||
|
Log.i("[Conference VM] Participant found: ${participant.address.asStringUriOnly()}")
|
||||||
|
val viewModel = ConferenceParticipantViewModel(conference, participant)
|
||||||
|
participants.add(viewModel)
|
||||||
|
}
|
||||||
|
conferenceParticipants.value = participants
|
||||||
|
isInConference.value = participants.isNotEmpty()
|
||||||
|
}
|
||||||
|
}
|
|
@ -285,8 +285,8 @@ class ControlsViewModel : ViewModel() {
|
||||||
|
|
||||||
if (conference != null && core.isInConference) {
|
if (conference != null && core.isInConference) {
|
||||||
val params = core.createConferenceParams()
|
val params = core.createConferenceParams()
|
||||||
val videoEnabled = conference.currentParams.videoEnabled()
|
val videoEnabled = conference.currentParams.isVideoEnabled
|
||||||
params.enableVideo(!videoEnabled)
|
params.isVideoEnabled = !videoEnabled
|
||||||
Log.i("[Controls VM] Conference current param for video is $videoEnabled")
|
Log.i("[Controls VM] Conference current param for video is $videoEnabled")
|
||||||
conference.updateParams(params)
|
conference.updateParams(params)
|
||||||
} else if (currentCall != null) {
|
} else if (currentCall != null) {
|
||||||
|
@ -362,7 +362,7 @@ class ControlsViewModel : ViewModel() {
|
||||||
val currentCallVideoEnabled = core.currentCall?.currentParams?.videoEnabled() ?: false
|
val currentCallVideoEnabled = core.currentCall?.currentParams?.videoEnabled() ?: false
|
||||||
|
|
||||||
val params = core.createConferenceParams()
|
val params = core.createConferenceParams()
|
||||||
params.enableVideo(currentCallVideoEnabled)
|
params.isVideoEnabled = currentCallVideoEnabled
|
||||||
Log.i("[Call] Setting videoEnabled to [$currentCallVideoEnabled] in conference params")
|
Log.i("[Call] Setting videoEnabled to [$currentCallVideoEnabled] in conference params")
|
||||||
|
|
||||||
val conference = core.conference ?: core.createConferenceWithParams(params)
|
val conference = core.conference ?: core.createConferenceWithParams(params)
|
||||||
|
|
|
@ -37,16 +37,8 @@ class StatisticsListViewModel : ViewModel() {
|
||||||
state: Call.State,
|
state: Call.State,
|
||||||
message: String
|
message: String
|
||||||
) {
|
) {
|
||||||
if (state == Call.State.End || state == Call.State.Error) {
|
if (state == Call.State.End || state == Call.State.Error || state == Call.State.Connected) {
|
||||||
val newList = arrayListOf<CallStatisticsData>()
|
computeCallsList()
|
||||||
for (stat in callStatsList.value.orEmpty()) {
|
|
||||||
if (stat.call != call) {
|
|
||||||
newList.add(stat)
|
|
||||||
} else {
|
|
||||||
stat.destroy()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callStatsList.value = newList
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,13 +46,7 @@ class StatisticsListViewModel : ViewModel() {
|
||||||
init {
|
init {
|
||||||
coreContext.core.addListener(listener)
|
coreContext.core.addListener(listener)
|
||||||
|
|
||||||
val list = arrayListOf<CallStatisticsData>()
|
computeCallsList()
|
||||||
for (call in coreContext.core.calls) {
|
|
||||||
if (call.state != Call.State.End && call.state != Call.State.Released && call.state != Call.State.Error) {
|
|
||||||
list.add(CallStatisticsData(call))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callStatsList.value = list
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
|
@ -69,4 +55,14 @@ class StatisticsListViewModel : ViewModel() {
|
||||||
|
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun computeCallsList() {
|
||||||
|
val list = arrayListOf<CallStatisticsData>()
|
||||||
|
for (call in coreContext.core.calls) {
|
||||||
|
if (call.state != Call.State.End && call.state != Call.State.Released && call.state != Call.State.Error) {
|
||||||
|
list.add(CallStatisticsData(call))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callStatsList.value = list
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ class StatusViewModel : StatusViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateCallQualityIcon() {
|
private fun updateCallQualityIcon() {
|
||||||
val call = coreContext.core.currentCall
|
val call = coreContext.core.currentCall ?: coreContext.core.calls.firstOrNull()
|
||||||
val quality = call?.currentQuality ?: 0f
|
val quality = call?.currentQuality ?: 0f
|
||||||
callQualityIcon.value = when {
|
callQualityIcon.value = when {
|
||||||
quality >= 4 -> R.drawable.call_quality_indicator_4
|
quality >= 4 -> R.drawable.call_quality_indicator_4
|
||||||
|
|
|
@ -26,11 +26,12 @@ import android.view.LayoutInflater
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.call.viewmodels.CallViewModel
|
import org.linphone.activities.call.viewmodels.ConferenceParticipantViewModel
|
||||||
import org.linphone.databinding.CallConferenceBinding
|
import org.linphone.core.tools.Log
|
||||||
|
import org.linphone.databinding.CallConferenceParticipantBinding
|
||||||
|
|
||||||
class ConferenceCallView : LinearLayout {
|
class ConferenceParticipantView : LinearLayout {
|
||||||
private lateinit var binding: CallConferenceBinding
|
private lateinit var binding: CallConferenceParticipantBinding
|
||||||
|
|
||||||
constructor(context: Context) : super(context) {
|
constructor(context: Context) : super(context) {
|
||||||
init(context)
|
init(context)
|
||||||
|
@ -53,15 +54,18 @@ class ConferenceCallView : LinearLayout {
|
||||||
|
|
||||||
fun init(context: Context) {
|
fun init(context: Context) {
|
||||||
binding = DataBindingUtil.inflate(
|
binding = DataBindingUtil.inflate(
|
||||||
LayoutInflater.from(context), R.layout.call_conference, this, true
|
LayoutInflater.from(context), R.layout.call_conference_participant, this, true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setViewModel(viewModel: CallViewModel) {
|
fun setViewModel(viewModel: ConferenceParticipantViewModel) {
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
binding.callTimer.base =
|
val currentTimeSecs = System.currentTimeMillis()
|
||||||
SystemClock.elapsedRealtime() - (1000 * viewModel.call.duration) // Linphone timestamps are in seconds
|
val participantTime = viewModel.participant.creationTime * 1000 // Linphone timestamps are in seconds
|
||||||
|
val diff = currentTimeSecs - participantTime
|
||||||
|
Log.i("[Conference Participant] Participant joined conference at $participantTime == ${diff / 1000} seconds ago.")
|
||||||
|
binding.callTimer.base = SystemClock.elapsedRealtime() - diff
|
||||||
binding.callTimer.start()
|
binding.callTimer.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -506,7 +506,7 @@ class CoreContext(val context: Context, coreConfig: Config) {
|
||||||
fun isVideoCallOrConferenceActive(): Boolean {
|
fun isVideoCallOrConferenceActive(): Boolean {
|
||||||
val conference = core.conference
|
val conference = core.conference
|
||||||
return if (conference != null && core.isInConference) {
|
return if (conference != null && core.isInConference) {
|
||||||
conference.currentParams.videoEnabled()
|
conference.currentParams.isVideoEnabled()
|
||||||
} else {
|
} else {
|
||||||
core.currentCall?.currentParams?.videoEnabled() ?: false
|
core.currentCall?.currentParams?.videoEnabled() ?: false
|
||||||
}
|
}
|
||||||
|
|
7
app/src/main/res/drawable/conference.xml
Normal file
7
app/src/main/res/drawable/conference.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<bitmap android:src="@drawable/options_start_conference_default"
|
||||||
|
android:tint="?attr/drawableTintColor2"/>
|
||||||
|
</item>
|
||||||
|
</selector>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<bitmap android:src="@drawable/conference_exit_default"
|
||||||
|
android:tint="?attr/drawableTintColor"/>
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
<variable
|
<variable
|
||||||
name="controlsViewModel"
|
name="controlsViewModel"
|
||||||
type="org.linphone.activities.call.viewmodels.ControlsViewModel" />
|
type="org.linphone.activities.call.viewmodels.ControlsViewModel" />
|
||||||
|
<variable
|
||||||
|
name="conferenceViewModel"
|
||||||
|
type="org.linphone.activities.call.viewmodels.ConferenceViewModel" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
@ -26,7 +29,7 @@
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/active_call_header"
|
android:id="@+id/active_call_header"
|
||||||
android:visibility="@{viewModel.currentCallViewModel == null ? View.GONE : View.VISIBLE}"
|
android:visibility="@{viewModel.currentCallViewModel == null || conferenceViewModel.isInConference() ? View.GONE : View.VISIBLE}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
|
@ -54,75 +57,16 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/call_conference"
|
||||||
android:visibility="@{viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused ? View.GONE : View.VISIBLE, default=gone}"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:layout_centerHorizontal="true"
|
android:layout_centerHorizontal="true"
|
||||||
android:background="?attr/backgroundColor"
|
app:controlsViewModel="@{controlsViewModel}"
|
||||||
android:orientation="vertical">
|
app:conferenceViewModel="@{conferenceViewModel}" />
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:paddingLeft="10dp"
|
|
||||||
android:textColor="?attr/primaryTextColor"
|
|
||||||
android:textSize="30sp"
|
|
||||||
android:text="@string/call_conference_title" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:onClick="@{() -> controlsViewModel.switchCamera()}"
|
|
||||||
android:visibility="@{controlsViewModel.isVideoEnabled ? View.VISIBLE : View.GONE, default=gone}"
|
|
||||||
android:contentDescription="@string/content_description_switch_camera"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_toLeftOf="@id/pause_conference"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:background="@drawable/round_button_background"
|
|
||||||
android:src="@drawable/camera_switch" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/pause_conference"
|
|
||||||
android:onClick="@{() -> viewModel.pauseConference()}"
|
|
||||||
android:contentDescription="@string/content_description_pause_conference"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_marginRight="10dp"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:background="@drawable/round_button_background"
|
|
||||||
android:src="@drawable/call_pause" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?attr/dividerColor" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="top"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:entries="@{viewModel.conferenceCalls}"
|
|
||||||
app:layout="@{@layout/call_conference_cell}"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<org.linphone.contact.BigContactAvatarView
|
<org.linphone.contact.BigContactAvatarView
|
||||||
android:visibility="@{controlsViewModel.isVideoEnabled ? View.GONE : View.VISIBLE, default=gone}"
|
android:visibility="@{controlsViewModel.isVideoEnabled || conferenceViewModel.isInConference ? View.GONE : View.VISIBLE, default=gone}"
|
||||||
android:id="@+id/avatar"
|
android:id="@+id/avatar"
|
||||||
android:layout_width="200dp"
|
android:layout_width="200dp"
|
||||||
android:layout_height="200dp"
|
android:layout_height="200dp"
|
||||||
|
@ -169,51 +113,15 @@
|
||||||
app:entries="@{viewModel.pausedCalls}"
|
app:entries="@{viewModel.pausedCalls}"
|
||||||
app:layout="@{@layout/call_paused_cell}" />
|
app:layout="@{@layout/call_paused_cell}" />
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/conference_paused"
|
||||||
android:visibility="@{viewModel.isConferencePaused && viewModel.conferenceCalls.size() > 1 ? View.VISIBLE : View.GONE, default=gone}"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:layout_above="@id/paused_calls"
|
android:layout_above="@id/paused_calls"
|
||||||
android:alpha="0.5"
|
app:conferenceViewModel="@{conferenceViewModel}" />
|
||||||
android:background="?attr/accentColor"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="5dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:contentDescription="@string/content_description_start_conference"
|
|
||||||
android:src="@drawable/options_start_conference" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="0dip"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:gravity="center_vertical|left"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:paddingLeft="20dp"
|
|
||||||
android:paddingRight="10dp"
|
|
||||||
android:textColor="?attr/secondaryTextColor"
|
|
||||||
android:textSize="15sp"
|
|
||||||
android:text="@string/call_conference_title" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:onClick="@{() -> viewModel.resumeConference()}"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:contentDescription="@string/content_description_resume_conference"
|
|
||||||
android:background="@drawable/round_button_background"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:src="@drawable/call_pause" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:onClick="@{() -> viewModel.currentCallViewModel.pause()}"
|
android:onClick="@{() -> viewModel.currentCallViewModel.pause()}"
|
||||||
android:visibility="@{viewModel.currentCallViewModel == null ? View.GONE : View.VISIBLE}"
|
android:visibility="@{viewModel.currentCallViewModel == null || conferenceViewModel.isInConference ? View.GONE : View.VISIBLE}"
|
||||||
android:selected="@{viewModel.currentCallViewModel.isPaused ?? false}"
|
android:selected="@{viewModel.currentCallViewModel.isPaused ?? false}"
|
||||||
android:enabled="@{!viewModel.callPausedByRemote && controlsViewModel.isPauseEnabled}"
|
android:enabled="@{!viewModel.callPausedByRemote && controlsViewModel.isPauseEnabled}"
|
||||||
android:contentDescription="@string/content_description_pause_call"
|
android:contentDescription="@string/content_description_pause_call"
|
||||||
|
@ -230,7 +138,7 @@
|
||||||
android:id="@+id/switch_camera"
|
android:id="@+id/switch_camera"
|
||||||
android:onClick="@{() -> controlsViewModel.switchCamera()}"
|
android:onClick="@{() -> controlsViewModel.switchCamera()}"
|
||||||
android:enabled="@{!viewModel.callPausedByRemote}"
|
android:enabled="@{!viewModel.callPausedByRemote}"
|
||||||
android:visibility="@{controlsViewModel.isVideoEnabled && controlsViewModel.showSwitchCamera && (viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused) ? View.VISIBLE : View.GONE, default=gone}"
|
android:visibility="@{controlsViewModel.isVideoEnabled && controlsViewModel.showSwitchCamera && !conferenceViewModel.isInConference ? View.VISIBLE : View.GONE, default=gone}"
|
||||||
android:contentDescription="@string/content_description_switch_camera"
|
android:contentDescription="@string/content_description_switch_camera"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
|
@ -244,7 +152,7 @@
|
||||||
<ImageView
|
<ImageView
|
||||||
android:onClick="@{() -> viewModel.takeScreenshot()}"
|
android:onClick="@{() -> viewModel.takeScreenshot()}"
|
||||||
android:enabled="@{!viewModel.callPausedByRemote}"
|
android:enabled="@{!viewModel.callPausedByRemote}"
|
||||||
android:visibility="@{controlsViewModel.isVideoEnabled && controlsViewModel.takeScreenshotEnabled && (viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused) ? View.VISIBLE : View.GONE, default=gone}"
|
android:visibility="@{controlsViewModel.isVideoEnabled && controlsViewModel.takeScreenshotEnabled && !conferenceViewModel.isInConference ? View.VISIBLE : View.GONE, default=gone}"
|
||||||
android:contentDescription="@string/content_description_take_screenshot"
|
android:contentDescription="@string/content_description_take_screenshot"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
|
|
|
@ -1,79 +1,89 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
<layout xmlns:tools="http://schemas.android.com/tools"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
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" />
|
||||||
<variable
|
<variable
|
||||||
name="viewModel"
|
name="controlsViewModel"
|
||||||
type="org.linphone.activities.call.viewmodels.CallViewModel" />
|
type="org.linphone.activities.call.viewmodels.ControlsViewModel" />
|
||||||
|
<variable
|
||||||
|
name="conferenceViewModel"
|
||||||
|
type="org.linphone.activities.call.viewmodels.ConferenceViewModel" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:visibility="@{!conferenceViewModel.isInConference || conferenceViewModel.isConferencePaused ? View.GONE : View.VISIBLE}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="70dp"
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/backgroundColor"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="60dp">
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_margin="10dp">
|
|
||||||
|
|
||||||
<org.linphone.contact.ContactAvatarView
|
<TextView
|
||||||
android:id="@+id/avatar"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:layout_centerVertical="true"
|
||||||
app:viewModel="@{viewModel}"
|
android:paddingLeft="10dp"
|
||||||
tools:layout="@layout/contact_avatar" />
|
android:textColor="?attr/primaryTextColor"
|
||||||
|
android:textSize="30sp"
|
||||||
<LinearLayout
|
android:text="@string/call_conference_title" />
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:paddingLeft="5dp"
|
|
||||||
android:paddingRight="10dp"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<org.linphone.views.MarqueeTextView
|
|
||||||
android:text="@{viewModel.contact.fullName ?? viewModel.displayName}"
|
|
||||||
style="@style/contact_name_list_cell_font"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center_vertical|left"
|
|
||||||
android:singleLine="true"/>
|
|
||||||
|
|
||||||
<Chronometer
|
|
||||||
android:id="@+id/call_timer"
|
|
||||||
android:textColor="?attr/accentColor"
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center_vertical|right" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:onClick="@{() -> viewModel.removeFromConference()}"
|
android:onClick="@{() -> controlsViewModel.switchCamera()}"
|
||||||
android:contentDescription="@string/content_description_remove_from_conference"
|
android:visibility="@{controlsViewModel.isVideoEnabled ? View.VISIBLE : View.GONE}"
|
||||||
android:layout_width="30dp"
|
android:contentDescription="@string/content_description_switch_camera"
|
||||||
android:layout_height="30dp"
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
android:layout_marginRight="10dp"
|
android:layout_marginRight="10dp"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_toLeftOf="@id/pause_conference"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:gravity="center_vertical"
|
android:padding="10dp"
|
||||||
android:src="@drawable/conference_exit_default" />
|
android:scaleType="fitCenter"
|
||||||
|
android:background="@drawable/round_button_background"
|
||||||
|
android:src="@drawable/camera_switch" />
|
||||||
|
|
||||||
</LinearLayout>
|
<ImageView
|
||||||
|
android:id="@+id/pause_conference"
|
||||||
|
android:onClick="@{() -> conferenceViewModel.pauseConference()}"
|
||||||
|
android:contentDescription="@string/content_description_pause_conference"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:background="@drawable/round_button_background"
|
||||||
|
android:src="@drawable/call_pause" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:background="?attr/dividerColor" />
|
android:background="?attr/dividerColor" />
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="top">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:entries="@{conferenceViewModel.conferenceParticipants}"
|
||||||
|
app:layout="@{@layout/call_conference_cell}"/>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
|
@ -5,10 +5,10 @@
|
||||||
<data>
|
<data>
|
||||||
<variable
|
<variable
|
||||||
name="data"
|
name="data"
|
||||||
type="org.linphone.activities.call.viewmodels.CallViewModel" />
|
type="org.linphone.activities.call.viewmodels.ConferenceParticipantViewModel" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<org.linphone.activities.call.views.ConferenceCallView
|
<org.linphone.activities.call.views.ConferenceParticipantView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
bind:viewModel="@{data}"/>
|
bind:viewModel="@{data}"/>
|
||||||
|
|
80
app/src/main/res/layout/call_conference_participant.xml
Normal file
80
app/src/main/res/layout/call_conference_participant.xml
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<import type="android.view.View" />
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="org.linphone.activities.call.viewmodels.ConferenceParticipantViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_margin="10dp">
|
||||||
|
|
||||||
|
<org.linphone.contact.ContactAvatarView
|
||||||
|
android:id="@+id/avatar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
app:viewModel="@{viewModel}"
|
||||||
|
tools:layout="@layout/contact_avatar" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:paddingLeft="5dp"
|
||||||
|
android:paddingRight="10dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<org.linphone.views.MarqueeTextView
|
||||||
|
android:text="@{viewModel.contact.fullName ?? viewModel.displayName}"
|
||||||
|
style="@style/contact_name_list_cell_font"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical|left"
|
||||||
|
android:singleLine="true"/>
|
||||||
|
|
||||||
|
<Chronometer
|
||||||
|
android:id="@+id/call_timer"
|
||||||
|
android:textColor="?attr/accentColor"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical|right" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:onClick="@{() -> viewModel.removeFromConference()}"
|
||||||
|
android:visibility="@{viewModel.isMeAdmin ? View.VISIBLE : View.GONE, default=gone}"
|
||||||
|
android:contentDescription="@string/content_description_remove_from_conference"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:src="@drawable/conference_remove_participant" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?attr/dividerColor" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</layout>
|
|
@ -11,6 +11,9 @@
|
||||||
<variable
|
<variable
|
||||||
name="controlsViewModel"
|
name="controlsViewModel"
|
||||||
type="org.linphone.activities.call.viewmodels.ControlsViewModel" />
|
type="org.linphone.activities.call.viewmodels.ControlsViewModel" />
|
||||||
|
<variable
|
||||||
|
name="conferenceViewModel"
|
||||||
|
type="org.linphone.activities.call.viewmodels.ConferenceViewModel" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
@ -25,7 +28,7 @@
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/active_call_header"
|
android:id="@+id/active_call_header"
|
||||||
android:visibility="@{viewModel.currentCallViewModel == null ? View.GONE : View.VISIBLE}"
|
android:visibility="@{viewModel.currentCallViewModel == null || conferenceViewModel.isInConference() ? View.GONE : View.VISIBLE}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
|
@ -53,75 +56,16 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/call_conference"
|
||||||
android:visibility="@{viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused ? View.GONE : View.VISIBLE, default=gone}"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:layout_centerHorizontal="true"
|
android:layout_centerHorizontal="true"
|
||||||
android:background="?attr/backgroundColor"
|
app:controlsViewModel="@{controlsViewModel}"
|
||||||
android:orientation="vertical">
|
app:conferenceViewModel="@{conferenceViewModel}" />
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="60dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:paddingLeft="10dp"
|
|
||||||
android:textColor="?attr/primaryTextColor"
|
|
||||||
android:textSize="30sp"
|
|
||||||
android:text="@string/call_conference_title" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:onClick="@{() -> controlsViewModel.switchCamera()}"
|
|
||||||
android:visibility="@{controlsViewModel.isVideoEnabled ? View.VISIBLE : View.GONE, default=gone}"
|
|
||||||
android:contentDescription="@string/content_description_switch_camera"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_toLeftOf="@id/pause_conference"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:background="@drawable/round_button_background"
|
|
||||||
android:src="@drawable/camera_switch" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/pause_conference"
|
|
||||||
android:onClick="@{() -> viewModel.pauseConference()}"
|
|
||||||
android:contentDescription="@string/content_description_pause_conference"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_marginRight="10dp"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:background="@drawable/round_button_background"
|
|
||||||
android:src="@drawable/call_pause" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?attr/dividerColor" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="top"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:entries="@{viewModel.conferenceCalls}"
|
|
||||||
app:layout="@{@layout/call_conference_cell}"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<org.linphone.contact.BigContactAvatarView
|
<org.linphone.contact.BigContactAvatarView
|
||||||
android:visibility="@{controlsViewModel.isVideoEnabled ? View.GONE : View.VISIBLE, default=gone}"
|
android:visibility="@{controlsViewModel.isVideoEnabled || conferenceViewModel.isInConference ? View.GONE : View.VISIBLE, default=gone}"
|
||||||
android:id="@+id/avatar"
|
android:id="@+id/avatar"
|
||||||
android:layout_width="200dp"
|
android:layout_width="200dp"
|
||||||
android:layout_height="200dp"
|
android:layout_height="200dp"
|
||||||
|
@ -148,7 +92,7 @@
|
||||||
android:src="@drawable/waiting_time" />
|
android:src="@drawable/waiting_time" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:textColor="?attr/secondaryTextColor"
|
android:textColor="@color/white_color"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -169,51 +113,15 @@
|
||||||
app:entries="@{viewModel.pausedCalls}"
|
app:entries="@{viewModel.pausedCalls}"
|
||||||
app:layout="@{@layout/call_paused_cell}" />
|
app:layout="@{@layout/call_paused_cell}" />
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/conference_paused"
|
||||||
android:visibility="@{viewModel.isConferencePaused && viewModel.conferenceCalls.size() > 1 ? View.VISIBLE : View.GONE, default=gone}"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:layout_above="@id/paused_calls"
|
android:layout_above="@id/paused_calls"
|
||||||
android:alpha="0.5"
|
app:conferenceViewModel="@{conferenceViewModel}" />
|
||||||
android:background="?attr/accentColor"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="5dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:contentDescription="@string/content_description_start_conference"
|
|
||||||
android:src="@drawable/options_start_conference" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="0dip"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:gravity="center_vertical|left"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:paddingLeft="20dp"
|
|
||||||
android:paddingRight="10dp"
|
|
||||||
android:textColor="?attr/secondaryTextColor"
|
|
||||||
android:textSize="15sp"
|
|
||||||
android:text="@string/call_conference_title" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:onClick="@{() -> viewModel.resumeConference()}"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:contentDescription="@string/content_description_resume_conference"
|
|
||||||
android:background="@drawable/round_button_background"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:src="@drawable/call_pause" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:onClick="@{() -> viewModel.currentCallViewModel.pause()}"
|
android:onClick="@{() -> viewModel.currentCallViewModel.pause()}"
|
||||||
android:visibility="@{viewModel.currentCallViewModel == null ? View.GONE : View.VISIBLE}"
|
android:visibility="@{viewModel.currentCallViewModel == null || conferenceViewModel.isInConference ? View.GONE : View.VISIBLE}"
|
||||||
android:selected="@{viewModel.currentCallViewModel.isPaused ?? false}"
|
android:selected="@{viewModel.currentCallViewModel.isPaused ?? false}"
|
||||||
android:enabled="@{!viewModel.callPausedByRemote && controlsViewModel.isPauseEnabled}"
|
android:enabled="@{!viewModel.callPausedByRemote && controlsViewModel.isPauseEnabled}"
|
||||||
android:contentDescription="@string/content_description_pause_call"
|
android:contentDescription="@string/content_description_pause_call"
|
||||||
|
@ -230,7 +138,7 @@
|
||||||
android:id="@+id/switch_camera"
|
android:id="@+id/switch_camera"
|
||||||
android:onClick="@{() -> controlsViewModel.switchCamera()}"
|
android:onClick="@{() -> controlsViewModel.switchCamera()}"
|
||||||
android:enabled="@{!viewModel.callPausedByRemote}"
|
android:enabled="@{!viewModel.callPausedByRemote}"
|
||||||
android:visibility="@{controlsViewModel.isVideoEnabled && controlsViewModel.showSwitchCamera && (viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused) ? View.VISIBLE : View.GONE, default=gone}"
|
android:visibility="@{controlsViewModel.isVideoEnabled && controlsViewModel.showSwitchCamera && !conferenceViewModel.isInConference ? View.VISIBLE : View.GONE, default=gone}"
|
||||||
android:contentDescription="@string/content_description_switch_camera"
|
android:contentDescription="@string/content_description_switch_camera"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
|
@ -244,7 +152,7 @@
|
||||||
<ImageView
|
<ImageView
|
||||||
android:onClick="@{() -> viewModel.takeScreenshot()}"
|
android:onClick="@{() -> viewModel.takeScreenshot()}"
|
||||||
android:enabled="@{!viewModel.callPausedByRemote}"
|
android:enabled="@{!viewModel.callPausedByRemote}"
|
||||||
android:visibility="@{controlsViewModel.isVideoEnabled && controlsViewModel.takeScreenshotEnabled && (viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused) ? View.VISIBLE : View.GONE, default=gone}"
|
android:visibility="@{controlsViewModel.isVideoEnabled && controlsViewModel.takeScreenshotEnabled && !conferenceViewModel.isInConference ? View.VISIBLE : View.GONE, default=gone}"
|
||||||
android:contentDescription="@string/content_description_take_screenshot"
|
android:contentDescription="@string/content_description_take_screenshot"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
|
|
54
app/src/main/res/layout/conference_paused.xml
Normal file
54
app/src/main/res/layout/conference_paused.xml
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<import type="android.view.View" />
|
||||||
|
<variable
|
||||||
|
name="conferenceViewModel"
|
||||||
|
type="org.linphone.activities.call.viewmodels.ConferenceViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:visibility="@{conferenceViewModel.isConferencePaused && conferenceViewModel.isInConference ? View.VISIBLE : View.GONE}"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:alpha="0.5"
|
||||||
|
android:background="?attr/accentColor"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="5dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:contentDescription="@string/content_description_start_conference"
|
||||||
|
android:src="@drawable/conference" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_vertical|left"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:paddingLeft="10dp"
|
||||||
|
android:paddingRight="10dp"
|
||||||
|
android:textColor="?attr/secondaryTextColor"
|
||||||
|
android:textSize="21sp"
|
||||||
|
android:text="@string/call_conference_title" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:onClick="@{() -> conferenceViewModel.resumeConference()}"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:contentDescription="@string/content_description_resume_conference"
|
||||||
|
android:background="@drawable/round_button_background"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:src="@drawable/call_pause" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</layout>
|
Loading…
Reference in a new issue