From e2fe55dd75cbd4262ece6e970942abc5bf66a4e6 Mon Sep 17 00:00:00 2001 From: Naveen Date: Sun, 5 May 2024 05:20:10 +0530 Subject: [PATCH] Use list adapter for efficient updates --- .../phone/adapters/RecentCallsAdapter.kt | 90 ++++++++++++------- .../phone/dialogs/ShowGroupedCallsDialog.kt | 2 +- .../phone/fragments/RecentsFragment.kt | 2 +- .../org/fossify/phone/models/CallLogItem.kt | 2 +- app/src/main/res/layout/item_recent_call.xml | 2 - 5 files changed, 63 insertions(+), 35 deletions(-) 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 027202d1..d867ece4 100644 --- a/app/src/main/kotlin/org/fossify/phone/adapters/RecentCallsAdapter.kt +++ b/app/src/main/kotlin/org/fossify/phone/adapters/RecentCallsAdapter.kt @@ -9,8 +9,9 @@ import android.text.TextUtils import android.util.TypedValue import android.view.* import android.widget.PopupMenu +import androidx.recyclerview.widget.DiffUtil import com.bumptech.glide.Glide -import org.fossify.commons.adapters.MyRecyclerViewAdapter +import org.fossify.commons.adapters.MyRecyclerViewListAdapter import org.fossify.commons.dialogs.ConfirmationDialog import org.fossify.commons.dialogs.FeatureLockedDialog import org.fossify.commons.extensions.* @@ -32,13 +33,12 @@ import org.joda.time.DateTime class RecentCallsAdapter( activity: SimpleActivity, - private var recentCalls: MutableList, recyclerView: MyRecyclerView, private val refreshItemsListener: RefreshItemsListener?, private val showOverflowMenu: Boolean, private val itemDelete: (List) -> Unit = {}, itemClick: (Any) -> Unit, -) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) { +) : MyRecyclerViewListAdapter(activity, recyclerView, RecentCallsDiffCallback(), itemClick) { private lateinit var outgoingCallIcon: Drawable private lateinit var incomingCallIcon: Drawable @@ -52,6 +52,8 @@ class RecentCallsAdapter( init { initDrawables() setupDragListener(true) + setHasStableIds(true) + recyclerView.itemAnimator?.changeDuration = 0 } override fun getActionMenuId() = R.menu.cab_recent_calls @@ -96,20 +98,22 @@ class RecentCallsAdapter( } } - override fun getSelectableItemCount() = recentCalls.filterIsInstance().size + override fun getItemId(position: Int) = currentList[position].getItemId().toLong() - override fun getIsItemSelectable(position: Int) = recentCalls[position] is RecentCall + override fun getSelectableItemCount() = currentList.filterIsInstance().size - override fun getItemSelectionKey(position: Int) = recentCalls.getOrNull(position)?.getItemId() + override fun getIsItemSelectable(position: Int) = currentList[position] is RecentCall - override fun getItemKeyPosition(key: Int) = recentCalls.indexOfFirst { it.getItemId() == key } + override fun getItemSelectionKey(position: Int) = currentList.getOrNull(position)?.getItemId() + + override fun getItemKeyPosition(key: Int) = currentList.indexOfFirst { it.getItemId() == key } override fun onActionModeCreated() {} override fun onActionModeDestroyed() {} override fun getItemViewType(position: Int): Int { - return when (recentCalls[position]) { + return when (currentList[position]) { is CallLogItem.Date -> VIEW_TYPE_DATE is RecentCall -> VIEW_TYPE_CALL } @@ -132,7 +136,7 @@ class RecentCallsAdapter( } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val callRecord = recentCalls[position] + val callRecord = currentList[position] when (holder) { is RecentCallDateViewHolder -> holder.bind(callRecord as CallLogItem.Date) is RecentCallViewHolder -> holder.bind(callRecord as RecentCall) @@ -141,8 +145,6 @@ class RecentCallsAdapter( bindViewHolder(holder) } - override fun getItemCount() = recentCalls.size - override fun onViewRecycled(holder: ViewHolder) { super.onViewRecycled(holder) if (!activity.isDestroyed && !activity.isFinishing) { @@ -152,6 +154,14 @@ class RecentCallsAdapter( } } + override fun submitList(list: List?) { + val layoutManager = recyclerView.layoutManager!! + val recyclerViewState = layoutManager.onSaveInstanceState() + super.submitList(list) { + layoutManager.onRestoreInstanceState(recyclerViewState) + } + } + fun initDrawables() { outgoingCallIcon = resources.getColoredDrawableWithColor(R.drawable.ic_outgoing_call_vector, activity.getProperTextColor()) incomingCallIcon = resources.getColoredDrawableWithColor(R.drawable.ic_incoming_call_vector, activity.getProperTextColor()) @@ -198,16 +208,14 @@ class RecentCallsAdapter( } val callsToBlock = getSelectedItems() - val positions = getSelectedItemPositions() - recentCalls.removeAll(callsToBlock) - ensureBackgroundThread { callsToBlock.map { it.phoneNumber }.forEach { number -> activity.addBlockedNumber(number) } + val recentCalls = currentList.toMutableList().also { it.removeAll(callsToBlock) } activity.runOnUiThread { - removeSelectedItems(positions) + submitList(recentCalls) finishActMode() } } @@ -255,7 +263,6 @@ class RecentCallsAdapter( } val callsToRemove = getSelectedItems() - val positions = getSelectedItemPositions() val idsToRemove = ArrayList() callsToRemove.forEach { idsToRemove.add(it.id) @@ -264,14 +271,11 @@ class RecentCallsAdapter( RecentsHelper(activity).removeRecentCalls(idsToRemove) { itemDelete(callsToRemove) - recentCalls.removeAll(callsToRemove) + val recentCalls = currentList.toMutableList().also { it.removeAll(callsToRemove) } activity.runOnUiThread { refreshItemsListener?.refreshItems() - if (recentCalls.isEmpty()) { - finishActMode() - } else { - removeSelectedItems(positions) - } + submitList(recentCalls) + finishActMode() } } } @@ -289,19 +293,17 @@ class RecentCallsAdapter( @SuppressLint("NotifyDataSetChanged") fun updateItems(newItems: List, highlightText: String = "") { textColor = activity.getProperTextColor() - if (newItems.hashCode() != recentCalls.hashCode()) { - recentCalls = newItems.toMutableList() + if (textToHighlight != highlightText) { textToHighlight = highlightText - recyclerView.resetItemCount() + submitList(newItems) notifyDataSetChanged() finishActMode() - } else if (textToHighlight != highlightText) { - textToHighlight = highlightText - notifyDataSetChanged() + } else { + submitList(newItems) } } - private fun getSelectedItems() = recentCalls.filterIsInstance() + private fun getSelectedItems() = currentList.filterIsInstance() .filter { selectedKeys.contains(it.getItemId()) } private fun getSelectedPhoneNumber() = getSelectedItems().firstOrNull()?.phoneNumber @@ -411,11 +413,13 @@ class RecentCallsAdapter( private inner class RecentCallViewHolder(val binding: ItemRecentCallBinding) : ViewHolder(binding.root) { fun bind(call: RecentCall) = bindView( - any = call, + item = call, allowSingleClick = refreshItemsListener != null && !call.isUnknownNumber, allowLongClick = refreshItemsListener != null && !call.isUnknownNumber ) { _, _ -> binding.apply { + root.setupViewBackground(activity) + val currentFontSize = fontSize itemRecentsHolder.isSelected = selectedKeys.contains(call.id) val name = findContactByCall(call)?.getNameToDisplay() ?: call.name @@ -521,3 +525,29 @@ class RecentCallsAdapter( private const val VIEW_TYPE_CALL = 1 } } + +class RecentCallsDiffCallback : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: CallLogItem, newItem: CallLogItem) = oldItem.getItemId() == newItem.getItemId() + + override fun areContentsTheSame(oldItem: CallLogItem, newItem: CallLogItem): Boolean { + return when { + oldItem is CallLogItem.Date && newItem is CallLogItem.Date -> oldItem.timestamp == newItem.timestamp && oldItem.dayCode == newItem.dayCode + oldItem is RecentCall && newItem is RecentCall -> { + oldItem.phoneNumber == newItem.phoneNumber && + oldItem.name == newItem.name && + oldItem.photoUri == newItem.photoUri && + oldItem.startTS == newItem.startTS && + oldItem.duration == newItem.duration && + oldItem.type == newItem.type && + oldItem.simID == newItem.simID && + oldItem.specificNumber == newItem.specificNumber && + oldItem.specificType == newItem.specificType && + oldItem.isUnknownNumber == newItem.isUnknownNumber && + oldItem.groupedCalls?.size == newItem.groupedCalls?.size + } + + else -> false + } + } +} diff --git a/app/src/main/kotlin/org/fossify/phone/dialogs/ShowGroupedCallsDialog.kt b/app/src/main/kotlin/org/fossify/phone/dialogs/ShowGroupedCallsDialog.kt index 237749e2..29285efa 100644 --- a/app/src/main/kotlin/org/fossify/phone/dialogs/ShowGroupedCallsDialog.kt +++ b/app/src/main/kotlin/org/fossify/phone/dialogs/ShowGroupedCallsDialog.kt @@ -18,13 +18,13 @@ class ShowGroupedCallsDialog(val activity: BaseSimpleActivity, recentCalls: List activity.runOnUiThread { RecentCallsAdapter( activity = activity as SimpleActivity, - recentCalls = recentCalls.toMutableList(), recyclerView = binding.selectGroupedCallsList, refreshItemsListener = null, showOverflowMenu = false, itemClick = {} ).apply { binding.selectGroupedCallsList.adapter = this + updateItems(recentCalls) } } 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 242fa356..f7f7a273 100644 --- a/app/src/main/kotlin/org/fossify/phone/fragments/RecentsFragment.kt +++ b/app/src/main/kotlin/org/fossify/phone/fragments/RecentsFragment.kt @@ -131,7 +131,6 @@ class RecentsFragment( if (binding.recentsList.adapter == null) { recentsAdapter = RecentCallsAdapter( activity = activity as SimpleActivity, - recentCalls = recents.toMutableList(), recyclerView = binding.recentsList, refreshItemsListener = this, showOverflowMenu = true, @@ -151,6 +150,7 @@ class RecentsFragment( ) binding.recentsList.adapter = recentsAdapter + recentsAdapter?.updateItems(recents) if (context.areSystemAnimationsEnabled) { binding.recentsList.scheduleLayoutAnimation() diff --git a/app/src/main/kotlin/org/fossify/phone/models/CallLogItem.kt b/app/src/main/kotlin/org/fossify/phone/models/CallLogItem.kt index 7231e657..fa1b5f41 100644 --- a/app/src/main/kotlin/org/fossify/phone/models/CallLogItem.kt +++ b/app/src/main/kotlin/org/fossify/phone/models/CallLogItem.kt @@ -8,7 +8,7 @@ sealed class CallLogItem { fun getItemId(): Int { return when (this) { - is Date -> timestamp.hashCode() + is Date -> dayCode.hashCode() is RecentCall -> id } } diff --git a/app/src/main/res/layout/item_recent_call.xml b/app/src/main/res/layout/item_recent_call.xml index 53505701..4e2cef64 100644 --- a/app/src/main/res/layout/item_recent_call.xml +++ b/app/src/main/res/layout/item_recent_call.xml @@ -5,10 +5,8 @@ android:id="@+id/item_recents_holder" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?attr/selectableItemBackground" android:clickable="true" android:focusable="true" - android:foreground="@drawable/selector" android:paddingTop="@dimen/medium_margin" android:paddingBottom="@dimen/medium_margin">