diff --git a/app/src/main/kotlin/com/goodwy/dialer/activities/DialpadActivity.kt b/app/src/main/kotlin/com/goodwy/dialer/activities/DialpadActivity.kt index f7289f60..c77d0ccb 100755 --- a/app/src/main/kotlin/com/goodwy/dialer/activities/DialpadActivity.kt +++ b/app/src/main/kotlin/com/goodwy/dialer/activities/DialpadActivity.kt @@ -1152,34 +1152,50 @@ class DialpadActivity : SimpleActivity() { val text = if (config.formatPhoneNumbers) textFormat.removeNumberFormatting() else textFormat + val langPref = config.dialpadSecondaryLanguage ?: "" + val langLocale = Locale.getDefault().language + val isAutoLang = DialpadT9.getSupportedSecondaryLanguages().contains(langLocale) && langPref == LANGUAGE_SYSTEM + val lang = if (isAutoLang) langLocale else langPref + val collator = Collator.getInstance(sysLocale()) + val callCounts = HashMap() + allRecentCalls.forEach { call -> + val key = call.phoneNumber.normalizePhoneNumber() + if (key.isNotEmpty()) callCounts[key] = (callCounts[key] ?: 0) + 1 + } val filtered = allContacts.filter { contact -> - val langPref = config.dialpadSecondaryLanguage ?: "" - val langLocale = Locale.getDefault().language - val isAutoLang = DialpadT9.getSupportedSecondaryLanguages().contains(langLocale) && langPref == LANGUAGE_SYSTEM - val lang = if (isAutoLang) langLocale else langPref - val convertedName = DialpadT9.convertLettersToNumbers( contact.name.normalizeString().uppercase(), lang) - val convertedNameWithoutSpaces = convertedName.filterNot { it.isWhitespace() } + val convertedNameDigitsOnly = convertedName.filter { it.isDigit() } val convertedNickname = DialpadT9.convertLettersToNumbers( contact.nickname.normalizeString().uppercase(), lang) + val convertedNicknameDigitsOnly = convertedNickname.filter { it.isDigit() } val convertedCompany = DialpadT9.convertLettersToNumbers( contact.organization.company.normalizeString().uppercase(), lang) + val convertedCompanyDigitsOnly = convertedCompany.filter { it.isDigit() } val convertedNameToDisplay = DialpadT9.convertLettersToNumbers( contact.getNameToDisplay().normalizeString().uppercase(), lang) - val convertedNameToDisplayWithoutSpaces = convertedNameToDisplay.filterNot { it.isWhitespace() } + val convertedNameToDisplayDigitsOnly = convertedNameToDisplay.filter { it.isDigit() } contact.doesContainPhoneNumber(text, convertLetters = true, search = true) || (convertedName.contains(text, true)) - || (convertedNameWithoutSpaces.contains(text, true)) + || (convertedNameDigitsOnly.contains(text, true)) || (convertedNameToDisplay.contains(text, true)) - || (convertedNameToDisplayWithoutSpaces.contains(text, true)) + || (convertedNameToDisplayDigitsOnly.contains(text, true)) || (convertedNickname.contains(text, true)) + || (convertedNicknameDigitsOnly.contains(text, true)) || (convertedCompany.contains(text, true)) - }.sortedWith(compareBy(collator) { - it.getNameToDisplay() - }).toMutableList() as ArrayList + || (convertedCompanyDigitsOnly.contains(text, true)) + }.sortedWith( + compareByDescending { contact -> + contact.phoneNumbers.maxOfOrNull { callCounts[it.value.normalizePhoneNumber()] ?: 0 } ?: 0 + }.thenByDescending { + DialpadT9.convertLettersToNumbers( + it.getNameToDisplay().normalizeString().uppercase(), lang) + .filter { c -> c.isDigit() } + .startsWith(text) + }.thenBy(collator) { it.getNameToDisplay() } + ).toMutableList() as ArrayList // binding.letterFastscroller.setupWithContacts(binding.dialpadList, filtered) diff --git a/app/src/main/kotlin/com/goodwy/dialer/adapters/ContactsAdapter.kt b/app/src/main/kotlin/com/goodwy/dialer/adapters/ContactsAdapter.kt index b84ab69e..b6928b58 100755 --- a/app/src/main/kotlin/com/goodwy/dialer/adapters/ContactsAdapter.kt +++ b/app/src/main/kotlin/com/goodwy/dialer/adapters/ContactsAdapter.kt @@ -406,14 +406,21 @@ class ContactsAdapter( private fun String.highlightTextFromNumbers(textToHighlight: String, primaryColor: Int, language: String): SpannableString { val spannableString = SpannableString(this) val digits = DialpadT9.convertLettersToNumbers(this.uppercase(), language) - if (digits.contains(textToHighlight)) { - //offsetting the characters to be extracted, by the number of first non-letter or non-numeric characters. - val lettersAndNumbers = Regex("[^A-Za-z0-9 ]") - val firstSymbol = lettersAndNumbers.replace(this, "").firstOrNull() - val offsetIndex = if (firstSymbol != null) this.indexOf(firstSymbol, 0, true) else 0 - - val startIndex = digits.indexOf(textToHighlight, 0, true) + offsetIndex - val endIndex = (startIndex + textToHighlight.length).coerceAtMost(length) + + val compressed = StringBuilder(digits.length) + val originalPos = IntArray(digits.length) + var written = 0 + digits.forEachIndexed { i, c -> + if (c.isDigit()) { + compressed.append(c) + originalPos[written++] = i + } + } + val start = compressed.indexOf(textToHighlight, 0, ignoreCase = true) + if (start >= 0) { + val startIndex = originalPos[start] + val endCompressed = (start + textToHighlight.length - 1).coerceAtMost(written - 1) + val endIndex = (originalPos[endCompressed] + 1).coerceAtMost(length) try { spannableString.setSpan(ForegroundColorSpan(primaryColor), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_INCLUSIVE) } catch (_: IndexOutOfBoundsException) { @@ -458,25 +465,11 @@ class ContactsAdapter( if (normalizedName.contains(normalizedSearchText, true)) { name.highlightTextPart(normalizedSearchText, properPrimaryColor) } else { - var spacedTextToHighlight = textToHighlight - val strippedName = PhoneNumberUtils.convertKeypadLettersToDigits(name.filterNot { it.isWhitespace() }) - val startIndex = strippedName.indexOf(textToHighlight) - - if (strippedName.contains(textToHighlight) && strippedName != name) { - for (i in 0..spacedTextToHighlight.length) { - if (name.toCharArray().size > startIndex + i) { - if (name[startIndex + i].isWhitespace()) { - spacedTextToHighlight = spacedTextToHighlight.replaceRange(i, i, " ") - } - } - } - } - val langPref = activity.config.dialpadSecondaryLanguage ?: "" val langLocale = Locale.getDefault().language val isAutoLang = DialpadT9.getSupportedSecondaryLanguages().contains(langLocale) && langPref == LANGUAGE_SYSTEM val lang = if (isAutoLang) langLocale else langPref - name.highlightTextFromNumbers(spacedTextToHighlight, properPrimaryColor, lang) + name.highlightTextFromNumbers(textToHighlight, properPrimaryColor, lang) } } }