Commit a2e5be2e authored by Leonardo Aramaki's avatar Leonardo Aramaki

Add read receipt to messages.

parent 3955c8d3
......@@ -4,6 +4,7 @@ import android.graphics.Color
import android.text.method.LinkMovementMethod
import android.view.View
import androidx.core.view.isVisible
import chat.rocket.android.R
import chat.rocket.android.chatroom.viewmodel.MessageViewModel
import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.widget.emoji.EmojiReactionListener
......@@ -40,6 +41,18 @@ class MessageViewHolder(
text_edit_indicator.isVisible = !it.isSystemMessage() && it.editedBy != null
image_star_indicator.isVisible = it.starred?.isNotEmpty() ?: false
}
if (data.unread == null) {
read_receipt_view.setVisible(false)
} else {
read_receipt_view.setImageResource(
if (data.unread == true) {
R.drawable.ic_check_unread_24dp
} else {
R.drawable.ic_check_read_24dp
}
)
read_receipt_view.setVisible(true)
}
}
}
}
\ No newline at end of file
......@@ -223,7 +223,8 @@ class ChatRoomPresenter @Inject constructor(
type = null,
updatedAt = null,
urls = null,
isTemporary = true
isTemporary = true,
unread = true
)
try {
messagesRepository.save(newMessage)
......
......@@ -14,7 +14,8 @@ data class AudioAttachmentViewModel(
override var reactions: List<ReactionViewModel>,
override var nextDownStreamMessage: BaseViewModel<*>? = null,
override var preview: Message? = null,
override var isTemporary: Boolean = false
override var isTemporary: Boolean = false,
override var unread: Boolean? = null
) : BaseFileAttachmentViewModel<AudioAttachment> {
override val viewType: Int
get() = BaseViewModel.ViewType.AUDIO_ATTACHMENT.viewType
......
......@@ -16,7 +16,8 @@ data class AuthorAttachmentViewModel(
override var reactions: List<ReactionViewModel>,
override var nextDownStreamMessage: BaseViewModel<*>? = null,
override var preview: Message? = null,
override var isTemporary: Boolean = false
override var isTemporary: Boolean = false,
override var unread: Boolean? = null
) : BaseAttachmentViewModel<AuthorAttachment> {
override val viewType: Int
get() = BaseViewModel.ViewType.AUTHOR_ATTACHMENT.viewType
......
......@@ -13,6 +13,7 @@ interface BaseViewModel<out T> {
var nextDownStreamMessage: BaseViewModel<*>?
var preview: Message?
var isTemporary: Boolean
var unread: Boolean?
enum class ViewType(val viewType: Int) {
MESSAGE(0),
......
......@@ -15,7 +15,8 @@ data class ColorAttachmentViewModel(
override var reactions: List<ReactionViewModel>,
override var nextDownStreamMessage: BaseViewModel<*>? = null,
override var preview: Message? = null,
override var isTemporary: Boolean = false
override var isTemporary: Boolean = false,
override var unread: Boolean? = null
) : BaseAttachmentViewModel<ColorAttachment> {
override val viewType: Int
get() = BaseViewModel.ViewType.COLOR_ATTACHMENT.viewType
......
......@@ -15,7 +15,8 @@ data class GenericFileAttachmentViewModel(
override var reactions: List<ReactionViewModel>,
override var nextDownStreamMessage: BaseViewModel<*>? = null,
override var preview: Message? = null,
override var isTemporary: Boolean = false
override var isTemporary: Boolean = false,
override var unread: Boolean? = null
) : BaseFileAttachmentViewModel<GenericFileAttachment> {
override val viewType: Int
get() = BaseViewModel.ViewType.GENERIC_FILE_ATTACHMENT.viewType
......
......@@ -14,7 +14,8 @@ data class ImageAttachmentViewModel(
override var reactions: List<ReactionViewModel>,
override var nextDownStreamMessage: BaseViewModel<*>? = null,
override var preview: Message? = null,
override var isTemporary: Boolean = false
override var isTemporary: Boolean = false,
override var unread: Boolean? = null
) : BaseFileAttachmentViewModel<ImageAttachment> {
override val viewType: Int
get() = BaseViewModel.ViewType.IMAGE_ATTACHMENT.viewType
......
......@@ -15,7 +15,8 @@ data class MessageAttachmentViewModel(
override var nextDownStreamMessage: BaseViewModel<*>? = null,
var messageLink: String? = null,
override var preview: Message? = null,
override var isTemporary: Boolean = false
override var isTemporary: Boolean = false,
override var unread: Boolean? = null
) : BaseViewModel<Message> {
override val viewType: Int
get() = BaseViewModel.ViewType.MESSAGE_ATTACHMENT.viewType
......
......@@ -11,7 +11,8 @@ data class MessageReplyViewModel(
override var nextDownStreamMessage: BaseViewModel<*>?,
override var preview: Message?,
override var isTemporary: Boolean = false,
override val message: Message
override val message: Message,
override var unread: Boolean? = null
) : BaseViewModel<MessageReply> {
override val viewType: Int
get() = BaseViewModel.ViewType.MESSAGE_REPLY.viewType
......
......@@ -16,7 +16,8 @@ data class MessageViewModel(
override var nextDownStreamMessage: BaseViewModel<*>? = null,
override var preview: Message? = null,
var isFirstUnread: Boolean,
override var isTemporary: Boolean = false
override var isTemporary: Boolean = false,
override var unread: Boolean? = null
) : BaseMessageViewModel<Message> {
override val viewType: Int
get() = BaseViewModel.ViewType.MESSAGE.viewType
......
......@@ -15,7 +15,8 @@ data class UrlPreviewViewModel(
override var reactions: List<ReactionViewModel>,
override var nextDownStreamMessage: BaseViewModel<*>? = null,
override var preview: Message? = null,
override var isTemporary: Boolean = false
override var isTemporary: Boolean = false,
override var unread: Boolean? = null
) : BaseViewModel<Url> {
override val viewType: Int
get() = BaseViewModel.ViewType.URL_PREVIEW.viewType
......
......@@ -14,7 +14,8 @@ data class VideoAttachmentViewModel(
override var reactions: List<ReactionViewModel>,
override var nextDownStreamMessage: BaseViewModel<*>? = null,
override var preview: Message? = null,
override var isTemporary: Boolean = false
override var isTemporary: Boolean = false,
override var unread: Boolean? = null
) : BaseFileAttachmentViewModel<VideoAttachment> {
override val viewType: Int
get() = BaseViewModel.ViewType.VIDEO_ATTACHMENT.viewType
......
......@@ -22,6 +22,8 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.baseUrl
import chat.rocket.android.server.domain.hasShowLastMessage
import chat.rocket.android.server.domain.messageReadReceiptEnabled
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.isNotNullNorEmpty
......@@ -232,7 +234,7 @@ class ViewModelMapper @Inject constructor(
ColorAttachmentViewModel(attachmentUrl = url, id = id, color = color.color,
text = text, message = message, rawData = attachment,
messageId = message.id, reactions = getReactions(message),
preview = message.copy(message = content.message))
preview = message.copy(message = content.message), unread = message.unread)
}
}
......@@ -260,7 +262,7 @@ class ViewModelMapper @Inject constructor(
AuthorAttachmentViewModel(attachmentUrl = url, id = id, name = authorName,
icon = authorIcon, fields = fieldsText, message = message, rawData = attachment,
messageId = message.id, reactions = getReactions(message),
preview = message.copy(message = content.message))
preview = message.copy(message = content.message), unread = message.unread)
}
}
......@@ -278,7 +280,7 @@ class ViewModelMapper @Inject constructor(
return MessageAttachmentViewModel(message = content, rawData = message,
messageId = message.id, time = time, senderName = attachmentAuthor,
content = attachmentText, isPinned = message.pinned, reactions = getReactions(message),
preview = message.copy(message = content.message))
preview = message.copy(message = content.message), unread = message.unread)
}
private fun mapFileAttachment(message: Message, attachment: FileAttachment): BaseViewModel<*>? {
......@@ -338,17 +340,24 @@ class ViewModelMapper @Inject constructor(
}
private suspend fun mapMessage(message: Message): MessageViewModel = withContext(CommonPool) {
val senderUsername = message.sender?.username
val sender = getSenderName(message)
val time = getTime(message.timestamp)
val avatar = getUserAvatar(message)
val preview = mapMessagePreview(message)
val isTemp = message.isTemporary ?: false
println("setting MESSAGE_READ_RECEIPT_STORE_USERS set to ${settings.messageReadReceiptEnabled()}")
val unread = if (settings.messageReadReceiptEnabled() && currentUsername == senderUsername) {
message.unread ?: false
} else {
null
}
val content = getContent(stripMessageQuotes(message))
MessageViewModel(message = stripMessageQuotes(message), rawData = message,
messageId = message.id, avatar = avatar!!, time = time, senderName = sender,
content = content, isPinned = message.pinned, reactions = getReactions(message),
isFirstUnread = false, preview = preview, isTemporary = isTemp)
isFirstUnread = false, preview = preview, isTemporary = isTemp, unread = unread)
}
private fun mapMessagePreview(message: Message): Message {
......@@ -411,7 +420,7 @@ class ViewModelMapper @Inject constructor(
}
val username = message.sender?.username ?: "?"
return baseUrl?.let {
return baseUrl.let {
baseUrl.avatarUrl(username)
}
}
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#1D74F5"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF1D74F5"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#999999"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF999999"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" />
</vector>
......@@ -19,8 +19,8 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible">
......@@ -62,6 +62,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/layout_avatar"
app:layout_constraintTop_toBottomOf="@+id/new_messages_notif">
......@@ -100,6 +101,14 @@
android:src="@drawable/ic_action_message_star_24dp"
android:visibility="gone"
tools:visibility="visible" />
<ImageView
android:id="@+id/read_receipt_view"
android:layout_width="24dp"
android:layout_height="24dp"
android:visibility="gone"
app:srcCompat="@drawable/ic_check_unread_24dp"
tools:visibility="visible" />
</LinearLayout>
<TextView
......@@ -109,10 +118,10 @@
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:layout_marginTop="5dp"
app:layout_constraintStart_toStartOf="@+id/top_container"
android:textDirection="locale"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/top_container"
app:layout_constraintTop_toBottomOf="@+id/top_container"
android:textDirection="locale"
tools:text="This is a multiline chat message from Bertie that will take more than just one line of text. I have sure that everything is amazing!" />
<include
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment