Follow contacts list filter for every contact/address picker

This commit is contained in:
Sylvain Berfini 2025-04-03 10:05:43 +02:00
parent 526d0fb4c7
commit 90ff2caf1b
4 changed files with 86 additions and 55 deletions

View file

@ -180,6 +180,21 @@ class CoreContext
@WorkerThread
override fun onDefaultAccountChanged(core: Core, account: Account?) {
defaultAccountHasVideoConferenceFactoryUri = account?.params?.audioVideoConferenceFactoryAddress != null
val defaultDomain = corePreferences.defaultDomain
val isAccountOnDefaultDomain = account?.params?.domain == defaultDomain
val domainFilter = corePreferences.contactsFilter
Log.i("$TAG Currently selected filter is [$domainFilter]")
if (!isAccountOnDefaultDomain && domainFilter == defaultDomain) {
corePreferences.contactsFilter = "*"
Log.i(
"$TAG New default account isn't on default domain, changing filter to any SIP contacts instead"
)
} else if (isAccountOnDefaultDomain && domainFilter != "") {
corePreferences.contactsFilter = defaultDomain
Log.i("$TAG New default account is on default domain, using that domain as filter instead of wildcard")
}
}
@WorkerThread

View file

@ -104,7 +104,8 @@ class ContactsListViewModel
showFilter.value = !corePreferences.hidePhoneNumbers
coreContext.postOnCoreThread { core ->
updateDomainFilter()
domainFilter = corePreferences.contactsFilter
checkIfDefaultAccountOnDefaultDomain()
coreContext.contactsManager.addListener(contactsListener)
magicSearch = core.createMagicSearch()
@ -141,7 +142,8 @@ class ContactsListViewModel
@UiThread
fun applyCurrentDefaultAccountFilter() {
coreContext.postOnCoreThread {
updateDomainFilter()
domainFilter = corePreferences.contactsFilter
checkIfDefaultAccountOnDefaultDomain()
coreContext.postOnMainThread {
applyFilter(currentFilter)
@ -179,28 +181,6 @@ class ContactsListViewModel
corePreferences.showFavoriteContacts = show
}
@WorkerThread
private fun updateDomainFilter() {
val defaultAccount = coreContext.core.defaultAccount
val defaultDomain = corePreferences.defaultDomain
val isAccountOnDefaultDomain = defaultAccount?.params?.domain == defaultDomain
isDefaultAccountLinphone.postValue(isAccountOnDefaultDomain)
domainFilter = corePreferences.contactsFilter
Log.i("$TAG Currently selected filter is [$domainFilter]")
if (!isAccountOnDefaultDomain && domainFilter == defaultDomain) {
domainFilter = "*"
corePreferences.contactsFilter = domainFilter
Log.i(
"$TAG New default account isn't on default domain, changing filter to all SIP contacts instead"
)
} else if (isAccountOnDefaultDomain && domainFilter != "") {
domainFilter = defaultDomain
corePreferences.contactsFilter = domainFilter
Log.i("$TAG New default account is on default domain, using that as filter instead")
}
}
@UiThread
fun exportContactAsVCard(friend: Friend) {
coreContext.postOnCoreThread {
@ -350,4 +330,12 @@ class ContactsListViewModel
Log.i("$TAG Processed [${results.size}] results into [${list.size} contacts]")
firstLoad = false
}
@WorkerThread
private fun checkIfDefaultAccountOnDefaultDomain() {
val defaultAccount = coreContext.core.defaultAccount
val defaultDomain = corePreferences.defaultDomain
val isAccountOnDefaultDomain = defaultAccount?.params?.domain == defaultDomain
isDefaultAccountLinphone.postValue(isAccountOnDefaultDomain)
}
}

View file

@ -38,7 +38,6 @@ import org.linphone.mediastream.Log
import org.linphone.ui.main.contacts.model.ContactAvatarModel
import org.linphone.ui.main.model.ConversationContactOrSuggestionModel
import org.linphone.ui.main.model.SelectedAddressModel
import org.linphone.ui.main.model.isEndToEndEncryptionMandatory
import org.linphone.utils.AppUtils
import org.linphone.utils.LinphoneUtils
@ -68,8 +67,6 @@ abstract class AddressSelectionViewModel
private var currentFilter = ""
private var previousFilter = "NotSet"
private var limitSearchToLinphoneAccounts = true
private lateinit var magicSearch: MagicSearch
private val magicSearchListener = object : MagicSearchListenerStub() {
@ -86,7 +83,6 @@ abstract class AddressSelectionViewModel
Log.i("$TAG Contacts have been (re)loaded, updating list")
applyFilter(
currentFilter,
if (limitSearchToLinphoneAccounts) corePreferences.defaultDomain else "",
magicSearchSourceFlags
)
}
@ -100,8 +96,6 @@ abstract class AddressSelectionViewModel
isEmpty.value = true
coreContext.postOnCoreThread { core ->
limitSearchToLinphoneAccounts = isEndToEndEncryptionMandatory()
coreContext.contactsManager.addListener(contactsListener)
magicSearch = core.createMagicSearch()
magicSearch.limitedSearch = true
@ -220,7 +214,6 @@ abstract class AddressSelectionViewModel
coreContext.postOnCoreThread {
applyFilter(
filter,
if (limitSearchToLinphoneAccounts) corePreferences.defaultDomain else "",
magicSearchSourceFlags
)
}
@ -229,7 +222,6 @@ abstract class AddressSelectionViewModel
@WorkerThread
private fun applyFilter(
filter: String,
domain: String,
sources: Int
) {
if (previousFilter.isNotEmpty() && (
@ -242,6 +234,7 @@ abstract class AddressSelectionViewModel
currentFilter = filter
previousFilter = filter
val domain = corePreferences.contactsFilter
Log.i(
"$TAG Asking Magic search for contacts matching filter [$filter], domain [$domain] and in sources [$sources]"
)
@ -269,23 +262,14 @@ abstract class AddressSelectionViewModel
for (result in results) {
val address = result.address
if (address != null) {
if (result.sourceFlags == MagicSearch.Source.Request.toInt()) {
val model = ConversationContactOrSuggestionModel(address) {
coreContext.startAudioCall(address)
}
suggestionsList.add(model)
continue
}
val friend = result.friend
if (friend != null) {
val found = contactsList.find { it.friend == friend }
if (found != null) continue
val friend = result.friend ?: coreContext.contactsManager.findContactByAddress(
address
)
if (friend != null) {
val found = contactsList.find { it.friend == friend }
if (found != null) continue
val model = ConversationContactOrSuggestionModel(address, friend = friend)
val mainAddress = address ?: LinphoneUtils.getFirstAvailableAddressForFriend(friend)
if (mainAddress != null) {
val model = ConversationContactOrSuggestionModel(mainAddress, friend = friend)
val avatarModel = coreContext.contactsManager.getContactAvatarModelForFriend(
friend
)
@ -297,18 +281,28 @@ abstract class AddressSelectionViewModel
contactsList.add(model)
}
} else {
val defaultAccountAddress = coreContext.core.defaultAccount?.params?.identityAddress
if (defaultAccountAddress != null && address.weakEqual(defaultAccountAddress)) {
Log.i("$TAG Removing from suggestions current default account address")
continue
}
Log.w("$TAG Found friend [${friend.name}] in search results but no Address could be found, skipping it")
}
} else if (address != null) {
if (result.sourceFlags == MagicSearch.Source.Request.toInt()) {
val model = ConversationContactOrSuggestionModel(address) {
coreContext.startAudioCall(address)
}
suggestionsList.add(model)
continue
}
val defaultAccountAddress = coreContext.core.defaultAccount?.params?.identityAddress
if (defaultAccountAddress != null && address.weakEqual(defaultAccountAddress)) {
Log.i("$TAG Removing from suggestions current default account address")
continue
}
val model = ConversationContactOrSuggestionModel(address) {
coreContext.startAudioCall(address)
}
suggestionsList.add(model)
}
}

View file

@ -143,6 +143,40 @@ class LinphoneUtils {
return null
}
@WorkerThread
fun getFirstAvailableAddressForFriend(friend: Friend): Address? {
// Return any SIP address first
val address = friend.address ?: friend.addresses.firstOrNull()
if (address != null) return address
val phoneNumbers = friend.phoneNumbers
// If no SIP address stored in Friend, check for SIP address in phone numbers presence
for (phoneNumber in phoneNumbers) {
val presenceModel = friend.getPresenceModelForUriOrTel(phoneNumber)
val hasPresenceInfo = !presenceModel?.contact.isNullOrEmpty()
if (presenceModel != null && hasPresenceInfo) {
val contact = presenceModel.contact
if (!contact.isNullOrEmpty()) {
val address = coreContext.core.interpretUrl(contact, false)
if (address != null) {
address.clean() // To remove ;user=phone
return address
}
}
}
}
// Finally format any phone number as SIP address
for (phoneNumber in phoneNumbers) {
val address = coreContext.core.interpretUrl(phoneNumber, false)
if (address != null) {
return address
}
}
return null
}
@AnyThread
fun isCallIncoming(callState: Call.State): Boolean {
return when (callState) {