Simple-Dialer/app/src/main/kotlin/com/simplemobiletools/dialer/fragments/RecentsFragment.kt

207 lines
8.4 KiB
Kotlin

package com.simplemobiletools.dialer.fragments
import android.content.Context
import android.util.AttributeSet
import com.simplemobiletools.commons.dialogs.CallConfirmationDialog
import com.simplemobiletools.commons.extensions.*
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.databinding.FragmentRecentsBinding
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
class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment<MyViewPagerFragment.RecentsInnerBinding>(context, attributeSet),
RefreshItemsListener {
private lateinit var binding: FragmentRecentsBinding
private var allRecentCalls = listOf<RecentCall>()
private var recentsAdapter: RecentCallsAdapter? = null
override fun onFinishInflate() {
super.onFinishInflate()
binding = FragmentRecentsBinding.bind(this)
innerBinding = RecentsInnerBinding(binding)
}
override fun setupFragment() {
val placeholderResId = if (context.hasPermission(PERMISSION_READ_CALL_LOG)) {
R.string.no_previous_calls
} else {
R.string.could_not_access_the_call_history
}
binding.recentsPlaceholder.text = context.getString(placeholderResId)
binding.recentsPlaceholder2.apply {
underlineText()
setOnClickListener {
requestCallLogPermission()
}
}
}
override fun setupColors(textColor: Int, primaryColor: Int, properPrimaryColor: Int) {
binding.recentsPlaceholder.setTextColor(textColor)
binding.recentsPlaceholder.setTextColor(properPrimaryColor)
recentsAdapter?.apply {
initDrawables()
updateTextColor(textColor)
}
}
override fun refreshItems(callback: (() -> Unit)?) {
val privateCursor = context?.getMyContactsCursor(false, true)
val groupSubsequentCalls = context?.config?.groupSubsequentCalls ?: false
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)
allRecentCalls = recents
.setNamesIfEmpty(contacts, privateContacts)
.hidePrivateContacts(privateContacts, SMT_PRIVATE in context.baseConfig.ignoredContactSources)
activity?.runOnUiThread {
gotRecents(allRecentCalls)
}
}
}
}
private fun gotRecents(recents: List<RecentCall>) {
if (recents.isEmpty()) {
binding.apply {
recentsPlaceholder.beVisible()
recentsPlaceholder2.beGoneIf(context.hasPermission(PERMISSION_READ_CALL_LOG))
recentsList.beGone()
}
} else {
binding.apply {
recentsPlaceholder.beGone()
recentsPlaceholder2.beGone()
recentsList.beVisible()
}
if (binding.recentsList.adapter == null) {
recentsAdapter = RecentCallsAdapter(activity as SimpleActivity, recents.toMutableList(), binding.recentsList, this, true) {
val recentCall = it as RecentCall
if (context.config.showCallConfirmation) {
CallConfirmationDialog(activity as SimpleActivity, recentCall.name) {
activity?.launchCallIntent(recentCall.phoneNumber)
}
} else {
activity?.launchCallIntent(recentCall.phoneNumber)
}
}
binding.recentsList.adapter = recentsAdapter
if (context.areSystemAnimationsEnabled) {
binding.recentsList.scheduleLayoutAnimation()
}
binding.recentsList.endlessScrollListener = object : MyRecyclerView.EndlessScrollListener {
override fun updateTop() {}
override fun updateBottom() {
getMoreRecentCalls()
}
}
} else {
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)
}
}
}
}
private fun requestCallLogPermission() {
activity?.handlePermission(PERMISSION_READ_CALL_LOG) {
if (it) {
binding.recentsPlaceholder.text = context.getString(R.string.no_previous_calls)
binding.recentsPlaceholder2.beGone()
val groupSubsequentCalls = context?.config?.groupSubsequentCalls ?: false
RecentsHelper(context).getRecentCalls(groupSubsequentCalls) { recents ->
activity?.runOnUiThread {
gotRecents(recents)
}
}
}
}
}
override fun onSearchClosed() {
binding.recentsPlaceholder.beVisibleIf(allRecentCalls.isEmpty())
recentsAdapter?.updateItems(allRecentCalls)
}
override fun onSearchQueryChanged(text: String) {
val recentCalls = allRecentCalls.filter {
it.name.contains(text, true) || it.doesContainPhoneNumber(text)
}.sortedByDescending {
it.name.startsWith(text, true)
}.toMutableList() as ArrayList<RecentCall>
binding.recentsPlaceholder.beVisibleIf(recentCalls.isEmpty())
recentsAdapter?.updateItems(recentCalls, text)
}
}
// hide private contacts from recent calls
private fun List<RecentCall>.hidePrivateContacts(privateContacts: List<Contact>, shouldHide: Boolean): List<RecentCall> {
return if (shouldHide) {
filterNot { recent ->
val privateNumbers = privateContacts.flatMap { it.phoneNumbers }.map { it.value }
recent.phoneNumber in privateNumbers
}
} else {
this
}
}
private fun List<RecentCall>.setNamesIfEmpty(contacts: List<Contact>, privateContacts: List<Contact>): ArrayList<RecentCall> {
val contactsWithNumbers = contacts.filter { it.phoneNumbers.isNotEmpty() }
return map { recent ->
if (recent.phoneNumber == recent.name) {
val privateContact = privateContacts.firstOrNull { it.doesContainPhoneNumber(recent.phoneNumber) }
val contact = contactsWithNumbers.firstOrNull { it.phoneNumbers.first().normalizedNumber == recent.phoneNumber }
when {
privateContact != null -> recent.copy(name = privateContact.getNameToDisplay())
contact != null -> recent.copy(name = contact.getNameToDisplay())
else -> recent
}
} else {
recent
}
} as ArrayList
}