Improved RecentCallsAdapter for onScroll loading

This commit is contained in:
merkost 2023-06-20 14:08:10 +10:00
parent 56d0a0ca07
commit 939cba30ea
4 changed files with 88 additions and 40 deletions

View File

@ -260,6 +260,7 @@ class RecentCallsAdapter(
if (newItems.hashCode() != recentCalls.hashCode()) {
recentCalls = newItems.clone() as ArrayList<RecentCall>
textToHighlight = highlightText
recyclerView.resetItemCount()
notifyDataSetChanged()
finishActMode()
} else if (textToHighlight != highlightText) {

View File

@ -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<RecentCall>()
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<RecentCall>
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<RecentCall>.hidePrivateContacts(privateContacts: ArrayList<Contact>, shouldHide: Boolean): ArrayList<RecentCall> {
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<RecentCall>.setNamesIfEmpty(contacts: ArrayList<Contact>, privateContacts: ArrayList<Contact>): ArrayList<RecentCall> {
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
}

View File

@ -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

View File

@ -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<RecentCall>) -> Unit) {
fun getRecentCalls(groupSubsequentCalls: Boolean, maxSize: Int = QUERY_LIMIT, callback: (ArrayList<RecentCall>) -> 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<Contact>, groupSubsequentCalls: Boolean, callback: (ArrayList<RecentCall>) -> Unit) {
private fun getRecents(contacts: ArrayList<Contact>, groupSubsequentCalls: Boolean, maxSize: Int, callback: (ArrayList<RecentCall>) -> Unit) {
var recentCalls = ArrayList<RecentCall>()
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()