From 7894311cddeb9ea08ecf36bc409f395876fa5cfd Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 15 Feb 2022 12:24:12 +0100 Subject: [PATCH] Reworked contacts list to use search results from Magic Search instead of directly fetched contacts from native addressbook --- CHANGELOG.md | 8 ++- .../fragments/MasterContactsFragment.kt | 9 +++ .../contact/viewmodels/ContactViewModel.kt | 5 +- .../viewmodels/ContactsListViewModel.kt | 69 ++++++++++++++----- .../main/java/org/linphone/contact/Contact.kt | 29 +++++++- .../org/linphone/contact/ContactsManager.kt | 14 ++-- .../res/layout/contact_detail_fragment.xml | 2 + app/src/main/res/layout/contact_list_cell.xml | 2 +- app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 10 files changed, 111 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f347deea..f55da3c2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,13 @@ Group changes to describe their impact on the project, as follows: Fixed for any bug fixes. Security to invite users to upgrade in case of vulnerabilities. -## [4.7.0] - Unreleased +## [4.6.2] - Unreleased + +### Added +- LDAP settings if SDK is built with OpenLDAP (requires 5.1.1 or higher linphone-sdk), will add contacts if any + +### Changed +- Contacts lists now show LDAP contacts if any, as well as "generated" contacts from SIP addresses you have interacted with ## [4.6.1] - 2022-02-14 diff --git a/app/src/main/java/org/linphone/activities/main/contact/fragments/MasterContactsFragment.kt b/app/src/main/java/org/linphone/activities/main/contact/fragments/MasterContactsFragment.kt index bc419400f..d4955614a 100644 --- a/app/src/main/java/org/linphone/activities/main/contact/fragments/MasterContactsFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/contact/fragments/MasterContactsFragment.kt @@ -173,6 +173,14 @@ class MasterContactsFragment : MasterFragment Log.i("[Contacts] Selected item in list changed: $contact") sharedViewModel.selectedContact.value = contact + (requireActivity() as MainActivity).hideKeyboard() if (editOnClick) { navigateToContactEditor(sipUriToAdd, binding.slidingPane) diff --git a/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactViewModel.kt b/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactViewModel.kt index c78c578b5..ee076322b 100644 --- a/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactViewModel.kt @@ -74,6 +74,8 @@ class ContactViewModel(val contactInternal: Contact) : ErrorReportingViewModel() val waitForChatRoomCreation = MutableLiveData() + val isNativeContact = MutableLiveData() + private val contactsUpdatedListener = object : ContactsUpdatedListenerStub() { override fun onContactUpdated(contact: Contact) { if (contact is NativeContact && contactInternal is NativeContact && contact.nativeId == contactInternal.nativeId) { @@ -127,6 +129,7 @@ class ContactViewModel(val contactInternal: Contact) : ErrorReportingViewModel() init { contact.value = contactInternal displayName.value = contactInternal.fullName ?: contactInternal.firstName + " " + contactInternal.lastName + isNativeContact.value = contactInternal is NativeContact updateNumbersAndAddresses(contactInternal) coreContext.contactsManager.addListener(contactsUpdatedListener) @@ -172,7 +175,7 @@ class ContactViewModel(val contactInternal: Contact) : ErrorReportingViewModel() } } - private fun updateNumbersAndAddresses(contact: Contact) { + fun updateNumbersAndAddresses(contact: Contact) { val list = arrayListOf() for (address in contact.sipAddresses) { val value = address.asStringUriOnly() diff --git a/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactsListViewModel.kt b/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactsListViewModel.kt index cf4bb3331..46a32f51c 100644 --- a/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactsListViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactsListViewModel.kt @@ -28,6 +28,7 @@ import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.contact.Contact import org.linphone.contact.ContactsUpdatedListenerStub import org.linphone.contact.NativeContact +import org.linphone.core.SearchResult import org.linphone.core.tools.Log class ContactsListViewModel : ViewModel() { @@ -36,6 +37,7 @@ class ContactsListViewModel : ViewModel() { val contactsList = MutableLiveData>() val filter = MutableLiveData() + private var previousFilter = "NotSet" private val contactsUpdatedListener = object : ContactsUpdatedListenerStub() { override fun onContactsUpdated() { @@ -57,27 +59,41 @@ class ContactsListViewModel : ViewModel() { super.onCleared() } - private fun getSelectedContactsList(): ArrayList { - val list = arrayListOf() - val source = - if (sipContactsSelected.value == true) coreContext.contactsManager.sipContacts - else coreContext.contactsManager.contacts - for (contact in source) { - list.add(ContactViewModel(contact)) - } - return list - } - fun updateContactsList() { - val list: ArrayList - val filterValue = filter.value.orEmpty() - list = if (filterValue.isNotEmpty()) { - getSelectedContactsList().filter { contact -> - contact.name.contains(filterValue, true) - } as ArrayList - } else { - getSelectedContactsList() + contactsList.value.orEmpty().forEach(ContactViewModel::destroy) + + if (previousFilter.isNotEmpty() && previousFilter.length > filterValue.length) { + coreContext.contactsManager.magicSearch.resetSearchCache() + } + previousFilter = filterValue + + val domain = if (sipContactsSelected.value == true) coreContext.core.defaultAccount?.params?.domain ?: "" else "" + val results = coreContext.contactsManager.magicSearch.getContactListFromFilter(filterValue, domain) + + val list = arrayListOf() + for (result in results) { + val contact = searchMatchingContact(result) ?: Contact(searchResult = result) + if (contact is NativeContact) { + val found = list.find { contactViewModel -> + contactViewModel.contactInternal is NativeContact && contactViewModel.contactInternal.nativeId == contact.nativeId + } + if (found != null) { + Log.d("[Contacts] Found a search result that matches a native contact [$contact] we already have, skipping") + continue + } + } else { + val found = list.find { contactViewModel -> + contactViewModel.displayName.value == contact.fullName + } + if (found != null) { + Log.i("[Contacts] Found a search result that matches a contact [$contact] we already have, updating it with the new information") + found.contactInternal.addAddressAndPhoneNumberFromSearchResult(result) + found.updateNumbersAndAddresses(found.contactInternal) + continue + } + } + list.add(ContactViewModel(contact)) } contactsList.postValue(list) @@ -146,4 +162,19 @@ class ContactsListViewModel : ViewModel() { } } } + + private fun searchMatchingContact(searchResult: SearchResult): Contact? { + val address = searchResult.address + + if (address != null) { + val contact = coreContext.contactsManager.findContactByAddress(address, ignoreLocalContact = true) + if (contact != null) return contact + } + + if (searchResult.phoneNumber != null) { + return coreContext.contactsManager.findContactByPhoneNumber(searchResult.phoneNumber.orEmpty()) + } + + return null + } } diff --git a/app/src/main/java/org/linphone/contact/Contact.kt b/app/src/main/java/org/linphone/contact/Contact.kt index 8cba22e3a..45fafcdcb 100644 --- a/app/src/main/java/org/linphone/contact/Contact.kt +++ b/app/src/main/java/org/linphone/contact/Contact.kt @@ -29,8 +29,10 @@ import org.linphone.R import org.linphone.core.Address import org.linphone.core.Friend import org.linphone.core.PresenceBasicStatus +import org.linphone.core.SearchResult import org.linphone.core.tools.Log import org.linphone.utils.ImageUtils +import org.linphone.utils.LinphoneUtils data class PhoneNumber(val value: String, val typeLabel: String) : Comparable { override fun compareTo(other: PhoneNumber): Int { @@ -38,7 +40,7 @@ data class PhoneNumber(val value: String, val typeLabel: String) : Comparable { +open class Contact() : Comparable { var fullName: String? = null var firstName: String? = null var lastName: String? = null @@ -55,6 +57,31 @@ open class Contact : Comparable { private var thumbnailUri: Uri? = null + constructor(searchResult: SearchResult) : this() { + friend = searchResult.friend + addAddressAndPhoneNumberFromSearchResult(searchResult) + } + + fun addAddressAndPhoneNumberFromSearchResult(searchResult: SearchResult) { + val address = searchResult.address + if (address != null) { + if (fullName == null) { + fullName = friend?.name ?: LinphoneUtils.getDisplayName(address) + } + + sipAddresses.add(address) + } + + val phoneNumber = searchResult.phoneNumber + if (phoneNumber != null) { + if (address == null && fullName == null) { + fullName = friend?.name ?: phoneNumber.orEmpty() + } + + phoneNumbers.add(PhoneNumber(phoneNumber, "")) + } + } + override fun compareTo(other: Contact): Int { val fn = fullName ?: "" val otherFn = other.fullName ?: "" diff --git a/app/src/main/java/org/linphone/contact/ContactsManager.kt b/app/src/main/java/org/linphone/contact/ContactsManager.kt index fdc2af0d8..eedc719b5 100644 --- a/app/src/main/java/org/linphone/contact/ContactsManager.kt +++ b/app/src/main/java/org/linphone/contact/ContactsManager.kt @@ -236,13 +236,15 @@ class ContactsManager(private val context: Context) { } @Synchronized - fun findContactByAddress(address: Address): Contact? { - val localContact = localAccountsContacts.find { localContact -> - localContact.sipAddresses.find { localAddress -> - address.weakEqual(localAddress) - } != null + fun findContactByAddress(address: Address, ignoreLocalContact: Boolean = false): Contact? { + if (!ignoreLocalContact) { + val localContact = localAccountsContacts.find { localContact -> + localContact.sipAddresses.find { localAddress -> + address.weakEqual(localAddress) + } != null + } + if (localContact != null) return localContact } - if (localContact != null) return localContact val cleanAddress = address.clone() cleanAddress.clean() // To remove gruu if any diff --git a/app/src/main/res/layout/contact_detail_fragment.xml b/app/src/main/res/layout/contact_detail_fragment.xml index 56a26aa3d..0d0263a7b 100644 --- a/app/src/main/res/layout/contact_detail_fragment.xml +++ b/app/src/main/res/layout/contact_detail_fragment.xml @@ -52,6 +52,7 @@ Domaine Divers Débogage + Ce contact ne peut être supprimé \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index acc871fca..829e23931 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -114,6 +114,7 @@ Choose where to save the contact Store locally + This contact can\'t be deleted Enter a number or an address