session-android/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt

124 lines
6.3 KiB
Kotlin
Raw Normal View History

2021-07-09 03:14:21 +02:00
package org.thoughtcrime.securesms.home
2019-12-17 14:27:59 +01:00
import android.content.Context
2021-06-21 01:45:09 +02:00
import android.content.res.Resources
2019-12-17 15:15:13 +01:00
import android.graphics.Typeface
2019-12-17 14:27:59 +01:00
import android.util.AttributeSet
2021-06-24 02:18:52 +02:00
import android.util.TypedValue
2019-12-17 14:27:59 +01:00
import android.view.LayoutInflater
2019-12-17 15:15:13 +01:00
import android.view.View
2019-12-17 14:27:59 +01:00
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
2021-06-24 02:18:52 +02:00
import androidx.core.view.isVisible
2021-06-21 01:45:09 +02:00
import androidx.recyclerview.widget.RecyclerView
2019-12-17 14:27:59 +01:00
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewConversationBinding
import org.session.libsession.utilities.recipients.Recipient
2021-07-09 05:18:48 +02:00
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities.highlightMentions
import org.thoughtcrime.securesms.database.RecipientDatabase
import org.thoughtcrime.securesms.database.model.ThreadRecord
2019-12-19 11:15:58 +01:00
import org.thoughtcrime.securesms.mms.GlideRequests
2019-12-17 15:15:13 +01:00
import org.thoughtcrime.securesms.util.DateUtils
import java.util.Locale
2019-12-17 14:27:59 +01:00
class ConversationView : LinearLayout {
private lateinit var binding: ViewConversationBinding
2021-06-21 01:45:09 +02:00
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
2019-12-17 15:15:13 +01:00
var thread: ThreadRecord? = null
2019-12-17 14:27:59 +01:00
// region Lifecycle
2021-06-21 01:40:23 +02:00
constructor(context: Context) : super(context) { initialize() }
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() }
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() }
2019-12-17 14:27:59 +01:00
2021-06-21 01:40:23 +02:00
private fun initialize() {
binding = ViewConversationBinding.inflate(LayoutInflater.from(context), this, true)
2021-06-21 01:45:09 +02:00
layoutParams = RecyclerView.LayoutParams(screenWidth, RecyclerView.LayoutParams.WRAP_CONTENT)
2019-12-17 16:24:42 +01:00
}
2019-12-17 14:27:59 +01:00
// endregion
// region Updating
2019-12-19 11:15:58 +01:00
fun bind(thread: ThreadRecord, isTyping: Boolean, glide: GlideRequests) {
2019-12-17 15:15:13 +01:00
this.thread = thread
background = if (thread.isPinned) {
binding.conversationViewDisplayNameTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_pin, 0)
ContextCompat.getDrawable(context, R.drawable.conversation_pinned_background)
} else {
binding.conversationViewDisplayNameTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
ContextCompat.getDrawable(context, R.drawable.conversation_view_background)
}
binding.profilePictureView.glide = glide
val unreadCount = thread.unreadCount
if (thread.recipient.isBlocked) {
binding.accentView.setBackgroundResource(R.color.destructive)
binding.accentView.visibility = View.VISIBLE
} else {
binding.accentView.setBackgroundResource(R.color.accent)
// Using thread.isRead we can determine if the last message was our own, and display it as 'read' even though previous messages may not be
// This would also not trigger the disappearing message timer which may or may not be desirable
binding.accentView.visibility = if (unreadCount > 0 && !thread.isRead) View.VISIBLE else View.INVISIBLE
}
val formattedUnreadCount = if (thread.isRead) {
null
} else {
if (unreadCount < 10000) unreadCount.toString() else "9999+"
}
binding.unreadCountTextView.text = formattedUnreadCount
val textSize = if (unreadCount < 10000) 12.0f else 9.0f
binding.unreadCountTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize)
binding.unreadCountTextView.setTypeface(Typeface.DEFAULT, if (unreadCount < 100) Typeface.BOLD else Typeface.NORMAL)
binding.unreadCountIndicator.isVisible = (unreadCount != 0 && !thread.isRead)
val senderDisplayName = getUserDisplayName(thread.recipient)
?: thread.recipient.address.toString()
binding.conversationViewDisplayNameTextView.text = senderDisplayName
binding.timestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), thread.date)
val recipient = thread.recipient
binding.muteIndicatorImageView.isVisible = recipient.isMuted || recipient.notifyType != RecipientDatabase.NOTIFY_TYPE_ALL
val drawableRes = if (recipient.isMuted || recipient.notifyType == RecipientDatabase.NOTIFY_TYPE_NONE) {
R.drawable.ic_outline_notifications_off_24
} else {
R.drawable.ic_notifications_mentions
}
binding.muteIndicatorImageView.setImageResource(drawableRes)
val rawSnippet = thread.getDisplayBody(context)
val snippet = highlightMentions(rawSnippet, thread.threadId, context)
binding.snippetTextView.text = snippet
binding.snippetTextView.typeface = if (unreadCount > 0 && !thread.isRead) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
binding.snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE
if (isTyping) {
binding.typingIndicatorView.startAnimation()
} else {
binding.typingIndicatorView.stopAnimation()
}
binding.typingIndicatorView.visibility = if (isTyping) View.VISIBLE else View.GONE
binding.statusIndicatorImageView.visibility = View.VISIBLE
when {
!thread.isOutgoing -> binding.statusIndicatorImageView.visibility = View.GONE
thread.isFailed -> {
val drawable = ContextCompat.getDrawable(context, R.drawable.ic_error)?.mutate()
drawable?.setTint(ContextCompat.getColor(context, R.color.destructive))
binding.statusIndicatorImageView.setImageDrawable(drawable)
}
thread.isPending -> binding.statusIndicatorImageView.setImageResource(R.drawable.ic_circle_dot_dot_dot)
thread.isRead -> binding.statusIndicatorImageView.setImageResource(R.drawable.ic_filled_circle_check)
else -> binding.statusIndicatorImageView.setImageResource(R.drawable.ic_circle_check)
}
post {
binding.profilePictureView.update(thread.recipient)
2019-12-19 11:15:58 +01:00
}
2019-12-17 14:27:59 +01:00
}
fun recycle() {
binding.profilePictureView.recycle()
}
2021-05-12 08:27:40 +02:00
private fun getUserDisplayName(recipient: Recipient): String? {
return if (recipient.isLocalNumber) {
context.getString(R.string.note_to_self)
2021-05-24 02:27:31 +02:00
} else {
recipient.name // Internally uses the Contact API
2021-05-24 02:27:31 +02:00
}
}
2019-12-17 14:27:59 +01:00
// endregion
}