diff --git a/app/src/main/java/org/linphone/core/CorePreferences.kt b/app/src/main/java/org/linphone/core/CorePreferences.kt index 353129377..269fc1949 100644 --- a/app/src/main/java/org/linphone/core/CorePreferences.kt +++ b/app/src/main/java/org/linphone/core/CorePreferences.kt @@ -167,6 +167,13 @@ class CorePreferences // Contacts related + @get:WorkerThread @set:WorkerThread + var sortContactsByFirstName: Boolean + get() = config.getBool("ui", "sort_contacts_by_first_name", true) // If disabled, last name will be used + set(value) { + config.setBool("ui", "sort_contacts_by_first_name", value) + } + @get:WorkerThread @set:WorkerThread var contactsFilter: String get() = config.getString("ui", "contacts_filter", "")!! // Default value must be empty! diff --git a/app/src/main/java/org/linphone/ui/main/contacts/adapter/ContactsListAdapter.kt b/app/src/main/java/org/linphone/ui/main/contacts/adapter/ContactsListAdapter.kt index 28004dc02..b3572b43c 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/adapter/ContactsListAdapter.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/adapter/ContactsListAdapter.kt @@ -125,12 +125,12 @@ class ContactsListAdapter( val previousItem = bindingAdapterPosition - 1 val previousLetter = if (previousItem >= 0) { - getItem(previousItem).contactName?.get(0).toString() + getItem(previousItem).sortingName?.get(0).toString() } else { "" } - val currentLetter = contactModel.contactName?.get(0).toString() + val currentLetter = contactModel.sortingName?.get(0).toString() val displayLetter = previousLetter.isEmpty() || currentLetter != previousLetter firstContactStartingByThatLetter = displayLetter diff --git a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt index 114259e31..8a372b1bb 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/fragment/ContactsListFragment.kt @@ -37,6 +37,7 @@ import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import androidx.databinding.DataBindingUtil import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.observe import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager @@ -181,9 +182,7 @@ class ContactsListFragment : AbstractMainFragment() { showFilterPopupMenu(binding.topBar.extraAction) } - sharedViewModel.showContactEvent.observe( - viewLifecycleOwner - ) { + sharedViewModel.showContactEvent.observe(viewLifecycleOwner) { it.consume { refKey -> Log.i("$TAG Displaying contact with ref key [$refKey]") val navController = binding.contactsNavContainer.findNavController() @@ -194,9 +193,7 @@ class ContactsListFragment : AbstractMainFragment() { } } - sharedViewModel.showNewContactEvent.observe( - viewLifecycleOwner - ) { + sharedViewModel.showNewContactEvent.observe(viewLifecycleOwner) { it.consume { if (findNavController().currentDestination?.id == R.id.contactsListFragment) { Log.i("$TAG Opening contact editor for creating new contact") @@ -207,6 +204,12 @@ class ContactsListFragment : AbstractMainFragment() { } } + sharedViewModel.forceRefreshContactsList.observe(viewLifecycleOwner) { + it.consume { + listViewModel.filter() + } + } + // AbstractMainFragment related listViewModel.title.value = getString(R.string.bottom_navigation_contacts_label) diff --git a/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt b/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt index f835624e0..6e8570440 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt @@ -36,6 +36,7 @@ import org.linphone.core.tools.Log import org.linphone.utils.AppUtils import org.linphone.utils.TimestampUtils import androidx.core.net.toUri +import org.linphone.LinphoneApplication.Companion.corePreferences class ContactAvatarModel @WorkerThread @@ -56,7 +57,9 @@ class ContactAvatarModel val name = MutableLiveData() - val firstLetter: String = AppUtils.getFirstLetter(friend.name.orEmpty()) + var sortingName: String? = null + + var firstLetter: String? = null private val friendListener = object : FriendListenerStub() { @WorkerThread @@ -76,6 +79,7 @@ class ContactAvatarModel } update(address) + refreshSortingName() } @WorkerThread @@ -85,6 +89,12 @@ class ContactAvatarModel } } + @WorkerThread + fun refreshSortingName() { + sortingName = getNameToUseForSorting() + firstLetter = AppUtils.getFirstLetter(getNameToUseForSorting().orEmpty()) + } + @WorkerThread fun update(address: Address?) { updateSecurityLevel(address) @@ -148,6 +158,13 @@ class ContactAvatarModel } } + @WorkerThread + fun getNameToUseForSorting(): String? { + val sortByFirstName = corePreferences.sortContactsByFirstName + val firstOrLastName = if (sortByFirstName) friend.vcard?.givenName else friend.vcard?.familyName + return firstOrLastName ?: friend.name ?: friend.organization ?: friend.vcard?.fullName + } + @WorkerThread private fun getAvatarUri(friend: Friend): Uri? { val picturePath = friend.photo diff --git a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt index 13b28858f..efddee3ce 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactsListViewModel.kt @@ -284,6 +284,7 @@ class ContactsListViewModel val list = arrayListOf() val favouritesList = arrayListOf() var count = 0 + val collator = Collator.getInstance(Locale.getDefault()) for (result in results) { val friend = result.friend @@ -308,6 +309,7 @@ class ContactsListViewModel } else { coreContext.contactsManager.getContactAvatarModelForAddress(result.address) } + model.refreshSortingName() list.add(model) count += 1 @@ -319,16 +321,18 @@ class ContactsListViewModel } if (firstLoad && count == 20) { + list.sortWith { model1, model2 -> + collator.compare(model1.getNameToUseForSorting(), model2.getNameToUseForSorting()) + } contactsList.postValue(list) } } - val collator = Collator.getInstance(Locale.getDefault()) favouritesList.sortWith { model1, model2 -> - collator.compare(model1.friend.name, model2.friend.name) + collator.compare(model1.getNameToUseForSorting(), model2.getNameToUseForSorting()) } list.sortWith { model1, model2 -> - collator.compare(model1.friend.name, model2.friend.name) + collator.compare(model1.getNameToUseForSorting(), model2.getNameToUseForSorting()) } favourites.postValue(favouritesList) diff --git a/app/src/main/java/org/linphone/ui/main/settings/fragment/SettingsFragment.kt b/app/src/main/java/org/linphone/ui/main/settings/fragment/SettingsFragment.kt index 1f58890f7..0bb802a72 100644 --- a/app/src/main/java/org/linphone/ui/main/settings/fragment/SettingsFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/settings/fragment/SettingsFragment.kt @@ -38,6 +38,7 @@ import org.linphone.ui.main.fragment.GenericMainFragment import org.linphone.utils.ConfirmationDialogModel import org.linphone.ui.main.settings.viewmodel.SettingsViewModel import org.linphone.utils.DialogUtils +import org.linphone.utils.Event @UiThread class SettingsFragment : GenericMainFragment() { @@ -49,6 +50,20 @@ class SettingsFragment : GenericMainFragment() { private lateinit var viewModel: SettingsViewModel + private val sortContactsByListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + val label = viewModel.sortContactsByNames[position] + val value = viewModel.sortContactsByValues[position] + Log.i("$TAG Selected contact sorting is now [$label] ($value)") + viewModel.setContactSorting(value) + + sharedViewModel.forceRefreshContactsList.postValue(Event(true)) + } + + override fun onNothingSelected(parent: AdapterView<*>?) { + } + } + private val layoutListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { val label = viewModel.availableLayoutsNames[position] @@ -155,6 +170,22 @@ class SettingsFragment : GenericMainFragment() { } } + // Setup sort contacts by spinner + val sortContactsByAdapter = ArrayAdapter( + requireContext(), + R.layout.drop_down_item, + viewModel.sortContactsByNames + ) + sortContactsByAdapter.setDropDownViewResource(R.layout.generic_dropdown_cell) + binding.contactsSettings.sortContactsByFirstNameSpinner.adapter = sortContactsByAdapter + + viewModel.sortContactsBy.observe(viewLifecycleOwner) { sort -> + binding.contactsSettings.sortContactsByFirstNameSpinner.setSelection( + viewModel.sortContactsByValues.indexOf(sort) + ) + } + binding.contactsSettings.sortContactsByFirstNameSpinner.onItemSelectedListener = sortContactsByListener + viewModel.addLdapServerEvent.observe(viewLifecycleOwner) { it.consume { if (findNavController().currentDestination?.id == R.id.settingsFragment) { diff --git a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt index 62a36d08b..3110077cc 100644 --- a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt @@ -97,6 +97,13 @@ class SettingsViewModel // Contacts settings val showContactsSettings = MutableLiveData() + val sortContactsBy = MutableLiveData() + val sortContactsByNames = arrayListOf( + AppUtils.getString(R.string.contact_editor_first_name), + AppUtils.getString(R.string.contact_editor_last_name), + ) + val sortContactsByValues = arrayListOf(0, 1) + val ldapAvailable = MutableLiveData() val ldapServers = MutableLiveData>() @@ -293,6 +300,8 @@ class SettingsViewModel corePreferences.markConversationAsReadWhenDismissingMessageNotification ) + sortContactsBy.postValue(if (corePreferences.sortContactsByFirstName) 0 else 1) + defaultLayout.postValue(core.defaultConferenceLayout.toInt()) theme.postValue(corePreferences.darkMode) @@ -467,6 +476,13 @@ class SettingsViewModel expandContacts.value = expandContacts.value == false } + @UiThread + fun setContactSorting(sortingValue: Int) { + coreContext.postOnCoreThread { core -> + corePreferences.sortContactsByFirstName = sortingValue == 0 + } + } + @UiThread fun addLdapServer() { addLdapServerEvent.value = Event(true) diff --git a/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt b/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt index 10643b305..2ce556ef5 100644 --- a/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/viewmodel/SharedMainViewModel.kt @@ -95,6 +95,10 @@ class SharedMainViewModel MutableLiveData>() } + val forceRefreshContactsList: MutableLiveData> by lazy { + MutableLiveData>() + } + var sipAddressToAddToNewContact: String = "" // Call logs related diff --git a/app/src/main/res/layout/settings_contacts.xml b/app/src/main/res/layout/settings_contacts.xml index 733ca61b9..40d189ed4 100644 --- a/app/src/main/res/layout/settings_contacts.xml +++ b/app/src/main/res/layout/settings_contacts.xml @@ -15,6 +15,53 @@ android:paddingBottom="20dp" android:background="@drawable/shape_squircle_white_background"> + + + + + + + diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index f0724223e..cc132a3bd 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -205,6 +205,7 @@ Rendre visible dans la galerie les médias téléchargés Marquer la conversation comme lue lorsqu\'une notification de message est supprimée Contacts + Trier les contacts par Ajouter un serveur LDAP Editer le serveur LDAP Ajouter un carnet d\'adresse CardDAV diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a4087876d..2109e1fff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -244,6 +244,7 @@ Make downloaded media public Mark conversation as read when dismissing message notification Contacts + Sort contacts by Add LDAP server Edit LDAP server Add CardDAV address book