Added LDAP settings, using MagicSearch in contacts list + updated CHANGELOG from 4.6.2 release
This commit is contained in:
parent
e34965d524
commit
62e2fb580f
20 changed files with 993 additions and 34 deletions
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -10,10 +10,18 @@ Group changes to describe their impact on the project, as follows:
|
||||||
Fixed for any bug fixes.
|
Fixed for any bug fixes.
|
||||||
Security to invite users to upgrade in case of vulnerabilities.
|
Security to invite users to upgrade in case of vulnerabilities.
|
||||||
|
|
||||||
|
|
||||||
## [4.7.0] - Unreleased
|
## [4.7.0] - Unreleased
|
||||||
|
|
||||||
## [4.6.2] - Unreleased
|
### Added
|
||||||
|
-
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
-
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
-
|
||||||
|
|
||||||
|
## [4.6.2] - 2022-03-01
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Request BLUETOOTH_CONNECT permission on Android 12+ devices, if not we won't be notified when a BT device is being connected/disconnected while app is alive.
|
- Request BLUETOOTH_CONNECT permission on Android 12+ devices, if not we won't be notified when a BT device is being connected/disconnected while app is alive.
|
||||||
|
@ -23,13 +31,15 @@ Group changes to describe their impact on the project, as follows:
|
||||||
- Prevent screen to turn off while recording a voice message
|
- Prevent screen to turn off while recording a voice message
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Contacts lists now show LDAP contacts if any, as well as "generated" contacts from SIP addresses you have interacted with
|
- Contacts lists now show LDAP contacts if any
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Negative gain in audio settings is allowed again
|
- Negative gain in audio settings is allowed again
|
||||||
- STUN server URL setting not enabling it for non sip.linphone.org accounts
|
- STUN server URL setting not enabling it for non sip.linphone.org accounts
|
||||||
- Contacts list header case comparison
|
- Contacts list header case comparison
|
||||||
- Stop voice recording playback when sending chat message
|
- Stop voice recording playback when sending chat message
|
||||||
|
- Call activity not finishing when hanging up sometimes
|
||||||
|
- Auto start setting disabled not working if background mode setting was enabled
|
||||||
|
|
||||||
## [4.6.1] - 2022-02-14
|
## [4.6.1] - 2022-02-14
|
||||||
|
|
||||||
|
|
|
@ -866,6 +866,17 @@ internal fun navigateToEmptySetting(navController: NavController) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun ContactsSettingsFragment.navigateToLdapSettings(configIndex: Int) {
|
||||||
|
if (findNavController().currentDestination?.id == R.id.contactsSettingsFragment) {
|
||||||
|
val bundle = bundleOf("LdapConfigIndex" to configIndex)
|
||||||
|
findNavController().navigate(
|
||||||
|
R.id.action_contactsSettingsFragment_to_ldapSettingsFragment,
|
||||||
|
bundle,
|
||||||
|
popupTo()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal fun AccountSettingsFragment.navigateToEmptySetting() {
|
internal fun AccountSettingsFragment.navigateToEmptySetting() {
|
||||||
navigateToEmptySetting(findNavController())
|
navigateToEmptySetting(findNavController())
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
|
import org.linphone.activities.SnackBarActivity
|
||||||
import org.linphone.activities.clearDisplayedContact
|
import org.linphone.activities.clearDisplayedContact
|
||||||
import org.linphone.activities.main.MainActivity
|
import org.linphone.activities.main.MainActivity
|
||||||
import org.linphone.activities.main.contact.adapters.ContactsListAdapter
|
import org.linphone.activities.main.contact.adapters.ContactsListAdapter
|
||||||
|
@ -172,6 +173,14 @@ class MasterContactsFragment : MasterFragment<ContactMasterFragmentBinding, Cont
|
||||||
val viewModel = DialogViewModel(getString(R.string.contact_delete_one_dialog))
|
val viewModel = DialogViewModel(getString(R.string.contact_delete_one_dialog))
|
||||||
val dialog: Dialog = DialogUtils.getDialog(requireContext(), viewModel)
|
val dialog: Dialog = DialogUtils.getDialog(requireContext(), viewModel)
|
||||||
|
|
||||||
|
val contactViewModel = adapter.currentList[viewHolder.bindingAdapterPosition]
|
||||||
|
if (contactViewModel.isNativeContact.value == false) {
|
||||||
|
adapter.notifyItemChanged(viewHolder.bindingAdapterPosition)
|
||||||
|
val activity = requireActivity() as MainActivity
|
||||||
|
activity.showSnackBar(R.string.contact_cant_be_deleted)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.showCancelButton {
|
viewModel.showCancelButton {
|
||||||
adapter.notifyItemChanged(viewHolder.bindingAdapterPosition)
|
adapter.notifyItemChanged(viewHolder.bindingAdapterPosition)
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
|
@ -211,6 +220,7 @@ class MasterContactsFragment : MasterFragment<ContactMasterFragmentBinding, Cont
|
||||||
it.consume { contact ->
|
it.consume { contact ->
|
||||||
Log.i("[Contacts] Selected item in list changed: $contact")
|
Log.i("[Contacts] Selected item in list changed: $contact")
|
||||||
sharedViewModel.selectedContact.value = contact
|
sharedViewModel.selectedContact.value = contact
|
||||||
|
(requireActivity() as MainActivity).hideKeyboard()
|
||||||
|
|
||||||
if (editOnClick) {
|
if (editOnClick) {
|
||||||
navigateToContactEditor(sipUriToAdd, binding.slidingPane)
|
navigateToContactEditor(sipUriToAdd, binding.slidingPane)
|
||||||
|
@ -237,6 +247,14 @@ class MasterContactsFragment : MasterFragment<ContactMasterFragmentBinding, Cont
|
||||||
adapter.submitList(it)
|
adapter.submitList(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listViewModel.moreResultsAvailableEvent.observe(
|
||||||
|
viewLifecycleOwner
|
||||||
|
) {
|
||||||
|
it.consume {
|
||||||
|
(requireActivity() as SnackBarActivity).showSnackBar(R.string.contacts_ldap_query_more_results_available)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.setAllContactsToggleClickListener {
|
binding.setAllContactsToggleClickListener {
|
||||||
listViewModel.sipContactsSelected.value = false
|
listViewModel.sipContactsSelected.value = false
|
||||||
}
|
}
|
||||||
|
@ -247,13 +265,13 @@ class MasterContactsFragment : MasterFragment<ContactMasterFragmentBinding, Cont
|
||||||
listViewModel.sipContactsSelected.observe(
|
listViewModel.sipContactsSelected.observe(
|
||||||
viewLifecycleOwner
|
viewLifecycleOwner
|
||||||
) {
|
) {
|
||||||
listViewModel.updateContactsList()
|
listViewModel.updateContactsList(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
listViewModel.filter.observe(
|
listViewModel.filter.observe(
|
||||||
viewLifecycleOwner
|
viewLifecycleOwner
|
||||||
) {
|
) {
|
||||||
listViewModel.updateContactsList()
|
listViewModel.updateContactsList(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.setNewContactClickListener {
|
binding.setNewContactClickListener {
|
||||||
|
|
|
@ -74,6 +74,8 @@ class ContactViewModel(val contactInternal: Contact) : MessageNotifierViewModel(
|
||||||
|
|
||||||
val waitForChatRoomCreation = MutableLiveData<Boolean>()
|
val waitForChatRoomCreation = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val isNativeContact = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
private val contactsUpdatedListener = object : ContactsUpdatedListenerStub() {
|
private val contactsUpdatedListener = object : ContactsUpdatedListenerStub() {
|
||||||
override fun onContactUpdated(contact: Contact) {
|
override fun onContactUpdated(contact: Contact) {
|
||||||
if (contact is NativeContact && contactInternal is NativeContact && contact.nativeId == contactInternal.nativeId) {
|
if (contact is NativeContact && contactInternal is NativeContact && contact.nativeId == contactInternal.nativeId) {
|
||||||
|
@ -127,6 +129,7 @@ class ContactViewModel(val contactInternal: Contact) : MessageNotifierViewModel(
|
||||||
init {
|
init {
|
||||||
contact.value = contactInternal
|
contact.value = contactInternal
|
||||||
displayName.value = contactInternal.fullName ?: contactInternal.firstName + " " + contactInternal.lastName
|
displayName.value = contactInternal.fullName ?: contactInternal.firstName + " " + contactInternal.lastName
|
||||||
|
isNativeContact.value = contactInternal is NativeContact
|
||||||
|
|
||||||
updateNumbersAndAddresses(contactInternal)
|
updateNumbersAndAddresses(contactInternal)
|
||||||
coreContext.contactsManager.addListener(contactsUpdatedListener)
|
coreContext.contactsManager.addListener(contactsUpdatedListener)
|
||||||
|
@ -172,7 +175,7 @@ class ContactViewModel(val contactInternal: Contact) : MessageNotifierViewModel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateNumbersAndAddresses(contact: Contact) {
|
fun updateNumbersAndAddresses(contact: Contact) {
|
||||||
val list = arrayListOf<ContactNumberOrAddressData>()
|
val list = arrayListOf<ContactNumberOrAddressData>()
|
||||||
for (address in contact.sipAddresses) {
|
for (address in contact.sipAddresses) {
|
||||||
val value = address.asStringUriOnly()
|
val value = address.asStringUriOnly()
|
||||||
|
|
|
@ -23,61 +23,125 @@ import android.content.ContentProviderOperation
|
||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlinx.coroutines.*
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.contact.Contact
|
import org.linphone.contact.Contact
|
||||||
import org.linphone.contact.ContactsUpdatedListenerStub
|
import org.linphone.contact.ContactsUpdatedListenerStub
|
||||||
import org.linphone.contact.NativeContact
|
import org.linphone.contact.NativeContact
|
||||||
|
import org.linphone.core.*
|
||||||
import org.linphone.core.tools.Log
|
import org.linphone.core.tools.Log
|
||||||
|
import org.linphone.utils.Event
|
||||||
|
|
||||||
class ContactsListViewModel : ViewModel() {
|
class ContactsListViewModel : ViewModel() {
|
||||||
val sipContactsSelected = MutableLiveData<Boolean>()
|
val sipContactsSelected = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
val contactsList = MutableLiveData<ArrayList<ContactViewModel>>()
|
val contactsList = MutableLiveData<ArrayList<ContactViewModel>>()
|
||||||
|
|
||||||
|
val fetchInProgress = MutableLiveData<Boolean>()
|
||||||
|
private var searchResultsPending: Boolean = false
|
||||||
|
private var fastFetchJob: Job? = null
|
||||||
|
|
||||||
val filter = MutableLiveData<String>()
|
val filter = MutableLiveData<String>()
|
||||||
|
private var previousFilter = "NotSet"
|
||||||
|
|
||||||
|
val moreResultsAvailableEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||||
|
MutableLiveData<Event<Boolean>>()
|
||||||
|
}
|
||||||
|
|
||||||
private val contactsUpdatedListener = object : ContactsUpdatedListenerStub() {
|
private val contactsUpdatedListener = object : ContactsUpdatedListenerStub() {
|
||||||
override fun onContactsUpdated() {
|
override fun onContactsUpdated() {
|
||||||
Log.i("[Contacts] Contacts have changed")
|
Log.i("[Contacts] Contacts have changed")
|
||||||
updateContactsList()
|
updateContactsList(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val magicSearchListener = object : MagicSearchListenerStub() {
|
||||||
|
override fun onSearchResultsReceived(magicSearch: MagicSearch) {
|
||||||
|
searchResultsPending = false
|
||||||
|
processMagicSearchResults(magicSearch.lastSearch)
|
||||||
|
fetchInProgress.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLdapHaveMoreResults(magicSearch: MagicSearch, ldap: Ldap) {
|
||||||
|
moreResultsAvailableEvent.value = Event(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
sipContactsSelected.value = coreContext.contactsManager.shouldDisplaySipContactsList()
|
sipContactsSelected.value = coreContext.contactsManager.shouldDisplaySipContactsList()
|
||||||
|
fetchInProgress.value = false
|
||||||
|
|
||||||
coreContext.contactsManager.addListener(contactsUpdatedListener)
|
coreContext.contactsManager.addListener(contactsUpdatedListener)
|
||||||
|
coreContext.contactsManager.magicSearch.addListener(magicSearchListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
contactsList.value.orEmpty().forEach(ContactViewModel::destroy)
|
contactsList.value.orEmpty().forEach(ContactViewModel::destroy)
|
||||||
|
coreContext.contactsManager.magicSearch.removeListener(magicSearchListener)
|
||||||
coreContext.contactsManager.removeListener(contactsUpdatedListener)
|
coreContext.contactsManager.removeListener(contactsUpdatedListener)
|
||||||
|
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSelectedContactsList(): ArrayList<ContactViewModel> {
|
fun updateContactsList(clearCache: Boolean) {
|
||||||
val list = arrayListOf<ContactViewModel>()
|
val filterValue = filter.value.orEmpty()
|
||||||
val source =
|
contactsList.value.orEmpty().forEach(ContactViewModel::destroy)
|
||||||
if (sipContactsSelected.value == true) coreContext.contactsManager.sipContacts
|
|
||||||
else coreContext.contactsManager.contacts
|
if (clearCache || (
|
||||||
for (contact in source) {
|
previousFilter.isNotEmpty() && (
|
||||||
list.add(ContactViewModel(contact))
|
previousFilter.length > filterValue.length ||
|
||||||
|
(previousFilter.length == filterValue.length && previousFilter != filterValue)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
coreContext.contactsManager.magicSearch.resetSearchCache()
|
||||||
|
}
|
||||||
|
previousFilter = filterValue
|
||||||
|
|
||||||
|
val domain = if (sipContactsSelected.value == true) coreContext.core.defaultAccount?.params?.domain ?: "" else ""
|
||||||
|
val filter = MagicSearchSource.Friends.toInt() or MagicSearchSource.LdapServers.toInt()
|
||||||
|
searchResultsPending = true
|
||||||
|
fastFetchJob?.cancel()
|
||||||
|
coreContext.contactsManager.magicSearch.getContactsAsync(filterValue, domain, filter)
|
||||||
|
|
||||||
|
fastFetchJob = viewModelScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
delay(200)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
if (searchResultsPending) {
|
||||||
|
fetchInProgress.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return list
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateContactsList() {
|
private fun processMagicSearchResults(results: Array<SearchResult>) {
|
||||||
val list: ArrayList<ContactViewModel>
|
val list = arrayListOf<ContactViewModel>()
|
||||||
|
for (result in results) {
|
||||||
val filterValue = filter.value.orEmpty()
|
val contact = searchMatchingContact(result) ?: Contact(searchResult = result)
|
||||||
list = if (filterValue.isNotEmpty()) {
|
if (contact is NativeContact) {
|
||||||
getSelectedContactsList().filter { contact ->
|
val found = list.find { contactViewModel ->
|
||||||
contact.name.contains(filterValue, true)
|
contactViewModel.contactInternal is NativeContact && contactViewModel.contactInternal.nativeId == contact.nativeId
|
||||||
} as ArrayList<ContactViewModel>
|
}
|
||||||
} else {
|
if (found != null) {
|
||||||
getSelectedContactsList()
|
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)
|
contactsList.postValue(list)
|
||||||
|
@ -146,4 +210,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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,10 @@ import androidx.lifecycle.ViewModelProvider
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
|
import org.linphone.activities.main.settings.SettingListenerStub
|
||||||
import org.linphone.activities.main.settings.viewmodels.ContactsSettingsViewModel
|
import org.linphone.activities.main.settings.viewmodels.ContactsSettingsViewModel
|
||||||
import org.linphone.activities.navigateToEmptySetting
|
import org.linphone.activities.navigateToEmptySetting
|
||||||
|
import org.linphone.activities.navigateToLdapSettings
|
||||||
import org.linphone.compatibility.Compatibility
|
import org.linphone.compatibility.Compatibility
|
||||||
import org.linphone.core.tools.Log
|
import org.linphone.core.tools.Log
|
||||||
import org.linphone.databinding.SettingsContactsFragmentBinding
|
import org.linphone.databinding.SettingsContactsFragmentBinding
|
||||||
|
@ -74,6 +76,22 @@ class ContactsSettingsFragment : GenericSettingFragment<SettingsContactsFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.ldapNewSettingsListener = object : SettingListenerStub() {
|
||||||
|
override fun onClicked() {
|
||||||
|
Log.i("[Contacts Settings] Clicked on new LDAP config")
|
||||||
|
navigateToLdapSettings(-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.ldapSettingsClickedEvent.observe(
|
||||||
|
viewLifecycleOwner
|
||||||
|
) {
|
||||||
|
it.consume { index ->
|
||||||
|
Log.i("[Contacts Settings] Clicked on LDAP config with index: $index")
|
||||||
|
navigateToLdapSettings(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!PermissionHelper.required(requireContext()).hasReadContactsPermission()) {
|
if (!PermissionHelper.required(requireContext()).hasReadContactsPermission()) {
|
||||||
Log.i("[Contacts Settings] Asking for READ_CONTACTS permission")
|
Log.i("[Contacts Settings] Asking for READ_CONTACTS permission")
|
||||||
requestPermissions(arrayOf(android.Manifest.permission.READ_CONTACTS), 0)
|
requestPermissions(arrayOf(android.Manifest.permission.READ_CONTACTS), 0)
|
||||||
|
@ -117,4 +135,9 @@ class ContactsSettingsFragment : GenericSettingFragment<SettingsContactsFragment
|
||||||
navigateToEmptySetting()
|
navigateToEmptySetting()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
viewModel.updateLdapConfigurationsList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2022 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.activities.main.settings.fragments
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import org.linphone.R
|
||||||
|
import org.linphone.activities.main.settings.viewmodels.LdapSettingsViewModel
|
||||||
|
import org.linphone.activities.main.settings.viewmodels.LdapSettingsViewModelFactory
|
||||||
|
import org.linphone.core.tools.Log
|
||||||
|
import org.linphone.databinding.SettingsLdapFragmentBinding
|
||||||
|
|
||||||
|
class LdapSettingsFragment : GenericSettingFragment<SettingsLdapFragmentBinding>() {
|
||||||
|
private lateinit var viewModel: LdapSettingsViewModel
|
||||||
|
|
||||||
|
override fun getLayoutId(): Int = R.layout.settings_ldap_fragment
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
binding.lifecycleOwner = viewLifecycleOwner
|
||||||
|
binding.sharedMainViewModel = sharedViewModel
|
||||||
|
|
||||||
|
val configIndex = arguments?.getInt("LdapConfigIndex")
|
||||||
|
if (configIndex == null) {
|
||||||
|
Log.e("[LDAP Settings] Config index not specified!")
|
||||||
|
goBack()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
viewModel = ViewModelProvider(this, LdapSettingsViewModelFactory(configIndex))[LdapSettingsViewModel::class.java]
|
||||||
|
} catch (nsee: NoSuchElementException) {
|
||||||
|
Log.e("[LDAP Settings] Failed to find LDAP object, aborting!")
|
||||||
|
goBack()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
viewModel.ldapConfigDeletedEvent.observe(
|
||||||
|
viewLifecycleOwner
|
||||||
|
) {
|
||||||
|
it.consume {
|
||||||
|
goBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.setBackClickListener { goBack() }
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@
|
||||||
package org.linphone.activities.main.settings.viewmodels
|
package org.linphone.activities.main.settings.viewmodels
|
||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.activities.main.settings.SettingListenerStub
|
import org.linphone.activities.main.settings.SettingListenerStub
|
||||||
import org.linphone.utils.Event
|
import org.linphone.utils.Event
|
||||||
import org.linphone.utils.PermissionHelper
|
import org.linphone.utils.PermissionHelper
|
||||||
|
@ -76,6 +77,20 @@ class ContactsSettingsViewModel : GenericSettingsViewModel() {
|
||||||
val launcherShortcuts = MutableLiveData<Boolean>()
|
val launcherShortcuts = MutableLiveData<Boolean>()
|
||||||
val launcherShortcutsEvent = MutableLiveData<Event<Boolean>>()
|
val launcherShortcutsEvent = MutableLiveData<Event<Boolean>>()
|
||||||
|
|
||||||
|
val ldapAvailable = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val ldapConfigurations = MutableLiveData<ArrayList<LdapSettingsViewModel>>()
|
||||||
|
|
||||||
|
lateinit var ldapNewSettingsListener: SettingListenerStub
|
||||||
|
val ldapSettingsClickedEvent: MutableLiveData<Event<Int>> by lazy {
|
||||||
|
MutableLiveData<Event<Int>>()
|
||||||
|
}
|
||||||
|
private var ldapSettingsListener = object : SettingListenerStub() {
|
||||||
|
override fun onAccountClicked(identity: String) {
|
||||||
|
ldapSettingsClickedEvent.value = Event(identity.toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
readContactsPermissionGranted.value = PermissionHelper.get().hasReadContactsPermission()
|
readContactsPermissionGranted.value = PermissionHelper.get().hasReadContactsPermission()
|
||||||
|
|
||||||
|
@ -84,5 +99,23 @@ class ContactsSettingsViewModel : GenericSettingsViewModel() {
|
||||||
nativePresence.value = prefs.storePresenceInNativeContact
|
nativePresence.value = prefs.storePresenceInNativeContact
|
||||||
showOrganization.value = prefs.displayOrganization
|
showOrganization.value = prefs.displayOrganization
|
||||||
launcherShortcuts.value = prefs.contactsShortcuts
|
launcherShortcuts.value = prefs.contactsShortcuts
|
||||||
|
|
||||||
|
ldapAvailable.value = core.ldapAvailable()
|
||||||
|
ldapConfigurations.value = arrayListOf()
|
||||||
|
|
||||||
|
updateLdapConfigurationsList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateLdapConfigurationsList() {
|
||||||
|
val list = arrayListOf<LdapSettingsViewModel>()
|
||||||
|
var index = 0
|
||||||
|
for (ldap in coreContext.core.ldapList) {
|
||||||
|
val viewModel = LdapSettingsViewModel(ldap, index.toString())
|
||||||
|
viewModel.ldapSettingsListener = ldapSettingsListener
|
||||||
|
list.add(viewModel)
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ldapConfigurations.value = list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,296 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2022 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.activities.main.settings.viewmodels
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import java.lang.NumberFormatException
|
||||||
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
|
import org.linphone.R
|
||||||
|
import org.linphone.activities.main.settings.SettingListenerStub
|
||||||
|
import org.linphone.core.Ldap
|
||||||
|
import org.linphone.core.LdapAuthMethod
|
||||||
|
import org.linphone.core.LdapCertVerificationMode
|
||||||
|
import org.linphone.core.LdapDebugLevel
|
||||||
|
import org.linphone.core.tools.Log
|
||||||
|
import org.linphone.utils.Event
|
||||||
|
|
||||||
|
class LdapSettingsViewModelFactory(private val index: Int) :
|
||||||
|
ViewModelProvider.NewInstanceFactory() {
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
if (index >= 0 && index <= coreContext.core.ldapList.size) {
|
||||||
|
val ldap = coreContext.core.ldapList[index]
|
||||||
|
return LdapSettingsViewModel(ldap, index.toString()) as T
|
||||||
|
}
|
||||||
|
|
||||||
|
val ldapParams = coreContext.core.createLdapParams()
|
||||||
|
val ldap = coreContext.core.createLdapWithParams(ldapParams)
|
||||||
|
return LdapSettingsViewModel(ldap, "-1") as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LdapSettingsViewModel(private val ldap: Ldap, val index: String) : GenericSettingsViewModel() {
|
||||||
|
lateinit var ldapSettingsListener: SettingListenerStub
|
||||||
|
|
||||||
|
val ldapConfigDeletedEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||||
|
MutableLiveData<Event<Boolean>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val ldapEnableListener = object : SettingListenerStub() {
|
||||||
|
override fun onBoolValueChanged(newValue: Boolean) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.enabled = newValue
|
||||||
|
ldap.params = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapEnable = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val deleteListener = object : SettingListenerStub() {
|
||||||
|
override fun onClicked() {
|
||||||
|
coreContext.core.removeLdap(ldap)
|
||||||
|
ldapConfigDeletedEvent.value = Event(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val ldapServerListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.server = newValue
|
||||||
|
ldap.params = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapServer = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val ldapBindDnListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.bindDn = newValue
|
||||||
|
ldap.params = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapBindDn = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val ldapPasswordListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.password = newValue
|
||||||
|
ldap.params = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapPassword = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val ldapAuthMethodListener = object : SettingListenerStub() {
|
||||||
|
override fun onListValueChanged(position: Int) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.authMethod = LdapAuthMethod.fromInt(ldapAuthMethodValues[position])
|
||||||
|
ldap.params = params
|
||||||
|
ldapAuthMethodIndex.value = position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapAuthMethodIndex = MutableLiveData<Int>()
|
||||||
|
val ldapAuthMethodLabels = MutableLiveData<ArrayList<String>>()
|
||||||
|
private val ldapAuthMethodValues = arrayListOf<Int>()
|
||||||
|
|
||||||
|
val ldapTlsListener = object : SettingListenerStub() {
|
||||||
|
override fun onBoolValueChanged(newValue: Boolean) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.isTlsEnabled = newValue
|
||||||
|
ldap.params = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapTls = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val ldapCertCheckListener = object : SettingListenerStub() {
|
||||||
|
override fun onListValueChanged(position: Int) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.serverCertificatesVerificationMode = LdapCertVerificationMode.fromInt(ldapCertCheckValues[position])
|
||||||
|
ldap.params = params
|
||||||
|
ldapCertCheckIndex.value = position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapCertCheckIndex = MutableLiveData<Int>()
|
||||||
|
val ldapCertCheckLabels = MutableLiveData<ArrayList<String>>()
|
||||||
|
private val ldapCertCheckValues = arrayListOf<Int>()
|
||||||
|
|
||||||
|
val ldapSearchBaseListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.baseObject = newValue
|
||||||
|
ldap.params = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapSearchBase = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val ldapSearchFilterListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.filter = newValue
|
||||||
|
ldap.params = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapSearchFilter = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val ldapSearchMaxResultsListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
try {
|
||||||
|
val intValue = newValue.toInt()
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.maxResults = intValue
|
||||||
|
ldap.params = params
|
||||||
|
} catch (nfe: NumberFormatException) {
|
||||||
|
Log.e("[LDAP Settings] Failed to set max results ($newValue): $nfe")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapSearchMaxResults = MutableLiveData<Int>()
|
||||||
|
|
||||||
|
val ldapSearchTimeoutListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
try {
|
||||||
|
val intValue = newValue.toInt()
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.timeout = intValue
|
||||||
|
ldap.params = params
|
||||||
|
} catch (nfe: NumberFormatException) {
|
||||||
|
Log.e("[LDAP Settings] Failed to set timeout ($newValue): $nfe")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapSearchTimeout = MutableLiveData<Int>()
|
||||||
|
|
||||||
|
val ldapRequestDelayListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
try {
|
||||||
|
val intValue = newValue.toInt()
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.delay = intValue
|
||||||
|
ldap.params = params
|
||||||
|
} catch (nfe: NumberFormatException) {
|
||||||
|
Log.e("[LDAP Settings] Failed to set request delay ($newValue): $nfe")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapRequestDelay = MutableLiveData<Int>()
|
||||||
|
|
||||||
|
val ldapMinimumCharactersListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
try {
|
||||||
|
val intValue = newValue.toInt()
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.minChars = intValue
|
||||||
|
ldap.params = params
|
||||||
|
} catch (nfe: NumberFormatException) {
|
||||||
|
Log.e("[LDAP Settings] Failed to set minimum characters ($newValue): $nfe")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapMinimumCharacters = MutableLiveData<Int>()
|
||||||
|
|
||||||
|
val ldapNameAttributeListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.nameAttribute = newValue
|
||||||
|
ldap.params = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapNameAttribute = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val ldapSipAttributeListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.sipAttribute = newValue
|
||||||
|
ldap.params = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapSipAttribute = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val ldapSipDomainListener = object : SettingListenerStub() {
|
||||||
|
override fun onTextValueChanged(newValue: String) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.sipDomain = newValue
|
||||||
|
ldap.params = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapSipDomain = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val ldapDebugListener = object : SettingListenerStub() {
|
||||||
|
override fun onBoolValueChanged(newValue: Boolean) {
|
||||||
|
val params = ldap.params.clone()
|
||||||
|
params.debugLevel = if (newValue) LdapDebugLevel.Verbose else LdapDebugLevel.Off
|
||||||
|
ldap.params = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val ldapDebug = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
val params = ldap.params
|
||||||
|
|
||||||
|
ldapEnable.value = params.enabled
|
||||||
|
ldapServer.value = params.server
|
||||||
|
ldapBindDn.value = params.bindDn
|
||||||
|
ldapPassword.value = params.password
|
||||||
|
ldapTls.value = params.isTlsEnabled
|
||||||
|
ldapSearchBase.value = params.baseObject
|
||||||
|
ldapSearchFilter.value = params.filter
|
||||||
|
ldapSearchMaxResults.value = params.maxResults
|
||||||
|
ldapSearchTimeout.value = params.timeout
|
||||||
|
ldapRequestDelay.value = params.delay
|
||||||
|
ldapMinimumCharacters.value = params.minChars
|
||||||
|
ldapNameAttribute.value = params.nameAttribute
|
||||||
|
ldapSipAttribute.value = params.sipAttribute
|
||||||
|
ldapSipDomain.value = params.sipDomain
|
||||||
|
ldapDebug.value = params.debugLevel == LdapDebugLevel.Verbose
|
||||||
|
|
||||||
|
initAuthMethodList()
|
||||||
|
initTlsCertCheckList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initAuthMethodList() {
|
||||||
|
val labels = arrayListOf<String>()
|
||||||
|
|
||||||
|
labels.add(prefs.getString(R.string.contacts_settings_ldap_auth_method_anonymous))
|
||||||
|
ldapAuthMethodValues.add(LdapAuthMethod.Anonymous.toInt())
|
||||||
|
|
||||||
|
labels.add(prefs.getString(R.string.contacts_settings_ldap_auth_method_simple))
|
||||||
|
ldapAuthMethodValues.add(LdapAuthMethod.Simple.toInt())
|
||||||
|
|
||||||
|
ldapAuthMethodLabels.value = labels
|
||||||
|
ldapAuthMethodIndex.value = ldapAuthMethodValues.indexOf(ldap.params.authMethod.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initTlsCertCheckList() {
|
||||||
|
val labels = arrayListOf<String>()
|
||||||
|
|
||||||
|
labels.add(prefs.getString(R.string.contacts_settings_ldap_cert_check_auto))
|
||||||
|
ldapCertCheckValues.add(LdapCertVerificationMode.Default.toInt())
|
||||||
|
|
||||||
|
labels.add(prefs.getString(R.string.contacts_settings_ldap_cert_check_disabled))
|
||||||
|
ldapCertCheckValues.add(LdapCertVerificationMode.Disabled.toInt())
|
||||||
|
|
||||||
|
labels.add(prefs.getString(R.string.contacts_settings_ldap_cert_check_enabled))
|
||||||
|
ldapCertCheckValues.add(LdapCertVerificationMode.Enabled.toInt())
|
||||||
|
|
||||||
|
ldapCertCheckLabels.value = labels
|
||||||
|
ldapCertCheckIndex.value = ldapCertCheckValues.indexOf(ldap.params.serverCertificatesVerificationMode.toInt())
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,8 +29,10 @@ import org.linphone.R
|
||||||
import org.linphone.core.Address
|
import org.linphone.core.Address
|
||||||
import org.linphone.core.Friend
|
import org.linphone.core.Friend
|
||||||
import org.linphone.core.PresenceBasicStatus
|
import org.linphone.core.PresenceBasicStatus
|
||||||
|
import org.linphone.core.SearchResult
|
||||||
import org.linphone.core.tools.Log
|
import org.linphone.core.tools.Log
|
||||||
import org.linphone.utils.ImageUtils
|
import org.linphone.utils.ImageUtils
|
||||||
|
import org.linphone.utils.LinphoneUtils
|
||||||
|
|
||||||
data class PhoneNumber(val value: String, val typeLabel: String) : Comparable<PhoneNumber> {
|
data class PhoneNumber(val value: String, val typeLabel: String) : Comparable<PhoneNumber> {
|
||||||
override fun compareTo(other: PhoneNumber): Int {
|
override fun compareTo(other: PhoneNumber): Int {
|
||||||
|
@ -38,7 +40,7 @@ data class PhoneNumber(val value: String, val typeLabel: String) : Comparable<Ph
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
var lastName: String? = null
|
var lastName: String? = null
|
||||||
|
@ -55,6 +57,31 @@ open class Contact : Comparable<Contact> {
|
||||||
|
|
||||||
private var thumbnailUri: Uri? = null
|
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 {
|
override fun compareTo(other: Contact): Int {
|
||||||
val fn = fullName ?: ""
|
val fn = fullName ?: ""
|
||||||
val otherFn = other.fullName ?: ""
|
val otherFn = other.fullName ?: ""
|
||||||
|
|
|
@ -238,13 +238,15 @@ class ContactsManager(private val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun findContactByAddress(address: Address): Contact? {
|
fun findContactByAddress(address: Address, ignoreLocalContact: Boolean = false): Contact? {
|
||||||
val localContact = localAccountsContacts.find { localContact ->
|
if (!ignoreLocalContact) {
|
||||||
localContact.sipAddresses.find { localAddress ->
|
val localContact = localAccountsContacts.find { localContact ->
|
||||||
address.weakEqual(localAddress)
|
localContact.sipAddresses.find { localAddress ->
|
||||||
} != null
|
address.weakEqual(localAddress)
|
||||||
|
} != null
|
||||||
|
}
|
||||||
|
if (localContact != null) return localContact
|
||||||
}
|
}
|
||||||
if (localContact != null) return localContact
|
|
||||||
|
|
||||||
val cleanAddress = address.clone()
|
val cleanAddress = address.clone()
|
||||||
cleanAddress.clean() // To remove gruu if any
|
cleanAddress.clean() // To remove gruu if any
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:onClick="@{editClickListener}"
|
android:onClick="@{editClickListener}"
|
||||||
|
android:visibility="@{viewModel.isNativeContact ? View.VISIBLE : View.INVISIBLE}"
|
||||||
android:contentDescription="@string/content_description_edit_contact"
|
android:contentDescription="@string/content_description_edit_contact"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -62,6 +63,7 @@
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:onClick="@{deleteClickListener}"
|
android:onClick="@{deleteClickListener}"
|
||||||
|
android:visibility="@{viewModel.isNativeContact ? View.VISIBLE : View.INVISIBLE}"
|
||||||
android:contentDescription="@string/content_description_delete_contact"
|
android:contentDescription="@string/content_description_delete_contact"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:onClick="@{() -> selectionListViewModel.onToggleSelect(position)}"
|
android:onClick="@{() -> selectionListViewModel.onToggleSelect(position)}"
|
||||||
android:visibility="@{selectionListViewModel.isEditionEnabled ? View.VISIBLE : View.GONE, default=gone}"
|
android:visibility="@{selectionListViewModel.isEditionEnabled && viewModel.isNativeContact ? View.VISIBLE : View.GONE, default=gone}"
|
||||||
android:checked="@{selectionListViewModel.selectedItems.contains(position)}"
|
android:checked="@{selectionListViewModel.selectedItems.contains(position)}"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
|
@ -175,6 +175,10 @@
|
||||||
android:text="@string/no_contact"
|
android:text="@string/no_contact"
|
||||||
android:visibility="@{!viewModel.sipContactsSelected && viewModel.contactsList.empty ? View.VISIBLE : View.GONE}" />
|
android:visibility="@{!viewModel.sipContactsSelected && viewModel.contactsList.empty ? View.VISIBLE : View.GONE}" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/wait_layout"
|
||||||
|
app:visibility="@{viewModel.fetchInProgress}"/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
|
|
|
@ -107,6 +107,35 @@
|
||||||
linphone:checked="@={viewModel.launcherShortcuts}"
|
linphone:checked="@={viewModel.launcherShortcuts}"
|
||||||
linphone:enabled="@{viewModel.readContactsPermissionGranted}"/>
|
linphone:enabled="@{viewModel.readContactsPermissionGranted}"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="@{viewModel.ldapAvailable ? View.VISIBLE : View.GONE}"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/settings_category_font"
|
||||||
|
android:text="@string/contacts_settings_ldap_title"
|
||||||
|
android:paddingTop="15dp"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
linphone:entries="@{viewModel.ldapConfigurations}"
|
||||||
|
linphone:layout="@{@layout/settings_ldap_cell}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_basic"
|
||||||
|
linphone:listener="@{viewModel.ldapNewSettingsListener}"
|
||||||
|
linphone:title="@{@string/contacts_settings_create_new_ldap_config_title}" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
37
app/src/main/res/layout/settings_ldap_cell.xml
Normal file
37
app/src/main/res/layout/settings_ldap_cell.xml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<import type="android.view.View" />
|
||||||
|
<variable
|
||||||
|
name="data"
|
||||||
|
type="org.linphone.activities.main.settings.viewmodels.LdapSettingsViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:onClick="@{() -> data.ldapSettingsListener.onAccountClicked(data.index)}"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical|left">
|
||||||
|
|
||||||
|
<org.linphone.views.MarqueeTextView
|
||||||
|
android:id="@+id/settings_title"
|
||||||
|
style="@style/settings_item_font"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@{data.ldapServer, default=`ldap://ldap.example.org`}" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_below="@id/settings_title"
|
||||||
|
android:background="?attr/dividerColor" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</layout>
|
238
app/src/main/res/layout/settings_ldap_fragment.xml
Normal file
238
app/src/main/res/layout/settings_ldap_fragment.xml
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:linphone="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<import type="android.view.View"/>
|
||||||
|
<import type="android.text.InputType"/>
|
||||||
|
<variable
|
||||||
|
name="backClickListener"
|
||||||
|
type="android.view.View.OnClickListener"/>
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="org.linphone.activities.main.settings.viewmodels.LdapSettingsViewModel"/>
|
||||||
|
<variable
|
||||||
|
name="sharedMainViewModel"
|
||||||
|
type="org.linphone.activities.main.viewmodels.SharedMainViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/top_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/main_activity_top_bar_size"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:background="?attr/lightToolbarBackgroundColor"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/back"
|
||||||
|
android:onClick="@{backClickListener}"
|
||||||
|
android:visibility="@{sharedMainViewModel.isSlidingPaneSlideable ? View.VISIBLE : View.GONE}"
|
||||||
|
android:contentDescription="@string/content_description_go_back"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="0.2"
|
||||||
|
android:background="?attr/button_background_drawable"
|
||||||
|
android:padding="18dp"
|
||||||
|
android:src="@drawable/back" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/accent_colored_title_font"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="0.6"
|
||||||
|
android:gravity="center"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:text="@string/contacts_settings_ldap_title"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="0.2"
|
||||||
|
android:visibility="@{sharedMainViewModel.isSlidingPaneSlideable ? View.INVISIBLE : View.GONE}" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_below="@id/top_bar">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_switch"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_enable_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapEnableListener}"
|
||||||
|
linphone:checked="@={viewModel.ldapEnable}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_basic"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_delete_title}"
|
||||||
|
linphone:listener="@{viewModel.deleteListener}"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/settings_category_font"
|
||||||
|
android:text="@string/contacts_settings_ldap_connection_title"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_server_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapServerListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapServer}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_TEXT_VARIATION_URI}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_bind_dn_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapBindDnListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapBindDn}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_CLASS_TEXT}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_password_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapPasswordListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapPassword}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_list"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_auth_method_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapAuthMethodListener}"
|
||||||
|
linphone:selectedIndex="@{viewModel.ldapAuthMethodIndex}"
|
||||||
|
linphone:labels="@{viewModel.ldapAuthMethodLabels}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_switch"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_tls_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapTlsListener}"
|
||||||
|
linphone:checked="@={viewModel.ldapTls}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_list"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_cert_check_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapCertCheckListener}"
|
||||||
|
linphone:selectedIndex="@{viewModel.ldapCertCheckIndex}"
|
||||||
|
linphone:labels="@{viewModel.ldapCertCheckLabels}"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/settings_category_font"
|
||||||
|
android:text="@string/contacts_settings_ldap_search_title"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_search_base_title}"
|
||||||
|
linphone:subtitle="@{@string/contacts_settings_ldap_search_base_subtitle}"
|
||||||
|
linphone:listener="@{viewModel.ldapSearchBaseListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapSearchBase}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_CLASS_TEXT}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_search_filter_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapSearchFilterListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapSearchFilter}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_CLASS_TEXT}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_search_max_results_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapSearchMaxResultsListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapSearchMaxResults.toString()}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_CLASS_NUMBER}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_search_timeout_title}"
|
||||||
|
linphone:subtitle="@{@string/contacts_settings_ldap_search_timeout_subtitle}"
|
||||||
|
linphone:listener="@{viewModel.ldapSearchTimeoutListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapSearchTimeout.toString()}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_CLASS_NUMBER}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_request_delay_title}"
|
||||||
|
linphone:subtitle="@{@string/contacts_settings_ldap_request_delay_subtitle}"
|
||||||
|
linphone:listener="@{viewModel.ldapRequestDelayListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapRequestDelay.toString()}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_CLASS_NUMBER}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_minimum_characters_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapMinimumCharactersListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapMinimumCharacters.toString()}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_CLASS_NUMBER}"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/settings_category_font"
|
||||||
|
android:text="@string/contacts_settings_ldap_parsing_title"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_name_attribute_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapNameAttributeListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapNameAttribute}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_CLASS_TEXT}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_sip_attribute_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapSipAttributeListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapSipAttribute}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_CLASS_TEXT}"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_text"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_sip_domain_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapSipDomainListener}"
|
||||||
|
linphone:defaultValue="@{viewModel.ldapSipDomain}"
|
||||||
|
linphone:inputType="@{InputType.TYPE_CLASS_TEXT}"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/settings_category_font"
|
||||||
|
android:text="@string/contacts_settings_ldap_misc_title"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/settings_widget_switch"
|
||||||
|
linphone:title="@{@string/contacts_settings_ldap_debug_title}"
|
||||||
|
linphone:listener="@{viewModel.ldapDebugListener}"
|
||||||
|
linphone:checked="@={viewModel.ldapDebug}"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</layout>
|
|
@ -49,7 +49,11 @@
|
||||||
android:id="@+id/contactsSettingsFragment"
|
android:id="@+id/contactsSettingsFragment"
|
||||||
android:name="org.linphone.activities.main.settings.fragments.ContactsSettingsFragment"
|
android:name="org.linphone.activities.main.settings.fragments.ContactsSettingsFragment"
|
||||||
tools:layout="@layout/settings_contacts_fragment"
|
tools:layout="@layout/settings_contacts_fragment"
|
||||||
android:label="ContactsSettingsFragment" />
|
android:label="ContactsSettingsFragment" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_contactsSettingsFragment_to_ldapSettingsFragment"
|
||||||
|
app:destination="@id/ldapSettingsFragment" />
|
||||||
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/networkSettingsFragment"
|
android:id="@+id/networkSettingsFragment"
|
||||||
android:name="org.linphone.activities.main.settings.fragments.NetworkSettingsFragment"
|
android:name="org.linphone.activities.main.settings.fragments.NetworkSettingsFragment"
|
||||||
|
@ -136,6 +140,11 @@
|
||||||
android:name="IsLinking"
|
android:name="IsLinking"
|
||||||
app:argType="boolean" />
|
app:argType="boolean" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/ldapSettingsFragment"
|
||||||
|
android:name="org.linphone.activities.main.settings.fragments.LdapSettingsFragment"
|
||||||
|
tools:layout="@layout/settings_ldap_fragment"
|
||||||
|
android:label="LdapSettingsFragment" />
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/conferencesSettingsFragment"
|
android:id="@+id/conferencesSettingsFragment"
|
||||||
tools:layout="@layout/settings_conferences_fragment"
|
tools:layout="@layout/settings_conferences_fragment"
|
||||||
|
|
|
@ -589,4 +589,38 @@
|
||||||
<string name="about_weblate_translation">Contribuer aux traductions</string>
|
<string name="about_weblate_translation">Contribuer aux traductions</string>
|
||||||
<string name="assistant_generic_account_warning">Certaines fonctionnalités avancées comme les messages de groupe ou les messages éphémères nécessitent un compte &appName;.\n\nElles seront masquées dans l\'application si vous configurez un compte SIP tiers.\n\nSi vous souhaitez les activer pour un projet professionnel, contactez-nous.</string>
|
<string name="assistant_generic_account_warning">Certaines fonctionnalités avancées comme les messages de groupe ou les messages éphémères nécessitent un compte &appName;.\n\nElles seront masquées dans l\'application si vous configurez un compte SIP tiers.\n\nSi vous souhaitez les activer pour un projet professionnel, contactez-nous.</string>
|
||||||
<string name="assistant_generic_account_warning_continue_button_text">J\'ai compris</string>
|
<string name="assistant_generic_account_warning_continue_button_text">J\'ai compris</string>
|
||||||
|
<string name="contacts_settings_create_new_ldap_config_title">Nouvelle configuration LDAP</string>
|
||||||
|
<string name="contacts_settings_ldap_title">LDAP</string>
|
||||||
|
<string name="contacts_settings_ldap_enable_title">Activer</string>
|
||||||
|
<string name="contacts_settings_ldap_delete_title">Supprimer</string>
|
||||||
|
<string name="contacts_settings_ldap_connection_title">Connexion</string>
|
||||||
|
<string name="contacts_settings_ldap_server_title">URL du serveur</string>
|
||||||
|
<string name="contacts_settings_ldap_bind_dn_title">Bind DN</string>
|
||||||
|
<string name="contacts_settings_ldap_password_title">Mot de passe</string>
|
||||||
|
<string name="contacts_settings_ldap_auth_method_title">Méthode d\'authentification</string>
|
||||||
|
<string name="contacts_settings_ldap_auth_method_anonymous">Anonyme</string>
|
||||||
|
<string name="contacts_settings_ldap_auth_method_simple">Simple</string>
|
||||||
|
<string name="contacts_settings_ldap_tls_title">Utiliser TLS</string>
|
||||||
|
<string name="contacts_settings_ldap_cert_check_title">Vérifier les certificats</string>
|
||||||
|
<string name="contacts_settings_ldap_cert_check_auto">Auto</string>
|
||||||
|
<string name="contacts_settings_ldap_cert_check_disabled">Désactivé</string>
|
||||||
|
<string name="contacts_settings_ldap_cert_check_enabled">Activé</string>
|
||||||
|
<string name="contacts_settings_ldap_search_title">Recherche</string>
|
||||||
|
<string name="contacts_settings_ldap_search_base_title">Base de recherche</string>
|
||||||
|
<string name="contacts_settings_ldap_search_base_subtitle">Ne doit pas être vide !</string>
|
||||||
|
<string name="contacts_settings_ldap_search_filter_title">Filtre</string>
|
||||||
|
<string name="contacts_settings_ldap_search_max_results_title">Résultats maximum</string>
|
||||||
|
<string name="contacts_settings_ldap_search_timeout_title">Durée max</string>
|
||||||
|
<string name="contacts_settings_ldap_search_timeout_subtitle">En secondes</string>
|
||||||
|
<string name="contacts_settings_ldap_request_delay_title">Délai entre 2 requêtes</string>
|
||||||
|
<string name="contacts_settings_ldap_request_delay_subtitle">En millisecondes</string>
|
||||||
|
<string name="contacts_settings_ldap_minimum_characters_title">Nombre minimum de caractères pour lancer la requête</string>
|
||||||
|
<string name="contacts_settings_ldap_parsing_title">Analyse</string>
|
||||||
|
<string name="contacts_settings_ldap_name_attribute_title">Attributs de nom</string>
|
||||||
|
<string name="contacts_settings_ldap_sip_attribute_title">Attributs SIP</string>
|
||||||
|
<string name="contacts_settings_ldap_sip_domain_title">Domaine</string>
|
||||||
|
<string name="contacts_settings_ldap_misc_title">Divers</string>
|
||||||
|
<string name="contacts_settings_ldap_debug_title">Débogage</string>
|
||||||
|
<string name="contact_cant_be_deleted">Ce contact ne peut être supprimé</string>
|
||||||
|
<string name="contacts_ldap_query_more_results_available">Plus de résultats sont disponibles, affinez votre recherche</string>
|
||||||
</resources>
|
</resources>
|
|
@ -111,6 +111,8 @@
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="contact_new_choose_sync_account">Choose where to save the contact</string>
|
<string name="contact_new_choose_sync_account">Choose where to save the contact</string>
|
||||||
<string name="contact_local_sync_account">Store locally</string>
|
<string name="contact_local_sync_account">Store locally</string>
|
||||||
|
<string name="contact_cant_be_deleted">This contact can\'t be deleted</string>
|
||||||
|
<string name="contacts_ldap_query_more_results_available">More results are available, refine your search</string>
|
||||||
|
|
||||||
<!-- Dialer -->
|
<!-- Dialer -->
|
||||||
<string name="dialer_address_bar_hint">Enter a number or an address</string>
|
<string name="dialer_address_bar_hint">Enter a number or an address</string>
|
||||||
|
@ -543,6 +545,40 @@
|
||||||
<string name="contacts_settings_launcher_shortcuts_summary">Will replace chat room shortcuts if any</string>
|
<string name="contacts_settings_launcher_shortcuts_summary">Will replace chat room shortcuts if any</string>
|
||||||
<string name="contacts_settings_show_new_contact_account_dialog_title">Always ask in which account save newly created contact</string>
|
<string name="contacts_settings_show_new_contact_account_dialog_title">Always ask in which account save newly created contact</string>
|
||||||
<string name="contacts_settings_show_new_contact_account_dialog_summary">If disabled contact will be stored locally</string>
|
<string name="contacts_settings_show_new_contact_account_dialog_summary">If disabled contact will be stored locally</string>
|
||||||
|
<string name="contacts_settings_create_new_ldap_config_title">New LDAP configuration</string>
|
||||||
|
|
||||||
|
<!-- LDAP Contacts settings -->
|
||||||
|
<string name="contacts_settings_ldap_title">LDAP</string>
|
||||||
|
<string name="contacts_settings_ldap_enable_title">Enable</string>
|
||||||
|
<string name="contacts_settings_ldap_delete_title">Delete</string>
|
||||||
|
<string name="contacts_settings_ldap_connection_title">Connection</string>
|
||||||
|
<string name="contacts_settings_ldap_server_title">Server URL</string>
|
||||||
|
<string name="contacts_settings_ldap_bind_dn_title">Bind DN</string>
|
||||||
|
<string name="contacts_settings_ldap_password_title">Password</string>
|
||||||
|
<string name="contacts_settings_ldap_auth_method_title">Authentication method</string>
|
||||||
|
<string name="contacts_settings_ldap_auth_method_anonymous">Anonymous</string>
|
||||||
|
<string name="contacts_settings_ldap_auth_method_simple">Simple</string>
|
||||||
|
<string name="contacts_settings_ldap_tls_title">Use TLS</string>
|
||||||
|
<string name="contacts_settings_ldap_cert_check_title">Check certificates</string>
|
||||||
|
<string name="contacts_settings_ldap_cert_check_auto">Auto</string>
|
||||||
|
<string name="contacts_settings_ldap_cert_check_disabled">Disabled</string>
|
||||||
|
<string name="contacts_settings_ldap_cert_check_enabled">Enabled</string>
|
||||||
|
<string name="contacts_settings_ldap_search_title">Search</string>
|
||||||
|
<string name="contacts_settings_ldap_search_base_title">Search base</string>
|
||||||
|
<string name="contacts_settings_ldap_search_base_subtitle">Must not be empty!</string>
|
||||||
|
<string name="contacts_settings_ldap_search_filter_title">Filter</string>
|
||||||
|
<string name="contacts_settings_ldap_search_max_results_title">Max results</string>
|
||||||
|
<string name="contacts_settings_ldap_search_timeout_title">Timeout</string>
|
||||||
|
<string name="contacts_settings_ldap_search_timeout_subtitle">In seconds</string>
|
||||||
|
<string name="contacts_settings_ldap_request_delay_title">Delay between two requests</string>
|
||||||
|
<string name="contacts_settings_ldap_request_delay_subtitle">In milliseconds</string>
|
||||||
|
<string name="contacts_settings_ldap_minimum_characters_title">Minimum characters to start query</string>
|
||||||
|
<string name="contacts_settings_ldap_parsing_title">Parsing</string>
|
||||||
|
<string name="contacts_settings_ldap_name_attribute_title">Name attributes</string>
|
||||||
|
<string name="contacts_settings_ldap_sip_attribute_title">SIP attributes</string>
|
||||||
|
<string name="contacts_settings_ldap_sip_domain_title">Domain</string>
|
||||||
|
<string name="contacts_settings_ldap_misc_title">Misc</string>
|
||||||
|
<string name="contacts_settings_ldap_debug_title">Debug</string>
|
||||||
|
|
||||||
<!-- Advanced settings -->
|
<!-- Advanced settings -->
|
||||||
<string name="advanced_settings_debug_mode_title">Debug logs</string>
|
<string name="advanced_settings_debug_mode_title">Debug logs</string>
|
||||||
|
|
Loading…
Reference in a new issue