From 0550873225fa6e853e26f085d6ff6e68a587ae92 Mon Sep 17 00:00:00 2001 From: Naveen Date: Thu, 2 May 2024 01:19:07 +0530 Subject: [PATCH] Group call history by date Closes https://github.com/FossifyOrg/Phone/issues/96 --- .../phone/adapters/RecentCallsAdapter.kt | 240 +++++++++++------- .../org/fossify/phone/extensions/Long.kt | 13 + .../phone/fragments/RecentsFragment.kt | 111 +++++--- .../org/fossify/phone/helpers/Constants.kt | 2 - .../fossify/phone/helpers/RecentsHelper.kt | 31 +-- .../org/fossify/phone/models/CallLogItem.kt | 15 ++ .../org/fossify/phone/models/RecentCall.kt | 5 +- app/src/main/res/layout/item_recent_call.xml | 2 +- app/src/main/res/layout/item_recents_date.xml | 10 + gradle/libs.versions.toml | 2 +- 10 files changed, 290 insertions(+), 141 deletions(-) create mode 100644 app/src/main/kotlin/org/fossify/phone/extensions/Long.kt create mode 100644 app/src/main/kotlin/org/fossify/phone/models/CallLogItem.kt create mode 100644 app/src/main/res/layout/item_recents_date.xml diff --git a/app/src/main/kotlin/org/fossify/phone/adapters/RecentCallsAdapter.kt b/app/src/main/kotlin/org/fossify/phone/adapters/RecentCallsAdapter.kt index 238252eb..401a55a3 100644 --- a/app/src/main/kotlin/org/fossify/phone/adapters/RecentCallsAdapter.kt +++ b/app/src/main/kotlin/org/fossify/phone/adapters/RecentCallsAdapter.kt @@ -1,5 +1,6 @@ package org.fossify.phone.adapters +import android.annotation.SuppressLint import android.content.Intent import android.graphics.drawable.Drawable import android.provider.CallLog.Calls @@ -20,15 +21,18 @@ import org.fossify.phone.R import org.fossify.phone.activities.MainActivity import org.fossify.phone.activities.SimpleActivity import org.fossify.phone.databinding.ItemRecentCallBinding +import org.fossify.phone.databinding.ItemRecentsDateBinding import org.fossify.phone.dialogs.ShowGroupedCallsDialog import org.fossify.phone.extensions.* import org.fossify.phone.helpers.RecentsHelper import org.fossify.phone.interfaces.RefreshItemsListener +import org.fossify.phone.models.CallLogItem import org.fossify.phone.models.RecentCall +import org.joda.time.DateTime class RecentCallsAdapter( activity: SimpleActivity, - private var recentCalls: MutableList, + private var recentCalls: MutableList, recyclerView: MyRecyclerView, private val refreshItemsListener: RefreshItemsListener?, private val showOverflowMenu: Boolean, @@ -92,32 +96,48 @@ class RecentCallsAdapter( } } - override fun getSelectableItemCount() = recentCalls.size + override fun getSelectableItemCount() = recentCalls.filterIsInstance().size - override fun getIsItemSelectable(position: Int) = true + override fun getIsItemSelectable(position: Int) = recentCalls[position] is RecentCall - override fun getItemSelectionKey(position: Int) = recentCalls.getOrNull(position)?.id + override fun getItemSelectionKey(position: Int) = recentCalls.getOrNull(position)?.getItemId() - override fun getItemKeyPosition(key: Int) = recentCalls.indexOfFirst { it.id == key } + override fun getItemKeyPosition(key: Int) = recentCalls.indexOfFirst { it.getItemId() == key } override fun onActionModeCreated() {} override fun onActionModeDestroyed() {} + override fun getItemViewType(position: Int): Int { + return when (recentCalls[position]) { + is CallLogItem.Date -> VIEW_TYPE_DATE + is RecentCall -> VIEW_TYPE_CALL + } + } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - return createViewHolder(ItemRecentCallBinding.inflate(layoutInflater, parent, false).root) + val viewHolder = when (viewType) { + VIEW_TYPE_DATE -> RecentCallDateViewHolder( + ItemRecentsDateBinding.inflate(layoutInflater, parent, false) + ) + + VIEW_TYPE_CALL -> RecentCallViewHolder( + ItemRecentCallBinding.inflate(layoutInflater, parent, false) + ) + + else -> throw IllegalArgumentException("Unknown view type: $viewType") + } + + return viewHolder } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val recentCall = recentCalls[position] - holder.bindView( - any = recentCall, - allowSingleClick = refreshItemsListener != null && !recentCall.isUnknownNumber, - allowLongClick = refreshItemsListener != null && !recentCall.isUnknownNumber - ) { itemView, _ -> - val binding = ItemRecentCallBinding.bind(itemView) - setupView(binding, recentCall) + val callRecord = recentCalls[position] + when (holder) { + is RecentCallDateViewHolder -> holder.bind(callRecord as CallLogItem.Date) + is RecentCallViewHolder -> holder.bind(callRecord as RecentCall) } + bindViewHolder(holder) } @@ -126,8 +146,8 @@ class RecentCallsAdapter( override fun onViewRecycled(holder: ViewHolder) { super.onViewRecycled(holder) if (!activity.isDestroyed && !activity.isFinishing) { - ItemRecentCallBinding.bind(holder.itemView).apply { - Glide.with(activity).clear(itemRecentsImage) + if (holder is RecentCallViewHolder) { + Glide.with(activity).clear(holder.binding.itemRecentsImage) } } } @@ -266,7 +286,9 @@ class RecentCallsAdapter( } } - fun updateItems(newItems: List, highlightText: String = "") { + @SuppressLint("NotifyDataSetChanged") + fun updateItems(newItems: List, highlightText: String = "") { + textColor = activity.getProperTextColor() if (newItems.hashCode() != recentCalls.hashCode()) { recentCalls = newItems.toMutableList() textToHighlight = highlightText @@ -279,84 +301,11 @@ class RecentCallsAdapter( } } - private fun getSelectedItems() = recentCalls.filter { selectedKeys.contains(it.id) } as ArrayList + private fun getSelectedItems() = recentCalls.filterIsInstance() + .filter { selectedKeys.contains(it.getItemId()) } private fun getSelectedPhoneNumber() = getSelectedItems().firstOrNull()?.phoneNumber - private fun setupView(binding: ItemRecentCallBinding, call: RecentCall) { - binding.apply { - val currentFontSize = fontSize - itemRecentsHolder.isSelected = selectedKeys.contains(call.id) - val name = findContactByCall(call)?.getNameToDisplay() ?: call.name - var nameToShow = SpannableString(name) - if (call.specificType.isNotEmpty()) { - nameToShow = SpannableString("${name} - ${call.specificType}") - - // show specific number at "Show call details" dialog too - if (refreshItemsListener == null) { - nameToShow = SpannableString("${name} - ${call.specificType}, ${call.specificNumber}") - } - } - - if (call.groupedCalls != null) { - nameToShow = SpannableString("$nameToShow (${call.groupedCalls.size})") - } - - if (textToHighlight.isNotEmpty() && nameToShow.contains(textToHighlight, true)) { - nameToShow = SpannableString(nameToShow.toString().highlightTextPart(textToHighlight, properPrimaryColor)) - } - - itemRecentsName.apply { - text = nameToShow - setTextColor(textColor) - setTextSize(TypedValue.COMPLEX_UNIT_PX, currentFontSize) - } - - itemRecentsDateTime.apply { - text = (call.startTS / 1000).toInt().formatDateOrTime(context, refreshItemsListener != null, false) - setTextColor(if (call.type == Calls.MISSED_TYPE) redColor else textColor) - setTextSize(TypedValue.COMPLEX_UNIT_PX, currentFontSize * 0.8f) - } - - itemRecentsDuration.apply { - text = call.duration.getFormattedDuration() - setTextColor(textColor) - beVisibleIf(call.type != Calls.MISSED_TYPE && call.type != Calls.REJECTED_TYPE && call.duration > 0) - setTextSize(TypedValue.COMPLEX_UNIT_PX, currentFontSize * 0.8f) - if (!showOverflowMenu) { - itemRecentsDuration.setPadding(0, 0, durationPadding, 0) - } - } - - itemRecentsSimImage.beVisibleIf(areMultipleSIMsAvailable && call.simID != -1) - itemRecentsSimId.beVisibleIf(areMultipleSIMsAvailable && call.simID != -1) - if (areMultipleSIMsAvailable && call.simID != -1) { - itemRecentsSimImage.applyColorFilter(textColor) - itemRecentsSimId.setTextColor(textColor.getContrastColor()) - itemRecentsSimId.text = call.simID.toString() - } - - SimpleContactsHelper(root.context).loadContactImage(call.photoUri, itemRecentsImage, call.name) - - val drawable = when (call.type) { - Calls.OUTGOING_TYPE -> outgoingCallIcon - Calls.MISSED_TYPE -> incomingMissedCallIcon - else -> incomingCallIcon - } - - itemRecentsType.setImageDrawable(drawable) - - overflowMenuIcon.beVisibleIf(showOverflowMenu) - overflowMenuIcon.drawable.apply { - mutate() - setTint(activity.getProperTextColor()) - } - overflowMenuIcon.setOnClickListener { - showPopupMenu(overflowMenuAnchor, call) - } - } - } - private fun showPopupMenu(view: View, call: RecentCall) { finishActMode() val theme = activity.getPopupMenuTheme() @@ -459,4 +408,111 @@ class RecentCallsAdapter( callback() selectedKeys.remove(callId) } + + private inner class RecentCallViewHolder(val binding: ItemRecentCallBinding) : ViewHolder(binding.root) { + fun bind(call: RecentCall) = bindView( + any = call, + allowSingleClick = refreshItemsListener != null && !call.isUnknownNumber, + allowLongClick = refreshItemsListener != null && !call.isUnknownNumber + ) { _, _ -> + binding.apply { + val currentFontSize = fontSize + itemRecentsHolder.isSelected = selectedKeys.contains(call.id) + val name = findContactByCall(call)?.getNameToDisplay() ?: call.name + var nameToShow = SpannableString(name) + if (call.specificType.isNotEmpty()) { + nameToShow = SpannableString("$name - ${call.specificType}") + + // show specific number at "Show call details" dialog too + if (refreshItemsListener == null) { + nameToShow = SpannableString("$name - ${call.specificType}, ${call.specificNumber}") + } + } + + if (call.groupedCalls != null) { + nameToShow = SpannableString("$nameToShow (${call.groupedCalls.size})") + } + + if (textToHighlight.isNotEmpty() && nameToShow.contains(textToHighlight, true)) { + nameToShow = SpannableString(nameToShow.toString().highlightTextPart(textToHighlight, properPrimaryColor)) + } + + itemRecentsName.apply { + text = nameToShow + setTextColor(textColor) + setTextSize(TypedValue.COMPLEX_UNIT_PX, currentFontSize) + } + + itemRecentsDateTime.apply { + text = if (refreshItemsListener == null) { + call.startTS.formatDateOrTime(context, hideTimeAtOtherDays = false, showYearEvenIfCurrent = false) + } else { + call.startTS.formatTime(activity) + } + + setTextColor(if (call.type == Calls.MISSED_TYPE) redColor else textColor) + setTextSize(TypedValue.COMPLEX_UNIT_PX, currentFontSize * 0.8f) + } + + itemRecentsDuration.apply { + text = call.duration.getFormattedDuration() + setTextColor(textColor) + beVisibleIf(call.type != Calls.MISSED_TYPE && call.type != Calls.REJECTED_TYPE && call.duration > 0) + setTextSize(TypedValue.COMPLEX_UNIT_PX, currentFontSize * 0.8f) + if (!showOverflowMenu) { + itemRecentsDuration.setPadding(0, 0, durationPadding, 0) + } + } + + itemRecentsSimImage.beVisibleIf(areMultipleSIMsAvailable && call.simID != -1) + itemRecentsSimId.beVisibleIf(areMultipleSIMsAvailable && call.simID != -1) + if (areMultipleSIMsAvailable && call.simID != -1) { + itemRecentsSimImage.applyColorFilter(textColor) + itemRecentsSimId.setTextColor(textColor.getContrastColor()) + itemRecentsSimId.text = call.simID.toString() + } + + SimpleContactsHelper(root.context).loadContactImage(call.photoUri, itemRecentsImage, call.name) + + val drawable = when (call.type) { + Calls.OUTGOING_TYPE -> outgoingCallIcon + Calls.MISSED_TYPE -> incomingMissedCallIcon + else -> incomingCallIcon + } + + itemRecentsType.setImageDrawable(drawable) + + overflowMenuIcon.beVisibleIf(showOverflowMenu) + overflowMenuIcon.drawable.apply { + mutate() + setTint(activity.getProperTextColor()) + } + + overflowMenuIcon.setOnClickListener { + showPopupMenu(overflowMenuAnchor, call) + } + } + } + } + + private inner class RecentCallDateViewHolder(val binding: ItemRecentsDateBinding) : ViewHolder(binding.root) { + fun bind(date: CallLogItem.Date) { + binding.dateTextView.apply { + setTextColor(textColor.adjustAlpha(0.6f)) + setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 0.76f) + + val now = DateTime.now() + text = when (date.dayCode) { + now.millis.toDayCode() -> activity.getString(R.string.today) + now.minusDays(1).millis.toDayCode() -> activity.getString(R.string.yesterday) + else -> date.timestamp.formatDateOrTime(activity, hideTimeAtOtherDays = true, showYearEvenIfCurrent = false) + } + } + } + } + + companion object { + private const val VIEW_TYPE_DATE = 0 + private const val VIEW_TYPE_CALL = 1 + } } diff --git a/app/src/main/kotlin/org/fossify/phone/extensions/Long.kt b/app/src/main/kotlin/org/fossify/phone/extensions/Long.kt new file mode 100644 index 00000000..40a2f458 --- /dev/null +++ b/app/src/main/kotlin/org/fossify/phone/extensions/Long.kt @@ -0,0 +1,13 @@ +package org.fossify.phone.extensions + +import android.content.Context +import android.text.format.DateFormat +import org.fossify.commons.extensions.getTimeFormat +import java.util.Calendar +import java.util.Locale + +fun Long.formatTime(context: Context): String { + val cal = Calendar.getInstance(Locale.ENGLISH) + cal.timeInMillis = this + return DateFormat.format(context.getTimeFormat(), cal).toString() +} diff --git a/app/src/main/kotlin/org/fossify/phone/fragments/RecentsFragment.kt b/app/src/main/kotlin/org/fossify/phone/fragments/RecentsFragment.kt index f3036f81..bd2ec94d 100644 --- a/app/src/main/kotlin/org/fossify/phone/fragments/RecentsFragment.kt +++ b/app/src/main/kotlin/org/fossify/phone/fragments/RecentsFragment.kt @@ -15,15 +15,15 @@ import org.fossify.phone.activities.SimpleActivity import org.fossify.phone.adapters.RecentCallsAdapter import org.fossify.phone.databinding.FragmentRecentsBinding import org.fossify.phone.extensions.config -import org.fossify.phone.helpers.MIN_RECENTS_THRESHOLD import org.fossify.phone.helpers.RecentsHelper import org.fossify.phone.interfaces.RefreshItemsListener +import org.fossify.phone.models.CallLogItem import org.fossify.phone.models.RecentCall class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet), RefreshItemsListener { private lateinit var binding: FragmentRecentsBinding - private var allRecentCalls = listOf() + private var allRecentCalls = listOf() private var recentsAdapter: RecentCallsAdapter? = null override fun onFinishInflate() { @@ -76,15 +76,44 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage } } - private fun getRecentCalls(callback: (List) -> Unit) { - if (context?.config?.groupSubsequentCalls == true) { - RecentsHelper(context).getGroupedRecentCalls(MIN_RECENTS_THRESHOLD, allRecentCalls, callback) + private fun getRecentCalls(callback: (List) -> Unit) { + val context = context ?: return + val recentsHelper = RecentsHelper(context) + val previousRecents = allRecentCalls.filterIsInstance() + + if (context.config.groupSubsequentCalls) { + recentsHelper.getGroupedRecentCalls(previousRecents) { + callback(prepareCallLog(it)) + } } else { - RecentsHelper(context).getRecentCalls(MIN_RECENTS_THRESHOLD, allRecentCalls, callback) + recentsHelper.getRecentCalls(previousRecents) { + callback(prepareCallLog(it)) + } + } + } + + private fun prepareCallLog(recentCalls: List): List { + if (recentCalls.isEmpty()) { + return emptyList() } + + val log = mutableListOf() + var lastDayCode = "" + + for (call in recentCalls) { + val currentDayCode = call.getDayCode() + if (currentDayCode != lastDayCode) { + log += CallLogItem.Date(timestamp = call.startTS, dayCode = currentDayCode) + lastDayCode = currentDayCode + } + + log += call + } + + return log } - private fun gotRecents(recents: List) { + private fun gotRecents(recents: List) { if (recents.isEmpty()) { binding.apply { showOrHidePlaceholder(true) @@ -179,11 +208,12 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage override fun onSearchQueryChanged(text: String) { val fixedText = text.trim().replace("\\s+".toRegex(), " ") - val recentCalls = allRecentCalls.filter { - it.name.contains(fixedText, true) || it.doesContainPhoneNumber(fixedText) - }.sortedByDescending { - it.name.startsWith(fixedText, true) - }.toMutableList() as ArrayList + val recentCalls = allRecentCalls + .filter { + it is CallLogItem.Date || it is RecentCall && (it.name.contains(fixedText, true) || it.doesContainPhoneNumber(fixedText)) + }.sortedByDescending { + it is CallLogItem.Date || it is RecentCall && it.name.startsWith(fixedText, true) + } showOrHidePlaceholder(recentCalls.isEmpty()) recentsAdapter?.updateItems(recentCalls, fixedText) @@ -199,31 +229,54 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage } // hide private contacts from recent calls -private fun List.hidePrivateContacts(privateContacts: List, shouldHide: Boolean): List { +private fun List.hidePrivateContacts(privateContacts: List, shouldHide: Boolean): List { return if (shouldHide) { - filterNot { recent -> - val privateNumbers = privateContacts.flatMap { it.phoneNumbers }.map { it.value } - recent.phoneNumber in privateNumbers + val privateNumbers = privateContacts.flatMap { it.phoneNumbers }.map { it.value } + filterNot { record -> + when (record) { + is CallLogItem.Date -> false + is RecentCall -> record.phoneNumber in privateNumbers + } } } else { this } } -private fun List.setNamesIfEmpty(contacts: List, privateContacts: List): ArrayList { +private fun List.setNamesIfEmpty(contacts: List, privateContacts: List): List { + if (isEmpty()) return mutableListOf() + 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 + val result = mutableListOf() + + forEach { record -> + when (record) { + is CallLogItem.Date -> result += record + is RecentCall -> { + result += if (record.phoneNumber == record.name) { + val privateContact = privateContacts.firstOrNull { it.doesContainPhoneNumber(record.phoneNumber) } + val contact = contactsWithNumbers.firstOrNull { it.phoneNumbers.first().normalizedNumber == record.phoneNumber } + + when { + privateContact != null -> record.copyWithName(name = privateContact.getNameToDisplay()) + contact != null -> record.copyWithName(name = contact.getNameToDisplay()) + else -> record + } + } else { + record + } } - } else { - recent } - } as ArrayList + } + + return result +} + +private fun RecentCall.copyWithName(name: String): RecentCall { + return copy( + name = name, + groupedCalls = groupedCalls + ?.map { it.copy(name = name) } + ?.ifEmpty { null } + ) } diff --git a/app/src/main/kotlin/org/fossify/phone/helpers/Constants.kt b/app/src/main/kotlin/org/fossify/phone/helpers/Constants.kt index 19e94e34..a9c144d0 100644 --- a/app/src/main/kotlin/org/fossify/phone/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/phone/helpers/Constants.kt @@ -29,5 +29,3 @@ 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 = 50 diff --git a/app/src/main/kotlin/org/fossify/phone/helpers/RecentsHelper.kt b/app/src/main/kotlin/org/fossify/phone/helpers/RecentsHelper.kt index adc1edb7..0859f3dc 100644 --- a/app/src/main/kotlin/org/fossify/phone/helpers/RecentsHelper.kt +++ b/app/src/main/kotlin/org/fossify/phone/helpers/RecentsHelper.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.content.ContentValues import android.content.Context import android.provider.CallLog.Calls +import android.telephony.PhoneNumberUtils import org.fossify.commons.extensions.* import org.fossify.commons.helpers.* import org.fossify.commons.models.contacts.Contact @@ -15,15 +16,15 @@ import org.fossify.phone.models.RecentCall class RecentsHelper(private val context: Context) { companion object { private const val COMPARABLE_PHONE_NUMBER_LENGTH = 9 - private const val QUERY_LIMIT = 200 + private const val QUERY_LIMIT = 50 } private val contentUri = Calls.CONTENT_URI private var queryLimit = QUERY_LIMIT fun getRecentCalls( - queryLimit: Int = QUERY_LIMIT, previousRecents: List = ArrayList(), + queryLimit: Int = QUERY_LIMIT, callback: (List) -> Unit, ) { val privateCursor = context.getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true) @@ -68,26 +69,26 @@ class RecentsHelper(private val context: Context) { } fun getGroupedRecentCalls( - queryLimit: Int = QUERY_LIMIT, previousRecents: List = ArrayList(), callback: (List) -> Unit, ) { - getRecentCalls( - queryLimit = queryLimit, - previousRecents = previousRecents, - ) { recentCalls -> + getRecentCalls(previousRecents) { recentCalls -> callback( - groupSubsequentCalls( - calls = recentCalls, - shouldGroup = { a, b -> - "${a.phoneNumber}${a.name}${a.simID}" == "${b.phoneNumber}${b.name}${b.simID}" - } - ) + groupSubsequentCalls(calls = recentCalls) ) } } - private fun groupSubsequentCalls(calls: List, shouldGroup: (RecentCall, RecentCall) -> Boolean): List { + private fun shouldGroupCalls(callA: RecentCall, callB: RecentCall): Boolean { + if (callA.simID != callB.simID || callA.name != callB.name || callA.getDayCode() != callB.getDayCode()) { + return false + } + + @Suppress("DEPRECATION") + return PhoneNumberUtils.compare(callA.phoneNumber, callB.phoneNumber) + } + + private fun groupSubsequentCalls(calls: List): List { val result = mutableListOf() if (calls.isEmpty()) return result @@ -95,7 +96,7 @@ class RecentsHelper(private val context: Context) { val groupedCalls = mutableListOf() for (i in 1 until calls.size) { val nextCall = calls[i] - if (shouldGroup(currentCall, nextCall)) { + if (shouldGroupCalls(currentCall, nextCall)) { groupedCalls += nextCall } else { if (groupedCalls.isNotEmpty()) { diff --git a/app/src/main/kotlin/org/fossify/phone/models/CallLogItem.kt b/app/src/main/kotlin/org/fossify/phone/models/CallLogItem.kt new file mode 100644 index 00000000..7231e657 --- /dev/null +++ b/app/src/main/kotlin/org/fossify/phone/models/CallLogItem.kt @@ -0,0 +1,15 @@ +package org.fossify.phone.models + +sealed class CallLogItem { + data class Date( + val timestamp: Long, + val dayCode: String, + ) : CallLogItem() + + fun getItemId(): Int { + return when (this) { + is Date -> timestamp.hashCode() + is RecentCall -> id + } + } +} diff --git a/app/src/main/kotlin/org/fossify/phone/models/RecentCall.kt b/app/src/main/kotlin/org/fossify/phone/models/RecentCall.kt index 5df44329..fad4e9de 100644 --- a/app/src/main/kotlin/org/fossify/phone/models/RecentCall.kt +++ b/app/src/main/kotlin/org/fossify/phone/models/RecentCall.kt @@ -2,6 +2,7 @@ package org.fossify.phone.models import android.telephony.PhoneNumberUtils import org.fossify.commons.extensions.normalizePhoneNumber +import org.fossify.commons.extensions.toDayCode /** * Used at displaying recent calls. @@ -21,7 +22,7 @@ data class RecentCall( val specificType: String, val isUnknownNumber: Boolean, val groupedCalls: List? = null, -) { +) : CallLogItem() { fun doesContainPhoneNumber(text: String): Boolean { return if (text.toIntOrNull() != null) { val normalizedText = text.normalizePhoneNumber() @@ -33,4 +34,6 @@ data class RecentCall( false } } + + fun getDayCode() = startTS.toDayCode() } diff --git a/app/src/main/res/layout/item_recent_call.xml b/app/src/main/res/layout/item_recent_call.xml index 219859e6..53505701 100644 --- a/app/src/main/res/layout/item_recent_call.xml +++ b/app/src/main/res/layout/item_recent_call.xml @@ -97,7 +97,7 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toEndOf="@+id/item_recents_type" app:layout_constraintTop_toBottomOf="@id/item_recents_name" - tools:text="18.11.2022" /> + tools:text="4 July, 04:37 PM" /> + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aa4d50c0..d5e31039 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ kotlinxSerializationJson = "1.5.1" #Eventbus eventbus = "3.3.1" #Fossify -commons = "5381db38e6" +commons = "f55b000a7b" #Gradle gradlePlugins-agp = "8.3.1" #Other