Added back disable chat feature in corePreferences

This commit is contained in:
Sylvain Berfini 2020-11-03 11:22:07 +01:00
parent a4e3abd4c4
commit 3b24fcd097
17 changed files with 184 additions and 150 deletions

View file

@ -85,6 +85,8 @@ class ControlsViewModel : ViewModel() {
val somethingClickedEvent = MutableLiveData<Event<Boolean>>() val somethingClickedEvent = MutableLiveData<Event<Boolean>>()
val chatAllowed = !LinphoneApplication.corePreferences.disableChat
private val vibrator = coreContext.context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator private val vibrator = coreContext.context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
val onKeyClick: NumpadDigitListener = object : NumpadDigitListener { val onKeyClick: NumpadDigitListener = object : NumpadDigitListener {

View file

@ -220,6 +220,8 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
findNavController(R.id.nav_host_fragment).navigate(Uri.parse(deepLink)) findNavController(R.id.nav_host_fragment).navigate(Uri.parse(deepLink))
} }
intent.hasExtra("Chat") -> { intent.hasExtra("Chat") -> {
if (corePreferences.disableChat) return
val deepLink = if (intent.hasExtra("RemoteSipUri") && intent.hasExtra("LocalSipUri")) { val deepLink = if (intent.hasExtra("RemoteSipUri") && intent.hasExtra("LocalSipUri")) {
val peerAddress = intent.getStringExtra("RemoteSipUri") val peerAddress = intent.getStringExtra("RemoteSipUri")
val localAddress = intent.getStringExtra("LocalSipUri") val localAddress = intent.getStringExtra("LocalSipUri")
@ -262,6 +264,8 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
} }
private fun handleSendText(intent: Intent) { private fun handleSendText(intent: Intent) {
if (corePreferences.disableChat) return
intent.getStringExtra(Intent.EXTRA_TEXT)?.let { intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
sharedViewModel.textToShare.value = it sharedViewModel.textToShare.value = it
} }
@ -270,6 +274,8 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
} }
private suspend fun handleSendFile(intent: Intent) { private suspend fun handleSendFile(intent: Intent) {
if (corePreferences.disableChat) return
(intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM) as? Uri)?.let { (intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM) as? Uri)?.let {
val list = arrayListOf<String>() val list = arrayListOf<String>()
coroutineScope { coroutineScope {
@ -289,6 +295,8 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
} }
private suspend fun handleSendMultipleFiles(intent: Intent) { private suspend fun handleSendMultipleFiles(intent: Intent) {
if (corePreferences.disableChat) return
intent.getParcelableArrayListExtra<Parcelable>(Intent.EXTRA_STREAM)?.let { intent.getParcelableArrayListExtra<Parcelable>(Intent.EXTRA_STREAM)?.let {
val list = arrayListOf<String>() val list = arrayListOf<String>()
coroutineScope { coroutineScope {
@ -310,6 +318,8 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
} }
private fun handleSendChatRoom(intent: Intent) { private fun handleSendChatRoom(intent: Intent) {
if (corePreferences.disableChat) return
val uri = intent.data val uri = intent.data
if (uri != null) { if (uri != null) {
Log.i("[Main Activity] Found uri: $uri to send a message to") Log.i("[Main Activity] Found uri: $uri to send a message to")

View file

@ -20,6 +20,7 @@
package org.linphone.activities.main.contact.viewmodels package org.linphone.activities.main.contact.viewmodels
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.core.Address import org.linphone.core.Address
class ContactNumberOrAddressViewModel( class ContactNumberOrAddressViewModel(
@ -32,6 +33,8 @@ class ContactNumberOrAddressViewModel(
) : ViewModel() { ) : ViewModel() {
val showInvite = !hasPresence && !isSip val showInvite = !hasPresence && !isSip
val chatAllowed = !corePreferences.disableChat
fun startCall() { fun startCall() {
address ?: return address ?: return
listener.onCall(address) listener.onCall(address)

View file

@ -25,6 +25,7 @@ import androidx.lifecycle.ViewModelProvider
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R import org.linphone.R
import org.linphone.contact.GenericContactViewModel import org.linphone.contact.GenericContactViewModel
import org.linphone.core.* import org.linphone.core.*
@ -105,6 +106,8 @@ class CallLogViewModel(val callLog: CallLog) : GenericContactViewModel(callLog.r
val waitForChatRoomCreation = MutableLiveData<Boolean>() val waitForChatRoomCreation = MutableLiveData<Boolean>()
val chatAllowed = !corePreferences.disableChat
val secureChatAllowed = contact.value?.friend?.getPresenceModelForUriOrTel(peerSipUri)?.hasCapability(FriendCapability.LimeX3Dh) ?: false val secureChatAllowed = contact.value?.friend?.getPresenceModelForUriOrTel(peerSipUri)?.hasCapability(FriendCapability.LimeX3Dh) ?: false
val relatedCallLogs = MutableLiveData<ArrayList<CallLog>>() val relatedCallLogs = MutableLiveData<ArrayList<CallLog>>()

View file

@ -22,12 +22,17 @@ package org.linphone.activities.main.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.LinphoneApplication.Companion.corePreferences
import org.linphone.core.* import org.linphone.core.*
class TabsViewModel : ViewModel() { class TabsViewModel : ViewModel() {
val unreadMessagesCount = MutableLiveData<Int>() val unreadMessagesCount = MutableLiveData<Int>()
val missedCallsCount = MutableLiveData<Int>() val missedCallsCount = MutableLiveData<Int>()
val leftAnchor = MutableLiveData<Float>()
val middleAnchor = MutableLiveData<Float>()
val rightAnchor = MutableLiveData<Float>()
private val listener: CoreListenerStub = object : CoreListenerStub() { private val listener: CoreListenerStub = object : CoreListenerStub() {
override fun onCallStateChanged( override fun onCallStateChanged(
core: Core, core: Core,
@ -58,6 +63,16 @@ class TabsViewModel : ViewModel() {
init { init {
coreContext.core.addListener(listener) coreContext.core.addListener(listener)
if (corePreferences.disableChat) {
leftAnchor.value = 1 / 3F
middleAnchor.value = 2 / 3F
rightAnchor.value = 1F
} else {
leftAnchor.value = 0.25F
middleAnchor.value = 0.5F
rightAnchor.value = 0.75F
}
updateUnreadChatCount() updateUnreadChatCount()
updateMissedCallCount() updateMissedCallCount()
} }
@ -72,6 +87,6 @@ class TabsViewModel : ViewModel() {
} }
fun updateUnreadChatCount() { fun updateUnreadChatCount() {
unreadMessagesCount.value = coreContext.core.unreadChatMessageCountFromActiveLocals unreadMessagesCount.value = if (corePreferences.disableChat) 0 else coreContext.core.unreadChatMessageCountFromActiveLocals
} }
} }

View file

@ -311,6 +311,10 @@ class CorePreferences constructor(private val context: Context) {
val dtmfKeypadVibration: Boolean val dtmfKeypadVibration: Boolean
get() = config.getBool("app", "dtmf_keypad_vibraton", false) get() = config.getBool("app", "dtmf_keypad_vibraton", false)
// Will disable chat feature completely
val disableChat: Boolean
get() = config.getBool("app", "disable_chat_feature", false)
/* Assistant */ /* Assistant */
val showCreateAccount: Boolean val showCreateAccount: Boolean

View file

@ -132,7 +132,7 @@ class NotificationsManager(private val context: Context) {
} }
override fun onMessageReceived(core: Core, room: ChatRoom, message: ChatMessage) { override fun onMessageReceived(core: Core, room: ChatRoom, message: ChatMessage) {
if (message.isOutgoing) return if (message.isOutgoing || corePreferences.disableChat) return
if (currentlyDisplayedChatRoomAddress == room.peerAddress.asStringUriOnly()) { if (currentlyDisplayedChatRoomAddress == room.peerAddress.asStringUriOnly()) {
Log.i("[Notifications Manager] Chat room is currently displayed, do not notify received message") Log.i("[Notifications Manager] Chat room is currently displayed, do not notify received message")

View file

@ -32,6 +32,8 @@ import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.* import android.widget.*
import android.widget.SeekBar.OnSeekBarChangeListener import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.Guideline
import androidx.databinding.* import androidx.databinding.*
import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.load.engine.GlideException
@ -135,6 +137,13 @@ fun setLayoutToLeftOf(view: View, oldTargetId: Int, newTargetId: Int) {
view.layoutParams = layoutParams view.layoutParams = layoutParams
} }
@BindingAdapter("layout_constraintGuide_percent")
fun setLayoutConstraintGuidePercent(guideline: Guideline, percent: Float) {
val params = guideline.layoutParams as ConstraintLayout.LayoutParams
params.guidePercent = percent
guideline.layoutParams = params
}
@BindingAdapter("onClickToggleSwitch") @BindingAdapter("onClickToggleSwitch")
fun switchSetting(view: View, switchId: Int) { fun switchSetting(view: View, switchId: Int) {
val switch: SwitchMaterial = view.findViewById(switchId) val switch: SwitchMaterial = view.findViewById(switchId)
@ -162,9 +171,9 @@ fun editTextSetting(view: EditText, lambda: () -> Unit) {
} }
} }
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
}) })
} }
@ -195,9 +204,9 @@ fun setListener(view: SeekBar, lambda: (Any) -> Unit) {
if (fromUser) lambda(progress) if (fromUser) lambda(progress)
} }
override fun onStartTrackingTouch(seekBar: SeekBar?) { } override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) { } override fun onStopTrackingTouch(seekBar: SeekBar?) {}
}) })
} }
@ -226,7 +235,12 @@ private fun <T> setEntries(
val inflater = viewGroup.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater val inflater = viewGroup.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
for (i in entries.indices) { for (i in entries.indices) {
val entry = entries[i] val entry = entries[i]
val binding = DataBindingUtil.inflate<ViewDataBinding>(inflater, layoutId, viewGroup, false) val binding = DataBindingUtil.inflate<ViewDataBinding>(
inflater,
layoutId,
viewGroup,
false
)
binding.setVariable(BR.data, entry) binding.setVariable(BR.data, entry)
binding.setVariable(BR.longClickListener, onLongClick) binding.setVariable(BR.longClickListener, onLongClick)
binding.setVariable(BR.parent, parent) binding.setVariable(BR.parent, parent)
@ -271,7 +285,9 @@ fun <T> setEntries(
@BindingAdapter("glideAvatarFallback") @BindingAdapter("glideAvatarFallback")
fun loadAvatarWithGlideFallback(imageView: ImageView, path: String?) { fun loadAvatarWithGlideFallback(imageView: ImageView, path: String?) {
if (path != null && path.isNotEmpty() && FileUtils.isExtensionImage(path)) { if (path != null && path.isNotEmpty() && FileUtils.isExtensionImage(path)) {
GlideApp.with(imageView).load(path).apply(RequestOptions.circleCropTransform()).into(imageView) GlideApp.with(imageView).load(path).apply(RequestOptions.circleCropTransform()).into(
imageView
)
} else { } else {
Log.w("[Data Binding] [Glide] Can't load $path") Log.w("[Data Binding] [Glide] Can't load $path")
imageView.setImageResource(R.drawable.avatar) imageView.setImageResource(R.drawable.avatar)
@ -295,30 +311,31 @@ fun loadAvatarWithGlide(imageView: ImageView, path: Uri?) {
@BindingAdapter("glideAvatar") @BindingAdapter("glideAvatar")
fun loadAvatarWithGlide(imageView: ImageView, path: String?) { fun loadAvatarWithGlide(imageView: ImageView, path: String?) {
if (path != null) { if (path != null) {
GlideApp.with(imageView).load(path).apply(RequestOptions.circleCropTransform()).listener(object : GlideApp.with(imageView).load(path).apply(RequestOptions.circleCropTransform()).listener(
RequestListener<Drawable?> { object :
override fun onLoadFailed( RequestListener<Drawable?> {
e: GlideException?, override fun onLoadFailed(
model: Any?, e: GlideException?,
target: Target<Drawable?>?, model: Any?,
isFirstResource: Boolean target: Target<Drawable?>?,
): Boolean { isFirstResource: Boolean
Log.w("[Data Binding] [Glide] Can't load $path") ): Boolean {
imageView.visibility = View.GONE Log.w("[Data Binding] [Glide] Can't load $path")
return false imageView.visibility = View.GONE
} return false
}
override fun onResourceReady( override fun onResourceReady(
resource: Drawable?, resource: Drawable?,
model: Any?, model: Any?,
target: Target<Drawable?>?, target: Target<Drawable?>?,
dataSource: DataSource?, dataSource: DataSource?,
isFirstResource: Boolean isFirstResource: Boolean
): Boolean { ): Boolean {
imageView.visibility = View.VISIBLE imageView.visibility = View.VISIBLE
return false return false
} }
}).into(imageView) }).into(imageView)
} else { } else {
imageView.visibility = View.GONE imageView.visibility = View.GONE
} }
@ -341,13 +358,14 @@ fun addPhoneNumberEditTextValidation(editText: EditText, enabled: Boolean) {
override fun afterTextChanged(s: Editable?) { override fun afterTextChanged(s: Editable?) {
when { when {
s?.matches(Regex("\\d+")) == false -> s?.matches(Regex("\\d+")) == false ->
editText.error = editText.context.getString(R.string.assistant_error_phone_number_invalid_characters) editText.error =
editText.context.getString(R.string.assistant_error_phone_number_invalid_characters)
} }
} }
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
}) })
} }
@ -355,9 +373,9 @@ fun addPhoneNumberEditTextValidation(editText: EditText, enabled: Boolean) {
fun addPrefixEditTextValidation(editText: EditText, enabled: Boolean) { fun addPrefixEditTextValidation(editText: EditText, enabled: Boolean) {
if (!enabled) return if (!enabled) return
editText.addTextChangedListener(object : TextWatcher { editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) { } override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if (s == null || s.isEmpty() || !s.startsWith("+")) { if (s == null || s.isEmpty() || !s.startsWith("+")) {
@ -370,22 +388,28 @@ fun addPrefixEditTextValidation(editText: EditText, enabled: Boolean) {
@BindingAdapter("assistantUsernameValidation") @BindingAdapter("assistantUsernameValidation")
fun addUsernameEditTextValidation(editText: EditText, enabled: Boolean) { fun addUsernameEditTextValidation(editText: EditText, enabled: Boolean) {
if (!enabled) return if (!enabled) return
val usernameRegexp = corePreferences.config.getString("assistant", "username_regex", "^[a-z0-9+_.\\-]*\$")!! val usernameRegexp = corePreferences.config.getString(
"assistant",
"username_regex",
"^[a-z0-9+_.\\-]*\$"
)!!
val usernameMaxLength = corePreferences.config.getInt("assistant", "username_max_length", 64) val usernameMaxLength = corePreferences.config.getInt("assistant", "username_max_length", 64)
editText.addTextChangedListener(object : TextWatcher { editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) { override fun afterTextChanged(s: Editable?) {
when { when {
s?.matches(Regex(usernameRegexp)) == false -> s?.matches(Regex(usernameRegexp)) == false ->
editText.error = editText.context.getString(R.string.assistant_error_username_invalid_characters) editText.error =
editText.context.getString(R.string.assistant_error_username_invalid_characters)
s?.length ?: 0 > usernameMaxLength -> { s?.length ?: 0 > usernameMaxLength -> {
editText.error = editText.context.getString(R.string.assistant_error_username_too_long) editText.error =
editText.context.getString(R.string.assistant_error_username_too_long)
} }
} }
} }
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
}) })
} }
@ -393,13 +417,14 @@ fun addUsernameEditTextValidation(editText: EditText, enabled: Boolean) {
fun addEmailEditTextValidation(editText: EditText, enabled: Boolean) { fun addEmailEditTextValidation(editText: EditText, enabled: Boolean) {
if (!enabled) return if (!enabled) return
editText.addTextChangedListener(object : TextWatcher { editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) { } override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (!Patterns.EMAIL_ADDRESS.matcher(s).matches()) { if (!Patterns.EMAIL_ADDRESS.matcher(s).matches()) {
editText.error = editText.context.getString(R.string.assistant_error_invalid_email_address) editText.error =
editText.context.getString(R.string.assistant_error_invalid_email_address)
} }
} }
}) })
@ -409,13 +434,14 @@ fun addEmailEditTextValidation(editText: EditText, enabled: Boolean) {
fun addUrlEditTextValidation(editText: EditText, enabled: Boolean) { fun addUrlEditTextValidation(editText: EditText, enabled: Boolean) {
if (!enabled) return if (!enabled) return
editText.addTextChangedListener(object : TextWatcher { editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) { } override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (!Patterns.WEB_URL.matcher(s).matches()) { if (!Patterns.WEB_URL.matcher(s).matches()) {
editText.error = editText.context.getString(R.string.assistant_remote_provisioning_wrong_format) editText.error =
editText.context.getString(R.string.assistant_remote_provisioning_wrong_format)
} }
} }
}) })
@ -426,11 +452,12 @@ fun addPasswordConfirmationEditTextValidation(password: EditText, passwordConfir
password.addTextChangedListener(object : TextWatcher { password.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {} override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if (passwordConfirmation.text == null || s == null || passwordConfirmation.text.toString() != s.toString()) { if (passwordConfirmation.text == null || s == null || passwordConfirmation.text.toString() != s.toString()) {
passwordConfirmation.error = passwordConfirmation.context.getString(R.string.assistant_error_passwords_dont_match) passwordConfirmation.error =
passwordConfirmation.context.getString(R.string.assistant_error_passwords_dont_match)
} else { } else {
passwordConfirmation.error = null // To clear other edit text field error passwordConfirmation.error = null // To clear other edit text field error
} }
@ -440,11 +467,12 @@ fun addPasswordConfirmationEditTextValidation(password: EditText, passwordConfir
passwordConfirmation.addTextChangedListener(object : TextWatcher { passwordConfirmation.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {} override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if (password.text == null || s == null || password.text.toString() != s.toString()) { if (password.text == null || s == null || password.text.toString() != s.toString()) {
passwordConfirmation.error = passwordConfirmation.context.getString(R.string.assistant_error_passwords_dont_match) passwordConfirmation.error =
passwordConfirmation.context.getString(R.string.assistant_error_passwords_dont_match)
} }
} }
}) })
@ -474,7 +502,7 @@ fun setEditTextErrorListener(editText: EditText, attrChange: InverseBindingListe
attrChange.onChange() attrChange.onChange()
} }
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
}) })
} }

View file

@ -124,6 +124,7 @@
<ImageView <ImageView
android:onClick="@{() -> viewModel.startChat(false)}" android:onClick="@{() -> viewModel.startChat(false)}"
android:visibility="@{viewModel.chatAllowed ? View.VISIBLE : View.GONE}"
android:contentDescription="@string/content_description_start_chat" android:contentDescription="@string/content_description_start_chat"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="60dp"
@ -133,7 +134,7 @@
<RelativeLayout <RelativeLayout
android:onClick="@{() -> viewModel.startChat(true)}" android:onClick="@{() -> viewModel.startChat(true)}"
android:visibility="@{viewModel.secureChatAllowed ? View.VISIBLE : View.GONE}" android:visibility="@{viewModel.chatAllowed &amp;&amp; viewModel.secureChatAllowed ? View.VISIBLE : View.GONE}"
android:layout_width="65dp" android:layout_width="65dp"
android:layout_height="60dp" android:layout_height="60dp"
android:layout_margin="10dp"> android:layout_margin="10dp">

View file

@ -33,21 +33,21 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintGuide_percent="0.25" /> layout_constraintGuide_percent="@{viewModel.leftAnchor, default=0.25}" />
<androidx.constraintlayout.widget.Guideline <androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineMiddle" android:id="@+id/guidelineMiddle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" /> layout_constraintGuide_percent="@{viewModel.middleAnchor, default=0.5}" />
<androidx.constraintlayout.widget.Guideline <androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineBottom" android:id="@+id/guidelineBottom"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintGuide_percent="0.75" /> layout_constraintGuide_percent="@{viewModel.rightAnchor, default=0.75}" />
<ImageView <ImageView
android:id="@+id/history" android:id="@+id/history"
@ -143,10 +143,7 @@
android:id="@+id/selector" android:id="@+id/selector"
android:layout_width="@dimen/tabs_fragment_selector_size" android:layout_width="@dimen/tabs_fragment_selector_size"
android:layout_height="0dp" android:layout_height="0dp"
android:background="?attr/accentColor" android:background="?attr/accentColor" />
app:layout_constraintHeight_percent=".25"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="@id/guidelineBottom" />
</androidx.constraintlayout.motion.widget.MotionLayout> </androidx.constraintlayout.motion.widget.MotionLayout>

View file

@ -118,6 +118,7 @@
<ImageView <ImageView
android:onClick="@{() -> viewModel.startChat(false)}" android:onClick="@{() -> viewModel.startChat(false)}"
android:visibility="@{viewModel.chatAllowed ? View.VISIBLE : View.GONE}"
android:contentDescription="@string/content_description_start_chat" android:contentDescription="@string/content_description_start_chat"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="60dp"
@ -127,7 +128,7 @@
<RelativeLayout <RelativeLayout
android:onClick="@{() -> viewModel.startChat(true)}" android:onClick="@{() -> viewModel.startChat(true)}"
android:visibility="@{viewModel.secureChatAllowed ? View.VISIBLE : View.GONE}" android:visibility="@{viewModel.chatAllowed &amp;&amp; viewModel.secureChatAllowed ? View.VISIBLE : View.GONE}"
android:layout_width="65dp" android:layout_width="65dp"
android:layout_height="60dp" android:layout_height="60dp"
android:layout_margin="10dp"> android:layout_margin="10dp">

View file

@ -8,94 +8,65 @@
type="org.linphone.activities.call.viewmodels.ControlsViewModel" /> type="org.linphone.activities.call.viewmodels.ControlsViewModel" />
</data> </data>
<RelativeLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp"> android:layout_height="60dp"
android:orientation="horizontal">
<View <ImageView
android:id="@+id/vertical_divider" android:onClick="@{() -> viewModel.toggleNumpadVisibility()}"
android:selected="@{viewModel.numpadVisibility}"
android:contentDescription="@string/content_description_show_numpad"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:layout_centerHorizontal="true" /> android:layout_weight="0.25"
android:background="@drawable/button_background_dark"
android:padding="15dp"
android:src="@drawable/call_numpad" />
<ImageView <ImageView
android:onClick="@{() -> viewModel.terminateCall()}" android:onClick="@{() -> viewModel.terminateCall()}"
android:contentDescription="@string/content_description_terminate_call" android:contentDescription="@string/content_description_terminate_call"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0.5"
android:background="@drawable/call_hangup_background" android:background="@drawable/call_hangup_background"
android:padding="12dp" android:padding="12dp"
android:src="@drawable/call_hangup" /> android:src="@drawable/call_hangup" />
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:onClick="@{() -> viewModel.onChatClicked()}"
android:layout_height="match_parent" android:visibility="@{viewModel.chatAllowed ? View.VISIBLE : View.GONE}"
android:layout_toLeftOf="@id/vertical_divider"> android:layout_width="0dp"
android:layout_height="wrap_content"
<View android:layout_weight="0.25"
android:id="@+id/left_vertical_divider" android:background="@drawable/footer_button">
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"/>
<ImageView <ImageView
android:onClick="@{() -> viewModel.toggleNumpadVisibility()}"
android:selected="@{viewModel.numpadVisibility}"
android:contentDescription="@string/content_description_show_numpad"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_toLeftOf="@id/left_vertical_divider" android:layout_centerInParent="true"
android:background="@drawable/button_background_dark" android:background="@drawable/button_background_dark"
android:contentDescription="@string/content_description_go_to_chat"
android:padding="15dp" android:padding="15dp"
android:src="@drawable/call_numpad" /> android:src="@drawable/footer_chat" />
</RelativeLayout> <TextView
android:id="@+id/chat_unread_count"
<RelativeLayout android:text="@{String.valueOf(viewModel.unreadMessagesCount)}"
android:layout_width="match_parent" android:visibility="@{viewModel.unreadMessagesCount == 0 ? View.GONE : View.VISIBLE}"
android:layout_height="match_parent" style="@style/unread_count_font"
android:layout_toRightOf="@id/vertical_divider"> android:layout_width="wrap_content"
<View
android:id="@+id/right_vertical_divider"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"/>
<RelativeLayout
android:onClick="@{() -> viewModel.onChatClicked()}"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_toRightOf="@id/right_vertical_divider" android:layout_alignParentRight="true"
android:background="@drawable/footer_button"> android:layout_alignParentTop="true"
android:layout_marginRight="25dp"
<ImageView android:layout_marginTop="5dp"
android:layout_width="match_parent" android:background="@drawable/unread_message_count_bg"
android:layout_height="wrap_content" android:gravity="center" />
android:layout_centerInParent="true"
android:background="@drawable/button_background_dark"
android:contentDescription="@string/content_description_go_to_chat"
android:padding="15dp"
android:src="@drawable/footer_chat" />
<TextView
android:id="@+id/chat_unread_count"
android:text="@{String.valueOf(viewModel.unreadMessagesCount)}"
android:visibility="@{viewModel.unreadMessagesCount == 0 ? View.GONE : View.VISIBLE}"
style="@style/unread_count_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="25dp"
android:layout_marginTop="5dp"
android:background="@drawable/unread_message_count_bg"
android:gravity="center" />
</RelativeLayout>
</RelativeLayout> </RelativeLayout>
</RelativeLayout> </LinearLayout>
</layout> </layout>

View file

@ -91,6 +91,7 @@
<ImageView <ImageView
android:onClick="@{() -> data.startChat(false)}" android:onClick="@{() -> data.startChat(false)}"
android:enabled="@{data.address != null}" android:enabled="@{data.address != null}"
android:visibility="@{data.chatAllowed ? View.VISIBLE : View.GONE}"
android:contentDescription="@string/content_description_start_chat" android:contentDescription="@string/content_description_start_chat"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="60dp"
@ -99,9 +100,9 @@
android:src="@drawable/chat_start_default" /> android:src="@drawable/chat_start_default" />
<RelativeLayout <RelativeLayout
android:visibility="@{data.showSecureChat ? View.VISIBLE : View.GONE}"
android:enabled="@{data.address != null}"
android:onClick="@{() -> data.startChat(true)}" android:onClick="@{() -> data.startChat(true)}"
android:enabled="@{data.address != null}"
android:visibility="@{data.chatAllowed &amp;&amp; data.showSecureChat ? View.VISIBLE : View.GONE}"
android:layout_width="65dp" android:layout_width="65dp"
android:layout_height="60dp" android:layout_height="60dp"
android:layout_margin="10dp"> android:layout_margin="10dp">

View file

@ -118,6 +118,7 @@
<ImageView <ImageView
android:onClick="@{() -> viewModel.startChat(false)}" android:onClick="@{() -> viewModel.startChat(false)}"
android:visibility="@{viewModel.chatAllowed ? View.VISIBLE : View.GONE}"
android:contentDescription="@string/content_description_start_chat" android:contentDescription="@string/content_description_start_chat"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="60dp"
@ -127,7 +128,7 @@
<RelativeLayout <RelativeLayout
android:onClick="@{() -> viewModel.startChat(true)}" android:onClick="@{() -> viewModel.startChat(true)}"
android:visibility="@{viewModel.secureChatAllowed ? View.VISIBLE : View.GONE}" android:visibility="@{viewModel.chatAllowed &amp;&amp; viewModel.secureChatAllowed ? View.VISIBLE : View.GONE}"
android:layout_width="65dp" android:layout_width="65dp"
android:layout_height="60dp" android:layout_height="60dp"
android:layout_margin="10dp"> android:layout_margin="10dp">

View file

@ -33,21 +33,21 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintGuide_percent="0.25" /> layout_constraintGuide_percent="@{viewModel.leftAnchor, default=0.25}" />
<androidx.constraintlayout.widget.Guideline <androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineMiddle" android:id="@+id/guidelineMiddle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" /> layout_constraintGuide_percent="@{viewModel.middleAnchor, default=0.5}" />
<androidx.constraintlayout.widget.Guideline <androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineRight" android:id="@+id/guidelineRight"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintGuide_percent="0.75" /> layout_constraintGuide_percent="@{viewModel.rightAnchor, default=0.75}" />
<ImageView <ImageView
android:id="@+id/history" android:id="@+id/history"
@ -143,10 +143,7 @@
android:id="@+id/selector" android:id="@+id/selector"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="@dimen/tabs_fragment_selector_size" android:layout_height="@dimen/tabs_fragment_selector_size"
android:background="?attr/accentColor" android:background="?attr/accentColor" />
app:layout_constraintWidth_percent=".25"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="@id/guidelineMiddle" />
</androidx.constraintlayout.motion.widget.MotionLayout> </androidx.constraintlayout.motion.widget.MotionLayout>

View file

@ -31,9 +31,9 @@
<Constraint <Constraint
android:id="@id/selector" android:id="@id/selector"
android:layout_height="@dimen/tabs_fragment_selector_size" android:layout_height="@dimen/tabs_fragment_selector_size"
motion:layout_constraintWidth_percent=".25"
motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintLeft_toLeftOf="parent" /> motion:layout_constraintLeft_toLeftOf="parent"
motion:layout_constraintRight_toLeftOf="@id/guidelineLeft" />
</ConstraintSet> </ConstraintSet>
@ -42,9 +42,9 @@
<Constraint <Constraint
android:id="@id/selector" android:id="@id/selector"
android:layout_height="@dimen/tabs_fragment_selector_size" android:layout_height="@dimen/tabs_fragment_selector_size"
motion:layout_constraintWidth_percent=".25"
motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintLeft_toLeftOf="@id/guidelineLeft" /> motion:layout_constraintLeft_toLeftOf="@id/guidelineLeft"
motion:layout_constraintRight_toLeftOf="@id/guidelineMiddle" />
</ConstraintSet> </ConstraintSet>
@ -53,9 +53,9 @@
<Constraint <Constraint
android:id="@id/selector" android:id="@id/selector"
android:layout_height="@dimen/tabs_fragment_selector_size" android:layout_height="@dimen/tabs_fragment_selector_size"
motion:layout_constraintWidth_percent=".25"
motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintLeft_toLeftOf="@id/guidelineMiddle" /> motion:layout_constraintLeft_toLeftOf="@id/guidelineMiddle"
motion:layout_constraintRight_toLeftOf="@id/guidelineRight" />
</ConstraintSet> </ConstraintSet>
@ -64,8 +64,8 @@
<Constraint <Constraint
android:id="@id/selector" android:id="@id/selector"
android:layout_height="@dimen/tabs_fragment_selector_size" android:layout_height="@dimen/tabs_fragment_selector_size"
motion:layout_constraintWidth_percent=".25"
motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintLeft_toLeftOf="@id/guidelineRight"
motion:layout_constraintRight_toRightOf="parent" /> motion:layout_constraintRight_toRightOf="parent" />
</ConstraintSet> </ConstraintSet>

View file

@ -31,9 +31,9 @@
<Constraint <Constraint
android:id="@id/selector" android:id="@id/selector"
android:layout_width="@dimen/tabs_fragment_selector_size" android:layout_width="@dimen/tabs_fragment_selector_size"
motion:layout_constraintHeight_percent=".25"
motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintLeft_toLeftOf="parent"
motion:layout_constraintTop_toTopOf="parent" /> motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintBottom_toBottomOf="@id/guidelineTop" />
</ConstraintSet> </ConstraintSet>
@ -42,9 +42,9 @@
<Constraint <Constraint
android:id="@id/selector" android:id="@id/selector"
android:layout_width="@dimen/tabs_fragment_selector_size" android:layout_width="@dimen/tabs_fragment_selector_size"
motion:layout_constraintHeight_percent=".25"
motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintLeft_toLeftOf="parent"
motion:layout_constraintTop_toTopOf="@id/guidelineTop" /> motion:layout_constraintTop_toTopOf="@id/guidelineTop"
motion:layout_constraintBottom_toBottomOf="@id/guidelineMiddle" />
</ConstraintSet> </ConstraintSet>
@ -53,9 +53,9 @@
<Constraint <Constraint
android:id="@id/selector" android:id="@id/selector"
android:layout_width="@dimen/tabs_fragment_selector_size" android:layout_width="@dimen/tabs_fragment_selector_size"
motion:layout_constraintHeight_percent=".25"
motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintLeft_toLeftOf="parent"
motion:layout_constraintTop_toTopOf="@id/guidelineMiddle" /> motion:layout_constraintTop_toTopOf="@id/guidelineMiddle"
motion:layout_constraintBottom_toBottomOf="@id/guidelineBottom" />
</ConstraintSet> </ConstraintSet>
@ -64,8 +64,8 @@
<Constraint <Constraint
android:id="@id/selector" android:id="@id/selector"
android:layout_width="@dimen/tabs_fragment_selector_size" android:layout_width="@dimen/tabs_fragment_selector_size"
motion:layout_constraintHeight_percent=".25"
motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintLeft_toLeftOf="parent"
motion:layout_constraintTop_toTopOf="@id/guidelineBottom"
motion:layout_constraintBottom_toBottomOf="parent" /> motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet> </ConstraintSet>