mirror of
https://github.com/SimpleMobileTools/Simple-SMS-Messenger.git
synced 2025-06-05 21:49:22 +02:00
Use DiffUtil at conversations screen
This commit is contained in:
@@ -299,7 +299,7 @@ class MainActivity : SimpleActivity() {
|
|||||||
val currAdapter = conversations_list.adapter
|
val currAdapter = conversations_list.adapter
|
||||||
if (currAdapter == null) {
|
if (currAdapter == null) {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
ConversationsAdapter(this, sortedConversations, conversations_list) {
|
ConversationsAdapter(this, conversations_list) {
|
||||||
Intent(this, ThreadActivity::class.java).apply {
|
Intent(this, ThreadActivity::class.java).apply {
|
||||||
val conversation = it as Conversation
|
val conversation = it as Conversation
|
||||||
putExtra(THREAD_ID, conversation.threadId)
|
putExtra(THREAD_ID, conversation.threadId)
|
||||||
@@ -308,6 +308,7 @@ class MainActivity : SimpleActivity() {
|
|||||||
}
|
}
|
||||||
}.apply {
|
}.apply {
|
||||||
conversations_list.adapter = this
|
conversations_list.adapter = this
|
||||||
|
updateConversations(sortedConversations)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (areSystemAnimationsEnabled) {
|
if (areSystemAnimationsEnabled) {
|
||||||
@@ -315,13 +316,14 @@ class MainActivity : SimpleActivity() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
(currAdapter as ConversationsAdapter).updateConversations(sortedConversations)
|
(currAdapter as ConversationsAdapter).updateConversations(sortedConversations) {
|
||||||
if (currAdapter.conversations.isEmpty()) {
|
if (currAdapter.currentList.isEmpty()) {
|
||||||
conversations_fastscroller.beGone()
|
conversations_fastscroller.beGone()
|
||||||
no_conversations_placeholder.text = getString(R.string.no_conversations_found)
|
no_conversations_placeholder.text = getString(R.string.no_conversations_found)
|
||||||
no_conversations_placeholder.beVisible()
|
no_conversations_placeholder.beVisible()
|
||||||
no_conversations_placeholder_2.beVisible()
|
no_conversations_placeholder_2.beVisible()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,15 +2,18 @@ package com.simplemobiletools.smsmessenger.adapters
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
|
import android.os.Parcelable
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
|
import com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
|
||||||
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
|
import com.simplemobiletools.commons.adapters.MyRecyclerViewListAdapter
|
||||||
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.KEY_PHONE
|
import com.simplemobiletools.commons.helpers.KEY_PHONE
|
||||||
@@ -26,14 +29,23 @@ import com.simplemobiletools.smsmessenger.models.Conversation
|
|||||||
import kotlinx.android.synthetic.main.item_conversation.view.*
|
import kotlinx.android.synthetic.main.item_conversation.view.*
|
||||||
|
|
||||||
class ConversationsAdapter(
|
class ConversationsAdapter(
|
||||||
activity: SimpleActivity, var conversations: ArrayList<Conversation>, recyclerView: MyRecyclerView, itemClick: (Any) -> Unit
|
activity: SimpleActivity, recyclerView: MyRecyclerView, itemClick: (Any) -> Unit
|
||||||
) : MyRecyclerViewAdapter(activity, recyclerView, itemClick), RecyclerViewFastScroller.OnPopupTextUpdate {
|
) : MyRecyclerViewListAdapter<Conversation>(activity, recyclerView, ConversationDiffCallback(), itemClick), RecyclerViewFastScroller.OnPopupTextUpdate {
|
||||||
private var fontSize = activity.getTextSize()
|
private var fontSize = activity.getTextSize()
|
||||||
private var drafts = HashMap<Long, String?>()
|
private var drafts = HashMap<Long, String?>()
|
||||||
|
|
||||||
|
private var recyclerViewState: Parcelable? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setupDragListener(true)
|
setupDragListener(true)
|
||||||
fetchDrafts(drafts)
|
fetchDrafts(drafts)
|
||||||
|
setHasStableIds(true)
|
||||||
|
|
||||||
|
registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||||
|
override fun onChanged() = restoreRecyclerViewState()
|
||||||
|
override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) = restoreRecyclerViewState()
|
||||||
|
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) = restoreRecyclerViewState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getActionMenuId() = R.menu.cab_conversations
|
override fun getActionMenuId() = R.menu.cab_conversations
|
||||||
@@ -71,13 +83,13 @@ class ConversationsAdapter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSelectableItemCount() = conversations.size
|
override fun getSelectableItemCount() = itemCount
|
||||||
|
|
||||||
override fun getIsItemSelectable(position: Int) = true
|
override fun getIsItemSelectable(position: Int) = true
|
||||||
|
|
||||||
override fun getItemSelectionKey(position: Int) = conversations.getOrNull(position)?.hashCode()
|
override fun getItemSelectionKey(position: Int) = currentList.getOrNull(position)?.hashCode()
|
||||||
|
|
||||||
override fun getItemKeyPosition(key: Int) = conversations.indexOfFirst { it.hashCode() == key }
|
override fun getItemKeyPosition(key: Int) = currentList.indexOfFirst { it.hashCode() == key }
|
||||||
|
|
||||||
override fun onActionModeCreated() {}
|
override fun onActionModeCreated() {}
|
||||||
|
|
||||||
@@ -86,14 +98,14 @@ class ConversationsAdapter(
|
|||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_conversation, parent)
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_conversation, parent)
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val conversation = conversations[position]
|
val conversation = getItem(position)
|
||||||
holder.bindView(conversation, true, true) { itemView, layoutPosition ->
|
holder.bindView(conversation, allowSingleClick = true, allowLongClick = true) { itemView, _ ->
|
||||||
setupView(itemView, conversation)
|
setupView(itemView, conversation)
|
||||||
}
|
}
|
||||||
bindViewHolder(holder)
|
bindViewHolder(holder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount() = conversations.size
|
override fun getItemId(position: Int) = getItem(position).threadId
|
||||||
|
|
||||||
override fun onViewRecycled(holder: ViewHolder) {
|
override fun onViewRecycled(holder: ViewHolder) {
|
||||||
super.onViewRecycled(holder)
|
super.onViewRecycled(holder)
|
||||||
@@ -118,8 +130,7 @@ class ConversationsAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val numbersToBlock = getSelectedItems()
|
val numbersToBlock = getSelectedItems()
|
||||||
val positions = getSelectedItemPositions()
|
val newList = currentList.toMutableList().apply { removeAll(numbersToBlock) }
|
||||||
conversations.removeAll(numbersToBlock)
|
|
||||||
|
|
||||||
ensureBackgroundThread {
|
ensureBackgroundThread {
|
||||||
numbersToBlock.map { it.phoneNumber }.forEach { number ->
|
numbersToBlock.map { it.phoneNumber }.forEach { number ->
|
||||||
@@ -127,7 +138,7 @@ class ConversationsAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
activity.runOnUiThread {
|
activity.runOnUiThread {
|
||||||
removeSelectedItems(positions)
|
submitList(newList)
|
||||||
finishActMode()
|
finishActMode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,25 +176,25 @@ class ConversationsAdapter(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val conversationsToRemove = conversations.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
val conversationsToRemove = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||||
val positions = getSelectedItemPositions()
|
|
||||||
conversationsToRemove.forEach {
|
conversationsToRemove.forEach {
|
||||||
activity.deleteConversation(it.threadId)
|
activity.deleteConversation(it.threadId)
|
||||||
activity.notificationManager.cancel(it.hashCode())
|
activity.notificationManager.cancel(it.hashCode())
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
val newList = try {
|
||||||
conversations.removeAll(conversationsToRemove.toSet())
|
currentList.toMutableList().apply { removeAll(conversationsToRemove) }
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
|
currentList.toMutableList()
|
||||||
}
|
}
|
||||||
|
|
||||||
activity.runOnUiThread {
|
activity.runOnUiThread {
|
||||||
if (conversationsToRemove.isEmpty()) {
|
if (newList.none { selectedKeys.contains(it.hashCode()) }) {
|
||||||
refreshMessages()
|
refreshMessages()
|
||||||
finishActMode()
|
finishActMode()
|
||||||
} else {
|
} else {
|
||||||
removeSelectedItems(positions)
|
submitList(newList)
|
||||||
if (conversations.isEmpty()) {
|
if (newList.isEmpty()) {
|
||||||
refreshMessages()
|
refreshMessages()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,7 +206,7 @@ class ConversationsAdapter(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val conversationsMarkedAsRead = conversations.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
val conversationsMarkedAsRead = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||||
ensureBackgroundThread {
|
ensureBackgroundThread {
|
||||||
conversationsMarkedAsRead.filter { conversation -> !conversation.read }.forEach {
|
conversationsMarkedAsRead.filter { conversation -> !conversation.read }.forEach {
|
||||||
activity.markThreadMessagesRead(it.threadId)
|
activity.markThreadMessagesRead(it.threadId)
|
||||||
@@ -213,7 +224,7 @@ class ConversationsAdapter(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val conversationsMarkedAsUnread = conversations.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
val conversationsMarkedAsUnread = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||||
ensureBackgroundThread {
|
ensureBackgroundThread {
|
||||||
conversationsMarkedAsUnread.filter { conversation -> conversation.read }.forEach {
|
conversationsMarkedAsUnread.filter { conversation -> conversation.read }.forEach {
|
||||||
activity.markThreadMessagesUnread(it.threadId)
|
activity.markThreadMessagesUnread(it.threadId)
|
||||||
@@ -236,7 +247,7 @@ class ConversationsAdapter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSelectedItems() = conversations.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
private fun getSelectedItems() = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||||
|
|
||||||
private fun pinConversation(pin: Boolean) {
|
private fun pinConversation(pin: Boolean) {
|
||||||
val conversations = getSelectedItems()
|
val conversations = getSelectedItems()
|
||||||
@@ -275,14 +286,9 @@ class ConversationsAdapter(
|
|||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateConversations(newConversations: ArrayList<Conversation>) {
|
fun updateConversations(newConversations: ArrayList<Conversation>, commitCallback: (() -> Unit)? = null) {
|
||||||
val latestConversations = newConversations.clone() as ArrayList<Conversation>
|
saveRecyclerViewState()
|
||||||
val oldHashCode = conversations.hashCode()
|
submitList(newConversations.toList(), commitCallback)
|
||||||
val newHashCode = latestConversations.hashCode()
|
|
||||||
if (newHashCode != oldHashCode) {
|
|
||||||
conversations = latestConversations
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateDrafts() {
|
fun updateDrafts() {
|
||||||
@@ -346,5 +352,23 @@ class ConversationsAdapter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onChange(position: Int) = conversations.getOrNull(position)?.title ?: ""
|
override fun onChange(position: Int) = currentList.getOrNull(position)?.title ?: ""
|
||||||
|
|
||||||
|
private fun saveRecyclerViewState() {
|
||||||
|
recyclerViewState = recyclerView.layoutManager?.onSaveInstanceState()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun restoreRecyclerViewState() {
|
||||||
|
recyclerView.layoutManager?.onRestoreInstanceState(recyclerViewState)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ConversationDiffCallback : DiffUtil.ItemCallback<Conversation>() {
|
||||||
|
override fun areItemsTheSame(oldItem: Conversation, newItem: Conversation): Boolean {
|
||||||
|
return oldItem.areItemsTheSame(newItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: Conversation, newItem: Conversation): Boolean {
|
||||||
|
return oldItem.areContentsTheSame(newItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,10 @@ data class Conversation(
|
|||||||
@ColumnInfo(name = "is_scheduled") var isScheduled: Boolean = false
|
@ColumnInfo(name = "is_scheduled") var isScheduled: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
fun areItemsTheSame(other: Conversation): Boolean {
|
||||||
|
return threadId == other.threadId
|
||||||
|
}
|
||||||
|
|
||||||
fun areContentsTheSame(other: Conversation): Boolean {
|
fun areContentsTheSame(other: Conversation): Boolean {
|
||||||
return snippet == other.snippet &&
|
return snippet == other.snippet &&
|
||||||
date == other.date &&
|
date == other.date &&
|
||||||
|
Reference in New Issue
Block a user