-
-
Notifications
You must be signed in to change notification settings - Fork 159
Implement #86 include call history in dialpad #332
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2aa0edd
f341a38
21d7e31
8065ff0
bea46a0
f3d77ab
50d5c65
9f4d926
452225d
df90376
1b56dbe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ import android.os.Bundle | |
| import android.os.Handler | ||
| import android.os.Looper | ||
| import android.provider.Telephony.Sms.Intents.SECRET_CODE_ACTION | ||
| import android.telephony.PhoneNumberUtils | ||
| import android.telephony.TelephonyManager | ||
| import android.util.TypedValue | ||
| import android.view.KeyEvent | ||
|
|
@@ -20,20 +21,24 @@ import org.fossify.commons.extensions.* | |
| import org.fossify.commons.helpers.* | ||
| import org.fossify.commons.models.contacts.Contact | ||
| import org.fossify.phone.R | ||
| import org.fossify.phone.adapters.ContactsAdapter | ||
| import org.fossify.phone.adapters.DialpadAdapter | ||
| import org.fossify.phone.databinding.ActivityDialpadBinding | ||
| import org.fossify.phone.extensions.* | ||
| import org.fossify.phone.helpers.DIALPAD_TONE_LENGTH_MS | ||
| import org.fossify.phone.helpers.RecentsHelper | ||
| import org.fossify.phone.helpers.ToneGeneratorHelper | ||
| import org.fossify.phone.interfaces.CachedContacts | ||
| import org.fossify.phone.models.DialpadItem | ||
| import org.fossify.phone.models.RecentCall | ||
| import org.fossify.phone.models.SpeedDial | ||
| import java.util.Locale | ||
| import kotlin.math.roundToInt | ||
|
|
||
| class DialpadActivity : SimpleActivity() { | ||
| class DialpadActivity : SimpleActivity(), CachedContacts { | ||
| private val binding by viewBinding(ActivityDialpadBinding::inflate) | ||
|
|
||
| private var allContacts = ArrayList<Contact>() | ||
| private var allCallItems = ArrayList<DialpadItem>() | ||
| private var dialpadAdapter: DialpadAdapter? = null | ||
| private var speedDialValues = ArrayList<SpeedDial>() | ||
| private val russianCharsMap = HashMap<Char, Int>() | ||
| private var hasRussianLocale = false | ||
|
|
@@ -42,6 +47,8 @@ class DialpadActivity : SimpleActivity() { | |
| private val longPressTimeout = ViewConfiguration.getLongPressTimeout().toLong() | ||
| private val longPressHandler = Handler(Looper.getMainLooper()) | ||
| private val pressedKeys = mutableSetOf<Char>() | ||
| override var cachedContacts = ArrayList<Contact>() | ||
| private var cachedRecentCalls = emptyList<RecentCall>() | ||
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
|
|
@@ -145,10 +152,6 @@ class DialpadActivity : SimpleActivity() { | |
| dialpadInput.disableKeyboard() | ||
| } | ||
|
|
||
| ContactsHelper(this).getContacts(showOnlyContactsWithNumbers = true) { allContacts -> | ||
| gotContacts(allContacts) | ||
| } | ||
|
|
||
| val properPrimaryColor = getProperPrimaryColor() | ||
| val callIconId = if (areMultipleSIMsAvailable()) { | ||
| val callIcon = resources.getColoredDrawableWithColor(R.drawable.ic_phone_two_vector, properPrimaryColor.getContrastColor()) | ||
|
|
@@ -185,6 +188,9 @@ class DialpadActivity : SimpleActivity() { | |
| binding.dialpadClearChar.applyColorFilter(getProperTextColor()) | ||
| updateNavigationBarColor(getProperBackgroundColor()) | ||
| setupToolbar(binding.dialpadToolbar, NavigationIcon.Arrow) | ||
| refreshCallItems { | ||
| refreshCallItems(true) | ||
| } | ||
| } | ||
|
|
||
| private fun setupOptionsMenu() { | ||
|
|
@@ -231,18 +237,54 @@ class DialpadActivity : SimpleActivity() { | |
| binding.dialpadInput.setText("") | ||
| } | ||
|
|
||
| private fun gotContacts(newContacts: ArrayList<Contact>) { | ||
| allContacts = newContacts | ||
| private fun refreshCallItems(loadAllRecents: Boolean = false, callback: (() -> Unit)? = null) { | ||
| val newItems = ArrayList<DialpadItem>() | ||
|
|
||
| getContacts { contacts -> | ||
| if (contacts.isNotEmpty()) { | ||
| newItems.add(DialpadItem("Contacts", true)) | ||
| newItems.addAll(contacts.map { DialpadItem(it) }) | ||
| } | ||
|
|
||
| getRecents(contacts, loadAllRecents) { recentCalls -> | ||
| if (recentCalls.isNotEmpty()) { | ||
| newItems.add(DialpadItem("Call History", false)) | ||
| newItems.addAll(recentCalls.map { DialpadItem(it) }) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| allCallItems = newItems | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since Also, the |
||
| } | ||
|
|
||
| val privateContacts = MyContactsContentProvider.getContacts(this, privateCursor) | ||
| if (privateContacts.isNotEmpty()) { | ||
| allContacts.addAll(privateContacts) | ||
| allContacts.sort() | ||
| private fun getContacts(callback: (List<Contact>) -> Unit) { | ||
| ContactsHelper(this).getContacts(showOnlyContactsWithNumbers = true) { contacts -> | ||
| ensureBackgroundThread { | ||
| callback(contacts) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private fun getRecents(contacts: List<Contact>, loadAllRecents: Boolean, callback: (List<RecentCall>) -> Unit) { | ||
| val queryCount = if (loadAllRecents) Int.MAX_VALUE else RecentsHelper.QUERY_LIMIT | ||
|
|
||
| RecentsHelper(this).getRecentCalls(cachedRecentCalls, queryCount) { recentCalls -> | ||
| ensureBackgroundThread { | ||
| cachedRecentCalls = recentCalls | ||
| val recentCallsNonContact = filterContactsInRecentCalls(recentCalls.distinctBy { it.phoneNumber }, contacts) | ||
|
|
||
| val privateContacts = MyContactsContentProvider.getContacts(this, privateCursor) | ||
| if (privateContacts.isNotEmpty()) { | ||
| allCallItems.addAll(privateContacts.map { DialpadItem(it) }) | ||
| } | ||
|
Comment on lines
+275
to
+279
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure what's happening here. If the goal is to add private contacts to
|
||
|
|
||
| runOnUiThread { | ||
| if (!checkDialIntent() && binding.dialpadInput.value.isEmpty()) { | ||
| dialpadValueChanged("") | ||
| runOnUiThread { | ||
| if (!checkDialIntent() && binding.dialpadInput.value.isEmpty()) { | ||
| dialpadValueChanged("") | ||
| } | ||
| } | ||
|
|
||
| callback(recentCallsNonContact) | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -264,47 +306,82 @@ class DialpadActivity : SimpleActivity() { | |
| return | ||
| } | ||
|
|
||
| (binding.dialpadList.adapter as? ContactsAdapter)?.finishActMode() | ||
| (binding.dialpadList.adapter as? DialpadAdapter)?.finishActMode() | ||
|
|
||
| val filtered = allContacts.filter { contact -> | ||
| var convertedName = KeypadHelper.convertKeypadLettersToDigits( | ||
| contact.name.normalizeString() | ||
| ).filterNot { it.isWhitespace() } | ||
| var filtered = allCallItems.filter { item -> | ||
| when (item.itemType) { | ||
| DialpadItem.DialpadItemType.HEADER -> true | ||
| DialpadItem.DialpadItemType.CONTACT -> { | ||
| val contact = item.contact!! | ||
|
|
||
| if (hasRussianLocale) { | ||
| var currConvertedName = "" | ||
| convertedName.lowercase(Locale.getDefault()).forEach { char -> | ||
| val convertedChar = russianCharsMap.getOrElse(char) { char } | ||
| currConvertedName += convertedChar | ||
| var convertedName = KeypadHelper.convertKeypadLettersToDigits( | ||
| contact.name.normalizeString() | ||
| ).filterNot { it.isWhitespace() } | ||
|
|
||
| if (hasRussianLocale) { | ||
| var currConvertedName = "" | ||
| convertedName.lowercase(Locale.getDefault()).forEach { char -> | ||
| val convertedChar = russianCharsMap.getOrElse(char) { char } | ||
| currConvertedName += convertedChar | ||
| } | ||
| convertedName = currConvertedName | ||
| } | ||
|
|
||
| contact.doesContainPhoneNumber(text) || (convertedName.contains(text, true)) | ||
| } | ||
|
|
||
| DialpadItem.DialpadItemType.RECENTCALL -> { | ||
| if (len > 0) { | ||
| val recentCall = item.recentCall!! | ||
| val fixedText = text.trim().replace("\\s+".toRegex(), " ") | ||
|
|
||
| recentCall.name.contains(fixedText, true) || recentCall.doesContainPhoneNumber(fixedText) | ||
| } else { | ||
| false | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| filtered = filtered.filter { item -> | ||
| when (item.itemType) { | ||
| DialpadItem.DialpadItemType.HEADER -> { | ||
| (item.isHeaderForContacts && filtered.any { it.isContact() }) || | ||
| (!item.isHeaderForContacts && filtered.any { it.isRecentCall() }) | ||
| } | ||
| convertedName = currConvertedName | ||
|
|
||
| DialpadItem.DialpadItemType.CONTACT -> true | ||
| DialpadItem.DialpadItemType.RECENTCALL -> true | ||
| } | ||
| } | ||
|
|
||
| if (dialpadAdapter == null) { | ||
| dialpadAdapter = DialpadAdapter( | ||
| activity = this, | ||
| recyclerView = binding.dialpadList, | ||
| highlightText = text, | ||
| itemClick = { | ||
| val dialpadItem = it as DialpadItem | ||
|
|
||
| startCallWithConfirmationCheck( | ||
| dialpadItem.contact?.getPrimaryNumber() ?: dialpadItem.recentCall!!.phoneNumber, | ||
| dialpadItem.contact?.getNameToDisplay() ?: dialpadItem.recentCall!!.phoneNumber | ||
| ) | ||
| Handler().postDelayed({ | ||
| binding.dialpadInput.setText("") | ||
| }, 1000) | ||
| }, profileIconClick = { | ||
| if ((it as DialpadItem).isContact()) { | ||
| startContactDetailsIntent(it.contact!!) | ||
| } | ||
| }) | ||
|
|
||
| contact.doesContainPhoneNumber(text) || (convertedName.contains(text, true)) | ||
| }.sortedWith(compareBy { | ||
| !it.doesContainPhoneNumber(text) | ||
| }).toMutableList() as ArrayList<Contact> | ||
|
|
||
| binding.letterFastscroller.setupWithContacts(binding.dialpadList, filtered) | ||
|
|
||
| ContactsAdapter( | ||
| activity = this, | ||
| contacts = filtered, | ||
| recyclerView = binding.dialpadList, | ||
| highlightText = text, | ||
| itemClick = { | ||
| val contact = it as Contact | ||
| startCallWithConfirmationCheck(contact.getPrimaryNumber() ?: return@ContactsAdapter, contact.getNameToDisplay()) | ||
| Handler().postDelayed({ | ||
| binding.dialpadInput.setText("") | ||
| }, 1000) | ||
| }, | ||
| profileIconClick = { | ||
| startContactDetailsIntent(it as Contact) | ||
| }).apply { | ||
| binding.dialpadList.adapter = this | ||
| binding.dialpadList.adapter = dialpadAdapter | ||
| } | ||
|
|
||
| dialpadAdapter!!.updateItems(filtered, text) | ||
| binding.letterFastscroller.setupWithDialpadItems(binding.dialpadList, filtered) | ||
|
|
||
| binding.dialpadPlaceholder.beVisibleIf(filtered.isEmpty()) | ||
| binding.dialpadList.beVisibleIf(filtered.isNotEmpty()) | ||
| } | ||
|
|
@@ -440,4 +517,17 @@ class DialpadActivity : SimpleActivity() { | |
| false | ||
| } | ||
| } | ||
|
|
||
| private fun filterContactsInRecentCalls(recentCalls: List<RecentCall>, contacts: List<Contact>): List<RecentCall> { | ||
| val contactNumbers = contacts.flatMap { it.phoneNumbers }.map { it.value } | ||
| return recentCalls.filterNot { recentCall -> | ||
| contactNumbers.any { contactNumber -> | ||
| PhoneNumberUtils.compare( | ||
| this, | ||
| recentCall.phoneNumber, | ||
| contactNumber | ||
| ) | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded strings here. There's already string resources available for both of these.