mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 11:28:06 +00:00
Added contacts avatars
This commit is contained in:
parent
369a6f1977
commit
c77fae435f
11 changed files with 228 additions and 94 deletions
69
app/src/main/java/org/linphone/contacts/ContactData.kt
Normal file
69
app/src/main/java/org/linphone/contacts/ContactData.kt
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.contacts
|
||||
|
||||
import android.content.ContentUris
|
||||
import android.net.Uri
|
||||
import android.provider.ContactsContract
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import org.linphone.core.*
|
||||
|
||||
class ContactData(val friend: Friend) {
|
||||
val presenceStatus = MutableLiveData<ConsolidatedPresence>()
|
||||
|
||||
val name = MutableLiveData<String>()
|
||||
|
||||
val avatar = getAvatarUri()
|
||||
|
||||
private val friendListener = object : FriendListenerStub() {
|
||||
override fun onPresenceReceived(fr: Friend) {
|
||||
presenceStatus.postValue(fr.consolidatedPresence)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
name.postValue(friend.name)
|
||||
presenceStatus.postValue(friend.consolidatedPresence)
|
||||
|
||||
friend.addListener(friendListener)
|
||||
|
||||
presenceStatus.postValue(ConsolidatedPresence.Offline)
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
friend.removeListener(friendListener)
|
||||
}
|
||||
|
||||
private fun getAvatarUri(): Uri? {
|
||||
val refKey = friend.refKey
|
||||
if (refKey != null) {
|
||||
val lookupUri = ContentUris.withAppendedId(
|
||||
ContactsContract.Contacts.CONTENT_URI,
|
||||
refKey.toLong()
|
||||
)
|
||||
return Uri.withAppendedPath(
|
||||
lookupUri,
|
||||
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* 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.contacts
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import org.linphone.core.*
|
||||
|
||||
class ContactSelectionData(searchResult: SearchResult) {
|
||||
val name = MutableLiveData<String>()
|
||||
|
||||
init {
|
||||
name.value = searchResult.friend?.name ?: searchResult.toString()
|
||||
}
|
||||
}
|
||||
|
|
@ -27,12 +27,11 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.linphone.R
|
||||
import org.linphone.core.SearchResult
|
||||
import org.linphone.databinding.ContactSelectionCellBinding
|
||||
|
||||
class ContactsSelectionAdapter(
|
||||
private val viewLifecycleOwner: LifecycleOwner
|
||||
) : ListAdapter<SearchResult, RecyclerView.ViewHolder>(SearchResultDiffCallback()) {
|
||||
) : ListAdapter<ContactData, RecyclerView.ViewHolder>(ContactDataDiffCallback()) {
|
||||
init {
|
||||
}
|
||||
|
||||
|
|
@ -53,10 +52,9 @@ class ContactsSelectionAdapter(
|
|||
inner class ViewHolder(
|
||||
private val binding: ContactSelectionCellBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(searchResult: SearchResult) {
|
||||
fun bind(contactData: ContactData) {
|
||||
with(binding) {
|
||||
val searchResultViewModel = ContactSelectionData(searchResult)
|
||||
data = searchResultViewModel
|
||||
data = contactData
|
||||
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
|
||||
|
|
@ -66,20 +64,18 @@ class ContactsSelectionAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
private class SearchResultDiffCallback : DiffUtil.ItemCallback<SearchResult>() {
|
||||
private class ContactDataDiffCallback : DiffUtil.ItemCallback<ContactData>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: SearchResult,
|
||||
newItem: SearchResult
|
||||
oldItem: ContactData,
|
||||
newItem: ContactData
|
||||
): Boolean {
|
||||
val oldAddress = oldItem.address
|
||||
val newAddress = newItem.address
|
||||
return if (oldAddress != null && newAddress != null) oldAddress.weakEqual(newAddress) else false
|
||||
return oldItem.friend.refKey == newItem.friend.refKey
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: SearchResult,
|
||||
newItem: SearchResult
|
||||
oldItem: ContactData,
|
||||
newItem: ContactData
|
||||
): Boolean {
|
||||
return newItem.friend != null
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@
|
|||
*/
|
||||
package org.linphone.ui.conversations
|
||||
|
||||
import android.text.SpannableStringBuilder
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import java.lang.StringBuilder
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||
import org.linphone.R
|
||||
import org.linphone.contacts.ContactData
|
||||
import org.linphone.core.*
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.utils.LinphoneUtils
|
||||
|
|
@ -36,7 +37,7 @@ class ChatRoomData(val chatRoom: ChatRoom) {
|
|||
|
||||
val subject = MutableLiveData<String>()
|
||||
|
||||
val lastMessage = MutableLiveData<SpannableStringBuilder>()
|
||||
val lastMessage = MutableLiveData<String>()
|
||||
|
||||
val unreadChatCount = MutableLiveData<Int>()
|
||||
|
||||
|
|
@ -56,6 +57,8 @@ class ChatRoomData(val chatRoom: ChatRoom) {
|
|||
|
||||
val lastMessageImdnIcon = MutableLiveData<Int>()
|
||||
|
||||
val contactData = MutableLiveData<ContactData>()
|
||||
|
||||
var chatRoomDataListener: ChatRoomDataListener? = null
|
||||
|
||||
val isOneToOne: Boolean by lazy {
|
||||
|
|
@ -92,9 +95,46 @@ class ChatRoomData(val chatRoom: ChatRoom) {
|
|||
}
|
||||
|
||||
init {
|
||||
coreContext.postOnCoreThread { core ->
|
||||
chatRoom.addListener(chatRoomListener)
|
||||
chatRoom.addListener(chatRoomListener)
|
||||
|
||||
if (chatRoom.hasCapability(ChatRoom.Capabilities.Basic.toInt())) {
|
||||
val remoteAddress = chatRoom.peerAddress
|
||||
val friend = chatRoom.core.findFriend(remoteAddress)
|
||||
if (friend != null) {
|
||||
contactData.postValue(ContactData(friend))
|
||||
}
|
||||
contactName.postValue(friend?.name ?: LinphoneUtils.getDisplayName(remoteAddress))
|
||||
} else {
|
||||
if (chatRoom.hasCapability(ChatRoom.Capabilities.OneToOne.toInt())) {
|
||||
val first = chatRoom.participants.firstOrNull()
|
||||
if (first != null) {
|
||||
val remoteAddress = first.address
|
||||
val friend = chatRoom.core.findFriend(remoteAddress)
|
||||
if (friend != null) {
|
||||
contactData.postValue(ContactData(friend))
|
||||
}
|
||||
contactName.postValue(
|
||||
friend?.name ?: LinphoneUtils.getDisplayName(remoteAddress)
|
||||
)
|
||||
} else {
|
||||
Log.e("[Chat Room Data] No participant in the chat room!")
|
||||
}
|
||||
}
|
||||
}
|
||||
subject.postValue(
|
||||
chatRoom.subject ?: LinphoneUtils.getDisplayName(chatRoom.peerAddress)
|
||||
)
|
||||
|
||||
lastMessageImdnIcon.postValue(R.drawable.imdn_sent)
|
||||
showLastMessageImdnIcon.postValue(false)
|
||||
computeLastMessage()
|
||||
|
||||
unreadChatCount.postValue(chatRoom.unreadMessagesCount)
|
||||
isComposing.postValue(chatRoom.isRemoteComposing)
|
||||
isSecure.postValue(chatRoom.securityLevel == ChatRoom.SecurityLevel.Encrypted)
|
||||
isSecureVerified.postValue(chatRoom.securityLevel == ChatRoom.SecurityLevel.Safe)
|
||||
isEphemeral.postValue(chatRoom.isEphemeralEnabled)
|
||||
isMuted.postValue(areNotificationsMuted())
|
||||
}
|
||||
|
||||
fun onCleared() {
|
||||
|
|
@ -112,39 +152,6 @@ class ChatRoomData(val chatRoom: ChatRoom) {
|
|||
return true
|
||||
}
|
||||
|
||||
fun update() {
|
||||
if (chatRoom.hasCapability(ChatRoom.Capabilities.Basic.toInt())) {
|
||||
val remoteAddress = chatRoom.peerAddress
|
||||
val friend = chatRoom.core.findFriend(remoteAddress)
|
||||
contactName.postValue(friend?.name ?: LinphoneUtils.getDisplayName(remoteAddress))
|
||||
} else {
|
||||
if (chatRoom.hasCapability(ChatRoom.Capabilities.OneToOne.toInt())) {
|
||||
val first = chatRoom.participants.firstOrNull()
|
||||
if (first != null) {
|
||||
val remoteAddress = first.address
|
||||
val friend = chatRoom.core.findFriend(remoteAddress)
|
||||
contactName.postValue(
|
||||
friend?.name ?: LinphoneUtils.getDisplayName(remoteAddress)
|
||||
)
|
||||
} else {
|
||||
Log.e("[Chat Room Data] No participant in the chat room!")
|
||||
}
|
||||
}
|
||||
}
|
||||
subject.postValue(chatRoom.subject ?: LinphoneUtils.getDisplayName(chatRoom.peerAddress))
|
||||
|
||||
lastMessageImdnIcon.postValue(R.drawable.imdn_sent)
|
||||
showLastMessageImdnIcon.postValue(false)
|
||||
computeLastMessage()
|
||||
|
||||
unreadChatCount.postValue(chatRoom.unreadMessagesCount)
|
||||
isComposing.postValue(chatRoom.isRemoteComposing)
|
||||
isSecure.postValue(chatRoom.securityLevel == ChatRoom.SecurityLevel.Encrypted)
|
||||
isSecureVerified.postValue(chatRoom.securityLevel == ChatRoom.SecurityLevel.Safe)
|
||||
isEphemeral.postValue(chatRoom.isEphemeralEnabled)
|
||||
isMuted.postValue(areNotificationsMuted())
|
||||
}
|
||||
|
||||
private fun computeLastMessageImdnIcon(message: ChatMessage) {
|
||||
val state = message.state
|
||||
showLastMessageImdnIcon.postValue(
|
||||
|
|
@ -174,7 +181,7 @@ class ChatRoomData(val chatRoom: ChatRoom) {
|
|||
val lastUpdateTime = chatRoom.lastUpdateTime
|
||||
lastUpdate.postValue(TimestampUtils.toString(lastUpdateTime, true))
|
||||
|
||||
val builder = SpannableStringBuilder()
|
||||
val builder = StringBuilder()
|
||||
|
||||
val message = chatRoom.lastMessageInHistory
|
||||
if (message != null) {
|
||||
|
|
@ -185,6 +192,10 @@ class ChatRoomData(val chatRoom: ChatRoom) {
|
|||
message.addListener(object : ChatMessageListenerStub() {
|
||||
override fun onMsgStateChanged(message: ChatMessage, state: ChatMessage.State) {
|
||||
computeLastMessageImdnIcon(message)
|
||||
|
||||
if (state == ChatMessage.State.Displayed) {
|
||||
message.removeListener(this)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -206,7 +217,12 @@ class ChatRoomData(val chatRoom: ChatRoom) {
|
|||
builder.trim()
|
||||
}
|
||||
|
||||
lastMessage.postValue(builder)
|
||||
val text = builder.toString()
|
||||
if (text.length > 128) { // This brings a huge performance improvement when scrolling
|
||||
lastMessage.postValue(text.substring(0, 128))
|
||||
} else {
|
||||
lastMessage.postValue(text)
|
||||
}
|
||||
}
|
||||
|
||||
private fun areNotificationsMuted(): Boolean {
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ class ConversationsFragment : Fragment() {
|
|||
it.consume { data ->
|
||||
}
|
||||
}
|
||||
|
||||
adapter.chatRoomLongClickedEvent.observe(viewLifecycleOwner) {
|
||||
it.consume { data ->
|
||||
val modalBottomSheet = ConversationMenuDialogFragment(data.chatRoom) {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ class ConversationsListAdapter(
|
|||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(chatRoomData: ChatRoomData) {
|
||||
with(binding) {
|
||||
chatRoomData.update()
|
||||
data = chatRoomData
|
||||
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
|
|
@ -98,6 +97,6 @@ private class ConversationDiffCallback : DiffUtil.ItemCallback<ChatRoomData>() {
|
|||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: ChatRoomData, newItem: ChatRoomData): Boolean {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,13 +22,14 @@ package org.linphone.ui.conversations
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.contacts.ContactData
|
||||
import org.linphone.core.MagicSearch
|
||||
import org.linphone.core.MagicSearchListenerStub
|
||||
import org.linphone.core.SearchResult
|
||||
import org.linphone.core.tools.Log
|
||||
|
||||
class NewConversationViewModel : ViewModel() {
|
||||
val contactsList = MutableLiveData<ArrayList<SearchResult>>()
|
||||
val contactsList = MutableLiveData<ArrayList<ContactData>>()
|
||||
|
||||
val filter = MutableLiveData<String>()
|
||||
private var previousFilter = "NotSet"
|
||||
|
|
@ -80,8 +81,16 @@ class NewConversationViewModel : ViewModel() {
|
|||
|
||||
private fun processMagicSearchResults(results: Array<SearchResult>) {
|
||||
Log.i("[New Conversation ViewModel] [${results.size}] matching results")
|
||||
val list = arrayListOf<SearchResult>()
|
||||
list.addAll(results)
|
||||
contactsList.value.orEmpty().forEach(ContactData::onDestroy)
|
||||
|
||||
val list = arrayListOf<ContactData>()
|
||||
for (searchResult in results) {
|
||||
val friend = searchResult.friend
|
||||
if (friend != null) {
|
||||
val data = ContactData(friend)
|
||||
list.add(data)
|
||||
}
|
||||
}
|
||||
contactsList.postValue(list)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ package org.linphone.utils
|
|||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.databinding.BindingAdapter
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import org.linphone.R
|
||||
import org.linphone.contacts.ContactData
|
||||
|
||||
/**
|
||||
* This file contains all the data binding necessary for the app
|
||||
|
|
@ -36,3 +40,13 @@ fun ImageView.setSourceImageResource(resource: Int) {
|
|||
fun TextView.setTypeface(typeface: Int) {
|
||||
this.setTypeface(null, typeface)
|
||||
}
|
||||
|
||||
@BindingAdapter("coilContact")
|
||||
fun loadContactPictureWithCoil(imageView: ImageView, contact: ContactData?) {
|
||||
contact ?: return
|
||||
|
||||
imageView.load(contact.avatar) {
|
||||
transformations(CircleCropTransformation())
|
||||
error(R.drawable.contact_avatar)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,14 @@
|
|||
*/
|
||||
package org.linphone.utils
|
||||
|
||||
import android.content.ContentUris
|
||||
import android.net.Uri
|
||||
import android.provider.ContactsContract
|
||||
import java.io.IOException
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.core.Address
|
||||
import org.linphone.core.ChatRoom
|
||||
import org.linphone.core.Friend
|
||||
|
||||
class LinphoneUtils {
|
||||
companion object {
|
||||
|
|
@ -52,5 +57,42 @@ class LinphoneUtils {
|
|||
// Do not return an empty display name
|
||||
return address.displayName ?: address.username ?: address.asString()
|
||||
}
|
||||
|
||||
fun Friend.getPictureUri(thumbnailPreferred: Boolean = false): Uri? {
|
||||
val refKey = refKey
|
||||
if (refKey != null) {
|
||||
try {
|
||||
val lookupUri = ContentUris.withAppendedId(
|
||||
ContactsContract.Contacts.CONTENT_URI,
|
||||
refKey.toLong()
|
||||
)
|
||||
|
||||
if (!thumbnailPreferred) {
|
||||
val pictureUri = Uri.withAppendedPath(
|
||||
lookupUri,
|
||||
ContactsContract.Contacts.Photo.DISPLAY_PHOTO
|
||||
)
|
||||
// Check that the URI points to a real file
|
||||
val contentResolver = coreContext.context.contentResolver
|
||||
try {
|
||||
if (contentResolver.openAssetFileDescriptor(pictureUri, "r") != null) {
|
||||
return pictureUri
|
||||
}
|
||||
} catch (ioe: IOException) { }
|
||||
}
|
||||
|
||||
// Fallback to thumbnail if high res picture isn't available
|
||||
return Uri.withAppendedPath(
|
||||
lookupUri,
|
||||
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY
|
||||
)
|
||||
} catch (e: Exception) { }
|
||||
} else if (photo != null) {
|
||||
try {
|
||||
return Uri.parse(photo)
|
||||
} catch (e: Exception) { }
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,39 +23,47 @@
|
|||
<ImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:src="@{data.isOneToOne ? @drawable/contact_avatar : @drawable/group_avatar, default=@drawable/contact_avatar}"
|
||||
coilContact="@{data.contactData}"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:text="@{data.isOneToOne ? data.contactName : data.subject, default=`John Doe`}"
|
||||
android:textColor="#000000"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="@{data.unreadChatCount > 0 ? Typeface.BOLD : Typeface.NORMAL, default=normal}"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintBottom_toTopOf="@id/subtitle"
|
||||
app:layout_constraintStart_toEndOf="@id/avatar"
|
||||
app:layout_constraintEnd_toStartOf="@id/date_time"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:text="@{data.isComposing ? `... est en train d'écrire` : data.lastMessage, default=`Lorem Ipsum`}"
|
||||
android:textColor="@{data.unreadChatCount > 0 ? @color/black : @color/gray_4, default=@color/gray_4}"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="@{data.unreadChatCount > 0 ? Typeface.BOLD : Typeface.NORMAL, default=normal}"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/avatar"
|
||||
app:layout_constraintEnd_toStartOf="@id/end_subtitle_barrier"
|
||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||
|
||||
<TextView
|
||||
|
|
@ -70,6 +78,13 @@
|
|||
app:layout_constraintTop_toTopOf="@id/title"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/end_subtitle_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:constraint_referenced_ids="imdn, unread"
|
||||
app:barrierDirection="left" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imdn"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<import type="org.linphone.core.ConsolidatedPresence"/>
|
||||
<variable
|
||||
name="data"
|
||||
type="org.linphone.contacts.ContactSelectionData" />
|
||||
type="org.linphone.contacts.ContactData" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
@ -17,11 +17,13 @@
|
|||
<ImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:src="@drawable/contact_avatar"
|
||||
coilContact="@{data}"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
|
@ -34,6 +36,8 @@
|
|||
android:text="@{data.name, default=`John Doe`}"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="14sp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintBottom_toBottomOf="@id/avatar"
|
||||
app:layout_constraintStart_toEndOf="@id/avatar"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue