diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SelectContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SelectContactActivity.kt index 7b02031f..0122f50b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SelectContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SelectContactActivity.kt @@ -118,7 +118,34 @@ class SelectContactActivity : SimpleActivity() { } private fun onSearchQueryChanged(text: String) { + val adapter = select_contact_list.adapter + if (adapter != null && adapter is SelectContactsAdapter) { + val shouldNormalize = text.normalizeString() == text + val filtered = contactsIgnoringSearch.filter { + getProperText(it.getNameToDisplay(), shouldNormalize).contains(text, true) || + getProperText(it.nickname, shouldNormalize).contains(text, true) || + it.doesContainPhoneNumber(text, false) || + it.emails.any { it.value.contains(text, true) } || + it.addresses.any { getProperText(it.value, shouldNormalize).contains(text, true) } || + it.IMs.any { it.value.contains(text, true) } || + getProperText(it.notes, shouldNormalize).contains(text, true) || + getProperText(it.organization.company, shouldNormalize).contains(text, true) || + getProperText(it.organization.jobPosition, shouldNormalize).contains(text, true) || + it.websites.any { it.contains(text, true) } + } as ArrayList + filtered.sortBy { + val nameToDisplay = it.getNameToDisplay() + !getProperText(nameToDisplay, shouldNormalize).startsWith(text, true) && !nameToDisplay.contains(text, true) + } + + if (filtered.isEmpty()) { + select_contact_placeholder.text = getString(R.string.no_items_found) + } + + select_contact_placeholder.beVisibleIf(filtered.isEmpty()) + adapter.updateItems(filtered, text.normalizeString()) + } } private fun onSearchOpened() { @@ -126,9 +153,11 @@ class SelectContactActivity : SimpleActivity() { } private fun onSearchClosed() { - + (select_contact_list.adapter as? SelectContactsAdapter)?.updateItems(contactsIgnoringSearch) } + private fun getProperText(text: String, shouldNormalize: Boolean) = if (shouldNormalize) text.normalizeString() else text + private fun showSortingDialog() { ChangeSortingDialog(this) { initContacts() @@ -165,7 +194,7 @@ class SelectContactActivity : SimpleActivity() { runOnUiThread { updatePlaceholderVisibility(contacts) - SelectContactsAdapter(this, contacts, ArrayList(), false, select_contact_list) { + SelectContactsAdapter(this, contacts, ArrayList(), false, select_contact_list, select_contact_fastscroller) { confirmSelection(it) }.apply { select_contact_list.adapter = this diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/SelectContactsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/SelectContactsAdapter.kt index d8c4e1fa..35ba0a5f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/SelectContactsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/SelectContactsAdapter.kt @@ -1,6 +1,10 @@ package com.simplemobiletools.contacts.pro.adapters import android.graphics.drawable.Drawable +import android.telephony.PhoneNumberUtils +import android.text.Spannable +import android.text.SpannableString +import android.text.style.ForegroundColorSpan import android.util.SparseArray import android.view.View import android.view.ViewGroup @@ -13,6 +17,8 @@ import com.bumptech.glide.signature.ObjectKey import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor import com.simplemobiletools.commons.extensions.getColoredDrawableWithColor +import com.simplemobiletools.commons.extensions.highlightTextPart +import com.simplemobiletools.commons.views.FastScroller import com.simplemobiletools.commons.views.MyRecyclerView import com.simplemobiletools.contacts.pro.R import com.simplemobiletools.contacts.pro.activities.SimpleActivity @@ -22,15 +28,19 @@ import com.simplemobiletools.contacts.pro.models.Contact import kotlinx.android.synthetic.main.item_add_favorite_with_number.view.* import java.util.* -class SelectContactsAdapter(val activity: SimpleActivity, val contacts: ArrayList, private val selectedContacts: ArrayList, private val allowPickMultiple: Boolean, - private val recyclerView: MyRecyclerView, private val itemClick: ((Contact) -> Unit)? = null) : RecyclerView.Adapter() { +class SelectContactsAdapter(val activity: SimpleActivity, var contacts: ArrayList, private val selectedContacts: ArrayList, private val allowPickMultiple: Boolean, + recyclerView: MyRecyclerView, val fastScroller: FastScroller, private val itemClick: ((Contact) -> Unit)? = null) : + RecyclerView.Adapter() { private val itemViews = SparseArray() private val selectedPositions = HashSet() private val config = activity.config private val textColor = config.textColor + private val adjustedPrimaryColor = activity.getAdjustedPrimaryColor() + private val contactDrawable = activity.resources.getColoredDrawableWithColor(R.drawable.ic_person_vector, textColor) private val showContactThumbnails = config.showContactThumbnails private val itemLayout = if (config.showPhoneNumbers) R.layout.item_add_favorite_with_number else R.layout.item_add_favorite_without_number + private var textToHighlight = "" private var smallPadding = activity.resources.getDimension(R.dimen.small_margin).toInt() private var bigPadding = activity.resources.getDimension(R.dimen.normal_margin).toInt() @@ -78,6 +88,25 @@ class SelectContactsAdapter(val activity: SimpleActivity, val contacts: ArrayLis override fun getItemCount() = contacts.size + fun updateItems(newItems: ArrayList, highlightText: String = "") { + if (newItems.hashCode() != contacts.hashCode()) { + contacts = newItems.clone() as ArrayList + textToHighlight = highlightText + notifyDataSetChanged() + } else if (textToHighlight != highlightText) { + textToHighlight = highlightText + notifyDataSetChanged() + } + fastScroller.measureRecyclerView() + } + + override fun onViewRecycled(holder: ViewHolder) { + super.onViewRecycled(holder) + if (!activity.isDestroyed && !activity.isFinishing) { + Glide.with(activity).clear(holder.itemView.contact_tmb) + } + } + inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { fun bindView(contact: Contact, contactDrawable: Drawable, config: Config, showContactThumbnails: Boolean, smallPadding: Int, bigPadding: Int): View { @@ -86,13 +115,30 @@ class SelectContactsAdapter(val activity: SimpleActivity, val contacts: ArrayLis contact_checkbox.setColors(config.textColor, context.getAdjustedPrimaryColor(), config.backgroundColor) val textColor = config.textColor - contact_name.text = contact.getNameToDisplay() + val fullName = contact.getNameToDisplay() + contact_name.text = if (textToHighlight.isEmpty()) fullName else { + if (fullName.contains(textToHighlight, true)) { + fullName.highlightTextPart(textToHighlight, adjustedPrimaryColor) + } else { + highlightTextFromNumbers(fullName, textToHighlight) + } + } + contact_name.setTextColor(textColor) contact_name.setPadding(if (showContactThumbnails) smallPadding else bigPadding, smallPadding, smallPadding, 0) - contact_number?.text = contact.phoneNumbers.firstOrNull()?.value ?: "" - contact_number?.setTextColor(textColor) - contact_number?.setPadding(if (showContactThumbnails) smallPadding else bigPadding, 0, smallPadding, 0) + if (contact_number != null) { + val phoneNumberToUse = if (textToHighlight.isEmpty()) { + contact.phoneNumbers.firstOrNull() + } else { + contact.phoneNumbers.firstOrNull { it.value.contains(textToHighlight) } ?: contact.phoneNumbers.firstOrNull() + } + + val numberText = phoneNumberToUse?.value ?: "" + contact_number.text = if (textToHighlight.isEmpty()) numberText else numberText.highlightTextPart(textToHighlight, adjustedPrimaryColor, false, true) + contact_number.setTextColor(textColor) + contact_number.setPadding(if (showContactThumbnails) smallPadding else bigPadding, 0, smallPadding, 0) + } contact_frame.setOnClickListener { if (itemClick != null) { @@ -128,10 +174,18 @@ class SelectContactsAdapter(val activity: SimpleActivity, val contacts: ArrayLis } } - override fun onViewRecycled(holder: ViewHolder) { - super.onViewRecycled(holder) - if (!activity.isDestroyed && !activity.isFinishing) { - Glide.with(activity).clear(holder.itemView.contact_tmb) + private fun highlightTextFromNumbers(name: String, textToHighlight: String): SpannableString { + val spannableString = SpannableString(name) + val digits = PhoneNumberUtils.convertKeypadLettersToDigits(name) + if (digits.contains(textToHighlight)) { + val startIndex = digits.indexOf(textToHighlight, 0, true) + val endIndex = Math.min(startIndex + textToHighlight.length, name.length) + try { + spannableString.setSpan(ForegroundColorSpan(adjustedPrimaryColor), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_INCLUSIVE) + } catch (ignored: IndexOutOfBoundsException) { + } } + + return spannableString } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactsDialog.kt index 5e93f5a0..3f8fc29d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactsDialog.kt @@ -29,7 +29,7 @@ class SelectContactsDialog(val activity: SimpleActivity, initialContacts: ArrayL activity.runOnUiThread { view.apply { - select_contact_list.adapter = SelectContactsAdapter(activity, allContacts, initiallySelectedContacts, true, select_contact_list) + select_contact_list.adapter = SelectContactsAdapter(activity, allContacts, initiallySelectedContacts, true, select_contact_list, select_contact_fastscroller) select_contact_fastscroller.allowBubbleDisplay = activity.baseConfig.showInfoBubble select_contact_fastscroller.setViews(select_contact_list) { select_contact_fastscroller.updateBubbleText(allContacts[it].getBubbleText()) diff --git a/app/src/main/res/layout/layout_select_contact.xml b/app/src/main/res/layout/layout_select_contact.xml index d2dde128..f6efaa90 100644 --- a/app/src/main/res/layout/layout_select_contact.xml +++ b/app/src/main/res/layout/layout_select_contact.xml @@ -12,20 +12,18 @@ android:layout_height="wrap_content" android:clipToPadding="false" android:scrollbars="none" - app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/> + app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager" /> - +