package com.simplemobiletools.smsmessenger.adapters import android.graphics.Typeface import android.os.Parcelable import android.util.TypedValue import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller import com.simplemobiletools.commons.adapters.MyRecyclerViewListAdapter import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.SimpleContactsHelper import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.commons.views.MyRecyclerView import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.activities.SimpleActivity import com.simplemobiletools.smsmessenger.extensions.* import com.simplemobiletools.smsmessenger.models.Conversation import kotlinx.android.synthetic.main.item_conversation.view.* @Suppress("LeakingThis") abstract class BaseConversationsAdapter( activity: SimpleActivity, recyclerView: MyRecyclerView, onRefresh: () -> Unit, itemClick: (Any) -> Unit ) : MyRecyclerViewListAdapter(activity, recyclerView, ConversationDiffCallback(), itemClick, onRefresh), RecyclerViewFastScroller.OnPopupTextUpdate { private var fontSize = activity.getTextSize() private var drafts = HashMap() private var recyclerViewState: Parcelable? = null init { setupDragListener(true) ensureBackgroundThread { 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() }) } fun updateFontSize() { fontSize = activity.getTextSize() notifyDataSetChanged() } fun updateConversations(newConversations: ArrayList, commitCallback: (() -> Unit)? = null) { saveRecyclerViewState() submitList(newConversations.toList(), commitCallback) } fun updateDrafts() { ensureBackgroundThread { val newDrafts = HashMap() fetchDrafts(newDrafts) if (drafts.hashCode() != newDrafts.hashCode()) { drafts = newDrafts activity.runOnUiThread { notifyDataSetChanged() } } } } override fun getSelectableItemCount() = itemCount protected fun getSelectedItems() = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList override fun getIsItemSelectable(position: Int) = true override fun getItemSelectionKey(position: Int) = currentList.getOrNull(position)?.hashCode() override fun getItemKeyPosition(key: Int) = currentList.indexOfFirst { it.hashCode() == key } override fun onActionModeCreated() {} override fun onActionModeDestroyed() {} override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_conversation, parent) override fun onBindViewHolder(holder: ViewHolder, position: Int) { val conversation = getItem(position) holder.bindView(conversation, allowSingleClick = true, allowLongClick = true) { itemView, _ -> setupView(itemView, conversation) } bindViewHolder(holder) } override fun getItemId(position: Int) = getItem(position).threadId override fun onViewRecycled(holder: ViewHolder) { super.onViewRecycled(holder) if (!activity.isDestroyed && !activity.isFinishing) { Glide.with(activity).clear(holder.itemView.conversation_image) } } private fun fetchDrafts(drafts: HashMap) { drafts.clear() for ((threadId, draft) in activity.getAllDrafts()) { drafts[threadId] = draft } } private fun setupView(view: View, conversation: Conversation) { view.apply { setupViewBackground(activity) val smsDraft = drafts[conversation.threadId] draft_indicator.beVisibleIf(smsDraft != null) draft_indicator.setTextColor(properPrimaryColor) pin_indicator.beVisibleIf(activity.config.pinnedConversations.contains(conversation.threadId.toString())) pin_indicator.applyColorFilter(textColor) conversation_frame.isSelected = selectedKeys.contains(conversation.hashCode()) conversation_address.apply { text = conversation.title setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 1.2f) } conversation_body_short.apply { text = smsDraft ?: conversation.snippet setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 0.9f) } conversation_date.apply { text = conversation.date.formatDateOrTime(context, true, false) setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 0.8f) } val style = if (conversation.read) { conversation_body_short.alpha = 0.7f if (conversation.isScheduled) Typeface.ITALIC else Typeface.NORMAL } else { conversation_body_short.alpha = 1f if (conversation.isScheduled) Typeface.BOLD_ITALIC else Typeface.BOLD } conversation_address.setTypeface(null, style) conversation_body_short.setTypeface(null, style) arrayListOf(conversation_address, conversation_body_short, conversation_date).forEach { it.setTextColor(textColor) } // at group conversations we use an icon as the placeholder, not any letter val placeholder = if (conversation.isGroupConversation) { SimpleContactsHelper(context).getColoredGroupIcon(conversation.title) } else { null } SimpleContactsHelper(context).loadContactImage(conversation.photoUri, conversation_image, conversation.title, placeholder) } } 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() { override fun areItemsTheSame(oldItem: Conversation, newItem: Conversation): Boolean { return Conversation.areItemsTheSame(oldItem, newItem) } override fun areContentsTheSame(oldItem: Conversation, newItem: Conversation): Boolean { return Conversation.areContentsTheSame(oldItem, newItem) } } }