Commit 05d9453c authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Show groupable messages.

parent d31b9ea1
......@@ -49,7 +49,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
val messagesViewModels = mapper.mapToViewModelList(messages, settings)
view.showMessages(messagesViewModels, serverInteractor.get()!!)
view.showMessages(messagesViewModels)
// Subscribe after getting the first page of messages from REST
if (offset == 0L) {
......
......@@ -10,9 +10,8 @@ interface ChatRoomView : LoadingView, MessageView {
* Shows the chat room messages.
*
* @param dataSet The data set to show.
* @param serverUrl The server URL.
*/
fun showMessages(dataSet: List<MessageViewModel>, serverUrl: String)
fun showMessages(dataSet: List<MessageViewModel>)
/**
* Send a message to a chat room.
......
......@@ -3,7 +3,6 @@ package chat.rocket.android.chatroom.ui
import android.support.v7.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import chat.rocket.android.R
import chat.rocket.android.chatroom.viewmodel.AttachmentType
......@@ -11,33 +10,33 @@ import chat.rocket.android.chatroom.viewmodel.MessageViewModel
import chat.rocket.android.player.PlayerActivity
import chat.rocket.android.util.inflate
import chat.rocket.android.util.setVisible
import chat.rocket.common.util.ifNull
import com.facebook.drawee.view.SimpleDraweeView
import com.stfalcon.frescoimageviewer.ImageViewer
import kotlinx.android.synthetic.main.avatar.view.*
import kotlinx.android.synthetic.main.item_message.view.*
import kotlinx.android.synthetic.main.message_attachment.view.*
class ChatRoomAdapter(private val serverUrl: String) : RecyclerView.Adapter<ChatRoomAdapter.ViewHolder>() {
class ChatRoomAdapter: RecyclerView.Adapter<ChatRoomAdapter.ViewHolder>() {
private val dataSet = ArrayList<MessageViewModel>()
init {
setHasStableIds(true)
}
val dataSet = ArrayList<MessageViewModel>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
ViewHolder(parent.inflate(R.layout.item_message), serverUrl)
ViewHolder(parent.inflate(R.layout.item_message))
override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(dataSet[position])
override fun onBindViewHolder(holder: ViewHolder, position: Int) =
holder.bind(dataSet[position], dataSet.getOrNull(position + 1))
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
onBindViewHolder(holder, position)
}
override fun getItemCount(): Int =
dataSet.size
override fun getItemCount(): Int = dataSet.size
override fun getItemViewType(position: Int): Int =
position
override fun getItemViewType(position: Int): Int = position
override fun getItemId(position: Int): Long =
dataSet[position].id.hashCode().toLong()
fun addDataSet(dataSet: List<MessageViewModel>) {
val previousDataSetSize = this.dataSet.size
......@@ -55,22 +54,28 @@ class ChatRoomAdapter(private val serverUrl: String) : RecyclerView.Adapter<Chat
notifyItemChanged(index)
}
override fun getItemId(position: Int): Long {
return dataSet[position].id.hashCode().toLong()
}
class ViewHolder(itemView: View, val serverUrl: String) : RecyclerView.ViewHolder(itemView) {
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(message: MessageViewModel) = with(itemView) {
bindUserAvatar(message, image_avatar, image_unknown_avatar)
text_user_name.text = message.sender
fun bind(message: MessageViewModel, nextMessage: MessageViewModel?) = with(itemView) {
image_avatar.setImageURI(message.avatarUri)
text_sender.text = message.senderName
text_message_time.text = message.time
text_content.text = message.content
bindAttachment(message, message_attachment, image_attachment, audio_video_attachment,
file_name)
if (nextMessage != null) {
if (isSequential(message, nextMessage)) {
image_avatar.setVisible(false)
text_sender.setVisible(false)
text_message_time.setVisible(false)
}
}
text_content.text = message.content
bindAttachment(message, message_attachment, image_attachment, audio_video_attachment, file_name)
}
private fun isSequential(message: MessageViewModel, nextMessage: MessageViewModel): Boolean =
(message.isGroupable && nextMessage.isGroupable) && (message.senderId == nextMessage.senderId)
private fun bindAttachment(message: MessageViewModel,
attachment_container: View,
image_attachment: SimpleDraweeView,
......@@ -113,14 +118,5 @@ class ChatRoomAdapter(private val serverUrl: String) : RecyclerView.Adapter<Chat
file_name.text = message.attachmentTitle
}
}
private fun bindUserAvatar(message: MessageViewModel, drawee: SimpleDraweeView, imageUnknownAvatar: ImageView) = message.getAvatarUrl(serverUrl).let {
drawee.setImageURI(it.toString())
drawee.setVisible(true)
imageUnknownAvatar.setVisible(false)
}.ifNull {
drawee.setVisible(false)
imageUnknownAvatar.setVisible(true)
}
}
}
\ No newline at end of file
......@@ -39,7 +39,6 @@ private const val BUNDLE_CHAT_ROOM_TYPE = "chat_room_type"
private const val BUNDLE_IS_CHAT_ROOM_READ_ONLY = "is_chat_room_read_only"
class ChatRoomFragment : Fragment(), ChatRoomView {
@Inject lateinit var presenter: ChatRoomPresenter
private lateinit var chatRoomId: String
private lateinit var chatRoomName: String
......@@ -75,10 +74,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
super.onDestroyView()
}
override fun showMessages(dataSet: List<MessageViewModel>, serverUrl: String) {
override fun showMessages(dataSet: List<MessageViewModel>) {
activity?.apply {
if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(serverUrl)
adapter = ChatRoomAdapter()
recycler_view.adapter = adapter
val linearLayoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, true)
recycler_view.layoutManager = linearLayoutManager
......
......@@ -26,22 +26,26 @@ data class MessageViewModel(val context: Context,
private val message: Message,
private val settings: Map<String, Value<Any>>?) {
val id: String = message.id
val isGroupable = message.groupable
val senderId = message.sender?.id
val avatarUri: String?
val time: CharSequence
val sender: CharSequence
val senderName: CharSequence
val content: CharSequence
var attachmentUrl: String? = null
var attachmentTitle: CharSequence? = null
var attachmentType: AttachmentType? = null
private val baseUrl = settings?.get(SITE_URL)
init {
sender = getSenderName()
content = getContent(context)
avatarUri = getUserAvatar()
time = getTime()
senderName = getSender()
content = getContent(context)
message.attachments?.let {
if (it.isEmpty() || it[0] == null) return@let
if (it.isEmpty()) return@let
val attachment = it[0] as FileAttachment
val baseUrl = settings?.get(SITE_URL)
baseUrl?.let {
attachmentUrl = attachmentUrl("${baseUrl.value}${attachment.url}")
attachmentTitle = attachment.title
......@@ -56,36 +60,55 @@ data class MessageViewModel(val context: Context,
}
}
fun getAvatarUrl(serverUrl: String): String? {
return message.sender?.username.let {
return@let UrlHelper.getAvatarUrl(serverUrl, it.toString())
private fun getUserAvatar(): String? {
val username = message.sender?.username ?: "?"
return baseUrl?.let {
UrlHelper.getAvatarUrl(baseUrl.value.toString(), username)
}
}
fun getTime() = DateTimeHelper.getTime(DateTimeHelper.getLocalDateTime(message.timestamp))
private fun getTime() =
DateTimeHelper.getTime(DateTimeHelper.getLocalDateTime(message.timestamp))
fun getSenderName(): CharSequence {
private fun getSender(): CharSequence {
val useRealName = settings?.get(USE_REALNAME)?.value as Boolean
val username = message.sender?.username
val realName = message.sender?.name
val senderName = if (useRealName) realName else username
return senderName ?: username.toString()
return senderName ?: context.getString(R.string.msg_unknown)
}
fun getContent(context: Context): CharSequence {
private fun getContent(context: Context): CharSequence {
val contentMessage: CharSequence
when (message.type) {
//TODO: Add implementation for Welcome type.
is MessageRemoved -> contentMessage = getSystemMessage(context.getString(R.string.message_removed))
is UserJoined -> contentMessage = getSystemMessage(context.getString(R.string.message_user_joined_channel))
is UserLeft -> contentMessage = getSystemMessage(context.getString(R.string.message_user_left))
is UserAdded -> contentMessage = getSystemMessage(
context.getString(R.string.message_user_added_by, message.message, message.sender?.username))
is RoomNameChanged -> contentMessage = getSystemMessage(
context.getString(R.string.message_room_name_changed, message.message, message.sender?.username))
is UserRemoved -> contentMessage = getSystemMessage(
context.getString(R.string.message_user_removed_by, message.message, message.sender?.username))
else -> contentMessage = getNormalMessage()
//TODO: Add implementation for Welcome type.
is MessageRemoved -> {
contentMessage = getSystemMessage(context.getString(R.string.message_removed))
}
is UserJoined -> {
contentMessage = getSystemMessage(context.getString(R.string.message_user_joined_channel))
}
is UserLeft -> {
contentMessage = getSystemMessage(context.getString(R.string.message_user_left))
}
is UserAdded -> {
contentMessage = getSystemMessage(context.getString(R.string.message_user_added_by,
message.message,
message.sender?.username))
}
is RoomNameChanged -> {
contentMessage = getSystemMessage(context.getString(R.string.message_room_name_changed,
message.message,
message.sender?.username))
}
is UserRemoved -> {
contentMessage = getSystemMessage(context.getString(R.string.message_user_removed_by,
message.message,
message.sender?.username))
}
else -> {
contentMessage = getNormalMessage()
}
}
return contentMessage
}
......@@ -94,10 +117,14 @@ data class MessageViewModel(val context: Context,
private fun getSystemMessage(content: String): CharSequence {
val spannableMsg = SpannableString(content)
spannableMsg.setSpan(StyleSpan(Typeface.ITALIC), 0, spannableMsg.length,
0)
spannableMsg.setSpan(ForegroundColorSpan(Color.GRAY), 0, spannableMsg.length,
0)
spannableMsg.setSpan(StyleSpan(Typeface.ITALIC),
0,
spannableMsg.length,
0)
spannableMsg.setSpan(ForegroundColorSpan(Color.GRAY),
0,
spannableMsg.length,
0)
val username = message.sender?.username
val message = message.message
......@@ -108,13 +135,17 @@ data class MessageViewModel(val context: Context,
val messageTextEndIndex = messageTextStartIndex + message.length
if (usernameTextStartIndex > -1) {
spannableMsg.setSpan(StyleSpan(Typeface.BOLD_ITALIC), usernameTextStartIndex, usernameTextEndIndex,
0)
spannableMsg.setSpan(StyleSpan(Typeface.BOLD_ITALIC),
usernameTextStartIndex,
usernameTextEndIndex,
0)
}
if (messageTextStartIndex > -1) {
spannableMsg.setSpan(StyleSpan(Typeface.BOLD_ITALIC), messageTextStartIndex, messageTextEndIndex,
0)
spannableMsg.setSpan(StyleSpan(Typeface.BOLD_ITALIC),
messageTextStartIndex,
messageTextEndIndex,
0)
}
return spannableMsg
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
......@@ -12,14 +11,4 @@
android:layout_height="40dp"
app:roundedCornerRadius="2dp" />
<!-- TODO define the correct bg color for this-->
<ImageView
android:id="@+id/image_unknown_avatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_help_black_24dp"
android:tint="@color/colorAccent"
android:visibility="gone"
tools:ignore="contentDescription" />
</LinearLayout>
\ No newline at end of file
......@@ -27,7 +27,7 @@
app:layout_constraintLeft_toRightOf="@+id/layout_avatar">
<TextView
android:id="@+id/text_user_name"
android:id="@+id/text_sender"
style="@style/TextAppearance.AppCompat.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......
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