diff --git a/app/build.gradle b/app/build.gradle index 41d9ba80..8e6e8c7e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,7 +56,7 @@ android { } dependencies { - implementation 'com.simplemobiletools:commons:5.27.2' + implementation 'com.simplemobiletools:commons:5.27.10' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4' implementation 'org.greenrobot:eventbus:3.2.0' implementation 'com.klinkerapps:android-smsmms:5.2.6' diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewConversationActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewConversationActivity.kt index 76bb20a5..f3890054 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewConversationActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewConversationActivity.kt @@ -7,13 +7,17 @@ import android.view.Menu import android.view.WindowManager import com.reddit.indicatorfastscroll.FastScrollItemIndicator import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.helpers.ContactsHelper import com.simplemobiletools.commons.helpers.PERMISSION_READ_CONTACTS import com.simplemobiletools.commons.helpers.ensureBackgroundThread +import com.simplemobiletools.commons.models.SimpleContact import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.adapters.ContactsAdapter -import com.simplemobiletools.smsmessenger.extensions.* +import com.simplemobiletools.smsmessenger.extensions.config +import com.simplemobiletools.smsmessenger.extensions.getSuggestedContacts +import com.simplemobiletools.smsmessenger.extensions.getThreadId +import com.simplemobiletools.smsmessenger.extensions.loadImage import com.simplemobiletools.smsmessenger.helpers.* -import com.simplemobiletools.smsmessenger.models.Contact import kotlinx.android.synthetic.main.activity_conversation.* import kotlinx.android.synthetic.main.item_suggested_contact.view.* import java.net.URLDecoder @@ -21,7 +25,7 @@ import java.util.* import kotlin.collections.ArrayList class NewConversationActivity : SimpleActivity() { - private var allContacts = ArrayList() + private var allContacts = ArrayList() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -57,7 +61,7 @@ class NewConversationActivity : SimpleActivity() { fetchContacts() new_conversation_address.onTextChangeListener { val searchString = it - val filteredContacts = ArrayList() + val filteredContacts = ArrayList() allContacts.forEach { if (it.phoneNumber.contains(searchString, true) || it.name.contains(searchString, true)) { filteredContacts.add(it) @@ -100,7 +104,7 @@ class NewConversationActivity : SimpleActivity() { private fun fetchContacts() { fillSuggestedContacts { - getAvailableContacts { + ContactsHelper(this).getAvailableContacts { allContacts = it runOnUiThread { @@ -110,7 +114,7 @@ class NewConversationActivity : SimpleActivity() { } } - private fun setupAdapter(contacts: ArrayList) { + private fun setupAdapter(contacts: ArrayList) { val hasContacts = contacts.isNotEmpty() contacts_list.beVisibleIf(hasContacts) no_contacts_placeholder.beVisibleIf(!hasContacts) @@ -123,7 +127,7 @@ class NewConversationActivity : SimpleActivity() { ContactsAdapter(this, contacts, contacts_list, null) { hideKeyboard() - launchThreadActivity((it as Contact).phoneNumber, it.name) + launchThreadActivity((it as SimpleContact).phoneNumber, it.name) }.apply { contacts_list.adapter = this } @@ -159,7 +163,7 @@ class NewConversationActivity : SimpleActivity() { } } - private fun setupLetterFastscroller(contacts: ArrayList) { + private fun setupLetterFastscroller(contacts: ArrayList) { contacts_letter_fastscroller.setupWithRecyclerView(contacts_list, { position -> try { val name = contacts[position].name diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt index de0a80c7..8202de0a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt @@ -30,9 +30,11 @@ import com.klinker.android.send_message.Settings import com.klinker.android.send_message.Transaction import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.helpers.ContactsHelper import com.simplemobiletools.commons.helpers.PERMISSION_READ_PHONE_STATE import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.commons.helpers.isNougatPlus +import com.simplemobiletools.commons.models.SimpleContact import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.adapters.AutoCompleteTextViewAdapter import com.simplemobiletools.smsmessenger.adapters.ThreadAdapter @@ -54,7 +56,7 @@ class ThreadActivity : SimpleActivity() { private var currentSIMCardIndex = 0 private var threadItems = ArrayList() private var bus: EventBus? = null - private var participants = ArrayList() + private var participants = ArrayList() private var messages = ArrayList() private val availableSIMCards = ArrayList() private var attachmentUris = LinkedHashSet() @@ -104,7 +106,7 @@ class ThreadActivity : SimpleActivity() { return@ensureBackgroundThread } - val contact = Contact(0, name, "", number) + val contact = SimpleContact(0, name, "", number) participants.add(contact) } @@ -200,7 +202,7 @@ class ThreadActivity : SimpleActivity() { thread_messages_list.adapter = adapter } - getAvailableContacts { + ContactsHelper(this).getAvailableContacts { runOnUiThread { val adapter = AutoCompleteTextViewAdapter(this, it) add_contact_or_number.setAdapter(adapter) @@ -219,7 +221,7 @@ class ThreadActivity : SimpleActivity() { confirm_inserted_number.setOnClickListener { val number = add_contact_or_number.value - val contact = Contact(number.hashCode(), number, "", number) + val contact = SimpleContact(number.hashCode(), number, "", number) addSelectedContact(contact) } } @@ -358,7 +360,7 @@ class ThreadActivity : SimpleActivity() { showSelectedContact(views) } - private fun addSelectedContact(contact: Contact) { + private fun addSelectedContact(contact: SimpleContact) { add_contact_or_number.setText("") if (participants.map { it.id }.contains(contact.id)) { return @@ -555,7 +557,7 @@ class ThreadActivity : SimpleActivity() { } private fun removeSelectedContact(id: Int) { - participants = participants.filter { it.id != id }.toMutableList() as ArrayList + participants = participants.filter { it.id != id }.toMutableList() as ArrayList showSelectedContacts() } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/AutoCompleteTextViewAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/AutoCompleteTextViewAdapter.kt index ff02fbc8..c7d7b913 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/AutoCompleteTextViewAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/AutoCompleteTextViewAdapter.kt @@ -6,15 +6,15 @@ import android.view.ViewGroup import android.widget.ArrayAdapter import android.widget.Filter import com.simplemobiletools.commons.extensions.normalizeString +import com.simplemobiletools.commons.models.SimpleContact import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.activities.SimpleActivity import com.simplemobiletools.smsmessenger.extensions.loadImage -import com.simplemobiletools.smsmessenger.models.Contact import kotlinx.android.synthetic.main.item_contact.view.* -class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: ArrayList) : - ArrayAdapter(activity, 0, contacts) { - var resultList = ArrayList() +class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: ArrayList) : + ArrayAdapter(activity, 0, contacts) { + var resultList = ArrayList() override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val contact = resultList[position] @@ -62,7 +62,7 @@ class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: Ar } } - override fun convertResultToString(resultValue: Any?) = (resultValue as? Contact)?.name + override fun convertResultToString(resultValue: Any?) = (resultValue as? SimpleContact)?.name } override fun getItem(index: Int) = resultList[index] diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ContactsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ContactsAdapter.kt index a7b87bff..b496c3d1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ContactsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ContactsAdapter.kt @@ -5,17 +5,17 @@ import android.view.View import android.view.ViewGroup import com.bumptech.glide.Glide import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter +import com.simplemobiletools.commons.models.SimpleContact import com.simplemobiletools.commons.views.FastScroller import com.simplemobiletools.commons.views.MyRecyclerView import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.activities.SimpleActivity import com.simplemobiletools.smsmessenger.extensions.loadImage -import com.simplemobiletools.smsmessenger.models.Contact import kotlinx.android.synthetic.main.item_contact_with_number.view.* import java.util.* class ContactsAdapter( - activity: SimpleActivity, var contacts: ArrayList, recyclerView: MyRecyclerView, + activity: SimpleActivity, var contacts: ArrayList, recyclerView: MyRecyclerView, fastScroller: FastScroller?, itemClick: (Any) -> Unit ) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) { @@ -57,7 +57,7 @@ class ContactsAdapter( } } - private fun setupView(view: View, contact: Contact) { + private fun setupView(view: View, contact: SimpleContact) { view.apply { contact_name.text = contact.name contact_name.setTextColor(textColor) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/ArrayList.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/ArrayList.kt index 6e71dd87..dfaf3202 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/ArrayList.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/ArrayList.kt @@ -1,6 +1,6 @@ package com.simplemobiletools.smsmessenger.extensions import android.text.TextUtils -import com.simplemobiletools.smsmessenger.models.Contact +import com.simplemobiletools.commons.models.SimpleContact -fun ArrayList.getThreadTitle() = TextUtils.join(", ", map { it.name }.toTypedArray()) +fun ArrayList.getThreadTitle() = TextUtils.join(", ", map { it.name }.toTypedArray()) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt index d5e8a2e5..350ecc0e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt @@ -15,10 +15,6 @@ import android.media.AudioAttributes import android.media.AudioManager import android.media.RingtoneManager import android.net.Uri -import android.provider.ContactsContract -import android.provider.ContactsContract.CommonDataKinds -import android.provider.ContactsContract.CommonDataKinds.Organization -import android.provider.ContactsContract.CommonDataKinds.StructuredName import android.provider.ContactsContract.PhoneLookup import android.provider.Telephony.* import android.text.TextUtils @@ -30,6 +26,7 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.bumptech.glide.request.RequestOptions import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* +import com.simplemobiletools.commons.models.SimpleContact import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.activities.ThreadActivity import com.simplemobiletools.smsmessenger.helpers.Config @@ -72,7 +69,7 @@ fun Context.getMessages(threadId: Int): ArrayList { val date = (cursor.getLongValue(Sms.DATE) / 1000).toInt() val read = cursor.getIntValue(Sms.READ) == 1 val thread = cursor.getIntValue(Sms.THREAD_ID) - val participant = Contact(0, senderName, photoUri, senderNumber) + val participant = SimpleContact(0, senderName, photoUri, senderNumber) val isMMS = false val message = Message(id, body, type, arrayListOf(participant), date, read, thread, isMMS, null, senderName, photoUri) messages.add(message) @@ -109,7 +106,7 @@ fun Context.getMMS(threadId: Int? = null, sortOrder: String? = null): ArrayList< } val messages = ArrayList() - val contactsMap = HashMap() + val contactsMap = HashMap() queryCursor(uri, projection, selection, selectionArgs, sortOrder, showErrors = true) { cursor -> val mmsId = cursor.getIntValue(Mms._ID) val type = cursor.getIntValue(Mms.MESSAGE_BOX) @@ -196,7 +193,7 @@ fun Context.getConversations(): ArrayList { val names = getThreadContactNames(phoneNumbers) val title = TextUtils.join(", ", names.toTypedArray()) - val photoUri = if (phoneNumbers.size == 1) getPhotoUriFromPhoneNumber(phoneNumbers.first()) else "" + val photoUri = if (phoneNumbers.size == 1) ContactsHelper(this).getPhotoUriFromPhoneNumber(phoneNumbers.first()) else "" val isGroupConversation = phoneNumbers.size > 1 val conversation = Conversation(id, snippet, date.toInt(), read, title, photoUri, isGroupConversation) conversations.add(conversation) @@ -279,14 +276,14 @@ fun Context.getThreadSnippet(threadId: Int): String { return snippet } -fun Context.getThreadParticipants(threadId: Int, contactsMap: HashMap?): ArrayList { +fun Context.getThreadParticipants(threadId: Int, contactsMap: HashMap?): ArrayList { val uri = Uri.parse("${MmsSms.CONTENT_CONVERSATIONS_URI}?simple=true") val projection = arrayOf( ThreadsColumns.RECIPIENT_IDS ) val selection = "${Mms._ID} = ?" val selectionArgs = arrayOf(threadId.toString()) - val participants = ArrayList() + val participants = ArrayList() try { val cursor = contentResolver.query(uri, projection, selection, selectionArgs, null) cursor?.use { @@ -303,7 +300,7 @@ fun Context.getThreadParticipants(threadId: Int, contactsMap: HashMap): ArrayList { fun Context.getThreadContactNames(phoneNumbers: List): ArrayList { val names = ArrayList() phoneNumbers.forEach { - names.add(getNameFromPhoneNumber(it)) + names.add(ContactsHelper(this).getNameFromPhoneNumber(it)) } return names } @@ -351,8 +348,8 @@ fun Context.getPhoneNumberFromAddressId(canonicalAddressId: Int): String { return "" } -fun Context.getSuggestedContacts(): ArrayList { - val contacts = ArrayList() +fun Context.getSuggestedContacts(): ArrayList { + val contacts = ArrayList() val uri = Sms.CONTENT_URI val projection = arrayOf( Sms.ADDRESS @@ -371,7 +368,7 @@ fun Context.getSuggestedContacts(): ArrayList { val senderName = namePhoto.name val photoUri = namePhoto.photoUri ?: "" - val contact = Contact(0, senderName, photoUri, senderNumber) + val contact = SimpleContact(0, senderName, photoUri, senderNumber) if (!contacts.map { it.phoneNumber.trimToComparableNumber() }.contains(senderNumber.trimToComparableNumber())) { contacts.add(contact) } @@ -380,34 +377,6 @@ fun Context.getSuggestedContacts(): ArrayList { return contacts } -fun Context.getAvailableContacts(callback: (ArrayList) -> Unit) { - ensureBackgroundThread { - val names = getContactNames() - var allContacts = getContactPhoneNumbers() - allContacts.forEach { - val contactId = it.id - val contact = names.firstOrNull { it.id == contactId } - val name = contact?.name - if (name != null) { - it.name = name - } - - val photoUri = contact?.photoUri - if (photoUri != null) { - it.photoUri = photoUri - } - } - - allContacts = allContacts.filter { it.name.isNotEmpty() }.distinctBy { - val startIndex = Math.max(0, it.phoneNumber.length - 9) - it.phoneNumber.substring(startIndex) - }.toMutableList() as ArrayList - - allContacts.sort() - callback(allContacts) - } -} - fun Context.getNameAndPhotoFromPhoneNumber(number: String): NamePhoto? { if (!hasPermission(PERMISSION_READ_CONTACTS)) { return NamePhoto(number, null) @@ -435,80 +404,6 @@ fun Context.getNameAndPhotoFromPhoneNumber(number: String): NamePhoto? { return NamePhoto(number, null) } -fun Context.getContactNames(): List { - val contacts = ArrayList() - val uri = ContactsContract.Data.CONTENT_URI - val projection = arrayOf( - ContactsContract.Data.CONTACT_ID, - StructuredName.PREFIX, - StructuredName.GIVEN_NAME, - StructuredName.MIDDLE_NAME, - StructuredName.FAMILY_NAME, - StructuredName.SUFFIX, - StructuredName.PHOTO_THUMBNAIL_URI, - Organization.COMPANY, - Organization.TITLE, - ContactsContract.Data.MIMETYPE - ) - - val selection = "${ContactsContract.Data.MIMETYPE} = ? OR ${ContactsContract.Data.MIMETYPE} = ?" - val selectionArgs = arrayOf( - StructuredName.CONTENT_ITEM_TYPE, - Organization.CONTENT_ITEM_TYPE - ) - - queryCursor(uri, projection, selection, selectionArgs) { cursor -> - val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) - val mimetype = cursor.getStringValue(ContactsContract.Data.MIMETYPE) - val photoUri = cursor.getStringValue(StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - val isPerson = mimetype == StructuredName.CONTENT_ITEM_TYPE - if (isPerson) { - val prefix = cursor.getStringValue(StructuredName.PREFIX) ?: "" - val firstName = cursor.getStringValue(StructuredName.GIVEN_NAME) ?: "" - val middleName = cursor.getStringValue(StructuredName.MIDDLE_NAME) ?: "" - val familyName = cursor.getStringValue(StructuredName.FAMILY_NAME) ?: "" - val suffix = cursor.getStringValue(StructuredName.SUFFIX) ?: "" - if (firstName.isNotEmpty() || middleName.isNotEmpty() || familyName.isNotEmpty()) { - val names = arrayOf(prefix, firstName, middleName, familyName, suffix).filter { it.isNotEmpty() } - val fullName = TextUtils.join(" ", names) - val contact = Contact(id, fullName, photoUri, "") - contacts.add(contact) - } - } - - val isOrganization = mimetype == Organization.CONTENT_ITEM_TYPE - if (isOrganization) { - val company = cursor.getStringValue(Organization.COMPANY) ?: "" - val jobTitle = cursor.getStringValue(Organization.TITLE) ?: "" - if (company.isNotEmpty() || jobTitle.isNotEmpty()) { - val fullName = "$company $jobTitle".trim() - val contact = Contact(id, fullName, photoUri, "") - contacts.add(contact) - } - } - } - return contacts -} - -fun Context.getContactPhoneNumbers(): ArrayList { - val contacts = ArrayList() - val uri = CommonDataKinds.Phone.CONTENT_URI - val projection = arrayOf( - ContactsContract.Data.CONTACT_ID, - CommonDataKinds.Phone.NORMALIZED_NUMBER - ) - - queryCursor(uri, projection) { cursor -> - val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) - val phoneNumber = cursor.getStringValue(CommonDataKinds.Phone.NORMALIZED_NUMBER) - if (phoneNumber != null) { - val contact = Contact(id, "", "", phoneNumber) - contacts.add(contact) - } - } - return contacts -} - fun Context.insertNewSMS(address: String, subject: String, body: String, date: Long, read: Int, threadId: Long, type: Int) { val uri = Sms.CONTENT_URI val contentValues = ContentValues().apply { diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Contact.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Contact.kt deleted file mode 100644 index a467254f..00000000 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Contact.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.simplemobiletools.smsmessenger.models - -import com.simplemobiletools.commons.extensions.normalizeString - -data class Contact(val id: Int, var name: String, var photoUri: String, var phoneNumber: String) : Comparable { - override fun compareTo(other: Contact): Int { - val firstString = name.normalizeString() - val secondString = other.name.normalizeString() - - return if (firstString.firstOrNull()?.isLetter() == true && secondString.firstOrNull()?.isLetter() == false) { - -1 - } else if (firstString.firstOrNull()?.isLetter() == false && secondString.firstOrNull()?.isLetter() == true) { - 1 - } else { - if (firstString.isEmpty() && secondString.isNotEmpty()) { - 1 - } else if (firstString.isNotEmpty() && secondString.isEmpty()) { - -1 - } else { - firstString.compareTo(secondString, true) - } - } - } -} diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Message.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Message.kt index 0b9f797f..031ae426 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Message.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Message.kt @@ -1,9 +1,10 @@ package com.simplemobiletools.smsmessenger.models import android.provider.Telephony +import com.simplemobiletools.commons.models.SimpleContact data class Message( - val id: Int, val body: String, val type: Int, val participants: ArrayList, val date: Int, val read: Boolean, val thread: Int, + val id: Int, val body: String, val type: Int, val participants: ArrayList, val date: Int, val read: Boolean, val thread: Int, val isMMS: Boolean, val attachment: MessageAttachment?, val senderName: String, val senderPhotoUri: String ) : ThreadItem() { fun isReceivedMessage() = type == Telephony.Sms.MESSAGE_TYPE_INBOX