diff --git a/app/build.gradle b/app/build.gradle index 5cae5e7a..016abf3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -63,7 +63,7 @@ android { } dependencies { - implementation 'com.github.SimpleMobileTools:Simple-Commons:94b616f462' + implementation 'com.github.SimpleMobileTools:Simple-Commons:8a1114e683' implementation 'com.googlecode.ez-vcard:ez-vcard:0.11.3' implementation 'com.github.tibbi:IndicatorFastScroll:4524cd0b61' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt index ae35e22d..a23049b5 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt @@ -10,6 +10,7 @@ import android.media.AudioManager import android.media.RingtoneManager import android.net.Uri import android.os.Bundle +import android.os.Handler import android.provider.ContactsContract.CommonDataKinds import android.provider.ContactsContract.CommonDataKinds.* import android.provider.MediaStore @@ -17,12 +18,10 @@ import android.telephony.PhoneNumberUtils import android.view.View import android.view.ViewGroup import android.view.WindowManager -import android.widget.EditText -import android.widget.ImageView -import android.widget.RelativeLayout -import android.widget.TextView +import android.widget.* import androidx.core.content.ContextCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.widget.doAfterTextChanged import com.simplemobiletools.commons.dialogs.ConfirmationAdvancedDialog import com.simplemobiletools.commons.dialogs.RadioGroupDialog import com.simplemobiletools.commons.dialogs.SelectAlarmSoundDialog @@ -34,7 +33,9 @@ import com.simplemobiletools.commons.models.contacts.* import com.simplemobiletools.commons.models.contacts.Email import com.simplemobiletools.commons.models.contacts.Event import com.simplemobiletools.commons.models.contacts.Organization +import com.simplemobiletools.commons.views.MyAutoCompleteTextView import com.simplemobiletools.contacts.pro.R +import com.simplemobiletools.contacts.pro.adapters.AutoCompleteTextViewAdapter import com.simplemobiletools.contacts.pro.dialogs.CustomLabelDialog import com.simplemobiletools.contacts.pro.dialogs.ManageVisibleFieldsDialog import com.simplemobiletools.contacts.pro.dialogs.MyDatePickerDialog @@ -59,6 +60,8 @@ class EditContactActivity : ContactActivity() { private val CHOOSE_PHOTO = 2 private val REMOVE_PHOTO = 3 + private val AUTO_COMPLETE_DELAY = 5000L + private var mLastSavePromptTS = 0L private var wasActivityInitialized = false private var lastPhotoIntentUri: Uri? = null @@ -261,6 +264,11 @@ class EditContactActivity : ContactActivity() { setOnLongClickListener { toast(R.string.toggle_favorite); true; } } + val nameTextViews = arrayOf(contact_first_name, contact_middle_name, contact_surname).filter { it.isVisible() } + if (nameTextViews.isNotEmpty()) { + setupAutoComplete(nameTextViews) + } + updateTextColors(contact_scrollview) numberViewToColor?.setTextColor(properPrimaryColor) emailViewToColor?.setTextColor(properPrimaryColor) @@ -1533,4 +1541,33 @@ class EditContactActivity : ContactActivity() { getString(R.string.jabber) -> Im.PROTOCOL_JABBER else -> Im.PROTOCOL_CUSTOM } + + private fun setupAutoComplete(nameTextViews: List) { + ContactsHelper(this).getContacts { contacts -> + val adapter = AutoCompleteTextViewAdapter(this, contacts) + val handler = Handler(mainLooper) + nameTextViews.forEach { view -> + view.setAdapter(adapter) + view.setOnItemClickListener { _, _, position, _ -> + val selectedContact = adapter.resultList[position] + + if (contact_first_name.isVisible()) { + contact_first_name.setText(selectedContact.firstName) + } + if (contact_middle_name.isVisible()) { + contact_middle_name.setText(selectedContact.middleName) + } + if (contact_surname.isVisible()) { + contact_surname.setText(selectedContact.surname) + } + } + view.doAfterTextChanged { + handler.postDelayed({ + adapter.autoComplete = true + adapter.filter.filter(it) + }, AUTO_COMPLETE_DELAY) + } + } + } + } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/AutoCompleteTextViewAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/AutoCompleteTextViewAdapter.kt new file mode 100644 index 00000000..d630502b --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/AutoCompleteTextViewAdapter.kt @@ -0,0 +1,114 @@ +package com.simplemobiletools.contacts.pro.adapters + +import android.graphics.drawable.BitmapDrawable +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.Filter +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions +import com.bumptech.glide.request.RequestOptions +import com.simplemobiletools.commons.extensions.beGone +import com.simplemobiletools.commons.extensions.getProperBackgroundColor +import com.simplemobiletools.commons.extensions.getProperTextColor +import com.simplemobiletools.commons.extensions.normalizeString +import com.simplemobiletools.commons.helpers.SimpleContactsHelper +import com.simplemobiletools.commons.models.contacts.Contact +import com.simplemobiletools.contacts.pro.R +import com.simplemobiletools.contacts.pro.activities.SimpleActivity +import kotlinx.android.synthetic.main.item_autocomplete_name_number.view.item_autocomplete_image +import kotlinx.android.synthetic.main.item_autocomplete_name_number.view.item_autocomplete_name +import kotlinx.android.synthetic.main.item_autocomplete_name_number.view.item_autocomplete_number + +class AutoCompleteTextViewAdapter( + val activity: SimpleActivity, + val contacts: ArrayList, + var autoComplete: Boolean = false +) : ArrayAdapter(activity, 0, contacts) { + var resultList = ArrayList() + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val contact = resultList[position] + var listItem = convertView + val nameToUse = contact.getNameToDisplay() + if (listItem == null || listItem.tag != nameToUse.isNotEmpty()) { + listItem = LayoutInflater.from(activity).inflate(R.layout.item_autocomplete_name_number, parent, false) + } + + val placeholder = BitmapDrawable(activity.resources, SimpleContactsHelper(context).getContactLetterIcon(nameToUse)) + listItem!!.apply { + setBackgroundColor(context.getProperBackgroundColor()) + item_autocomplete_name.setTextColor(context.getProperTextColor()) + item_autocomplete_number.setTextColor(context.getProperTextColor()) + + tag = nameToUse.isNotEmpty() + item_autocomplete_name.text = nameToUse + contact.phoneNumbers.apply { + val phoneNumber = firstOrNull { it.isPrimary }?.normalizedNumber ?: firstOrNull()?.normalizedNumber + if (phoneNumber.isNullOrEmpty()) { + item_autocomplete_number.beGone() + } else { + item_autocomplete_number.text = phoneNumber + } + } + + val options = RequestOptions() + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .error(placeholder) + .centerCrop() + + Glide.with(context) + .load(contact.photoUri) + .transition(DrawableTransitionOptions.withCrossFade()) + .placeholder(placeholder) + .apply(options) + .apply(RequestOptions.circleCropTransform()) + .into(item_autocomplete_image) + } + + return listItem + } + + override fun getFilter() = object : Filter() { + override fun performFiltering(constraint: CharSequence?): FilterResults { + val filterResults = FilterResults() + if (constraint != null && autoComplete) { + val searchString = constraint.toString().normalizeString() + val results = mutableListOf() + contacts.forEach { + if (it.getNameToDisplay().contains(searchString, true)) { + results.add(it) + } + } + + results.sortWith(compareBy + { it.name.startsWith(searchString, true) }.thenBy + { it.name.contains(searchString, true) }) + results.reverse() + + filterResults.values = results + filterResults.count = results.size + } + return filterResults + } + + override fun publishResults(constraint: CharSequence?, results: FilterResults?) { + if (results != null && results.count > 0) { + resultList.clear() + @Suppress("UNCHECKED_CAST") + resultList.addAll(results.values as List) + notifyDataSetChanged() + } else { + notifyDataSetInvalidated() + } + } + + override fun convertResultToString(resultValue: Any?) = (resultValue as? Contact)?.name + } + + override fun getItem(index: Int) = resultList[index] + + override fun getCount() = resultList.size +} diff --git a/app/src/main/res/layout/activity_edit_contact.xml b/app/src/main/res/layout/activity_edit_contact.xml index 0d25eb73..2434400f 100644 --- a/app/src/main/res/layout/activity_edit_contact.xml +++ b/app/src/main/res/layout/activity_edit_contact.xml @@ -12,7 +12,8 @@ android:layout_height="wrap_content" android:clipToPadding="false" android:scrollbars="none" - android:visibility="gone"> + android:visibility="gone" + tools:visibility="visible"> - - - + + + + + + + + +