diff --git a/app/src/main/java/org/linphone/ui/main/chat/adapter/ConversationsContactsAndSuggestionsListAdapter.kt b/app/src/main/java/org/linphone/ui/adapter/ConversationsContactsAndSuggestionsListAdapter.kt similarity index 73% rename from app/src/main/java/org/linphone/ui/main/chat/adapter/ConversationsContactsAndSuggestionsListAdapter.kt rename to app/src/main/java/org/linphone/ui/adapter/ConversationsContactsAndSuggestionsListAdapter.kt index 0b005a4ee..97cde1bb0 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/adapter/ConversationsContactsAndSuggestionsListAdapter.kt +++ b/app/src/main/java/org/linphone/ui/adapter/ConversationsContactsAndSuggestionsListAdapter.kt @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.linphone.ui.main.chat.adapter +package org.linphone.ui.adapter import android.content.Context import android.view.LayoutInflater @@ -31,11 +31,11 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import org.linphone.R -import org.linphone.databinding.ChatMessageForwardContactListCellBinding -import org.linphone.databinding.ChatMessageForwardConversationListCellBinding -import org.linphone.databinding.ChatMessageForwardSuggestionListCellBinding -import org.linphone.databinding.StartCallSuggestionListDecorationBinding -import org.linphone.ui.main.chat.model.ConversationContactOrSuggestionModel +import org.linphone.databinding.GenericAddressPickerContactListCellBinding +import org.linphone.databinding.GenericAddressPickerConversationListCellBinding +import org.linphone.databinding.GenericAddressPickerListDecorationBinding +import org.linphone.databinding.GenericAddressPickerSuggestionListCellBinding +import org.linphone.ui.main.model.ConversationContactOrSuggestionModel import org.linphone.utils.AppUtils import org.linphone.utils.Event import org.linphone.utils.HeaderAdapter @@ -64,16 +64,18 @@ class ConversationsContactsAndSuggestionsListAdapter : } override fun getHeaderViewForPosition(context: Context, position: Int): View { - val binding = StartCallSuggestionListDecorationBinding.inflate(LayoutInflater.from(context)) + val binding = GenericAddressPickerListDecorationBinding.inflate( + LayoutInflater.from(context) + ) binding.header.text = when (getItemViewType(position)) { CONVERSATION_TYPE -> { - AppUtils.getString(R.string.conversation_message_forward_conversations_list_title) + AppUtils.getString(R.string.generic_address_picker_conversations_list_title) } SUGGESTION_TYPE -> { - AppUtils.getString(R.string.history_call_start_suggestions_list_title) + AppUtils.getString(R.string.generic_address_picker_suggestions_list_title) } else -> { - AppUtils.getString(R.string.history_call_start_contacts_list_title) + AppUtils.getString(R.string.generic_address_picker_contacts_list_title) } } return binding.root @@ -93,33 +95,51 @@ class ConversationsContactsAndSuggestionsListAdapter : override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { CONVERSATION_TYPE -> { - val binding: ChatMessageForwardConversationListCellBinding = DataBindingUtil.inflate( + val binding: GenericAddressPickerConversationListCellBinding = DataBindingUtil.inflate( LayoutInflater.from(parent.context), - R.layout.chat_message_forward_conversation_list_cell, + R.layout.generic_address_picker_conversation_list_cell, parent, false ) - binding.lifecycleOwner = parent.findViewTreeLifecycleOwner() + binding.apply { + lifecycleOwner = parent.findViewTreeLifecycleOwner() + + setOnClickListener { + onClickedEvent.value = Event(model!!) + } + } ConversationViewHolder(binding) } CONTACT_TYPE -> { - val binding: ChatMessageForwardContactListCellBinding = DataBindingUtil.inflate( + val binding: GenericAddressPickerContactListCellBinding = DataBindingUtil.inflate( LayoutInflater.from(parent.context), - R.layout.chat_message_forward_contact_list_cell, + R.layout.generic_address_picker_contact_list_cell, parent, false ) - binding.lifecycleOwner = parent.findViewTreeLifecycleOwner() + binding.apply { + lifecycleOwner = parent.findViewTreeLifecycleOwner() + + setOnClickListener { + onClickedEvent.value = Event(model!!) + } + } ContactViewHolder(binding) } else -> { - val binding: ChatMessageForwardSuggestionListCellBinding = DataBindingUtil.inflate( + val binding: GenericAddressPickerSuggestionListCellBinding = DataBindingUtil.inflate( LayoutInflater.from(parent.context), - R.layout.chat_message_forward_suggestion_list_cell, + R.layout.generic_address_picker_suggestion_list_cell, parent, false ) - binding.lifecycleOwner = parent.findViewTreeLifecycleOwner() + binding.apply { + lifecycleOwner = parent.findViewTreeLifecycleOwner() + + setOnClickListener { + onClickedEvent.value = Event(model!!) + } + } SuggestionViewHolder(binding) } } @@ -134,33 +154,25 @@ class ConversationsContactsAndSuggestionsListAdapter : } inner class ConversationViewHolder( - val binding: ChatMessageForwardConversationListCellBinding + val binding: GenericAddressPickerConversationListCellBinding ) : RecyclerView.ViewHolder(binding.root) { @UiThread fun bind(conversationContactOrSuggestionModel: ConversationContactOrSuggestionModel) { with(binding) { model = conversationContactOrSuggestionModel - setOnClickListener { - onClickedEvent.value = Event(conversationContactOrSuggestionModel) - } - executePendingBindings() } } } inner class ContactViewHolder( - val binding: ChatMessageForwardContactListCellBinding + val binding: GenericAddressPickerContactListCellBinding ) : RecyclerView.ViewHolder(binding.root) { @UiThread fun bind(conversationContactOrSuggestionModel: ConversationContactOrSuggestionModel) { with(binding) { - model = conversationContactOrSuggestionModel.avatarModel.value - - setOnClickListener { - onClickedEvent.value = Event(conversationContactOrSuggestionModel) - } + model = conversationContactOrSuggestionModel val previousItem = bindingAdapterPosition - 1 val previousLetter = if (previousItem >= 0) { @@ -179,17 +191,13 @@ class ConversationsContactsAndSuggestionsListAdapter : } inner class SuggestionViewHolder( - val binding: ChatMessageForwardSuggestionListCellBinding + val binding: GenericAddressPickerSuggestionListCellBinding ) : RecyclerView.ViewHolder(binding.root) { @UiThread fun bind(conversationContactOrSuggestionModel: ConversationContactOrSuggestionModel) { with(binding) { model = conversationContactOrSuggestionModel - setOnClickListener { - onClickedEvent.value = Event(conversationContactOrSuggestionModel) - } - executePendingBindings() } } diff --git a/app/src/main/java/org/linphone/ui/call/conference/fragment/ConferenceAddParticipantsFragment.kt b/app/src/main/java/org/linphone/ui/call/conference/fragment/ConferenceAddParticipantsFragment.kt index 19baceba1..4bba36a4c 100644 --- a/app/src/main/java/org/linphone/ui/call/conference/fragment/ConferenceAddParticipantsFragment.kt +++ b/app/src/main/java/org/linphone/ui/call/conference/fragment/ConferenceAddParticipantsFragment.kt @@ -84,7 +84,7 @@ class ConferenceAddParticipantsFragment : GenericAddressPickerFragment() { setupRecyclerView(binding.contactsList) - viewModel.contactsAndSuggestionsList.observe( + viewModel.modelsList.observe( viewLifecycleOwner ) { Log.i("$TAG Contacts & suggestions list is ready with [${it.size}] items") diff --git a/app/src/main/java/org/linphone/ui/call/fragment/AbstractNewTransferCallFragment.kt b/app/src/main/java/org/linphone/ui/call/fragment/AbstractNewTransferCallFragment.kt index bdae477a1..93d2fef78 100644 --- a/app/src/main/java/org/linphone/ui/call/fragment/AbstractNewTransferCallFragment.kt +++ b/app/src/main/java/org/linphone/ui/call/fragment/AbstractNewTransferCallFragment.kt @@ -37,12 +37,12 @@ import org.linphone.contacts.getListOfSipAddressesAndPhoneNumbers import org.linphone.core.Address import org.linphone.core.tools.Log import org.linphone.databinding.StartCallFragmentBinding +import org.linphone.ui.adapter.ConversationsContactsAndSuggestionsListAdapter import org.linphone.ui.main.contacts.model.ContactNumberOrAddressClickListener import org.linphone.ui.main.contacts.model.ContactNumberOrAddressModel import org.linphone.ui.main.contacts.model.NumberOrAddressPickerDialogModel -import org.linphone.ui.main.history.adapter.ContactsAndSuggestionsListAdapter -import org.linphone.ui.main.history.model.ContactOrSuggestionModel import org.linphone.ui.main.history.viewmodel.StartCallViewModel +import org.linphone.ui.main.model.ConversationContactOrSuggestionModel import org.linphone.ui.main.model.isEndToEndEncryptionMandatory import org.linphone.utils.DialogUtils import org.linphone.utils.LinphoneUtils @@ -62,7 +62,7 @@ abstract class AbstractNewTransferCallFragment : GenericCallFragment() { R.id.call_nav_graph ) - private lateinit var adapter: ContactsAndSuggestionsListAdapter + private lateinit var adapter: ConversationsContactsAndSuggestionsListAdapter private val listener = object : ContactNumberOrAddressClickListener { @UiThread @@ -87,7 +87,7 @@ abstract class AbstractNewTransferCallFragment : GenericCallFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - adapter = ContactsAndSuggestionsListAdapter() + adapter = ConversationsContactsAndSuggestionsListAdapter() } override fun onCreateView( @@ -125,7 +125,7 @@ abstract class AbstractNewTransferCallFragment : GenericCallFragment() { binding.contactsAndSuggestionsList.adapter = adapter } - adapter.contactClickedEvent.observe(viewLifecycleOwner) { + adapter.onClickedEvent.observe(viewLifecycleOwner) { it.consume { model -> startCall(model) } @@ -133,7 +133,7 @@ abstract class AbstractNewTransferCallFragment : GenericCallFragment() { binding.contactsAndSuggestionsList.layoutManager = LinearLayoutManager(requireContext()) - viewModel.contactsAndSuggestionsList.observe( + viewModel.modelsList.observe( viewLifecycleOwner ) { Log.i("$TAG Contacts & suggestions list is ready with [${it.size}] items") @@ -213,7 +213,7 @@ abstract class AbstractNewTransferCallFragment : GenericCallFragment() { @WorkerThread abstract fun action(address: Address) - private fun startCall(model: ContactOrSuggestionModel) { + private fun startCall(model: ConversationContactOrSuggestionModel) { coreContext.postOnCoreThread { core -> val friend = model.friend if (friend == null) { @@ -225,7 +225,7 @@ abstract class AbstractNewTransferCallFragment : GenericCallFragment() { val numbersCount = friend.phoneNumbers.size // Do not consider phone numbers if default account is in secure mode - val enablePhoneNumbers = isEndToEndEncryptionMandatory() != true + val enablePhoneNumbers = !isEndToEndEncryptionMandatory() if (addressesCount == 1 && (numbersCount == 0 || !enablePhoneNumbers)) { Log.i( diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationForwardMessageFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationForwardMessageFragment.kt index 4b9ca79be..4c9310b18 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationForwardMessageFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationForwardMessageFragment.kt @@ -32,7 +32,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import org.linphone.R import org.linphone.core.tools.Log import org.linphone.databinding.ChatMessageForwardFragmentBinding -import org.linphone.ui.main.chat.adapter.ConversationsContactsAndSuggestionsListAdapter +import org.linphone.ui.adapter.ConversationsContactsAndSuggestionsListAdapter import org.linphone.ui.main.chat.viewmodel.ConversationForwardMessageViewModel import org.linphone.ui.main.contacts.model.ContactNumberOrAddressModel import org.linphone.ui.main.contacts.model.NumberOrAddressPickerDialogModel @@ -103,7 +103,7 @@ class ConversationForwardMessageFragment : SlidingPaneChildFragment() { val headerItemDecoration = RecyclerViewHeaderDecoration(requireContext(), adapter) binding.contactsList.addItemDecoration(headerItemDecoration) - viewModel.conversationsContactsAndSuggestionsList.observe( + viewModel.modelsList.observe( viewLifecycleOwner ) { Log.i( diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/StartConversationFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/StartConversationFragment.kt index 951431d91..8e7340dca 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/fragment/StartConversationFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/StartConversationFragment.kt @@ -79,7 +79,7 @@ class StartConversationFragment : GenericAddressPickerFragment() { setupRecyclerView(binding.contactsList) - viewModel.contactsAndSuggestionsList.observe( + viewModel.modelsList.observe( viewLifecycleOwner ) { Log.i("$TAG Contacts & suggestions list is ready with [${it.size}] items") diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/MessageModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/MessageModel.kt index 501cd60e4..c228c4d56 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/MessageModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/model/MessageModel.kt @@ -101,7 +101,7 @@ class MessageModel @WorkerThread constructor( val time = TimestampUtils.toString(timestamp) val chatRoomIsReadOnly = chatMessage.chatRoom.isReadOnly || - (!chatMessage.chatRoom.hasCapability(ChatRoom.Capabilities.Encrypted.toInt()) && isEndToEndEncryptionMandatory() == true) + (!chatMessage.chatRoom.hasCapability(ChatRoom.Capabilities.Encrypted.toInt()) && isEndToEndEncryptionMandatory()) val groupedWithNextMessage = MutableLiveData() diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationForwardMessageViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationForwardMessageViewModel.kt index e9d7ff0b1..5169f778a 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationForwardMessageViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationForwardMessageViewModel.kt @@ -22,49 +22,29 @@ package org.linphone.ui.main.chat.viewmodel import androidx.annotation.UiThread import androidx.annotation.WorkerThread import androidx.lifecycle.MutableLiveData -import java.text.Collator -import java.util.Locale import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R -import org.linphone.contacts.ContactsManager import org.linphone.contacts.getListOfSipAddressesAndPhoneNumbers import org.linphone.core.Address import org.linphone.core.ChatRoom import org.linphone.core.ChatRoomListenerStub import org.linphone.core.ChatRoomParams -import org.linphone.core.MagicSearch -import org.linphone.core.MagicSearchListenerStub -import org.linphone.core.SearchResult import org.linphone.core.tools.Log -import org.linphone.ui.GenericViewModel -import org.linphone.ui.main.chat.model.ConversationContactOrSuggestionModel -import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.ui.main.contacts.model.ContactNumberOrAddressClickListener import org.linphone.ui.main.contacts.model.ContactNumberOrAddressModel +import org.linphone.ui.main.model.ConversationContactOrSuggestionModel import org.linphone.ui.main.model.isEndToEndEncryptionMandatory +import org.linphone.ui.main.viewmodel.AddressSelectionViewModel import org.linphone.utils.AppUtils import org.linphone.utils.Event import org.linphone.utils.LinphoneUtils -class ConversationForwardMessageViewModel @UiThread constructor() : GenericViewModel() { +class ConversationForwardMessageViewModel @UiThread constructor() : AddressSelectionViewModel() { companion object { private const val TAG = "[Conversation Forward Message ViewModel]" } - protected var magicSearchSourceFlags = MagicSearch.Source.All.toInt() - - private var currentFilter = "" - private var previousFilter = "NotSet" - - val searchFilter = MutableLiveData() - - val conversationsContactsAndSuggestionsList = MutableLiveData>() - - private var limitSearchToLinphoneAccounts = true - - private lateinit var magicSearch: MagicSearch - val operationInProgress = MutableLiveData() val chatRoomCreatedEvent: MutableLiveData>> by lazy { @@ -79,26 +59,6 @@ class ConversationForwardMessageViewModel @UiThread constructor() : GenericViewM MutableLiveData>() } - private val magicSearchListener = object : MagicSearchListenerStub() { - @WorkerThread - override fun onSearchResultsReceived(magicSearch: MagicSearch) { - Log.i("$TAG Magic search contacts available") - processMagicSearchResults(magicSearch.lastSearch) - } - } - - private val contactsListener = object : ContactsManager.ContactsListener { - @WorkerThread - override fun onContactsLoaded() { - Log.i("$TAG Contacts have been (re)loaded, updating list") - applyFilter( - currentFilter, - if (limitSearchToLinphoneAccounts) corePreferences.defaultDomain else "", - magicSearchSourceFlags - ) - } - } - private val listener = object : ContactNumberOrAddressClickListener { @UiThread override fun onClicked(model: ContactNumberOrAddressModel) { @@ -152,182 +112,7 @@ class ConversationForwardMessageViewModel @UiThread constructor() : GenericViewM } init { - coreContext.postOnCoreThread { core -> - limitSearchToLinphoneAccounts = isEndToEndEncryptionMandatory() - - coreContext.contactsManager.addListener(contactsListener) - magicSearch = core.createMagicSearch() - magicSearch.limitedSearch = false - magicSearch.addListener(magicSearchListener) - } - - applyFilter(currentFilter) - } - - @UiThread - override fun onCleared() { - coreContext.postOnCoreThread { - magicSearch.removeListener(magicSearchListener) - coreContext.contactsManager.removeListener(contactsListener) - } - super.onCleared() - } - - @UiThread - fun clearFilter() { - if (searchFilter.value.orEmpty().isNotEmpty()) { - searchFilter.value = "" - } - } - - @UiThread - fun applyFilter(filter: String) { - coreContext.postOnCoreThread { - applyFilter( - filter, - if (limitSearchToLinphoneAccounts) corePreferences.defaultDomain else "", - magicSearchSourceFlags - ) - } - } - - @WorkerThread - private fun applyFilter( - filter: String, - domain: String, - sources: Int - ) { - if (previousFilter.isNotEmpty() && ( - previousFilter.length > filter.length || - (previousFilter.length == filter.length && previousFilter != filter) - ) - ) { - magicSearch.resetSearchCache() - } - currentFilter = filter - previousFilter = filter - - Log.i( - "$TAG Asking Magic search for contacts matching filter [$filter], domain [$domain] and in sources [$sources]" - ) - magicSearch.getContactsListAsync( - filter, - domain, - sources, - MagicSearch.Aggregation.Friend - ) - } - - @WorkerThread - private fun processMagicSearchResults(results: Array) { - Log.i("$TAG Processing [${results.size}] results") - - val conversationsList = arrayListOf() - for (chatRoom in LinphoneUtils.getDefaultAccount()?.chatRooms.orEmpty()) { - // Only get group conversations - if (!chatRoom.currentParams.isGroupEnabled) { - continue - } - - val found = if (currentFilter.isEmpty()) { - null - } else { - chatRoom.participants.find { - // Search in address but also in contact name if exists - val model = - coreContext.contactsManager.getContactAvatarModelForAddress(it.address) - model.contactName?.contains( - currentFilter, - ignoreCase = true - ) == true || it.address.asStringUriOnly().contains( - currentFilter, - ignoreCase = true - ) - } - } - if ( - currentFilter.isEmpty() || - found != null || - chatRoom.peerAddress.asStringUriOnly().contains(currentFilter, ignoreCase = true) || - chatRoom.subject.orEmpty().contains(currentFilter, ignoreCase = true) - ) { - val localAddress = chatRoom.localAddress - val remoteAddress = chatRoom.peerAddress - val model = ConversationContactOrSuggestionModel( - remoteAddress, - localAddress, - chatRoom.subject - ) - - val fakeFriend = coreContext.core.createFriend() - fakeFriend.name = chatRoom.subject - val avatarModel = ContactAvatarModel(fakeFriend) - avatarModel.defaultToConversationIcon.postValue(true) - - model.avatarModel.postValue(avatarModel) - conversationsList.add(model) - } - } - - val contactsList = arrayListOf() - val suggestionsList = arrayListOf() - - for (result in results) { - val address = result.address - if (address != null) { - val friend = coreContext.contactsManager.findContactByAddress(address) - if (friend != null) { - val model = ConversationContactOrSuggestionModel(address, friend = friend) - val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress( - address - ) - model.avatarModel.postValue(avatarModel) - - contactsList.add(model) - } else { - // If user-input generated result (always last) already exists, don't show it again - if (result.sourceFlags == MagicSearch.Source.Request.toInt()) { - val found = suggestionsList.find { - it.address.weakEqual(address) - } - if (found != null) { - Log.i( - "$TAG Result generated from user input is a duplicate of an existing solution, preventing double" - ) - 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) - } - } - } - - val collator = Collator.getInstance(Locale.getDefault()) - contactsList.sortWith { model1, model2 -> - collator.compare(model1.name, model2.name) - } - suggestionsList.sortWith { model1, model2 -> - collator.compare(model1.name, model2.name) - } - - val list = arrayListOf() - list.addAll(conversationsList) - list.addAll(contactsList) - list.addAll(suggestionsList) - conversationsContactsAndSuggestionsList.postValue(list) - Log.i( - "$TAG Processed [${results.size}] results, including [${conversationsList.size}] conversations, [${contactsList.size}] contacts and [${suggestionsList.size}] suggestions" - ) + skipConversation = false } @WorkerThread diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt index ed6c26e32..3182ee7f9 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt @@ -498,7 +498,7 @@ class ConversationViewModel @UiThread constructor() : AbstractConversationViewMo @WorkerThread fun checkIfConversationShouldBeDisabledForSecurityReasons() { if (!chatRoom.hasCapability(ChatRoom.Capabilities.Encrypted.toInt())) { - if (isEndToEndEncryptionMandatory() == true) { + if (isEndToEndEncryptionMandatory()) { Log.w( "$TAG Conversation with subject [${chatRoom.subject}] has been disabled because it isn't encrypted and default account is in secure mode" ) diff --git a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactViewModel.kt b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactViewModel.kt index 5c200f243..e368dd456 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/viewmodel/ContactViewModel.kt @@ -250,7 +250,7 @@ class ContactViewModel @UiThread constructor() : GenericViewModel() { ) // Only expand contacts' devices & trust by default if in E2E encrypted mode expandDevicesTrust.postValue( - isEndToEndEncryptionMandatory() == true + isEndToEndEncryptionMandatory() ) coreContext.contactsManager.addListener(contactsListener) } @@ -427,7 +427,7 @@ class ContactViewModel @UiThread constructor() : GenericViewModel() { val numbersCount = friend.phoneNumbers.size // Do not consider phone numbers if default account is in secure mode - val enablePhoneNumbers = isEndToEndEncryptionMandatory() != true + val enablePhoneNumbers = !isEndToEndEncryptionMandatory() if (addressesCount == 1 && (numbersCount == 0 || !enablePhoneNumbers)) { Log.i( @@ -464,7 +464,7 @@ class ContactViewModel @UiThread constructor() : GenericViewModel() { val numbersCount = friend.phoneNumbers.size // Do not consider phone numbers if default account is in secure mode - val enablePhoneNumbers = isEndToEndEncryptionMandatory() != true + val enablePhoneNumbers = !isEndToEndEncryptionMandatory() if (addressesCount == 1 && (numbersCount == 0 || !enablePhoneNumbers)) { Log.i( @@ -501,7 +501,7 @@ class ContactViewModel @UiThread constructor() : GenericViewModel() { val numbersCount = friend.phoneNumbers.size // Do not consider phone numbers if default account is in secure mode - val enablePhoneNumbers = isEndToEndEncryptionMandatory() != true + val enablePhoneNumbers = !isEndToEndEncryptionMandatory() if (addressesCount == 1 && (numbersCount == 0 || !enablePhoneNumbers)) { Log.i( 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 11e31b7d7..967537c6f 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 @@ -163,7 +163,7 @@ class ContactsListViewModel @UiThread constructor() : AbstractMainViewModel() { val defaultAccount = coreContext.core.defaultAccount val defaultDomain = defaultAccount?.params?.domain == corePreferences.defaultDomain isDefaultAccountLinphone.postValue(defaultDomain) - domainFilter = if (isEndToEndEncryptionMandatory() == true) { + domainFilter = if (isEndToEndEncryptionMandatory()) { corePreferences.defaultDomain } else { "*" diff --git a/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt b/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt index 706f54255..125b650b3 100644 --- a/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/fragment/AddParticipantsFragment.kt @@ -85,7 +85,7 @@ class AddParticipantsFragment : GenericAddressPickerFragment() { viewModel.addSelectedParticipants(participants) } - viewModel.contactsAndSuggestionsList.observe( + viewModel.modelsList.observe( viewLifecycleOwner ) { Log.i("$TAG Contacts & suggestions list is ready with [${it.size}] items") diff --git a/app/src/main/java/org/linphone/ui/main/fragment/GenericAddressPickerFragment.kt b/app/src/main/java/org/linphone/ui/main/fragment/GenericAddressPickerFragment.kt index c199afa30..c3e88f410 100644 --- a/app/src/main/java/org/linphone/ui/main/fragment/GenericAddressPickerFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/fragment/GenericAddressPickerFragment.kt @@ -31,11 +31,11 @@ import org.linphone.contacts.getListOfSipAddressesAndPhoneNumbers import org.linphone.core.Address import org.linphone.core.Friend import org.linphone.core.tools.Log +import org.linphone.ui.adapter.ConversationsContactsAndSuggestionsListAdapter import org.linphone.ui.main.contacts.model.ContactNumberOrAddressClickListener import org.linphone.ui.main.contacts.model.ContactNumberOrAddressModel import org.linphone.ui.main.contacts.model.NumberOrAddressPickerDialogModel -import org.linphone.ui.main.history.adapter.ContactsAndSuggestionsListAdapter -import org.linphone.ui.main.history.model.ContactOrSuggestionModel +import org.linphone.ui.main.model.ConversationContactOrSuggestionModel import org.linphone.ui.main.model.SelectedAddressModel import org.linphone.ui.main.model.isEndToEndEncryptionMandatory import org.linphone.ui.main.viewmodel.AddressSelectionViewModel @@ -51,7 +51,7 @@ abstract class GenericAddressPickerFragment : GenericMainFragment() { private var numberOrAddressPickerDialog: Dialog? = null - protected lateinit var adapter: ContactsAndSuggestionsListAdapter + protected lateinit var adapter: ConversationsContactsAndSuggestionsListAdapter protected abstract val viewModel: AddressSelectionViewModel @@ -85,13 +85,13 @@ abstract class GenericAddressPickerFragment : GenericMainFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - adapter = ContactsAndSuggestionsListAdapter() + adapter = ConversationsContactsAndSuggestionsListAdapter() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - adapter.contactClickedEvent.observe(viewLifecycleOwner) { + adapter.onClickedEvent.observe(viewLifecycleOwner) { it.consume { model -> handleClickOnContactModel(model) } @@ -147,7 +147,7 @@ abstract class GenericAddressPickerFragment : GenericMainFragment() { } } - private fun handleClickOnContactModel(model: ContactOrSuggestionModel) { + private fun handleClickOnContactModel(model: ConversationContactOrSuggestionModel) { coreContext.postOnCoreThread { core -> val friend = model.friend if (friend == null) { @@ -162,7 +162,7 @@ abstract class GenericAddressPickerFragment : GenericMainFragment() { val numbersCount = friend.phoneNumbers.size // Do not consider phone numbers if default account is in secure mode - val enablePhoneNumbers = isEndToEndEncryptionMandatory() != true + val enablePhoneNumbers = !isEndToEndEncryptionMandatory() if (addressesCount == 1 && (numbersCount == 0 || !enablePhoneNumbers)) { val address = friend.addresses.first() diff --git a/app/src/main/java/org/linphone/ui/main/history/adapter/ContactsAndSuggestionsListAdapter.kt b/app/src/main/java/org/linphone/ui/main/history/adapter/ContactsAndSuggestionsListAdapter.kt deleted file mode 100644 index f4278f33a..000000000 --- a/app/src/main/java/org/linphone/ui/main/history/adapter/ContactsAndSuggestionsListAdapter.kt +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2010-2023 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 . - */ -package org.linphone.ui.main.history.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.annotation.UiThread -import androidx.databinding.DataBindingUtil -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.findViewTreeLifecycleOwner -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import org.linphone.R -import org.linphone.databinding.ContactListCellBinding -import org.linphone.databinding.StartCallSuggestionListCellBinding -import org.linphone.databinding.StartCallSuggestionListDecorationBinding -import org.linphone.ui.main.history.model.ContactOrSuggestionModel -import org.linphone.utils.AppUtils -import org.linphone.utils.Event -import org.linphone.utils.HeaderAdapter - -class ContactsAndSuggestionsListAdapter : - ListAdapter( - ContactOrSuggestionDiffCallback() - ), - HeaderAdapter { - companion object { - private const val CONTACT_TYPE = 0 - private const val SUGGESTION_TYPE = 1 - } - - val contactClickedEvent: MutableLiveData> by lazy { - MutableLiveData>() - } - - override fun displayHeaderForPosition(position: Int): Boolean { - val model = getItem(position) - if (position == 0) { - return true - } else if (model.friend == null) { - val previousModel = getItem(position - 1) - return previousModel.friend != null - } - return false - } - - override fun getHeaderViewForPosition(context: Context, position: Int): View { - val binding = StartCallSuggestionListDecorationBinding.inflate(LayoutInflater.from(context)) - binding.header.text = if (position == 0) { - if (getItemViewType(0) == SUGGESTION_TYPE) { - AppUtils.getString(R.string.history_call_start_suggestions_list_title) - } else { - AppUtils.getString(R.string.history_call_start_contacts_list_title) - } - } else { - AppUtils.getString(R.string.history_call_start_suggestions_list_title) - } - return binding.root - } - - override fun getItemViewType(position: Int): Int { - val model = getItem(position) - return if (model.friend == null) SUGGESTION_TYPE else CONTACT_TYPE - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - return when (viewType) { - CONTACT_TYPE -> { - val binding: ContactListCellBinding = DataBindingUtil.inflate( - LayoutInflater.from(parent.context), - R.layout.contact_list_cell, - parent, - false - ) - binding.lifecycleOwner = parent.findViewTreeLifecycleOwner() - ContactViewHolder(binding) - } - else -> { - val binding: StartCallSuggestionListCellBinding = DataBindingUtil.inflate( - LayoutInflater.from(parent.context), - R.layout.start_call_suggestion_list_cell, - parent, - false - ) - binding.apply { - lifecycleOwner = parent.findViewTreeLifecycleOwner() - - setOnClickListener { - contactClickedEvent.value = Event(model!!) - } - } - SuggestionViewHolder(binding) - } - } - } - - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - when (getItemViewType(position)) { - CONTACT_TYPE -> (holder as ContactViewHolder).bind(getItem(position)) - else -> (holder as SuggestionViewHolder).bind(getItem(position)) - } - } - - inner class ContactViewHolder( - val binding: ContactListCellBinding - ) : RecyclerView.ViewHolder(binding.root) { - @UiThread - fun bind(contactOrSuggestionModel: ContactOrSuggestionModel) { - with(binding) { - model = contactOrSuggestionModel.avatarModel.value - - setOnClickListener { - contactClickedEvent.value = Event(contactOrSuggestionModel) - } - - val previousItem = bindingAdapterPosition - 1 - val previousLetter = if (previousItem >= 0) { - getItem(previousItem).name[0].toString() - } else { - "" - } - - val currentLetter = contactOrSuggestionModel.name[0].toString() - val displayLetter = previousLetter.isEmpty() || currentLetter != previousLetter - firstContactStartingByThatLetter = displayLetter - - executePendingBindings() - } - } - } - - inner class SuggestionViewHolder( - val binding: StartCallSuggestionListCellBinding - ) : RecyclerView.ViewHolder(binding.root) { - @UiThread - fun bind(contactOrSuggestionModel: ContactOrSuggestionModel) { - with(binding) { - model = contactOrSuggestionModel - executePendingBindings() - } - } - } - - private class ContactOrSuggestionDiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame( - oldItem: ContactOrSuggestionModel, - newItem: ContactOrSuggestionModel - ): Boolean { - return oldItem.id == newItem.id - } - - override fun areContentsTheSame( - oldItem: ContactOrSuggestionModel, - newItem: ContactOrSuggestionModel - ): Boolean { - return false - } - } -} diff --git a/app/src/main/java/org/linphone/ui/main/history/fragment/StartCallFragment.kt b/app/src/main/java/org/linphone/ui/main/history/fragment/StartCallFragment.kt index e59f753f1..8f964e234 100644 --- a/app/src/main/java/org/linphone/ui/main/history/fragment/StartCallFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/history/fragment/StartCallFragment.kt @@ -91,7 +91,7 @@ class StartCallFragment : GenericAddressPickerFragment() { setupRecyclerView(binding.contactsAndSuggestionsList) - viewModel.contactsAndSuggestionsList.observe( + viewModel.modelsList.observe( viewLifecycleOwner ) { Log.i("$TAG Contacts & suggestions list is ready with [${it.size}] items") diff --git a/app/src/main/java/org/linphone/ui/main/history/model/ContactOrSuggestionModel.kt b/app/src/main/java/org/linphone/ui/main/history/model/ContactOrSuggestionModel.kt deleted file mode 100644 index 9100408d6..000000000 --- a/app/src/main/java/org/linphone/ui/main/history/model/ContactOrSuggestionModel.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2010-2023 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 . - */ -package org.linphone.ui.main.history.model - -import androidx.annotation.UiThread -import androidx.annotation.WorkerThread -import androidx.lifecycle.MutableLiveData -import org.linphone.core.Address -import org.linphone.core.Friend -import org.linphone.ui.main.contacts.model.ContactAvatarModel -import org.linphone.utils.AppUtils -import org.linphone.utils.LinphoneUtils - -class ContactOrSuggestionModel @WorkerThread constructor( - val address: Address, - val friend: Friend? = null, - private val onClicked: ((Address) -> Unit)? = null -) { - val id = friend?.refKey ?: address.asStringUriOnly().hashCode() - - val name = if (friend != null) { - friend.name ?: LinphoneUtils.getDisplayName(address) - } else { - address.username.orEmpty() - } - - val sipUri = address.asStringUriOnly() - - val initials = AppUtils.getInitials(name) - - val avatarModel = MutableLiveData() - - @UiThread - fun onClicked() { - onClicked?.invoke(address) - } -} diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/ConversationContactOrSuggestionModel.kt b/app/src/main/java/org/linphone/ui/main/model/ConversationContactOrSuggestionModel.kt similarity index 95% rename from app/src/main/java/org/linphone/ui/main/chat/model/ConversationContactOrSuggestionModel.kt rename to app/src/main/java/org/linphone/ui/main/model/ConversationContactOrSuggestionModel.kt index 71ee77e62..419bff3d9 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/ConversationContactOrSuggestionModel.kt +++ b/app/src/main/java/org/linphone/ui/main/model/ConversationContactOrSuggestionModel.kt @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.linphone.ui.main.chat.model +package org.linphone.ui.main.model import androidx.annotation.UiThread import androidx.annotation.WorkerThread @@ -31,7 +31,7 @@ import org.linphone.utils.LinphoneUtils class ConversationContactOrSuggestionModel @WorkerThread constructor( val address: Address, val localAddress: Address? = null, - private val conversationSubject: String? = null, + conversationSubject: String? = null, val friend: Friend? = null, private val onClicked: ((Address) -> Unit)? = null ) { diff --git a/app/src/main/java/org/linphone/ui/main/settings/model/CodecModel.kt b/app/src/main/java/org/linphone/ui/main/settings/model/CodecModel.kt index 9ea8bb89f..cc2237609 100644 --- a/app/src/main/java/org/linphone/ui/main/settings/model/CodecModel.kt +++ b/app/src/main/java/org/linphone/ui/main/settings/model/CodecModel.kt @@ -25,9 +25,9 @@ import androidx.lifecycle.MutableLiveData class CodecModel @WorkerThread constructor( val mimeType: String, - val clockRate: Int, - val recvFmtp: String?, - val isAudioCodec: Boolean, + clockRate: Int, + recvFmtp: String?, + private val isAudioCodec: Boolean, enabled: Boolean, val onEnabledChanged: ((enabled: Boolean) -> Unit) ) { 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 311634269..a9b81e065 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 @@ -79,7 +79,6 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { val showConversationsSettings = MutableLiveData() val autoDownloadEnabled = MutableLiveData() - val exportMediaEnabled = MutableLiveData() // Contacts settings val showContactsSettings = MutableLiveData() diff --git a/app/src/main/java/org/linphone/ui/main/viewmodel/AddressSelectionViewModel.kt b/app/src/main/java/org/linphone/ui/main/viewmodel/AddressSelectionViewModel.kt index 939c79ed1..0ba5aa32e 100644 --- a/app/src/main/java/org/linphone/ui/main/viewmodel/AddressSelectionViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/viewmodel/AddressSelectionViewModel.kt @@ -32,10 +32,12 @@ import org.linphone.core.MagicSearch import org.linphone.core.MagicSearchListenerStub import org.linphone.core.SearchResult import org.linphone.mediastream.Log -import org.linphone.ui.main.history.model.ContactOrSuggestionModel +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 abstract class AddressSelectionViewModel @UiThread constructor() : DefaultAccountChangedViewModel() { companion object { @@ -48,15 +50,19 @@ abstract class AddressSelectionViewModel @UiThread constructor() : DefaultAccoun val selectionCount = MutableLiveData() + val searchFilter = MutableLiveData() + + val modelsList = MutableLiveData>() + + val isEmpty = MutableLiveData() + protected var magicSearchSourceFlags = MagicSearch.Source.All.toInt() + protected var skipConversation: Boolean = true + private var currentFilter = "" private var previousFilter = "NotSet" - val searchFilter = MutableLiveData() - - val contactsAndSuggestionsList = MutableLiveData>() - private var limitSearchToLinphoneAccounts = true private lateinit var magicSearch: MagicSearch @@ -83,6 +89,7 @@ abstract class AddressSelectionViewModel @UiThread constructor() : DefaultAccoun init { multipleSelectionMode.value = false + isEmpty.value = true coreContext.postOnCoreThread { core -> limitSearchToLinphoneAccounts = isEndToEndEncryptionMandatory() @@ -221,15 +228,67 @@ abstract class AddressSelectionViewModel @UiThread constructor() : DefaultAccoun private fun processMagicSearchResults(results: Array) { Log.i("$TAG Processing [${results.size}] results") - val contactsList = arrayListOf() - val suggestionsList = arrayListOf() + val conversationsList = arrayListOf() + if (!skipConversation) { + for (chatRoom in LinphoneUtils.getDefaultAccount()?.chatRooms.orEmpty()) { + // Only get group conversations + if (!chatRoom.currentParams.isGroupEnabled) { + continue + } + + val found = if (currentFilter.isEmpty()) { + null + } else { + chatRoom.participants.find { + // Search in address but also in contact name if exists + val model = + coreContext.contactsManager.getContactAvatarModelForAddress(it.address) + model.contactName?.contains( + currentFilter, + ignoreCase = true + ) == true || it.address.asStringUriOnly().contains( + currentFilter, + ignoreCase = true + ) + } + } + if ( + currentFilter.isEmpty() || + found != null || + chatRoom.peerAddress.asStringUriOnly().contains( + currentFilter, + ignoreCase = true + ) || + chatRoom.subject.orEmpty().contains(currentFilter, ignoreCase = true) + ) { + val localAddress = chatRoom.localAddress + val remoteAddress = chatRoom.peerAddress + val model = ConversationContactOrSuggestionModel( + remoteAddress, + localAddress, + chatRoom.subject + ) + + val fakeFriend = coreContext.core.createFriend() + fakeFriend.name = chatRoom.subject + val avatarModel = ContactAvatarModel(fakeFriend) + avatarModel.defaultToConversationIcon.postValue(true) + + model.avatarModel.postValue(avatarModel) + conversationsList.add(model) + } + } + } + + val contactsList = arrayListOf() + val suggestionsList = arrayListOf() for (result in results) { val address = result.address if (address != null) { val friend = coreContext.contactsManager.findContactByAddress(address) if (friend != null) { - val model = ContactOrSuggestionModel(address, friend) + val model = ConversationContactOrSuggestionModel(address, friend = friend) val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress( address ) @@ -255,7 +314,7 @@ abstract class AddressSelectionViewModel @UiThread constructor() : DefaultAccoun continue } - val model = ContactOrSuggestionModel(address) { + val model = ConversationContactOrSuggestionModel(address) { coreContext.startAudioCall(address) } @@ -272,12 +331,14 @@ abstract class AddressSelectionViewModel @UiThread constructor() : DefaultAccoun collator.compare(model1.name, model2.name) } - val list = arrayListOf() + val list = arrayListOf() + list.addAll(conversationsList) list.addAll(contactsList) list.addAll(suggestionsList) - contactsAndSuggestionsList.postValue(list) + modelsList.postValue(list) + isEmpty.postValue(list.isEmpty()) Log.i( - "$TAG Processed [${results.size}] results, extracted [${suggestionsList.size}] suggestions" + "$TAG Processed [${results.size}] results: [${conversationsList.size}] conversations, [${contactsList.size}] contacts and [${suggestionsList.size}] suggestions" ) } } diff --git a/app/src/main/res/layout/chat_message_forward_fragment.xml b/app/src/main/res/layout/chat_message_forward_fragment.xml index f47fc0124..0321671b9 100644 --- a/app/src/main/res/layout/chat_message_forward_fragment.xml +++ b/app/src/main/res/layout/chat_message_forward_fragment.xml @@ -93,7 +93,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:layout_marginTop="8dp" - android:visibility="@{viewModel.conversationsContactsAndSuggestionsList.size() == 0 ? View.GONE : View.VISIBLE}" + android:visibility="@{viewModel.isEmpty ? View.GONE : View.VISIBLE}" app:layout_constraintTop_toBottomOf="@id/search_bar" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/chat_message_forward_suggestion_list_cell.xml b/app/src/main/res/layout/chat_message_forward_suggestion_list_cell.xml deleted file mode 100644 index 96ed2e62c..000000000 --- a/app/src/main/res/layout/chat_message_forward_suggestion_list_cell.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/generic_add_participants_fragment.xml b/app/src/main/res/layout/generic_add_participants_fragment.xml index 65963fced..313a280ea 100644 --- a/app/src/main/res/layout/generic_add_participants_fragment.xml +++ b/app/src/main/res/layout/generic_add_participants_fragment.xml @@ -134,7 +134,7 @@ android:layout_margin="10dp" android:src="@drawable/illu" android:contentDescription="@null" - android:visibility="@{viewModel.contactsAndSuggestionsList.size() == 0 ? View.VISIBLE : View.GONE}" + android:visibility="@{viewModel.isEmpty ? View.VISIBLE : View.GONE}" app:layout_constraintDimensionRatio="1:1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHeight_max="200dp" @@ -150,7 +150,7 @@ android:layout_height="wrap_content" android:text="@{viewModel.searchFilter.length() > 0 ? @string/new_conversation_no_matching_contact : @string/new_conversation_no_contact, default=@string/new_conversation_no_contact}" android:gravity="center" - android:visibility="@{viewModel.contactsAndSuggestionsList.size() == 0 ? View.VISIBLE : View.GONE}" + android:visibility="@{viewModel.isEmpty ? View.VISIBLE : View.GONE}" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/no_contact_image" /> @@ -160,7 +160,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:layout_marginTop="8dp" - android:visibility="@{viewModel.contactsAndSuggestionsList.size() == 0 ? View.GONE : View.VISIBLE}" + android:visibility="@{viewModel.isEmpty ? View.GONE : View.VISIBLE}" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/search_bar" diff --git a/app/src/main/res/layout/chat_message_forward_contact_list_cell.xml b/app/src/main/res/layout/generic_address_picker_contact_list_cell.xml similarity index 94% rename from app/src/main/res/layout/chat_message_forward_contact_list_cell.xml rename to app/src/main/res/layout/generic_address_picker_contact_list_cell.xml index 7ebdc0022..33567f776 100644 --- a/app/src/main/res/layout/chat_message_forward_contact_list_cell.xml +++ b/app/src/main/res/layout/generic_address_picker_contact_list_cell.xml @@ -6,15 +6,15 @@ - + diff --git a/app/src/main/res/layout/chat_message_forward_conversation_list_cell.xml b/app/src/main/res/layout/generic_address_picker_conversation_list_cell.xml similarity index 96% rename from app/src/main/res/layout/chat_message_forward_conversation_list_cell.xml rename to app/src/main/res/layout/generic_address_picker_conversation_list_cell.xml index 6ca96de31..03108152c 100644 --- a/app/src/main/res/layout/chat_message_forward_conversation_list_cell.xml +++ b/app/src/main/res/layout/generic_address_picker_conversation_list_cell.xml @@ -11,7 +11,7 @@ type="View.OnClickListener" /> + type="org.linphone.ui.main.model.ConversationContactOrSuggestionModel" /> \ No newline at end of file diff --git a/app/src/main/res/layout/start_call_suggestion_list_cell.xml b/app/src/main/res/layout/generic_address_picker_suggestion_list_cell.xml similarity index 96% rename from app/src/main/res/layout/start_call_suggestion_list_cell.xml rename to app/src/main/res/layout/generic_address_picker_suggestion_list_cell.xml index 8288a89e3..b42081728 100644 --- a/app/src/main/res/layout/start_call_suggestion_list_cell.xml +++ b/app/src/main/res/layout/generic_address_picker_suggestion_list_cell.xml @@ -10,7 +10,7 @@ type="View.OnClickListener" /> + type="org.linphone.ui.main.model.ConversationContactOrSuggestionModel" /> @@ -242,7 +242,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:layout_marginTop="8dp" - android:visibility="@{viewModel.contactsAndSuggestionsList.size() == 0 ? View.GONE : View.VISIBLE}" + android:visibility="@{viewModel.isEmpty ? View.GONE : View.VISIBLE}" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/group_call_icon" diff --git a/app/src/main/res/layout/start_chat_fragment.xml b/app/src/main/res/layout/start_chat_fragment.xml index 9f623afae..83883bc74 100644 --- a/app/src/main/res/layout/start_chat_fragment.xml +++ b/app/src/main/res/layout/start_chat_fragment.xml @@ -198,7 +198,7 @@ android:layout_margin="10dp" android:src="@drawable/illu" android:contentDescription="@null" - android:visibility="@{viewModel.contactsAndSuggestionsList.size() == 0 ? View.VISIBLE : View.GONE}" + android:visibility="@{viewModel.isEmpty ? View.VISIBLE : View.GONE}" app:layout_constraintDimensionRatio="1:1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHeight_max="200dp" @@ -214,7 +214,7 @@ android:layout_height="wrap_content" android:text="@{viewModel.searchFilter.length() > 0 ? @string/new_conversation_no_matching_contact : @string/new_conversation_no_contact, default=@string/new_conversation_no_contact}" android:gravity="center" - android:visibility="@{viewModel.contactsAndSuggestionsList.size() == 0 ? View.VISIBLE : View.GONE}" + android:visibility="@{viewModel.isEmpty ? View.VISIBLE : View.GONE}" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/no_contact_image" /> @@ -224,7 +224,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:layout_marginTop="8dp" - android:visibility="@{viewModel.contactsAndSuggestionsList.size() == 0 ? View.GONE : View.VISIBLE}" + android:visibility="@{viewModel.isEmpty ? View.GONE : View.VISIBLE}" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/group_chat_icon" diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 66d56747a..bb857aa28 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -36,7 +36,6 @@ OK Appeler Supprimer - Fermer Installer Ne plus me montrer ce message Non @@ -183,7 +182,6 @@ Appels Utiliser l\'annulateur d\'écho Évite que de l\'écho soit entendu par votre correspondant - Utiliser le périphérique Bluetooth si possible Activer la vidéo Activer la FEC vidéo Vibrer lors de la réception d\'un appel @@ -306,8 +304,6 @@ Cherchez un contact ou une suggestion Démarrer un appel de groupe Aucun contact ni suggestion pour le moment… - Contacts - Suggestions Nommer l\'appel de groupe Nom de l\'appel de groupe Aucun appel dans votre historique… @@ -379,7 +375,6 @@ Aucune conversation pour le moment… En cours de suppression… %s : - Message en attente de transfert %s fichier en attente de partage %s fichiers en attente de partage @@ -495,7 +490,6 @@ Transférer à… Le message a été transféré Transfert du message abandonné - Conversations Lu %s Reçu %s @@ -691,6 +685,9 @@ Vous n\'êtes pas connecté à internet Opération en cours, merci de patienter… + Conversations + Contacts + Suggestions Passer diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ec3502469..17775d160 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -72,7 +72,6 @@ OK Call Delete - Close Install Do not show this dialog anymore No @@ -219,7 +218,6 @@ Calls Use echo canceller Prevents echo from being heard by remote end - Route audio to bluetooth device, if any Enable video Enable video FEC Vibrate while incoming call is ringing @@ -343,8 +341,6 @@ Search contact or history call Create a group call No suggestion and no contact for the moment… - Contacts - Suggestions Set group call subject Group call subject No call for the moment… @@ -416,7 +412,6 @@ No conversation for the moment… Removal in progress… %s: - A message is waiting to be forwarded %s file waiting to be shared %s files waiting to be shared @@ -532,7 +527,6 @@ Forward message to… Message was forwarded Message forward was cancelled - Conversations Read %s Received %s @@ -728,6 +722,9 @@ You aren\'t connected to internet Operation in progress, please wait + Conversations + Contacts + Suggestions Skip