From 939cba30ea24b60a24400f5e7e5839c4db2af738 Mon Sep 17 00:00:00 2001 From: merkost Date: Tue, 20 Jun 2023 14:08:10 +1000 Subject: [PATCH 1/2] Improved RecentCallsAdapter for onScroll loading --- .../dialer/adapters/RecentCallsAdapter.kt | 1 + .../dialer/fragments/RecentsFragment.kt | 113 ++++++++++++------ .../dialer/helpers/Constants.kt | 2 + .../dialer/helpers/RecentsHelper.kt | 12 +- 4 files changed, 88 insertions(+), 40 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/adapters/RecentCallsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/adapters/RecentCallsAdapter.kt index 785bcb2f..7a7829c3 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/adapters/RecentCallsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/adapters/RecentCallsAdapter.kt @@ -260,6 +260,7 @@ class RecentCallsAdapter( if (newItems.hashCode() != recentCalls.hashCode()) { recentCalls = newItems.clone() as ArrayList textToHighlight = highlightText + recyclerView.resetItemCount() notifyDataSetChanged() finishActMode() } else if (textToHighlight != highlightText) { diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/fragments/RecentsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/fragments/RecentsFragment.kt index 0a995e11..03831309 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/fragments/RecentsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/fragments/RecentsFragment.kt @@ -8,17 +8,23 @@ import com.simplemobiletools.commons.helpers.ContactsHelper import com.simplemobiletools.commons.helpers.MyContactsContentProvider import com.simplemobiletools.commons.helpers.PERMISSION_READ_CALL_LOG import com.simplemobiletools.commons.helpers.SMT_PRIVATE +import com.simplemobiletools.commons.models.contacts.Contact +import com.simplemobiletools.commons.views.MyRecyclerView import com.simplemobiletools.dialer.R import com.simplemobiletools.dialer.activities.SimpleActivity import com.simplemobiletools.dialer.adapters.RecentCallsAdapter import com.simplemobiletools.dialer.extensions.config +import com.simplemobiletools.dialer.helpers.MIN_RECENTS_THRESHOLD import com.simplemobiletools.dialer.helpers.RecentsHelper import com.simplemobiletools.dialer.interfaces.RefreshItemsListener import com.simplemobiletools.dialer.models.RecentCall -import kotlinx.android.synthetic.main.fragment_recents.view.* +import kotlinx.android.synthetic.main.fragment_recents.view.recents_list +import kotlinx.android.synthetic.main.fragment_recents.view.recents_placeholder +import kotlinx.android.synthetic.main.fragment_recents.view.recents_placeholder_2 class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet), RefreshItemsListener { private var allRecentCalls = ArrayList() + private var recentsAdapter: RecentCallsAdapter? = null override fun setupFragment() { val placeholderResId = if (context.hasPermission(PERMISSION_READ_CALL_LOG)) { @@ -40,7 +46,7 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage recents_placeholder.setTextColor(textColor) recents_placeholder_2.setTextColor(properPrimaryColor) - (recents_list?.adapter as? RecentCallsAdapter)?.apply { + recentsAdapter?.apply { initDrawables() updateTextColor(textColor) } @@ -49,36 +55,14 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage override fun refreshItems(callback: (() -> Unit)?) { val privateCursor = context?.getMyContactsCursor(false, true) val groupSubsequentCalls = context?.config?.groupSubsequentCalls ?: false - RecentsHelper(context).getRecentCalls(groupSubsequentCalls) { recents -> + val querySize = allRecentCalls.size.coerceAtLeast(MIN_RECENTS_THRESHOLD) + RecentsHelper(context).getRecentCalls(groupSubsequentCalls, querySize) { recents -> ContactsHelper(context).getContacts(showOnlyContactsWithNumbers = true) { contacts -> val privateContacts = MyContactsContentProvider.getContacts(context, privateCursor) - recents.filter { it.phoneNumber == it.name }.forEach { recent -> - var wasNameFilled = false - if (privateContacts.isNotEmpty()) { - val privateContact = privateContacts.firstOrNull { it.doesContainPhoneNumber(recent.phoneNumber) } - if (privateContact != null) { - recent.name = privateContact.getNameToDisplay() - wasNameFilled = true - } - } - - if (!wasNameFilled) { - val contact = contacts.filter { it.phoneNumbers.isNotEmpty() }.firstOrNull { it.phoneNumbers.first().normalizedNumber == recent.phoneNumber } - if (contact != null) { - recent.name = contact.getNameToDisplay() - } - } - } allRecentCalls = recents - - // hide private contacts from recent calls - if (SMT_PRIVATE in context.baseConfig.ignoredContactSources) { - allRecentCalls = recents.filterNot { recent -> - val privateNumbers = privateContacts.flatMap { it.phoneNumbers }.map { it.value } - recent.phoneNumber in privateNumbers - } as ArrayList - } + .setNamesIfEmpty(contacts, privateContacts) + .hidePrivateContacts(privateContacts, SMT_PRIVATE in context.baseConfig.ignoredContactSources) activity?.runOnUiThread { gotRecents(allRecentCalls) @@ -99,7 +83,7 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage val currAdapter = recents_list.adapter if (currAdapter == null) { - RecentCallsAdapter(activity as SimpleActivity, recents, recents_list, this, true) { + recentsAdapter = RecentCallsAdapter(activity as SimpleActivity, recents, recents_list, this, true) { val recentCall = it as RecentCall if (context.config.showCallConfirmation) { CallConfirmationDialog(activity as SimpleActivity, recentCall.name) { @@ -108,15 +92,43 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage } else { activity?.launchCallIntent(recentCall.phoneNumber) } - }.apply { - recents_list.adapter = this } + recents_list.adapter = recentsAdapter + if (context.areSystemAnimationsEnabled) { recents_list.scheduleLayoutAnimation() } + + recents_list.endlessScrollListener = object : MyRecyclerView.EndlessScrollListener { + override fun updateTop() {} + + override fun updateBottom() { + getMoreRecentCalls() + } + } + } else { - (currAdapter as RecentCallsAdapter).updateItems(recents) + recentsAdapter?.updateItems(recents) + } + } + } + + private fun getMoreRecentCalls() { + val privateCursor = context?.getMyContactsCursor(false, true) + val groupSubsequentCalls = context?.config?.groupSubsequentCalls ?: false + val querySize = allRecentCalls.size.plus(MIN_RECENTS_THRESHOLD) + RecentsHelper(context).getRecentCalls(groupSubsequentCalls, querySize) { recents -> + ContactsHelper(context).getContacts(showOnlyContactsWithNumbers = true) { contacts -> + val privateContacts = MyContactsContentProvider.getContacts(context, privateCursor) + + allRecentCalls = recents + .setNamesIfEmpty(contacts, privateContacts) + .hidePrivateContacts(privateContacts, SMT_PRIVATE in context.baseConfig.ignoredContactSources) + + activity?.runOnUiThread { + gotRecents(allRecentCalls) + } } } } @@ -139,7 +151,7 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage override fun onSearchClosed() { recents_placeholder.beVisibleIf(allRecentCalls.isEmpty()) - (recents_list.adapter as? RecentCallsAdapter)?.updateItems(allRecentCalls) + recentsAdapter?.updateItems(allRecentCalls) } override fun onSearchQueryChanged(text: String) { @@ -150,6 +162,39 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage }.toMutableList() as ArrayList recents_placeholder.beVisibleIf(recentCalls.isEmpty()) - (recents_list.adapter as? RecentCallsAdapter)?.updateItems(recentCalls, text) + recentsAdapter?.updateItems(recentCalls, text) } } + +// hide private contacts from recent calls +private fun List.hidePrivateContacts(privateContacts: ArrayList, shouldHide: Boolean): ArrayList { + return if (shouldHide) { + filterNot { recent -> + val privateNumbers = privateContacts.flatMap { it.phoneNumbers }.map { it.value } + recent.phoneNumber in privateNumbers + } as ArrayList + } else { + this as ArrayList + } +} + +private fun ArrayList.setNamesIfEmpty(contacts: ArrayList, privateContacts: ArrayList): ArrayList { + filter { it.phoneNumber == it.name }.forEach { recent -> + var wasNameFilled = false + if (privateContacts.isNotEmpty()) { + val privateContact = privateContacts.firstOrNull { it.doesContainPhoneNumber(recent.phoneNumber) } + if (privateContact != null) { + recent.name = privateContact.getNameToDisplay() + wasNameFilled = true + } + } + + if (!wasNameFilled) { + val contact = contacts.filter { it.phoneNumbers.isNotEmpty() }.firstOrNull { it.phoneNumbers.first().normalizedNumber == recent.phoneNumber } + if (contact != null) { + recent.name = contact.getNameToDisplay() + } + } + } + return this +} diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/Constants.kt index a1329979..b1ac3e48 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/Constants.kt @@ -28,3 +28,5 @@ const val ACCEPT_CALL = PATH + "accept_call" const val DECLINE_CALL = PATH + "decline_call" const val DIALPAD_TONE_LENGTH_MS = 150L // The length of DTMF tones in milliseconds + +const val MIN_RECENTS_THRESHOLD = 30 diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/RecentsHelper.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/RecentsHelper.kt index 1dd7d8ed..a0f2fdaf 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/RecentsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/RecentsHelper.kt @@ -13,10 +13,10 @@ import com.simplemobiletools.dialer.models.RecentCall class RecentsHelper(private val context: Context) { private val COMPARABLE_PHONE_NUMBER_LENGTH = 9 - private val QUERY_LIMIT = "200" + private val QUERY_LIMIT = 200 @SuppressLint("MissingPermission") - fun getRecentCalls(groupSubsequentCalls: Boolean, callback: (ArrayList) -> Unit) { + fun getRecentCalls(groupSubsequentCalls: Boolean, maxSize: Int = QUERY_LIMIT, callback: (ArrayList) -> Unit) { val privateCursor = context.getMyContactsCursor(false, true) ensureBackgroundThread { if (!context.hasPermission(PERMISSION_READ_CALL_LOG)) { @@ -30,13 +30,13 @@ class RecentsHelper(private val context: Context) { contacts.addAll(privateContacts) } - getRecents(contacts, groupSubsequentCalls, callback) + getRecents(contacts, groupSubsequentCalls, maxSize, callback = callback) } } } @SuppressLint("NewApi") - private fun getRecents(contacts: ArrayList, groupSubsequentCalls: Boolean, callback: (ArrayList) -> Unit) { + private fun getRecents(contacts: ArrayList, groupSubsequentCalls: Boolean, maxSize: Int, callback: (ArrayList) -> Unit) { var recentCalls = ArrayList() var previousRecentCallFrom = "" @@ -64,7 +64,7 @@ class RecentsHelper(private val context: Context) { val cursor = if (isNougatPlus()) { // https://issuetracker.google.com/issues/175198972?pli=1#comment6 val limitedUri = uri.buildUpon() - .appendQueryParameter(Calls.LIMIT_PARAM_KEY, QUERY_LIMIT) + .appendQueryParameter(Calls.LIMIT_PARAM_KEY, QUERY_LIMIT.toString()) .build() val sortOrder = "${Calls._ID} DESC" context.contentResolver.query(limitedUri, projection, null, null, sortOrder) @@ -163,7 +163,7 @@ class RecentsHelper(private val context: Context) { } previousRecentCallFrom = "$number$name$simID" - } while (cursor.moveToNext()) + } while (cursor.moveToNext() && recentCalls.size < maxSize) } cursor?.close() From 571aeec97761d40e2740a36a747d68c105c02f4b Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Tue, 20 Jun 2023 13:43:58 +0200 Subject: [PATCH 2/2] optimizing imports --- .../com/simplemobiletools/dialer/fragments/RecentsFragment.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/fragments/RecentsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/fragments/RecentsFragment.kt index 03831309..38e81a68 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/fragments/RecentsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/fragments/RecentsFragment.kt @@ -18,9 +18,7 @@ import com.simplemobiletools.dialer.helpers.MIN_RECENTS_THRESHOLD import com.simplemobiletools.dialer.helpers.RecentsHelper import com.simplemobiletools.dialer.interfaces.RefreshItemsListener import com.simplemobiletools.dialer.models.RecentCall -import kotlinx.android.synthetic.main.fragment_recents.view.recents_list -import kotlinx.android.synthetic.main.fragment_recents.view.recents_placeholder -import kotlinx.android.synthetic.main.fragment_recents.view.recents_placeholder_2 +import kotlinx.android.synthetic.main.fragment_recents.view.* class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet), RefreshItemsListener { private var allRecentCalls = ArrayList()