|
|
|
@ -11,8 +11,10 @@ import android.os.Looper
|
|
|
|
|
import android.util.AttributeSet
|
|
|
|
|
import android.view.Gravity
|
|
|
|
|
import android.view.HapticFeedbackConstants
|
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
|
import android.view.MotionEvent
|
|
|
|
|
import android.view.View
|
|
|
|
|
import android.view.ViewGroup
|
|
|
|
|
import android.widget.FrameLayout
|
|
|
|
|
import android.widget.LinearLayout
|
|
|
|
|
import androidx.annotation.ColorInt
|
|
|
|
@ -26,17 +28,17 @@ import androidx.core.view.isVisible
|
|
|
|
|
import androidx.core.view.marginBottom
|
|
|
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
|
|
|
import network.loki.messenger.R
|
|
|
|
|
import network.loki.messenger.databinding.ViewEmojiReactionsBinding
|
|
|
|
|
import network.loki.messenger.databinding.ViewVisibleMessageBinding
|
|
|
|
|
import network.loki.messenger.databinding.ViewstubVisibleMessageMarkerContainerBinding
|
|
|
|
|
import org.session.libsession.messaging.contacts.Contact
|
|
|
|
|
import org.session.libsession.messaging.contacts.Contact.ContactContext
|
|
|
|
|
import org.session.libsession.messaging.open_groups.OpenGroupApi
|
|
|
|
|
import org.session.libsession.utilities.Address
|
|
|
|
|
import org.session.libsession.utilities.TextSecurePreferences
|
|
|
|
|
import org.session.libsession.utilities.ViewUtil
|
|
|
|
|
import org.session.libsession.utilities.getColorFromAttr
|
|
|
|
|
import org.session.libsession.utilities.modifyLayoutParams
|
|
|
|
|
import org.session.libsignal.utilities.IdPrefix
|
|
|
|
|
import org.session.libsignal.utilities.Log
|
|
|
|
|
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
|
|
|
|
|
import org.thoughtcrime.securesms.database.LastSentTimestampCache
|
|
|
|
|
import org.thoughtcrime.securesms.database.LokiAPIDatabase
|
|
|
|
@ -65,7 +67,7 @@ import kotlin.math.sqrt
|
|
|
|
|
private const val TAG = "VisibleMessageView"
|
|
|
|
|
|
|
|
|
|
@AndroidEntryPoint
|
|
|
|
|
class VisibleMessageView : LinearLayout {
|
|
|
|
|
class VisibleMessageView : FrameLayout {
|
|
|
|
|
private var replyDisabled: Boolean = false
|
|
|
|
|
@Inject lateinit var threadDb: ThreadDatabase
|
|
|
|
|
@Inject lateinit var lokiThreadDb: LokiThreadDatabase
|
|
|
|
@ -75,7 +77,16 @@ class VisibleMessageView : LinearLayout {
|
|
|
|
|
@Inject lateinit var mmsDb: MmsDatabase
|
|
|
|
|
@Inject lateinit var lastSentTimestampCache: LastSentTimestampCache
|
|
|
|
|
|
|
|
|
|
private val binding by lazy { ViewVisibleMessageBinding.bind(this) }
|
|
|
|
|
private val binding = ViewVisibleMessageBinding.inflate(LayoutInflater.from(context), this, true)
|
|
|
|
|
|
|
|
|
|
private val markerContainerBinding = lazy(LazyThreadSafetyMode.NONE) {
|
|
|
|
|
ViewstubVisibleMessageMarkerContainerBinding.bind(binding.unreadMarkerContainerStub.inflate())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private val emojiReactionsBinding = lazy(LazyThreadSafetyMode.NONE) {
|
|
|
|
|
ViewEmojiReactionsBinding.bind(binding.emojiReactionsView.inflate())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private val swipeToReplyIcon = ContextCompat.getDrawable(context, R.drawable.ic_baseline_reply_24)!!.mutate()
|
|
|
|
|
private val swipeToReplyIconRect = Rect()
|
|
|
|
|
private var dx = 0.0f
|
|
|
|
@ -94,7 +105,7 @@ class VisibleMessageView : LinearLayout {
|
|
|
|
|
var onPress: ((event: MotionEvent) -> Unit)? = null
|
|
|
|
|
var onSwipeToReply: (() -> Unit)? = null
|
|
|
|
|
var onLongPress: (() -> Unit)? = null
|
|
|
|
|
val messageContentView: VisibleMessageContentView by lazy { binding.messageContentView.root }
|
|
|
|
|
val messageContentView: VisibleMessageContentView get() = binding.messageContentView.root
|
|
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
|
const val swipeToReplyThreshold = 64.0f // dp
|
|
|
|
@ -108,12 +119,7 @@ class VisibleMessageView : LinearLayout {
|
|
|
|
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
|
|
|
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
|
|
|
|
|
|
|
|
|
override fun onFinishInflate() {
|
|
|
|
|
super.onFinishInflate()
|
|
|
|
|
initialize()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun initialize() {
|
|
|
|
|
init {
|
|
|
|
|
isHapticFeedbackEnabled = true
|
|
|
|
|
setWillNotDraw(false)
|
|
|
|
|
binding.root.disableClipping()
|
|
|
|
@ -121,7 +127,11 @@ class VisibleMessageView : LinearLayout {
|
|
|
|
|
binding.messageInnerContainer.disableClipping()
|
|
|
|
|
binding.messageInnerLayout.disableClipping()
|
|
|
|
|
binding.messageContentView.root.disableClipping()
|
|
|
|
|
|
|
|
|
|
// Default layout params
|
|
|
|
|
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// endregion
|
|
|
|
|
|
|
|
|
|
// region Updating
|
|
|
|
@ -203,7 +213,13 @@ class VisibleMessageView : LinearLayout {
|
|
|
|
|
binding.senderNameTextView.text = contact?.displayName(contactContext) ?: senderAccountID
|
|
|
|
|
|
|
|
|
|
// Unread marker
|
|
|
|
|
binding.unreadMarkerContainer.isVisible = lastSeen != -1L && message.timestamp > lastSeen && (previous == null || previous.timestamp <= lastSeen) && !message.isOutgoing
|
|
|
|
|
val shouldShowUnreadMarker = lastSeen != -1L && message.timestamp > lastSeen && (previous == null || previous.timestamp <= lastSeen) && !message.isOutgoing
|
|
|
|
|
if (shouldShowUnreadMarker) {
|
|
|
|
|
markerContainerBinding.value.root.isVisible = true
|
|
|
|
|
} else if (markerContainerBinding.isInitialized()) {
|
|
|
|
|
// Only need to hide the binding when the binding is inflated. (default is gone)
|
|
|
|
|
markerContainerBinding.value.root.isVisible = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Date break
|
|
|
|
|
val showDateBreak = isStartOfMessageCluster || snIsSelected
|
|
|
|
@ -214,21 +230,22 @@ class VisibleMessageView : LinearLayout {
|
|
|
|
|
showStatusMessage(message)
|
|
|
|
|
|
|
|
|
|
// Emoji Reactions
|
|
|
|
|
val emojiLayoutParams = binding.emojiReactionsView.root.layoutParams as ConstraintLayout.LayoutParams
|
|
|
|
|
emojiLayoutParams.horizontalBias = if (message.isOutgoing) 1f else 0f
|
|
|
|
|
binding.emojiReactionsView.root.layoutParams = emojiLayoutParams
|
|
|
|
|
|
|
|
|
|
if (message.reactions.isNotEmpty()) {
|
|
|
|
|
val capabilities = lokiThreadDb.getOpenGroupChat(threadID)?.server?.let { lokiApiDb.getServerCapabilities(it) }
|
|
|
|
|
if (capabilities.isNullOrEmpty() || capabilities.contains(OpenGroupApi.Capability.REACTIONS.name.lowercase())) {
|
|
|
|
|
binding.emojiReactionsView.root.setReactions(message.id, message.reactions, message.isOutgoing, delegate)
|
|
|
|
|
binding.emojiReactionsView.root.isVisible = true
|
|
|
|
|
} else {
|
|
|
|
|
binding.emojiReactionsView.root.isVisible = false
|
|
|
|
|
emojiReactionsBinding.value.root.let { root ->
|
|
|
|
|
root.setReactions(message.id, message.reactions, message.isOutgoing, delegate)
|
|
|
|
|
root.isVisible = true
|
|
|
|
|
(root.layoutParams as ConstraintLayout.LayoutParams).apply {
|
|
|
|
|
horizontalBias = if (message.isOutgoing) 1f else 0f
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (emojiReactionsBinding.isInitialized()) {
|
|
|
|
|
emojiReactionsBinding.value.root.isVisible = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
binding.emojiReactionsView.root.isVisible = false
|
|
|
|
|
else if (emojiReactionsBinding.isInitialized()) {
|
|
|
|
|
emojiReactionsBinding.value.root.isVisible = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Populate content view
|
|
|
|
|