From 0eb5128b22ff1bcddd44a8e6ccab920e0c46100c Mon Sep 17 00:00:00 2001 From: Hussein El Feky Date: Sun, 26 May 2019 23:48:34 +0200 Subject: [PATCH 1/2] Implemented system messages --- .../chatroom/adapter/BaseViewHolder.kt | 3 +- .../chatroom/adapter/ChatRoomAdapter.kt | 18 ++- .../chatroom/adapter/MessageViewHolder.kt | 7 +- .../adapter/SystemMessageViewHolder.kt | 51 +++++++ .../chatroom/uimodel/SystemMessageUiModel.kt | 31 ++++ .../android/chatroom/uimodel/UiModelMapper.kt | 62 +++++++- app/src/main/res/layout/avatar.xml | 7 +- app/src/main/res/layout/avatar_small.xml | 13 ++ .../main/res/layout/item_file_attachment.xml | 1 - .../res/layout/item_generic_attachment.xml | 1 - app/src/main/res/layout/item_message.xml | 10 -- .../main/res/layout/item_system_message.xml | 140 ++++++++++++++++++ 12 files changed, 306 insertions(+), 38 deletions(-) create mode 100644 app/src/main/java/chat/rocket/android/chatroom/adapter/SystemMessageViewHolder.kt create mode 100644 app/src/main/java/chat/rocket/android/chatroom/uimodel/SystemMessageUiModel.kt create mode 100644 app/src/main/res/layout/avatar_small.xml create mode 100644 app/src/main/res/layout/item_system_message.xml diff --git a/app/src/main/java/chat/rocket/android/chatroom/adapter/BaseViewHolder.kt b/app/src/main/java/chat/rocket/android/chatroom/adapter/BaseViewHolder.kt index 68b420e7d5..fdd5186e82 100644 --- a/app/src/main/java/chat/rocket/android/chatroom/adapter/BaseViewHolder.kt +++ b/app/src/main/java/chat/rocket/android/chatroom/adapter/BaseViewHolder.kt @@ -18,7 +18,6 @@ import chat.rocket.android.util.extensions.toList import chat.rocket.core.model.Message import chat.rocket.core.model.isSystemMessage import com.google.android.flexbox.FlexDirection -import com.google.android.flexbox.FlexWrap import com.google.android.flexbox.FlexboxLayoutManager import com.google.android.flexbox.JustifyContent @@ -63,7 +62,7 @@ abstract class BaseViewHolder>( } override fun onReactionLongClicked(shortname: String, isCustom: Boolean, url: String?, usernames: List) { - reactionListener?.onReactionLongClicked(shortname, isCustom,url, usernames) + reactionListener?.onReactionLongClicked(shortname, isCustom, url, usernames) } } diff --git a/app/src/main/java/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt b/app/src/main/java/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt index ad1788ee43..27ff05d672 100644 --- a/app/src/main/java/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt +++ b/app/src/main/java/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt @@ -11,6 +11,7 @@ import chat.rocket.android.chatroom.uimodel.AttachmentUiModel import chat.rocket.android.chatroom.uimodel.BaseUiModel import chat.rocket.android.chatroom.uimodel.MessageReplyUiModel import chat.rocket.android.chatroom.uimodel.MessageUiModel +import chat.rocket.android.chatroom.uimodel.SystemMessageUiModel import chat.rocket.android.chatroom.uimodel.UrlPreviewUiModel import chat.rocket.android.chatroom.uimodel.toViewType import chat.rocket.android.emoji.EmojiReactionListener @@ -21,7 +22,6 @@ import chat.rocket.core.model.attachment.actions.Action import chat.rocket.core.model.attachment.actions.ButtonAction import chat.rocket.core.model.isSystemMessage import timber.log.Timber -import java.security.InvalidParameterException class ChatRoomAdapter( private val roomId: String? = null, @@ -44,6 +44,14 @@ class ChatRoomAdapter( BaseUiModel.ViewType.MESSAGE -> { val view = parent.inflate(R.layout.item_message) MessageViewHolder( + view, + actionsListener, + reactionListener + ) { userId -> navigator?.toUserDetails(userId) } + } + BaseUiModel.ViewType.SYSTEM_MESSAGE -> { + val view = parent.inflate(R.layout.item_system_message) + SystemMessageViewHolder( view, actionsListener, reactionListener, @@ -78,9 +86,6 @@ class ChatRoomAdapter( actionSelectListener?.openDirectMessage(roomName, permalink) } } - else -> { - throw InvalidParameterException("TODO - implement for ${viewType.toViewType()}") - } } } @@ -109,9 +114,10 @@ class ChatRoomAdapter( when (holder) { is MessageViewHolder -> holder.bind(dataSet[position] as MessageUiModel) - is UrlPreviewViewHolder -> { + is SystemMessageViewHolder -> + holder.bind(dataSet[position] as SystemMessageUiModel) + is UrlPreviewViewHolder -> holder.bind(dataSet[position] as UrlPreviewUiModel) - } is MessageReplyViewHolder -> holder.bind(dataSet[position] as MessageReplyUiModel) is AttachmentViewHolder -> diff --git a/app/src/main/java/chat/rocket/android/chatroom/adapter/MessageViewHolder.kt b/app/src/main/java/chat/rocket/android/chatroom/adapter/MessageViewHolder.kt index 7773d483d3..22a83afc43 100644 --- a/app/src/main/java/chat/rocket/android/chatroom/adapter/MessageViewHolder.kt +++ b/app/src/main/java/chat/rocket/android/chatroom/adapter/MessageViewHolder.kt @@ -10,7 +10,6 @@ import androidx.core.view.isVisible import chat.rocket.android.R import chat.rocket.android.chatroom.uimodel.MessageUiModel import chat.rocket.android.emoji.EmojiReactionListener -import chat.rocket.core.model.MessageType import chat.rocket.core.model.isSystemMessage import com.bumptech.glide.load.resource.gif.GifDrawable import kotlinx.android.synthetic.main.avatar.view.* @@ -20,8 +19,7 @@ class MessageViewHolder( itemView: View, listener: ActionsListener, reactionListener: EmojiReactionListener? = null, - private val avatarListener: (String) -> Unit, - private val joinVideoCallListener: (View) -> Unit + private val avatarListener: (String) -> Unit ) : BaseViewHolder(itemView, listener, reactionListener), Drawable.Callback { init { @@ -53,9 +51,6 @@ class MessageViewHolder( text_content.text_content.text = data.content - button_join_video_call.isVisible = data.message.type is MessageType.JitsiCallStarted - button_join_video_call.setOnClickListener { joinVideoCallListener(it) } - image_avatar.setImageURI(data.avatar) text_content.setTextColor(if (data.isTemporary) Color.GRAY else Color.BLACK) diff --git a/app/src/main/java/chat/rocket/android/chatroom/adapter/SystemMessageViewHolder.kt b/app/src/main/java/chat/rocket/android/chatroom/adapter/SystemMessageViewHolder.kt new file mode 100644 index 0000000000..41a55a7814 --- /dev/null +++ b/app/src/main/java/chat/rocket/android/chatroom/adapter/SystemMessageViewHolder.kt @@ -0,0 +1,51 @@ +package chat.rocket.android.chatroom.adapter + +import android.graphics.Color +import android.text.method.LinkMovementMethod +import android.view.View +import androidx.core.view.isVisible +import chat.rocket.android.chatroom.uimodel.SystemMessageUiModel +import chat.rocket.android.emoji.EmojiReactionListener +import chat.rocket.core.model.MessageType +import kotlinx.android.synthetic.main.avatar.view.* +import kotlinx.android.synthetic.main.item_system_message.view.* + +class SystemMessageViewHolder( + itemView: View, + listener: ActionsListener, + reactionListener: EmojiReactionListener? = null, + private val avatarListener: (String) -> Unit, + private val joinVideoCallListener: (View) -> Unit +) : BaseViewHolder(itemView, listener, reactionListener) { + + init { + with(itemView) { + setupActionMenu(message_container) + text_content.movementMethod = LinkMovementMethod() + } + } + + override fun bindViews(data: SystemMessageUiModel) { + with(itemView) { + day.text = data.currentDayMarkerText + day_marker_layout.isVisible = data.showDayMarker + + new_messages_notif.isVisible = data.isFirstUnread + + text_sender.text = data.senderName + text_content.text_content.text = data.content + + button_join_video_call.isVisible = data.message.type is MessageType.JitsiCallStarted + button_join_video_call.setOnClickListener { joinVideoCallListener(it) } + + image_avatar.setImageURI(data.avatar) + text_content.setTextColor(if (data.isTemporary) Color.GRAY else Color.BLACK) + + itemView.setOnClickListener { + data.message.sender?.id?.let { userId -> + avatarListener(userId) + } + } + } + } +} diff --git a/app/src/main/java/chat/rocket/android/chatroom/uimodel/SystemMessageUiModel.kt b/app/src/main/java/chat/rocket/android/chatroom/uimodel/SystemMessageUiModel.kt new file mode 100644 index 0000000000..9c058fb1c1 --- /dev/null +++ b/app/src/main/java/chat/rocket/android/chatroom/uimodel/SystemMessageUiModel.kt @@ -0,0 +1,31 @@ +package chat.rocket.android.chatroom.uimodel + +import chat.rocket.android.R +import chat.rocket.core.model.Message + +data class SystemMessageUiModel( + override val message: Message, + override val rawData: Message, + override val messageId: String, + override val avatar: String, + override val time: CharSequence, + override val senderName: CharSequence, + override val content: CharSequence, + override val isPinned: Boolean, + override var currentDayMarkerText: String, + override var showDayMarker: Boolean, + override var reactions: List, + override var nextDownStreamMessage: BaseUiModel<*>? = null, + override var preview: Message? = null, + override var unread: Boolean? = null, + var isFirstUnread: Boolean, + override var isTemporary: Boolean = false, + override var menuItemsToHide: MutableList = mutableListOf(), + override var permalink: String, + val subscriptionId: String +) : BaseMessageUiModel { + override val viewType: Int + get() = BaseUiModel.ViewType.SYSTEM_MESSAGE.viewType + override val layoutId: Int + get() = R.layout.item_system_message +} \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt b/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt index 4a1be35286..2eea479214 100644 --- a/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt +++ b/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt @@ -140,11 +140,20 @@ class UiModelMapper @Inject constructor( list.addAll(it) } - mapMessage(message, chatRoom).let { - if (list.isNotEmpty()) { - it.preview = list.first().preview + if (message.isSystemMessage()) { + mapSystemMessage(message, chatRoom).let { + if (list.isNotEmpty()) { + it.preview = list.first().preview + } + list.add(it) + } + } else { + mapMessage(message, chatRoom).let { + if (list.isNotEmpty()) { + it.preview = list.first().preview + } + list.add(it) } - list.add(it) } } @@ -217,11 +226,20 @@ class UiModelMapper @Inject constructor( val list = ArrayList>() getChatRoomAsync(message.roomId)?.let { chatRoom -> - mapMessage(message, chatRoom).let { - if (list.isNotEmpty()) { - it.preview = list.first().preview + if (message.isSystemMessage()) { + mapSystemMessage(message, chatRoom).let { + if (list.isNotEmpty()) { + it.preview = list.first().preview + } + list.add(it) + } + } else { + mapMessage(message, chatRoom).let { + if (list.isNotEmpty()) { + it.preview = list.first().preview + } + list.add(it) } - list.add(it) } message.attachments?.forEach { @@ -268,6 +286,34 @@ class UiModelMapper @Inject constructor( senderUsername != currentUsername } + private suspend fun mapSystemMessage( + message: Message, + chatRoom: ChatRoom + ): SystemMessageUiModel = withContext(Dispatchers.IO) { + val sender = getSenderName(message) + val time = getTime(message.timestamp) + val avatar = getUserAvatar(message) + val preview = mapMessagePreview(message) + val synced = message.synced + val unread = if (settings.messageReadReceiptEnabled()) { + message.unread ?: false + } else { + null + } + + val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp) + val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context) + val permalink = messageHelper.createPermalink(message, chatRoom, false) + + val content = getContent(stripMessageQuotes(message)) + SystemMessageUiModel(message = stripMessageQuotes(message), rawData = message, + messageId = message.id, avatar = avatar!!, time = time, senderName = sender, + content = content, isPinned = message.pinned, currentDayMarkerText = dayMarkerText, + showDayMarker = false, reactions = getReactions(message), isFirstUnread = false, + preview = preview, isTemporary = !synced, unread = unread, permalink = permalink, + subscriptionId = chatRoom.subscriptionId) + } + private fun mapMessageReply(message: Message, chatRoom: ChatRoom): MessageReplyUiModel { val name = message.sender?.name val roomName = diff --git a/app/src/main/res/layout/avatar.xml b/app/src/main/res/layout/avatar.xml index 64e38375cc..f400752124 100644 --- a/app/src/main/res/layout/avatar.xml +++ b/app/src/main/res/layout/avatar.xml @@ -1,9 +1,8 @@ - + android:layout_height="match_parent"> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/avatar_small.xml b/app/src/main/res/layout/avatar_small.xml new file mode 100644 index 0000000000..2b729850de --- /dev/null +++ b/app/src/main/res/layout/avatar_small.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_file_attachment.xml b/app/src/main/res/layout/item_file_attachment.xml index 9c9830aea0..2083e7f134 100644 --- a/app/src/main/res/layout/item_file_attachment.xml +++ b/app/src/main/res/layout/item_file_attachment.xml @@ -12,7 +12,6 @@ android:paddingEnd="@dimen/screen_edge_left_and_right_padding" android:paddingStart="@dimen/screen_edge_left_and_right_padding"> - - -