Migrate from kotlin synthetics to View binding

This commit is contained in:
Naveen 2023-08-17 15:54:29 +05:30
parent 3e1675d579
commit 0c01e607bb
No known key found for this signature in database
GPG key ID: 0E155DAD31671DA3
36 changed files with 1139 additions and 1083 deletions

View file

@ -2,11 +2,12 @@ package com.simplemobiletools.smsmessenger.adapters
import android.content.Intent
import android.graphics.drawable.Drawable
import android.view.View
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy
@ -21,11 +22,12 @@ import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.VCardViewerActivity
import com.simplemobiletools.smsmessenger.databinding.ItemAttachmentDocumentPreviewBinding
import com.simplemobiletools.smsmessenger.databinding.ItemAttachmentMediaPreviewBinding
import com.simplemobiletools.smsmessenger.databinding.ItemAttachmentVcardPreviewBinding
import com.simplemobiletools.smsmessenger.extensions.*
import com.simplemobiletools.smsmessenger.helpers.*
import com.simplemobiletools.smsmessenger.models.AttachmentSelection
import kotlinx.android.synthetic.main.item_attachment_media_preview.view.*
import kotlinx.android.synthetic.main.item_remove_attachment_button.view.*
class AttachmentsAdapter(
val activity: BaseSimpleActivity,
@ -46,36 +48,34 @@ class AttachmentsAdapter(
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutRes = when (viewType) {
ATTACHMENT_DOCUMENT -> R.layout.item_attachment_document_preview
ATTACHMENT_VCARD -> R.layout.item_attachment_vcard_preview
ATTACHMENT_MEDIA -> R.layout.item_attachment_media_preview
val inflater = LayoutInflater.from(parent.context)
val binding = when (viewType) {
ATTACHMENT_DOCUMENT -> ItemAttachmentDocumentPreviewBinding.inflate(inflater, parent, false)
ATTACHMENT_VCARD -> ItemAttachmentVcardPreviewBinding.inflate(inflater, parent, false)
ATTACHMENT_MEDIA -> ItemAttachmentMediaPreviewBinding.inflate(inflater, parent, false)
else -> throw IllegalArgumentException("Unknown view type: $viewType")
}
val view = activity.layoutInflater.inflate(layoutRes, parent, false)
return ViewHolder(view)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val attachment = getItem(position)
holder.bindView() { view, _ ->
holder.bindView { binding, _ ->
when (attachment.viewType) {
ATTACHMENT_DOCUMENT -> {
view.setupDocumentPreview(
(binding as ItemAttachmentDocumentPreviewBinding).setupDocumentPreview(
uri = attachment.uri,
title = attachment.filename,
mimeType = attachment.mimetype,
attachment = true,
onClick = { activity.launchViewIntent(attachment.uri, attachment.mimetype, attachment.filename) },
onRemoveButtonClicked = { removeAttachment(attachment) }
)
}
ATTACHMENT_VCARD -> {
view.setupVCardPreview(
(binding as ItemAttachmentVcardPreviewBinding).setupVCardPreview(
activity = activity,
uri = attachment.uri,
attachment = true,
onClick = {
val intent = Intent(activity, VCardViewerActivity::class.java).also {
it.putExtra(EXTRA_VCARD_URI, attachment.uri)
@ -85,7 +85,10 @@ class AttachmentsAdapter(
onRemoveButtonClicked = { removeAttachment(attachment) }
)
}
ATTACHMENT_MEDIA -> setupMediaPreview(view, attachment)
ATTACHMENT_MEDIA -> setupMediaPreview(
binding = binding as ItemAttachmentMediaPreviewBinding,
attachment = attachment
)
}
}
}
@ -113,13 +116,14 @@ class AttachmentsAdapter(
}
}
private fun setupMediaPreview(view: View, attachment: AttachmentSelection) {
view.apply {
media_attachment_holder.background.applyColorFilter(primaryColor.darkenColor())
media_attachment_holder.setOnClickListener {
private fun setupMediaPreview(binding: ItemAttachmentMediaPreviewBinding, attachment: AttachmentSelection) {
binding.apply {
mediaAttachmentHolder.background.applyColorFilter(primaryColor.darkenColor())
mediaAttachmentHolder.setOnClickListener {
activity.launchViewIntent(attachment.uri, attachment.mimetype, attachment.filename)
}
remove_attachment_button.apply {
removeAttachmentButtonHolder.removeAttachmentButton.apply {
beVisible()
background.applyColorFilter(primaryColor)
setOnClickListener {
@ -130,19 +134,21 @@ class AttachmentsAdapter(
val compressImage = attachment.mimetype.isImageMimeType() && !attachment.mimetype.isGifMimeType()
if (compressImage && attachment.isPending && config.mmsFileSizeLimit != FILE_SIZE_NONE) {
thumbnail.beGone()
compression_progress.beVisible()
compressionProgress.beVisible()
imageCompressor.compressImage(attachment.uri, config.mmsFileSizeLimit) { compressedUri ->
activity.runOnUiThread {
when (compressedUri) {
attachment.uri -> {
attachments.find { it.uri == attachment.uri }?.isPending = false
loadMediaPreview(view, attachment)
loadMediaPreview(this, attachment)
}
null -> {
activity.toast(R.string.compress_error)
removeAttachment(attachment)
}
else -> {
attachments.remove(attachment)
addAttachment(attachment.copy(uri = compressedUri, isPending = false))
@ -152,12 +158,12 @@ class AttachmentsAdapter(
}
}
} else {
loadMediaPreview(view, attachment)
loadMediaPreview(this, attachment)
}
}
}
private fun loadMediaPreview(view: View, attachment: AttachmentSelection) {
private fun loadMediaPreview(binding: ItemAttachmentMediaPreviewBinding, attachment: AttachmentSelection) {
val roundedCornersRadius = resources.getDimension(R.dimen.activity_margin).toInt()
val size = resources.getDimension(R.dimen.attachment_preview_size).toInt()
@ -165,7 +171,7 @@ class AttachmentsAdapter(
.diskCacheStrategy(DiskCacheStrategy.NONE)
.transform(CenterCrop(), RoundedCorners(roundedCornersRadius))
Glide.with(view.thumbnail)
Glide.with(binding.thumbnail)
.load(attachment.uri)
.transition(DrawableTransitionOptions.withCrossFade())
.override(size, size)
@ -178,20 +184,18 @@ class AttachmentsAdapter(
}
override fun onResourceReady(dr: Drawable?, a: Any?, t: Target<Drawable>?, d: DataSource?, i: Boolean): Boolean {
view.thumbnail.beVisible()
view.play_icon.beVisibleIf(attachment.mimetype.isVideoMimeType())
view.compression_progress.beGone()
binding.thumbnail.beVisible()
binding.playIcon.beVisibleIf(attachment.mimetype.isVideoMimeType())
binding.compressionProgress.beGone()
return false
}
})
.into(view.thumbnail)
.into(binding.thumbnail)
}
open inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bindView(callback: (itemView: View, adapterPosition: Int) -> Unit): View {
return itemView.apply {
callback(this, adapterPosition)
}
inner class ViewHolder(val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) {
fun bindView(callback: (binding: ViewBinding, adapterPosition: Int) -> Unit) {
callback(binding, adapterPosition)
}
}
}

View file

@ -15,7 +15,6 @@ import com.simplemobiletools.commons.helpers.SimpleContactsHelper
import com.simplemobiletools.commons.models.SimpleContact
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import com.simplemobiletools.smsmessenger.extensions.config
class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: ArrayList<SimpleContact>) : ArrayAdapter<SimpleContact>(activity, 0, contacts) {
var resultList = ArrayList<SimpleContact>()
@ -72,7 +71,7 @@ class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: Ar
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
if (results?.count ?: -1 > 0) {
if ((results?.count ?: -1) > 0) {
notifyDataSetChanged()
} else {
notifyDataSetInvalidated()

View file

@ -5,7 +5,6 @@ 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
@ -15,11 +14,10 @@ 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.databinding.ItemConversationBinding
import com.simplemobiletools.smsmessenger.extensions.*
import com.simplemobiletools.smsmessenger.models.Conversation
import kotlinx.android.synthetic.main.item_conversation.view.*
@Suppress("LeakingThis")
abstract class BaseConversationsAdapter(
@ -82,7 +80,10 @@ abstract class BaseConversationsAdapter(
override fun onActionModeDestroyed() {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_conversation, parent)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemConversationBinding.inflate(layoutInflater, parent, false)
return createViewHolder(binding.root)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val conversation = getItem(position)
@ -97,7 +98,8 @@ abstract class BaseConversationsAdapter(
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
if (!activity.isDestroyed && !activity.isFinishing) {
Glide.with(activity).clear(holder.itemView.conversation_image)
val itemView = ItemConversationBinding.bind(holder.itemView)
Glide.with(activity).clear(itemView.conversationImage)
}
}
@ -109,55 +111,55 @@ abstract class BaseConversationsAdapter(
}
private fun setupView(view: View, conversation: Conversation) {
view.apply {
setupViewBackground(activity)
ItemConversationBinding.bind(view).apply {
root.setupViewBackground(activity)
val smsDraft = drafts[conversation.threadId]
draft_indicator.beVisibleIf(smsDraft != null)
draft_indicator.setTextColor(properPrimaryColor)
draftIndicator.beVisibleIf(smsDraft != null)
draftIndicator.setTextColor(properPrimaryColor)
pin_indicator.beVisibleIf(activity.config.pinnedConversations.contains(conversation.threadId.toString()))
pin_indicator.applyColorFilter(textColor)
pinIndicator.beVisibleIf(activity.config.pinnedConversations.contains(conversation.threadId.toString()))
pinIndicator.applyColorFilter(textColor)
conversation_frame.isSelected = selectedKeys.contains(conversation.hashCode())
conversationFrame.isSelected = selectedKeys.contains(conversation.hashCode())
conversation_address.apply {
conversationAddress.apply {
text = conversation.title
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 1.2f)
}
conversation_body_short.apply {
conversationBodyShort.apply {
text = smsDraft ?: conversation.snippet
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 0.9f)
}
conversation_date.apply {
conversationDate.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
conversationBodyShort.alpha = 0.7f
if (conversation.isScheduled) Typeface.ITALIC else Typeface.NORMAL
} else {
conversation_body_short.alpha = 1f
conversationBodyShort.alpha = 1f
if (conversation.isScheduled) Typeface.BOLD_ITALIC else Typeface.BOLD
}
conversation_address.setTypeface(null, style)
conversation_body_short.setTypeface(null, style)
conversationAddress.setTypeface(null, style)
conversationBodyShort.setTypeface(null, style)
arrayListOf<TextView>(conversation_address, conversation_body_short, conversation_date).forEach {
arrayListOf(conversationAddress, conversationBodyShort, conversationDate).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)
SimpleContactsHelper(activity).getColoredGroupIcon(conversation.title)
} else {
null
}
SimpleContactsHelper(context).loadContactImage(conversation.photoUri, conversation_image, conversation.title, placeholder)
SimpleContactsHelper(activity).loadContactImage(conversation.photoUri, conversationImage, conversation.title, placeholder)
}
}

View file

@ -5,17 +5,14 @@ import android.util.TypedValue
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import com.bumptech.glide.Glide
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.databinding.ItemContactWithNumberBinding
import com.simplemobiletools.commons.extensions.getTextSize
import com.simplemobiletools.commons.helpers.SimpleContactsHelper
import com.simplemobiletools.commons.models.SimpleContact
import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import java.util.*
class ContactsAdapter(
activity: SimpleActivity, var contacts: ArrayList<SimpleContact>, recyclerView: MyRecyclerView, itemClick: (Any) -> Unit
@ -40,11 +37,14 @@ class ContactsAdapter(
override fun onActionModeDestroyed() {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_contact_with_number, parent)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemContactWithNumberBinding.inflate(layoutInflater, parent, false)
return createViewHolder(binding.root)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val contact = contacts[position]
holder.bindView(contact, true, false) { itemView, layoutPosition ->
holder.bindView(contact, allowSingleClick = true, allowLongClick = false) { itemView, _ ->
setupView(itemView, contact)
}
bindViewHolder(holder)
@ -62,27 +62,28 @@ class ContactsAdapter(
}
private fun setupView(view: View, contact: SimpleContact) {
view.apply {
findViewById<TextView>(R.id.item_contact_name).apply {
ItemContactWithNumberBinding.bind(view).apply {
itemContactName.apply {
text = contact.name
setTextColor(textColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 1.2f)
}
findViewById<TextView>(R.id.item_contact_number).apply {
itemContactNumber.apply {
text = TextUtils.join(", ", contact.phoneNumbers.map { it.normalizedNumber })
setTextColor(textColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize)
}
SimpleContactsHelper(context).loadContactImage(contact.photoUri, findViewById(R.id.item_contact_image), contact.name)
SimpleContactsHelper(activity).loadContactImage(contact.photoUri, itemContactImage, contact.name)
}
}
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
if (!activity.isDestroyed && !activity.isFinishing) {
Glide.with(activity).clear(holder.itemView.findViewById<ImageView>(R.id.item_contact_image))
val binding = ItemContactWithNumberBinding.bind(holder.itemView)
Glide.with(activity).clear(binding.itemContactImage)
}
}
}

View file

@ -10,10 +10,9 @@ import com.simplemobiletools.commons.extensions.getTextSize
import com.simplemobiletools.commons.extensions.highlightTextPart
import com.simplemobiletools.commons.helpers.SimpleContactsHelper
import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import com.simplemobiletools.smsmessenger.databinding.ItemSearchResultBinding
import com.simplemobiletools.smsmessenger.models.SearchResult
import kotlinx.android.synthetic.main.item_search_result.view.*
class SearchResultsAdapter(
activity: SimpleActivity, var searchResults: ArrayList<SearchResult>, recyclerView: MyRecyclerView, highlightText: String, itemClick: (Any) -> Unit
@ -40,11 +39,14 @@ class SearchResultsAdapter(
override fun onActionModeDestroyed() {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_search_result, parent)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemSearchResultBinding.inflate(layoutInflater, parent, false)
return createViewHolder(binding.root)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val searchResult = searchResults[position]
holder.bindView(searchResult, true, false) { itemView, layoutPosition ->
holder.bindView(searchResult, allowSingleClick = true, allowLongClick = false) { itemView, _ ->
setupView(itemView, searchResult)
}
bindViewHolder(holder)
@ -64,33 +66,34 @@ class SearchResultsAdapter(
}
private fun setupView(view: View, searchResult: SearchResult) {
view.apply {
search_result_title.apply {
ItemSearchResultBinding.bind(view).apply {
searchResultTitle.apply {
text = searchResult.title.highlightTextPart(textToHighlight, properPrimaryColor)
setTextColor(textColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 1.2f)
}
search_result_snippet.apply {
searchResultSnippet.apply {
text = searchResult.snippet.highlightTextPart(textToHighlight, properPrimaryColor)
setTextColor(textColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 0.9f)
}
search_result_date.apply {
searchResultDate.apply {
text = searchResult.date
setTextColor(textColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 0.8f)
}
SimpleContactsHelper(context).loadContactImage(searchResult.photoUri, search_result_image, searchResult.title)
SimpleContactsHelper(activity).loadContactImage(searchResult.photoUri, searchResultImage, searchResult.title)
}
}
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
if (!activity.isDestroyed && !activity.isFinishing && holder.itemView.search_result_image != null) {
Glide.with(activity).clear(holder.itemView.search_result_image)
if (!activity.isDestroyed && !activity.isFinishing) {
val binding = ItemSearchResultBinding.bind(holder.itemView)
Glide.with(activity).clear(binding.searchResultImage)
}
}
}

View file

@ -12,7 +12,13 @@ import android.util.TypedValue
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.appcompat.content.res.AppCompatResources
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.DiffUtil
import androidx.viewbinding.ViewBinding
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy
@ -33,6 +39,7 @@ import com.simplemobiletools.smsmessenger.activities.NewConversationActivity
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import com.simplemobiletools.smsmessenger.activities.ThreadActivity
import com.simplemobiletools.smsmessenger.activities.VCardViewerActivity
import com.simplemobiletools.smsmessenger.databinding.*
import com.simplemobiletools.smsmessenger.dialogs.DeleteConfirmationDialog
import com.simplemobiletools.smsmessenger.dialogs.MessageDetailsDialog
import com.simplemobiletools.smsmessenger.dialogs.SelectTextDialog
@ -42,18 +49,6 @@ import com.simplemobiletools.smsmessenger.models.Attachment
import com.simplemobiletools.smsmessenger.models.Message
import com.simplemobiletools.smsmessenger.models.ThreadItem
import com.simplemobiletools.smsmessenger.models.ThreadItem.*
import kotlinx.android.synthetic.main.item_attachment_image.view.*
import kotlinx.android.synthetic.main.item_received_message.view.*
import kotlinx.android.synthetic.main.item_received_message.view.thread_mesage_attachments_holder
import kotlinx.android.synthetic.main.item_received_message.view.thread_message_body
import kotlinx.android.synthetic.main.item_received_message.view.thread_message_holder
import kotlinx.android.synthetic.main.item_received_message.view.thread_message_play_outline
import kotlinx.android.synthetic.main.item_sent_message.view.*
import kotlinx.android.synthetic.main.item_thread_date_time.view.*
import kotlinx.android.synthetic.main.item_thread_error.view.*
import kotlinx.android.synthetic.main.item_thread_loading.view.*
import kotlinx.android.synthetic.main.item_thread_sending.view.*
import kotlinx.android.synthetic.main.item_thread_success.view.*
class ThreadAdapter(
activity: SimpleActivity,
@ -121,16 +116,16 @@ class ThreadAdapter(
override fun onActionModeDestroyed() {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layout = when (viewType) {
THREAD_LOADING -> R.layout.item_thread_loading
THREAD_DATE_TIME -> R.layout.item_thread_date_time
THREAD_RECEIVED_MESSAGE -> R.layout.item_received_message
THREAD_SENT_MESSAGE_ERROR -> R.layout.item_thread_error
THREAD_SENT_MESSAGE_SENT -> R.layout.item_thread_success
THREAD_SENT_MESSAGE_SENDING -> R.layout.item_thread_sending
else -> R.layout.item_sent_message
val binding = when (viewType) {
THREAD_LOADING -> ItemThreadLoadingBinding.inflate(layoutInflater, parent, false)
THREAD_DATE_TIME -> ItemThreadDateTimeBinding.inflate(layoutInflater, parent, false)
THREAD_SENT_MESSAGE_ERROR -> ItemThreadErrorBinding.inflate(layoutInflater, parent, false)
THREAD_SENT_MESSAGE_SENT -> ItemThreadSuccessBinding.inflate(layoutInflater, parent, false)
THREAD_SENT_MESSAGE_SENDING -> ItemThreadSendingBinding.inflate(layoutInflater, parent, false)
else -> ItemMessageBinding.inflate(layoutInflater, parent, false)
}
return createViewHolder(layout, parent)
return ThreadViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@ -278,258 +273,285 @@ class ThreadAdapter(
}
private fun setupView(holder: ViewHolder, view: View, message: Message) {
view.apply {
thread_message_holder.isSelected = selectedKeys.contains(message.hashCode())
thread_message_body.apply {
ItemMessageBinding.bind(view).apply {
threadMessageHolder.isSelected = selectedKeys.contains(message.hashCode())
threadMessageBody.apply {
text = message.body
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize)
beVisibleIf(message.body.isNotEmpty())
setOnLongClickListener {
holder.viewLongClicked()
true
}
setOnClickListener {
holder.viewClicked(message)
}
}
thread_message_body.beVisibleIf(message.body.isNotEmpty())
if (message.isReceivedMessage()) {
setupReceivedMessageView(view, message)
setupReceivedMessageView(messageBinding = this, message = message)
} else {
setupSentMessageView(view, message)
}
thread_message_body.setOnLongClickListener {
holder.viewLongClicked()
true
}
thread_message_body.setOnClickListener {
holder.viewClicked(message)
setupSentMessageView(messageBinding = this, message = message)
}
if (message.attachment?.attachments?.isNotEmpty() == true) {
thread_mesage_attachments_holder.beVisible()
thread_mesage_attachments_holder.removeAllViews()
threadMessageAttachmentsHolder.beVisible()
threadMessageAttachmentsHolder.removeAllViews()
for (attachment in message.attachment.attachments) {
val mimetype = attachment.mimetype
when {
mimetype.isImageMimeType() || mimetype.isVideoMimeType() -> setupImageView(holder, view, message, attachment)
mimetype.isVCardMimeType() -> setupVCardView(holder, view, message, attachment)
else -> setupFileView(holder, view, message, attachment)
mimetype.isImageMimeType() || mimetype.isVideoMimeType() -> setupImageView(holder, binding = this, message, attachment)
mimetype.isVCardMimeType() -> setupVCardView(holder, threadMessageAttachmentsHolder, message, attachment)
else -> setupFileView(holder, threadMessageAttachmentsHolder, message, attachment)
}
thread_message_play_outline.beVisibleIf(mimetype.startsWith("video/"))
threadMessagePlayOutline.beVisibleIf(mimetype.startsWith("video/"))
}
} else {
thread_mesage_attachments_holder.beGone()
threadMessageAttachmentsHolder.beGone()
threadMessagePlayOutline.beGone()
}
}
}
private fun setupReceivedMessageView(view: View, message: Message) {
view.apply {
thread_message_sender_photo.beVisible()
thread_message_sender_photo.setOnClickListener {
private fun setupReceivedMessageView(messageBinding: ItemMessageBinding, message: Message) {
messageBinding.apply {
with(ConstraintSet()) {
clone(threadMessageHolder)
clear(threadMessageWrapper.id, ConstraintSet.END)
connect(threadMessageWrapper.id, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START)
applyTo(threadMessageHolder)
}
threadMessageSenderPhoto.beVisible()
threadMessageSenderPhoto.setOnClickListener {
val contact = message.getSender()!!
context.getContactFromAddress(contact.phoneNumbers.first().normalizedNumber) {
activity.getContactFromAddress(contact.phoneNumbers.first().normalizedNumber) {
if (it != null) {
activity.startContactDetailsIntent(it)
}
}
}
thread_message_body.setTextColor(textColor)
thread_message_body.setLinkTextColor(context.getProperPrimaryColor())
threadMessageBody.apply {
background = AppCompatResources.getDrawable(activity, R.drawable.item_received_background)
setTextColor(textColor)
setLinkTextColor(activity.getProperPrimaryColor())
}
if (!activity.isFinishing && !activity.isDestroyed) {
val contactLetterIcon = SimpleContactsHelper(context).getContactLetterIcon(message.senderName)
val placeholder = BitmapDrawable(context.resources, contactLetterIcon)
val contactLetterIcon = SimpleContactsHelper(activity).getContactLetterIcon(message.senderName)
val placeholder = BitmapDrawable(activity.resources, contactLetterIcon)
val options = RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.error(placeholder)
.centerCrop()
Glide.with(context)
Glide.with(activity)
.load(message.senderPhotoUri)
.placeholder(placeholder)
.apply(options)
.apply(RequestOptions.circleCropTransform())
.into(thread_message_sender_photo)
.into(threadMessageSenderPhoto)
}
}
}
private fun setupSentMessageView(view: View, message: Message) {
view.apply {
thread_message_sender_photo?.beGone()
val background = context.getProperPrimaryColor()
thread_message_body.background.applyColorFilter(background)
val contrastColor = background.getContrastColor()
thread_message_body.setTextColor(contrastColor)
thread_message_body.setLinkTextColor(contrastColor)
val padding = thread_message_body.paddingStart
if (message.isScheduled) {
thread_message_scheduled_icon.beVisible()
thread_message_scheduled_icon.applyColorFilter(contrastColor)
val iconWidth = resources.getDimensionPixelSize(R.dimen.small_icon_size)
val rightPadding = padding + iconWidth
thread_message_body.setPadding(padding, padding, rightPadding, padding)
thread_message_body.typeface = Typeface.create(Typeface.DEFAULT, Typeface.ITALIC)
} else {
thread_message_scheduled_icon.beGone()
thread_message_body.setPadding(padding, padding, padding, padding)
thread_message_body.typeface = Typeface.DEFAULT
}
}
}
private fun setupImageView(holder: ViewHolder, parent: View, message: Message, attachment: Attachment) {
val mimetype = attachment.mimetype
val uri = attachment.getUri()
parent.apply {
val imageView = layoutInflater.inflate(R.layout.item_attachment_image, null)
thread_mesage_attachments_holder.addView(imageView)
val placeholderDrawable = ColorDrawable(Color.TRANSPARENT)
val isTallImage = attachment.height > attachment.width
val transformation = if (isTallImage) CenterCrop() else FitCenter()
val options = RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.placeholder(placeholderDrawable)
.transform(transformation)
var builder = Glide.with(context)
.load(uri)
.apply(options)
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
thread_message_play_outline.beGone()
thread_mesage_attachments_holder.removeView(imageView)
return false
}
override fun onResourceReady(dr: Drawable?, a: Any?, t: Target<Drawable>?, d: DataSource?, i: Boolean) = false
})
// limit attachment sizes to avoid causing OOM
var wantedAttachmentSize = Size(attachment.width, attachment.height)
if (wantedAttachmentSize.width > maxChatBubbleWidth) {
val newHeight = wantedAttachmentSize.height / (wantedAttachmentSize.width / maxChatBubbleWidth)
wantedAttachmentSize = Size(maxChatBubbleWidth.toInt(), newHeight.toInt())
private fun setupSentMessageView(messageBinding: ItemMessageBinding, message: Message) {
messageBinding.apply {
with(ConstraintSet()) {
clone(threadMessageHolder)
clear(threadMessageWrapper.id, ConstraintSet.START)
connect(threadMessageWrapper.id, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END)
applyTo(threadMessageHolder)
}
builder = if (isTallImage) {
builder.override(wantedAttachmentSize.width, wantedAttachmentSize.width)
} else {
builder.override(wantedAttachmentSize.width, wantedAttachmentSize.height)
}
val primaryColor = activity.getProperPrimaryColor()
val contrastColor = primaryColor.getContrastColor()
try {
builder.into(imageView.attachment_image)
} catch (ignore: Exception) {
}
threadMessageBody.apply {
updateLayoutParams<RelativeLayout.LayoutParams> {
removeRule(RelativeLayout.END_OF)
addRule(RelativeLayout.ALIGN_PARENT_END)
}
imageView.attachment_image.setOnClickListener {
if (actModeCallback.isSelectable) {
holder.viewClicked(message)
background = AppCompatResources.getDrawable(activity, R.drawable.item_sent_background)
background.applyColorFilter(primaryColor)
setTextColor(contrastColor)
setLinkTextColor(contrastColor)
if (message.isScheduled) {
typeface = Typeface.create(Typeface.DEFAULT, Typeface.ITALIC)
val scheduledDrawable = AppCompatResources.getDrawable(activity, R.drawable.scheduled_message_icon)
scheduledDrawable?.applyColorFilter(contrastColor)
setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, scheduledDrawable, null)
} else {
activity.launchViewIntent(uri, mimetype, attachment.filename)
typeface = Typeface.DEFAULT
setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, null, null)
}
}
imageView.setOnLongClickListener {
holder.viewLongClicked()
true
}
}
}
private fun setupVCardView(holder: ViewHolder, parent: View, message: Message, attachment: Attachment) {
val uri = attachment.getUri()
parent.apply {
val vCardView = layoutInflater.inflate(R.layout.item_attachment_vcard, null).apply {
setupVCardPreview(
activity = activity,
uri = uri,
onClick = {
if (actModeCallback.isSelectable) {
holder.viewClicked(message)
} else {
val intent = Intent(context, VCardViewerActivity::class.java).also {
it.putExtra(EXTRA_VCARD_URI, uri)
}
context.startActivity(intent)
}
},
onLongClick = { holder.viewLongClicked() }
)
}
thread_mesage_attachments_holder.addView(vCardView)
}
}
private fun setupFileView(holder: ViewHolder, parent: View, message: Message, attachment: Attachment) {
private fun setupImageView(holder: ViewHolder, binding: ItemMessageBinding, message: Message, attachment: Attachment) = binding.apply {
val mimetype = attachment.mimetype
val uri = attachment.getUri()
parent.apply {
val attachmentView = layoutInflater.inflate(R.layout.item_attachment_document, null).apply {
setupDocumentPreview(
uri = uri,
title = attachment.filename,
mimeType = attachment.mimetype,
onClick = {
if (actModeCallback.isSelectable) {
holder.viewClicked(message)
} else {
activity.launchViewIntent(uri, mimetype, attachment.filename)
}
},
onLongClick = { holder.viewLongClicked() },
)
}
thread_mesage_attachments_holder.addView(attachmentView)
val imageView = ItemAttachmentImageBinding.inflate(layoutInflater)
threadMessageAttachmentsHolder.addView(imageView.root)
val placeholderDrawable = ColorDrawable(Color.TRANSPARENT)
val isTallImage = attachment.height > attachment.width
val transformation = if (isTallImage) CenterCrop() else FitCenter()
val options = RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.placeholder(placeholderDrawable)
.transform(transformation)
var builder = Glide.with(root.context)
.load(uri)
.apply(options)
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
threadMessagePlayOutline.beGone()
threadMessageAttachmentsHolder.removeView(imageView.root)
return false
}
override fun onResourceReady(dr: Drawable?, a: Any?, t: Target<Drawable>?, d: DataSource?, i: Boolean) = false
})
// limit attachment sizes to avoid causing OOM
var wantedAttachmentSize = Size(attachment.width, attachment.height)
if (wantedAttachmentSize.width > maxChatBubbleWidth) {
val newHeight = wantedAttachmentSize.height / (wantedAttachmentSize.width / maxChatBubbleWidth)
wantedAttachmentSize = Size(maxChatBubbleWidth.toInt(), newHeight.toInt())
}
builder = if (isTallImage) {
builder.override(wantedAttachmentSize.width, wantedAttachmentSize.width)
} else {
builder.override(wantedAttachmentSize.width, wantedAttachmentSize.height)
}
try {
builder.into(imageView.attachmentImage)
} catch (ignore: Exception) {
}
imageView.attachmentImage.setOnClickListener {
if (actModeCallback.isSelectable) {
holder.viewClicked(message)
} else {
activity.launchViewIntent(uri, mimetype, attachment.filename)
}
}
imageView.root.setOnLongClickListener {
holder.viewLongClicked()
true
}
}
private fun setupVCardView(holder: ViewHolder, parent: LinearLayout, message: Message, attachment: Attachment) {
val uri = attachment.getUri()
val vCardView = ItemAttachmentVcardBinding.inflate(layoutInflater).apply {
setupVCardPreview(
activity = activity,
uri = uri,
onClick = {
if (actModeCallback.isSelectable) {
holder.viewClicked(message)
} else {
val intent = Intent(activity, VCardViewerActivity::class.java).also {
it.putExtra(EXTRA_VCARD_URI, uri)
}
activity.startActivity(intent)
}
},
onLongClick = { holder.viewLongClicked() }
)
}.root
parent.addView(vCardView)
}
private fun setupFileView(holder: ViewHolder, parent: LinearLayout, message: Message, attachment: Attachment) {
val mimetype = attachment.mimetype
val uri = attachment.getUri()
val attachmentView = ItemAttachmentDocumentBinding.inflate(layoutInflater).apply {
setupDocumentPreview(
uri = uri,
title = attachment.filename,
mimeType = attachment.mimetype,
onClick = {
if (actModeCallback.isSelectable) {
holder.viewClicked(message)
} else {
activity.launchViewIntent(uri, mimetype, attachment.filename)
}
},
onLongClick = { holder.viewLongClicked() },
)
}.root
parent.addView(attachmentView)
}
private fun setupDateTime(view: View, dateTime: ThreadDateTime) {
view.apply {
thread_date_time.apply {
text = dateTime.date.formatDateOrTime(context, false, false)
ItemThreadDateTimeBinding.bind(view).apply {
threadDateTime.apply {
text = dateTime.date.formatDateOrTime(context, hideTimeAtOtherDays = false, showYearEvenIfCurrent = false)
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize)
}
thread_date_time.setTextColor(textColor)
threadDateTime.setTextColor(textColor)
thread_sim_icon.beVisibleIf(hasMultipleSIMCards)
thread_sim_number.beVisibleIf(hasMultipleSIMCards)
threadSimIcon.beVisibleIf(hasMultipleSIMCards)
threadSimNumber.beVisibleIf(hasMultipleSIMCards)
if (hasMultipleSIMCards) {
thread_sim_number.text = dateTime.simID
thread_sim_number.setTextColor(textColor.getContrastColor())
thread_sim_icon.applyColorFilter(textColor)
threadSimNumber.text = dateTime.simID
threadSimNumber.setTextColor(textColor.getContrastColor())
threadSimIcon.applyColorFilter(textColor)
}
}
}
private fun setupThreadSuccess(view: View, isDelivered: Boolean) {
view.thread_success.setImageResource(if (isDelivered) R.drawable.ic_check_double_vector else R.drawable.ic_check_vector)
view.thread_success.applyColorFilter(textColor)
ItemThreadSuccessBinding.bind(view).apply {
threadSuccess.setImageResource(if (isDelivered) R.drawable.ic_check_double_vector else R.drawable.ic_check_vector)
threadSuccess.applyColorFilter(textColor)
}
}
private fun setupThreadError(view: View) {
view.thread_error.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize - 4)
val binding = ItemThreadErrorBinding.bind(view)
binding.threadError.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize - 4)
}
private fun setupThreadSending(view: View) {
view.thread_sending.apply {
ItemThreadSendingBinding.bind(view).threadSending.apply {
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize)
setTextColor(textColor)
}
}
private fun setupThreadLoading(view: View) = view.thread_loading.setIndicatorColor(properPrimaryColor)
private fun setupThreadLoading(view: View) {
val binding = ItemThreadLoadingBinding.bind(view)
binding.threadLoading.setIndicatorColor(properPrimaryColor)
}
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
if (!activity.isDestroyed && !activity.isFinishing && holder.itemView.thread_message_sender_photo != null) {
Glide.with(activity).clear(holder.itemView.thread_message_sender_photo)
if (!activity.isDestroyed && !activity.isFinishing) {
val binding = (holder as ThreadViewHolder).binding
if (binding is ItemMessageBinding) {
Glide.with(activity).clear(binding.threadMessageSenderPhoto)
}
}
}
inner class ThreadViewHolder(val binding: ViewBinding) : ViewHolder(binding.root)
}
private class ThreadItemDiffCallback : DiffUtil.ItemCallback<ThreadItem>() {

View file

@ -1,7 +1,6 @@
package com.simplemobiletools.smsmessenger.adapters
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import androidx.core.graphics.drawable.toDrawable
import androidx.recyclerview.widget.RecyclerView
@ -14,14 +13,17 @@ import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.SimpleContactsHelper
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import com.simplemobiletools.smsmessenger.databinding.ItemVcardContactBinding
import com.simplemobiletools.smsmessenger.databinding.ItemVcardContactPropertyBinding
import com.simplemobiletools.smsmessenger.models.VCardPropertyWrapper
import com.simplemobiletools.smsmessenger.models.VCardWrapper
import kotlinx.android.synthetic.main.item_vcard_contact.view.*
import kotlinx.android.synthetic.main.item_vcard_contact_property.view.*
private const val TYPE_VCARD_CONTACT = 1
private const val TYPE_VCARD_CONTACT_PROPERTY = 2
class VCardViewerAdapter(
activity: SimpleActivity, private var items: MutableList<Any>, private val itemClick: (Any) -> Unit
) : RecyclerView.Adapter<VCardViewerAdapter.VCardViewHolder>() {
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var fontSize = activity.getTextSize()
private var textColor = activity.getProperTextColor()
@ -31,123 +33,128 @@ class VCardViewerAdapter(
override fun getItemViewType(position: Int): Int {
return when (val item = items[position]) {
is VCardWrapper -> R.layout.item_vcard_contact
is VCardPropertyWrapper -> R.layout.item_vcard_contact_property
is VCardWrapper -> TYPE_VCARD_CONTACT
is VCardPropertyWrapper -> TYPE_VCARD_CONTACT_PROPERTY
else -> throw IllegalArgumentException("Unexpected type: ${item::class.simpleName}")
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VCardViewHolder {
val view = layoutInflater.inflate(viewType, parent, false)
return VCardViewHolder(view)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
TYPE_VCARD_CONTACT -> VCardContactViewHolder(
binding = ItemVcardContactBinding.inflate(layoutInflater, parent, false)
)
TYPE_VCARD_CONTACT_PROPERTY -> VCardPropertyViewHolder(
binding = ItemVcardContactPropertyBinding.inflate(layoutInflater, parent, false)
)
else -> throw IllegalArgumentException("Unexpected type: $viewType")
}
}
override fun onBindViewHolder(holder: VCardViewerAdapter.VCardViewHolder, position: Int) {
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = items[position]
val itemView = holder.bindView()
when (item) {
is VCardWrapper -> setupVCardView(itemView, item)
is VCardPropertyWrapper -> setupVCardPropertyView(itemView, item)
else -> throw IllegalArgumentException("Unexpected type: ${item::class.simpleName}")
when (holder) {
is VCardContactViewHolder -> holder.bindView(item as VCardWrapper)
is VCardPropertyViewHolder -> holder.bindView(item as VCardPropertyWrapper)
}
}
private fun setupVCardView(view: View, item: VCardWrapper) {
val name = item.fullName
view.apply {
item_contact_name.apply {
text = name
setTextColor(textColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 1.1f)
}
item_contact_image.apply {
val photo = item.vCard.photos.firstOrNull()
val placeholder = if (name != null) {
SimpleContactsHelper(context).getContactLetterIcon(name).toDrawable(resources)
} else {
null
inner class VCardContactViewHolder(val binding: ItemVcardContactBinding) : RecyclerView.ViewHolder(binding.root) {
fun bindView(item: VCardWrapper) {
val name = item.fullName
binding.apply {
itemContactName.apply {
text = name
setTextColor(textColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 1.1f)
}
val roundingRadius = resources.getDimensionPixelSize(R.dimen.big_margin)
val transformation = RoundedCorners(roundingRadius)
val options = RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.placeholder(placeholder)
.transform(transformation)
Glide.with(this)
.load(photo?.data ?: photo?.url)
.apply(options)
.transition(DrawableTransitionOptions.withCrossFade())
.into(this)
}
expand_collapse_icon.apply {
val expandCollapseDrawable = if (item.expanded) {
R.drawable.ic_collapse_up
} else {
R.drawable.ic_expand_down
itemContactImage.apply {
val photo = item.vCard.photos.firstOrNull()
val placeholder = if (name != null) {
SimpleContactsHelper(context).getContactLetterIcon(name).toDrawable(resources)
} else {
null
}
val roundingRadius = resources.getDimensionPixelSize(R.dimen.big_margin)
val transformation = RoundedCorners(roundingRadius)
val options = RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.placeholder(placeholder)
.transform(transformation)
Glide.with(this)
.load(photo?.data ?: photo?.url)
.apply(options)
.transition(DrawableTransitionOptions.withCrossFade())
.into(this)
}
expandCollapseIcon.apply {
val expandCollapseDrawable = if (item.expanded) {
R.drawable.ic_collapse_up
} else {
R.drawable.ic_expand_down
}
setImageResource(expandCollapseDrawable)
applyColorFilter(textColor)
}
setImageResource(expandCollapseDrawable)
applyColorFilter(textColor)
}
if (items.size > 1) {
setOnClickListener {
expandOrCollapseRow(view, item)
if (items.size > 1) {
root.setOnClickListener {
expandOrCollapseRow(item)
}
}
}
onGlobalLayout {
if (items.size == 1) {
expandOrCollapseRow(view, item)
view.expand_collapse_icon.beGone()
root.onGlobalLayout {
if (items.size == 1) {
expandOrCollapseRow(item)
expandCollapseIcon.beGone()
}
}
}
}
}
private fun setupVCardPropertyView(view: View, property: VCardPropertyWrapper) {
view.apply {
item_vcard_property_title.apply {
text = property.value
setTextColor(textColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 1.1f)
private fun expandOrCollapseRow(item: VCardWrapper) {
val properties = item.properties
if (item.expanded) {
collapseRow(properties, item)
} else {
expandRow(properties, item)
}
item_vcard_property_subtitle.apply {
text = property.type
setTextColor(textColor)
}
view.setOnClickListener {
itemClick(property)
}
private fun expandRow(properties: List<VCardPropertyWrapper>, vCardWrapper: VCardWrapper) {
vCardWrapper.expanded = true
val nextPosition = items.indexOf(vCardWrapper) + 1
items.addAll(nextPosition, properties)
notifyItemRangeInserted(nextPosition, properties.size)
binding.expandCollapseIcon.setImageResource(R.drawable.ic_collapse_up)
}
private fun collapseRow(properties: List<VCardPropertyWrapper>, vCardWrapper: VCardWrapper) {
vCardWrapper.expanded = false
val nextPosition = items.indexOf(vCardWrapper) + 1
repeat(properties.size) {
items.removeAt(nextPosition)
}
notifyItemRangeRemoved(nextPosition, properties.size)
binding.expandCollapseIcon.setImageResource(R.drawable.ic_expand_down)
}
}
private fun expandOrCollapseRow(view: View, item: VCardWrapper) {
val properties = item.properties
if (item.expanded) {
collapseRow(view, properties, item)
} else {
expandRow(view, properties, item)
inner class VCardPropertyViewHolder(val binding: ItemVcardContactPropertyBinding) : RecyclerView.ViewHolder(binding.root) {
fun bindView(item: VCardPropertyWrapper) {
binding.apply {
itemVcardPropertyTitle.apply {
text = item.value
setTextColor(textColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 1.1f)
}
itemVcardPropertySubtitle.apply {
text = item.type
setTextColor(textColor)
}
root.setOnClickListener {
itemClick(item)
}
}
}
}
private fun expandRow(view: View, properties: List<VCardPropertyWrapper>, vCardWrapper: VCardWrapper) {
vCardWrapper.expanded = true
val nextPosition = items.indexOf(vCardWrapper) + 1
items.addAll(nextPosition, properties)
notifyItemRangeInserted(nextPosition, properties.size)
view.expand_collapse_icon.setImageResource(R.drawable.ic_collapse_up)
}
private fun collapseRow(view: View, properties: List<VCardPropertyWrapper>, vCardWrapper: VCardWrapper) {
vCardWrapper.expanded = false
val nextPosition = items.indexOf(vCardWrapper) + 1
repeat(properties.size) {
items.removeAt(nextPosition)
}
notifyItemRangeRemoved(nextPosition, properties.size)
view.expand_collapse_icon.setImageResource(R.drawable.ic_expand_down)
}
inner class VCardViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bindView() = itemView
}
}