Display phone number type/label in contact view detail

This commit is contained in:
Sylvain Berfini 2021-03-15 16:38:22 +01:00
parent ee9a843a6e
commit e9abb5cef4
8 changed files with 54 additions and 15 deletions

View file

@ -192,7 +192,7 @@ class ContactEditorViewModel(val c: Contact?) : ViewModel(), ContactViewModelInt
private fun updateNumbersAndAddresses() { private fun updateNumbersAndAddresses() {
val phoneNumbers = arrayListOf<NumberOrAddressEditorViewModel>() val phoneNumbers = arrayListOf<NumberOrAddressEditorViewModel>()
for (number in c?.phoneNumbers.orEmpty()) { for (number in c?.rawPhoneNumbers.orEmpty()) {
phoneNumbers.add(NumberOrAddressEditorViewModel(number, false)) phoneNumbers.add(NumberOrAddressEditorViewModel(number, false))
} }
if (phoneNumbers.isEmpty()) { if (phoneNumbers.isEmpty()) {

View file

@ -29,6 +29,7 @@ class ContactNumberOrAddressViewModel(
val displayedValue: String, val displayedValue: String,
val isSip: Boolean = true, val isSip: Boolean = true,
val showSecureChat: Boolean = false, val showSecureChat: Boolean = false,
val typeLabel: String = "",
private val listener: ContactNumberOrAddressClickListener private val listener: ContactNumberOrAddressClickListener
) : ViewModel() { ) : ViewModel() {
val showInvite = !hasPresence && !isSip val showInvite = !hasPresence && !isSip

View file

@ -175,14 +175,15 @@ class ContactViewModel(private val c: Contact) : ErrorReportingViewModel(), Cont
val noa = ContactNumberOrAddressViewModel(address, hasPresence, displayValue, showSecureChat = secureChatAllowed, listener = listener) val noa = ContactNumberOrAddressViewModel(address, hasPresence, displayValue, showSecureChat = secureChatAllowed, listener = listener)
list.add(noa) list.add(noa)
} }
for (number in contact.phoneNumbers) { for (phoneNumber in contact.phoneNumbers) {
val number = phoneNumber.value
val presenceModel = contact.friend?.getPresenceModelForUriOrTel(number) val presenceModel = contact.friend?.getPresenceModelForUriOrTel(number)
val hasPresence = presenceModel != null && presenceModel.basicStatus == PresenceBasicStatus.Open val hasPresence = presenceModel != null && presenceModel.basicStatus == PresenceBasicStatus.Open
val contactAddress = presenceModel?.contact ?: number val contactAddress = presenceModel?.contact ?: number
val address = coreContext.core.interpretUrl(contactAddress) val address = coreContext.core.interpretUrl(contactAddress)
val isMe = if (address != null) coreContext.core.defaultProxyConfig?.identityAddress?.weakEqual(address) ?: false else false val isMe = if (address != null) coreContext.core.defaultProxyConfig?.identityAddress?.weakEqual(address) ?: false else false
val secureChatAllowed = !isMe && contact.friend?.getPresenceModelForUriOrTel(number)?.hasCapability(FriendCapability.LimeX3Dh) ?: false val secureChatAllowed = !isMe && contact.friend?.getPresenceModelForUriOrTel(number)?.hasCapability(FriendCapability.LimeX3Dh) ?: false
val noa = ContactNumberOrAddressViewModel(address, hasPresence, number, isSip = false, showSecureChat = secureChatAllowed, listener = listener) val noa = ContactNumberOrAddressViewModel(address, hasPresence, number, isSip = false, showSecureChat = secureChatAllowed, typeLabel = phoneNumber.typeLabel, listener = listener)
list.add(noa) list.add(noa)
} }
numbersAndAddresses.value = list numbersAndAddresses.value = list

View file

@ -41,8 +41,8 @@ class AsyncContactsLoader(private val context: Context) :
ContactsContract.Contacts.STARRED, ContactsContract.Contacts.STARRED,
ContactsContract.Contacts.LOOKUP_KEY, ContactsContract.Contacts.LOOKUP_KEY,
"data1", // Company, Phone or SIP Address "data1", // Company, Phone or SIP Address
"data2", // ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME "data2", // ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.SipAddress.TYPE
"data3", // ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME "data3", // ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, ContactsContract.CommonDataKinds.Phone.LABEL, ContactsContract.CommonDataKinds.SipAddress.LABEL
"data4" "data4"
) )
} }
@ -75,6 +75,7 @@ class AsyncContactsLoader(private val context: Context) :
contact.sipAddresses.clear() contact.sipAddresses.clear()
contact.rawSipAddresses.clear() contact.rawSipAddresses.clear()
contact.phoneNumbers.clear() contact.phoneNumbers.clear()
contact.rawPhoneNumbers.clear()
androidContactsCache[contact.nativeId] = contact androidContactsCache[contact.nativeId] = contact
nativeIds.add(contact.nativeId) nativeIds.add(contact.nativeId)
} else { } else {

View file

@ -33,6 +33,12 @@ import org.linphone.core.PresenceBasicStatus
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
import org.linphone.utils.ImageUtils import org.linphone.utils.ImageUtils
data class PhoneNumber(val value: String, val typeLabel: String) : Comparable<PhoneNumber> {
override fun compareTo(other: PhoneNumber): Int {
return value.compareTo(other.value)
}
}
open class Contact : Comparable<Contact> { open class Contact : Comparable<Contact> {
var fullName: String? = null var fullName: String? = null
var firstName: String? = null var firstName: String? = null
@ -40,7 +46,8 @@ open class Contact : Comparable<Contact> {
var organization: String? = null var organization: String? = null
var isStarred: Boolean = false var isStarred: Boolean = false
var phoneNumbers = arrayListOf<String>() var phoneNumbers = arrayListOf<PhoneNumber>()
var rawPhoneNumbers = arrayListOf<String>()
var sipAddresses = arrayListOf<Address>() var sipAddresses = arrayListOf<Address>()
// Raw SIP addresses are only used for contact edition // Raw SIP addresses are only used for contact edition
var rawSipAddresses = arrayListOf<String>() var rawSipAddresses = arrayListOf<String>()
@ -53,7 +60,7 @@ open class Contact : Comparable<Contact> {
if (fn == otherFn) { if (fn == otherFn) {
if (phoneNumbers.size == other.phoneNumbers.size && phoneNumbers.size > 0) { if (phoneNumbers.size == other.phoneNumbers.size && phoneNumbers.size > 0) {
if (phoneNumbers != other.phoneNumbers) { if (phoneNumbers != other.phoneNumbers) {
for (i in 0..phoneNumbers.size) { for (i in 0 until phoneNumbers.size) {
val compare = phoneNumbers[i].compareTo(other.phoneNumbers[i]) val compare = phoneNumbers[i].compareTo(other.phoneNumbers[i])
if (compare != 0) return compare if (compare != 0) return compare
} }
@ -64,7 +71,7 @@ open class Contact : Comparable<Contact> {
if (sipAddresses.size == other.sipAddresses.size && sipAddresses.size > 0) { if (sipAddresses.size == other.sipAddresses.size && sipAddresses.size > 0) {
if (sipAddresses != other.sipAddresses) { if (sipAddresses != other.sipAddresses) {
for (i in 0..sipAddresses.size) { for (i in 0 until sipAddresses.size) {
val compare = sipAddresses[i].asStringUriOnly().compareTo(other.sipAddresses[i].asStringUriOnly()) val compare = sipAddresses[i].asStringUriOnly().compareTo(other.sipAddresses[i].asStringUriOnly())
if (compare != 0) return compare if (compare != 0) return compare
} }
@ -89,7 +96,10 @@ open class Contact : Comparable<Contact> {
phoneNumbers.clear() phoneNumbers.clear()
for (number in friend.phoneNumbers) { for (number in friend.phoneNumbers) {
if (!phoneNumbers.contains(number)) phoneNumbers.add(number) if (!rawPhoneNumbers.contains(number)) {
phoneNumbers.add(PhoneNumber(number, ""))
rawPhoneNumbers.add(number)
}
} }
sipAddresses.clear() sipAddresses.clear()
@ -151,7 +161,7 @@ open class Contact : Comparable<Contact> {
val presenceModel = friend?.getPresenceModelForUriOrTel(address.asStringUriOnly()) val presenceModel = friend?.getPresenceModelForUriOrTel(address.asStringUriOnly())
if (presenceModel != null && presenceModel.basicStatus == PresenceBasicStatus.Open) return true if (presenceModel != null && presenceModel.basicStatus == PresenceBasicStatus.Open) return true
} }
for (number in phoneNumbers) { for (number in rawPhoneNumbers) {
val presenceModel = friend?.getPresenceModelForUriOrTel(number) val presenceModel = friend?.getPresenceModelForUriOrTel(number)
if (presenceModel != null && presenceModel.basicStatus == PresenceBasicStatus.Open) return true if (presenceModel != null && presenceModel.basicStatus == PresenceBasicStatus.Open) return true
} }

View file

@ -345,7 +345,7 @@ class ContactsManager(private val context: Context) {
} }
private fun storePresenceInNativeContact(contact: NativeContact) { private fun storePresenceInNativeContact(contact: NativeContact) {
for (phoneNumber in contact.phoneNumbers) { for (phoneNumber in contact.rawPhoneNumbers) {
val sipAddress = contact.getContactForPhoneNumberOrAddress(phoneNumber) val sipAddress = contact.getContactForPhoneNumberOrAddress(phoneNumber)
if (sipAddress != null) { if (sipAddress != null) {
Log.d("[Contacts Manager] Found presence information to store in native contact $contact under Linphone sync account") Log.d("[Contacts Manager] Found presence information to store in native contact $contact under Linphone sync account")

View file

@ -108,9 +108,24 @@ class NativeContact(val nativeId: String, private val lookupKey: String? = null)
return return
} }
Log.d("[Native Contact] Found phone number $data1 ($data4)") val labelColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.LABEL)
val label: String? = cursor.getString(labelColumnIndex)
val typeColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE)
val type: Int = cursor.getInt(typeColumnIndex)
val typeLabel = ContactsContract.CommonDataKinds.Phone.getTypeLabel(
coreContext.context.resources,
type,
label
).toString()
val number = data4 ?: data1 val number = data4 ?: data1
if (number != null && number.isNotEmpty() && !phoneNumbers.contains(number)) phoneNumbers.add(number) if (number != null && number.isNotEmpty()) {
Log.d("[Native Contact] Found phone number $data1 ($data4), type label is $typeLabel")
if (!rawPhoneNumbers.contains(number)) {
phoneNumbers.add(PhoneNumber(number, typeLabel))
rawPhoneNumbers.add(number)
}
}
} }
linphoneMime, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE -> { linphoneMime, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE -> {
if (data1 == null) { if (data1 == null) {
@ -119,7 +134,7 @@ class NativeContact(val nativeId: String, private val lookupKey: String? = null)
} }
Log.d("[Native Contact] Found SIP address $data1") Log.d("[Native Contact] Found SIP address $data1")
if (phoneNumbers.contains(data1)) { if (rawPhoneNumbers.contains(data1)) {
Log.d("[Native Contact] SIP address value already exists in phone numbers list, skipping") Log.d("[Native Contact] SIP address value already exists in phone numbers list, skipping")
return return
} }
@ -131,6 +146,7 @@ class NativeContact(val nativeId: String, private val lookupKey: String? = null)
} }
val stringAddress = address.asStringUriOnly() val stringAddress = address.asStringUriOnly()
Log.d("[Native Contact] Found SIP address $stringAddress")
if (!rawSipAddresses.contains(stringAddress)) { if (!rawSipAddresses.contains(stringAddress)) {
sipAddresses.add(address) sipAddresses.add(address)
rawSipAddresses.add(stringAddress) rawSipAddresses.add(stringAddress)
@ -191,7 +207,7 @@ class NativeContact(val nativeId: String, private val lookupKey: String? = null)
} }
for (address in sipAddresses) friend.addAddress(address) for (address in sipAddresses) friend.addAddress(address)
for (number in phoneNumbers) friend.addPhoneNumber(number) for (number in rawPhoneNumbers) friend.addPhoneNumber(number)
friend.done() friend.done()
if (created) coreContext.core.defaultFriendList?.addFriend(friend) if (created) coreContext.core.defaultFriendList?.addFriend(friend)
@ -220,6 +236,7 @@ class NativeContact(val nativeId: String, private val lookupKey: String? = null)
sipAddresses.clear() sipAddresses.clear()
rawSipAddresses.clear() rawSipAddresses.clear()
phoneNumbers.clear() phoneNumbers.clear()
rawPhoneNumbers.clear()
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
syncValuesFromAndroidCursor(cursor) syncValuesFromAndroidCursor(cursor)

View file

@ -72,6 +72,15 @@
android:scrollHorizontally="true" android:scrollHorizontally="true"
android:singleLine="true" /> android:singleLine="true" />
<TextView
android:text="@{data.typeLabel}"
android:visibility="@{data.typeLabel.length() > 0 ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="?attr/primarySubtextDarkColor"
android:textSize="13sp" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"