sms-translate/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt
2020-04-12 09:47:03 +02:00

234 lines
9.1 KiB
Kotlin

package com.simplemobiletools.smsmessenger.adapters
import android.content.Intent
import android.graphics.drawable.Drawable
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.bitmap.FitCenter
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.commons.views.FastScroller
import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import com.simplemobiletools.smsmessenger.extensions.deleteMessage
import com.simplemobiletools.smsmessenger.extensions.loadImage
import com.simplemobiletools.smsmessenger.helpers.*
import com.simplemobiletools.smsmessenger.models.Message
import com.simplemobiletools.smsmessenger.models.ThreadDateTime
import com.simplemobiletools.smsmessenger.models.ThreadError
import com.simplemobiletools.smsmessenger.models.ThreadItem
import kotlinx.android.synthetic.main.item_received_message.view.*
import kotlinx.android.synthetic.main.item_thread_date_time.view.*
class ThreadAdapter(
activity: SimpleActivity, var messages: ArrayList<ThreadItem>,
recyclerView: MyRecyclerView,
fastScroller: FastScroller,
itemClick: (Any) -> Unit
) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
private val roundedCornersRadius = resources.getDimension(R.dimen.normal_margin).toInt()
init {
setupDragListener(true)
}
override fun getActionMenuId() = R.menu.cab_thread
override fun prepareActionMode(menu: Menu) {
val isOneItemSelected = isOneItemSelected()
menu.apply {
findItem(R.id.cab_copy_to_clipboard).isVisible = isOneItemSelected
findItem(R.id.cab_share).isVisible = isOneItemSelected
}
}
override fun actionItemPressed(id: Int) {
if (selectedKeys.isEmpty()) {
return
}
when (id) {
R.id.cab_copy_to_clipboard -> copyToClipboard()
R.id.cab_share -> shareText()
R.id.cab_select_all -> selectAll()
R.id.cab_delete -> askConfirmDelete()
}
}
override fun getSelectableItemCount() = messages.filter { it is Message }.size
override fun getIsItemSelectable(position: Int) = !isThreadDateTime(position)
override fun getItemSelectionKey(position: Int) = (messages.getOrNull(position) as? Message)?.id
override fun getItemKeyPosition(key: Int) = messages.indexOfFirst { (it as? Message)?.id == key }
override fun onActionModeCreated() {}
override fun onActionModeDestroyed() {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layout = when (viewType) {
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
else -> R.layout.item_sent_message
}
return createViewHolder(layout, parent)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = messages[position]
holder.bindView(item, true, item is Message) { itemView, layoutPosition ->
if (item is ThreadDateTime) {
setupDateTime(itemView, item)
} else if (item !is ThreadError) {
setupView(itemView, item as Message)
}
}
bindViewHolder(holder)
}
override fun getItemCount() = messages.size
override fun getItemViewType(position: Int): Int {
val item = messages[position]
return when {
item is ThreadDateTime -> THREAD_DATE_TIME
(messages[position] as? Message)?.isReceivedMessage() == true -> THREAD_RECEIVED_MESSAGE
item is ThreadError -> THREAD_SENT_MESSAGE_ERROR
else -> THREAD_SENT_MESSAGE
}
}
private fun copyToClipboard() {
val firstItem = getSelectedItems().first() as? Message ?: return
activity.copyToClipboard(firstItem.body)
}
private fun shareText() {
val firstItem = getSelectedItems().first() as? Message ?: return
activity.shareTextIntent(firstItem.body)
}
private fun askConfirmDelete() {
val itemsCnt = selectedKeys.size
val items = resources.getQuantityString(R.plurals.delete_messages, itemsCnt, itemsCnt)
val baseString = R.string.deletion_confirmation
val question = String.format(resources.getString(baseString), items)
ConfirmationDialog(activity, question) {
ensureBackgroundThread {
deleteMessages()
}
}
}
private fun deleteMessages() {
if (selectedKeys.isEmpty()) {
return
}
val messagesToRemove = messages.filter { selectedKeys.contains((it as? Message)?.id ?: 0) } as ArrayList<ThreadItem>
val positions = getSelectedItemPositions()
messagesToRemove.forEach {
activity.deleteMessage((it as Message).id)
}
messages.removeAll(messagesToRemove)
activity.runOnUiThread {
if (messages.filter { it is Message }.isEmpty()) {
activity.finish()
} else {
removeSelectedItems(positions)
}
refreshMessages()
}
}
private fun getSelectedItems() = messages.filter { selectedKeys.contains((it as? Message)?.id ?: 0) } as ArrayList<ThreadItem>
private fun isThreadDateTime(position: Int) = messages.getOrNull(position) is ThreadDateTime
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
if (!activity.isDestroyed && !activity.isFinishing && holder.itemView.thread_message_photo != null) {
Glide.with(activity).clear(holder.itemView.thread_message_photo)
}
}
private fun setupView(view: View, message: Message) {
view.apply {
thread_message_body.text = message.body
if (message.isReceivedMessage()) {
thread_message_photo.beVisible()
thread_message_body.setTextColor(textColor)
context.loadImage(message.senderPhotoUri, thread_message_photo, message.senderName)
} else {
thread_message_photo?.beGone()
val background = context.getAdjustedPrimaryColor()
thread_message_body.background.applyColorFilter(background.adjustAlpha(0.8f))
thread_message_body.setTextColor(background.getContrastColor())
}
if (message.attachment != null) {
val type = message.attachment.type
if (type.startsWith("image/") || type.startsWith("video/")) {
val uri = message.attachment.uri
val options = RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.transform(FitCenter(), RoundedCorners(roundedCornersRadius))
Glide.with(context)
.load(uri)
.transition(DrawableTransitionOptions.withCrossFade())
.apply(options)
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
thread_message_play_outline.beGone()
return false
}
override fun onResourceReady(dr: Drawable?, a: Any?, t: Target<Drawable>?, d: DataSource?, i: Boolean) = false
})
.into(thread_message_image)
thread_message_image.setOnClickListener {
Intent().apply {
action = Intent.ACTION_VIEW
setDataAndType(uri, type)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
activity.startActivity(this)
}
}
}
thread_message_play_outline.beVisibleIf(type.startsWith("video/"))
}
}
}
private fun setupDateTime(view: View, dateTime: ThreadDateTime) {
view.apply {
thread_date_time.text = dateTime.date.formatDateOrTime(context, false)
thread_date_time.setTextColor(textColor)
}
}
}