Commit 24ff98f4 authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Redsign chat list

parent f3288109
......@@ -2,9 +2,6 @@ package chat.rocket.android.chatrooms.adapter
import android.app.Application
import android.text.SpannableStringBuilder
import androidx.core.content.ContextCompat
import androidx.core.text.bold
import androidx.core.text.color
import chat.rocket.android.R
import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
import chat.rocket.android.db.model.ChatRoom
......@@ -32,18 +29,13 @@ class RoomUiModelMapper(
private val serverUrl: String,
private val permissions: PermissionsInteractor
) {
private val nameUnreadColor = ContextCompat.getColor(context, R.color.colorPrimaryText)
private val nameColor = ContextCompat.getColor(context, R.color.colorSecondaryText)
private val dateUnreadColor = ContextCompat.getColor(context, R.color.colorAccent)
private val dateColor = ContextCompat.getColor(context, R.color.colorSecondaryText)
private val messageUnreadColor = ContextCompat.getColor(context, android.R.color.primary_text_light)
private val messageColor = ContextCompat.getColor(context, R.color.colorSecondaryText)
private val currentUser by lazy { userInteractor.get() }
private val currentUser by lazy {
userInteractor.get()
}
fun map(rooms: List<ChatRoom>, grouped: Boolean = false, showLastMessage: Boolean = true): List<ItemHolder<*>> {
fun map(
rooms: List<ChatRoom>,
grouped: Boolean = false,
showLastMessage: Boolean = true
): List<ItemHolder<*>> {
val list = ArrayList<ItemHolder<*>>(rooms.size + 4)
var lastType: String? = null
rooms.forEach { room ->
......@@ -72,7 +64,7 @@ class RoomUiModelMapper(
private fun mapUser(user: User): RoomUiModel {
return with(user) {
val name = mapName(user.username!!, user.name, false)
val name = mapName(user.username!!, user.name)
val status = user.status
val avatar = serverUrl.avatarUrl(user.username!!)
val username = user.username!!
......@@ -88,41 +80,56 @@ class RoomUiModelMapper(
}
}
private fun mapRoom(room: Room, showLastMessage:Boolean = true): RoomUiModel {
private fun mapRoom(room: Room, showLastMessage: Boolean = true): RoomUiModel {
return with(room) {
RoomUiModel(
id = id,
name = name!!,
type = type,
avatar = serverUrl.avatarUrl(name!!, isGroupOrChannel = true),
lastMessage = if(showLastMessage) { mapLastMessage(lastMessage?.sender?.id, lastMessage?.sender?.username,
lastMessage = if (showLastMessage) {
mapLastMessage(
lastMessage?.sender?.id, lastMessage?.sender?.username,
lastMessage?.sender?.name, lastMessage?.message,
isDirectMessage = type is RoomType.DirectMessage)} else { null },
isDirectMessage = type is RoomType.DirectMessage
)
} else {
null
},
muted = muted.orEmpty(),
writable = isChannelWritable(muted)
)
}
}
fun map(chatRoom: ChatRoom, showLastMessage:Boolean = true): RoomUiModel {
fun map(chatRoom: ChatRoom, showLastMessage: Boolean = true): RoomUiModel {
return with(chatRoom.chatRoom) {
val isUnread = alert || unread > 0
val type = roomTypeOf(type)
val status = chatRoom.status?.let { userStatusOf(it) }
val roomName = mapName(name, fullname, isUnread)
val timestamp = mapDate(lastMessageTimestamp ?: updatedAt, isUnread)
val roomName = mapName(name, fullname)
val timestamp = mapDate(lastMessageTimestamp ?: updatedAt)
val avatar = if (type is RoomType.DirectMessage) {
serverUrl.avatarUrl(name)
} else {
serverUrl.avatarUrl(name, isGroupOrChannel = true)
}
val unread = mapUnread(unread)
val lastMessage = if(showLastMessage) { mapLastMessage(lastMessageUserId, chatRoom.lastMessageUserName,
chatRoom.lastMessageUserFullName, lastMessageText, isUnread,
type is RoomType.DirectMessage) } else { null }
val lastMessage = if (showLastMessage) {
mapLastMessage(
lastMessageUserId,
chatRoom.lastMessageUserName,
chatRoom.lastMessageUserFullName,
lastMessageText,
type is RoomType.DirectMessage
)
} else {
null
}
val open = open
val lastMessageMarkdown = lastMessage?.let { Markwon.markdown(context, it.toString()).toString() }
val lastMessageMarkdown =
lastMessage?.let { Markwon.markdown(context, it.toString()).toString() }
RoomUiModel(
id = id,
......@@ -158,47 +165,37 @@ class RoomUiModelMapper(
}
}
private fun mapLastMessage(userId: String?, name: String?, fullName: String?, text: String?,
unread: Boolean = false,
isDirectMessage: Boolean = false): CharSequence? {
private fun mapLastMessage(
userId: String?,
name: String?,
fullName: String?,
text: String?,
isDirectMessage: Boolean = false
): CharSequence? {
return if (!settings.showLastMessage()) {
null
} else if (name != null && text != null) {
val user = if (currentUser != null && currentUser!!.id == userId) {
"${context.getString(R.string.msg_you)}: "
} else {
if (isDirectMessage) "" else "${mapName(name, fullName, unread)}: "
}
val color = if (unread) messageUnreadColor else messageColor
SpannableStringBuilder()
.color(color) {
bold { append(user) }
append(text)
if (isDirectMessage) "" else "${mapName(name, fullName)}: "
}
SpannableStringBuilder().append(user).append(text)
} else {
context.getText(R.string.msg_no_messages_yet)
}
}
private fun mapName(name: String, fullName: String?, unread: Boolean): CharSequence {
val roomName = if (settings.useSpecialCharsOnRoom() || settings.useRealName()) {
private fun mapName(name: String, fullName: String?): CharSequence {
return if (settings.useSpecialCharsOnRoom() || settings.useRealName()) {
fullName ?: name
} else {
name
}
val color = if (unread) nameUnreadColor else nameColor
return SpannableStringBuilder()
.color(color) {
append(roomName)
}
}
private fun mapUnread(unread: Long): String? {
return when(unread) {
return when (unread) {
0L -> null
in 1..99 -> unread.toString()
else -> context.getString(R.string.msg_more_than_ninety_nine_unread_messages)
......@@ -206,12 +203,5 @@ class RoomUiModelMapper(
}
}
private fun mapDate(date: Long?, unread: Boolean): CharSequence? {
return date?.localDateTime()?.date(context)?.let {
val color = if (unread) dateUnreadColor else dateColor
SpannableStringBuilder().color(color) {
append(it)
}
}
}
private fun mapDate(date: Long?): CharSequence? = date?.localDateTime()?.date(context)
}
......@@ -4,6 +4,7 @@ import android.content.res.Resources
import android.graphics.drawable.Drawable
import android.view.View
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import chat.rocket.android.R
import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
......@@ -11,19 +12,16 @@ import chat.rocket.common.model.RoomType
import chat.rocket.common.model.UserStatus
import kotlinx.android.synthetic.main.item_chat.view.*
import kotlinx.android.synthetic.main.unread_messages_badge.view.*
import ru.noties.markwon.Markwon
class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit) : ViewHolder<RoomItemHolder>(itemView) {
class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit) :
ViewHolder<RoomItemHolder>(itemView) {
private val resources: Resources = itemView.resources
private val channelUnread: Drawable = resources.getDrawable(R.drawable.ic_hashtag_black_12dp)
private val channel: Drawable = resources.getDrawable(R.drawable.ic_hashtag_12dp)
private val groupUnread: Drawable = resources.getDrawable(R.drawable.ic_lock_black_12_dp)
private val group: Drawable = resources.getDrawable(R.drawable.ic_lock_12_dp)
private val online: Drawable = resources.getDrawable(R.drawable.ic_status_online_12dp)
private val away: Drawable = resources.getDrawable(R.drawable.ic_status_away_12dp)
private val busy: Drawable = resources.getDrawable(R.drawable.ic_status_busy_12dp)
private val offline: Drawable = resources.getDrawable(R.drawable.ic_status_invisible_12dp)
private val channelIcon: Drawable = resources.getDrawable(R.drawable.ic_hashtag_12dp)
private val groupIcon: Drawable = resources.getDrawable(R.drawable.ic_lock_12_dp)
private val onlineIcon: Drawable = resources.getDrawable(R.drawable.ic_status_online_12dp)
private val awayIcon: Drawable = resources.getDrawable(R.drawable.ic_status_away_12dp)
private val busyIcon: Drawable = resources.getDrawable(R.drawable.ic_status_busy_12dp)
private val offlineIcon: Drawable = resources.getDrawable(R.drawable.ic_status_invisible_12dp)
override fun bindViews(data: RoomItemHolder) {
val room = data.data
......@@ -32,52 +30,50 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit
text_chat_name.text = room.name
if (room.lastMessage != null) {
text_last_message.isVisible = true
text_last_message.text = room.lastMessage
text_last_message.isVisible = true
} else {
text_last_message.isGone = true
}
if (room.date != null) {
text_last_message_date_time.isVisible = true
text_last_message_date_time.text = room.date
text_last_message_date_time.isVisible = true
} else {
text_last_message_date_time.isGone = true
text_last_message_date_time.isInvisible = true
}
if (room.unread != null) {
text_total_unread_messages.isVisible = true
text_total_unread_messages.text = room.unread
text_total_unread_messages.isVisible = true
} else {
text_total_unread_messages.isGone = true
text_total_unread_messages.isInvisible = true
}
if (room.status != null && room.type is RoomType.DirectMessage) {
image_chat_icon.setImageDrawable(getStatusDrawable(room.status))
} else {
image_chat_icon.setImageDrawable(getRoomDrawable(room.type, room.alert))
image_chat_icon.setImageDrawable(getRoomDrawable(room.type))
}
setOnClickListener {
listener(room)
}
setOnClickListener { listener(room) }
}
}
private fun getRoomDrawable(type: RoomType, alert: Boolean): Drawable? {
return when(type) {
is RoomType.Channel -> if (alert) channelUnread else channel
is RoomType.PrivateGroup -> if (alert) groupUnread else group
private fun getRoomDrawable(type: RoomType): Drawable? {
return when (type) {
is RoomType.Channel -> channelIcon
is RoomType.PrivateGroup -> groupIcon
else -> null
}
}
private fun getStatusDrawable(status: UserStatus): Drawable {
return when(status) {
is UserStatus.Online -> online
is UserStatus.Away -> away
is UserStatus.Busy -> busy
else -> offline
return when (status) {
is UserStatus.Online -> onlineIcon
is UserStatus.Away -> awayIcon
is UserStatus.Busy -> busyIcon
else -> offlineIcon
}
}
}
\ No newline at end of file
......@@ -6,7 +6,8 @@ import chat.rocket.android.R
import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
import chat.rocket.android.util.extensions.inflate
class RoomsAdapter(private val listener: (RoomUiModel) -> Unit) : RecyclerView.Adapter<ViewHolder<*>>() {
class RoomsAdapter(private val listener: (RoomUiModel) -> Unit) :
RecyclerView.Adapter<ViewHolder<*>>() {
init {
setHasStableIds(true)
......@@ -40,16 +41,16 @@ class RoomsAdapter(private val listener: (RoomUiModel) -> Unit) : RecyclerView.A
override fun getItemId(position: Int): Long {
val item = values[position]
return when(item) {
is HeaderItemHolder -> item.data.hashCode().toLong()
return when (item) {
is RoomItemHolder -> item.data.id.hashCode().toLong()
is HeaderItemHolder -> item.data.hashCode().toLong()
is LoadingItemHolder -> "loading".hashCode().toLong()
else -> throw IllegalStateException("View type must be either Room, Header or Loading")
}
}
override fun getItemViewType(position: Int): Int {
return when(values[position]) {
return when (values[position]) {
is RoomItemHolder -> VIEW_TYPE_ROOM
is HeaderItemHolder -> VIEW_TYPE_HEADER
is LoadingItemHolder -> VIEW_TYPE_LOADING
......
package chat.rocket.android.chatrooms.ui
import DateTimeHelper
import DrawableHelper
import android.content.Context
import android.graphics.Color
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.isVisible
import chat.rocket.android.R
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.checkIfMyself
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.showLastMessage
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.domain.useSpecialCharsOnRoom
import chat.rocket.android.util.extensions.*
import chat.rocket.common.model.RoomType
import chat.rocket.core.model.ChatRoom
import com.facebook.drawee.view.SimpleDraweeView
import kotlinx.android.synthetic.main.item_chat.view.*
import kotlinx.android.synthetic.main.unread_messages_badge.view.*
class ChatRoomsAdapter(
private val context: Context,
private val settings: PublicSettings,
private val localRepository: LocalRepository,
private val listener: (ChatRoom) -> Unit
) : RecyclerView.Adapter<ChatRoomsAdapter.ViewHolder>() {
var dataSet: MutableList<ChatRoom> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(parent.inflate(R.layout.item_chat))
override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(dataSet[position])
override fun getItemCount(): Int = dataSet.size
fun updateRooms(newRooms: List<ChatRoom>) {
dataSet.clear()
dataSet.addAll(newRooms)
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(chatRoom: ChatRoom) = with(itemView) {
bindAvatar(chatRoom, image_avatar)
bindName(chatRoom, text_chat_name)
bindIcon(chatRoom, image_chat_icon)
if (settings.showLastMessage()) {
text_last_message.isVisible = true
text_last_message_date_time.isVisible = true
bindLastMessageDateTime(chatRoom, text_last_message_date_time)
bindLastMessage(chatRoom, text_last_message)
} else {
text_last_message.isVisible = false
text_last_message_date_time.isVisible = false
}
bindUnreadMessages(chatRoom, text_total_unread_messages)
if (chatRoom.alert || chatRoom.unread > 0) {
text_chat_name.setTextColor(ContextCompat.getColor(context,
R.color.colorPrimaryText))
text_last_message_date_time.setTextColor(ContextCompat.getColor(context,
R.color.colorAccent))
text_last_message.setTextColor(ContextCompat.getColor(context,
android.R.color.primary_text_light))
} else {
text_chat_name.setTextColor(ContextCompat.getColor(context,
R.color.colorSecondaryText))
text_last_message_date_time.setTextColor(ContextCompat.getColor(context,
R.color.colorSecondaryText))
text_last_message.setTextColor(ContextCompat.getColor(context,
R.color.colorSecondaryText))
}
setOnClickListener { listener(chatRoom) }
}
private fun bindAvatar(chatRoom: ChatRoom, drawee: SimpleDraweeView) {
if (chatRoom.type is RoomType.DirectMessage) {
drawee.setImageURI(chatRoom.client.url.avatarUrl(chatRoom.name))
} else {
drawee.setImageURI(chatRoom.client.url.avatarUrl(chatRoom.name, true))
}
}
private fun bindIcon(chatRoom: ChatRoom, imageView: ImageView) {
val drawable = when (chatRoom.type) {
is RoomType.Channel -> DrawableHelper.getDrawableFromId(
R.drawable.ic_hashtag_black_12dp,
context
)
is RoomType.PrivateGroup -> DrawableHelper.getDrawableFromId(
R.drawable.ic_lock_black_12_dp,
context
)
is RoomType.DirectMessage -> DrawableHelper.getUserStatusDrawable(
chatRoom.status,
context
)
else -> null
}
drawable?.let {
val mutateDrawable = DrawableHelper.wrapDrawable(it).mutate()
if (chatRoom.type !is RoomType.DirectMessage) {
val color = when (chatRoom.alert || chatRoom.unread > 0) {
true -> R.color.colorPrimaryText
false -> R.color.colorSecondaryText
}
DrawableHelper.tintDrawable(mutateDrawable, context, color)
}
imageView.setImageDrawable(mutateDrawable)
}
}
private fun bindName(chatRoom: ChatRoom, textView: TextView) {
textView.textContent = chatRoomName(chatRoom)
}
private fun chatRoomName(chatRoom: ChatRoom): String {
return if (settings.useSpecialCharsOnRoom() || settings.useRealName()) {
chatRoom.fullName ?: chatRoom.name
} else {
chatRoom.name
}
}
private fun bindLastMessageDateTime(chatRoom: ChatRoom, textView: TextView) {
val lastMessage = chatRoom.lastMessage
if (lastMessage != null) {
val localDateTime = DateTimeHelper.getLocalDateTime(lastMessage.timestamp)
textView.content = DateTimeHelper.getDate(localDateTime, context)
} else {
textView.content = ""
}
}
private fun bindLastMessage(chatRoom: ChatRoom, textView: TextView) {
val lastMessage = chatRoom.lastMessage
val lastMessageSender = lastMessage?.sender
if (lastMessage != null && lastMessageSender != null) {
val message = lastMessage.message
val senderUsername = if (settings.useRealName()) {
lastMessageSender.name ?: lastMessageSender.username
} else {
lastMessageSender.username
}
when (senderUsername) {
chatRoom.name -> {
textView.content = message
}
else -> {
val user = if (localRepository.checkIfMyself(lastMessageSender.username!!)) {
"${context.getString(R.string.msg_you)}: "
} else {
"$senderUsername: "
}
val spannable = SpannableStringBuilder(user)
val len = spannable.length
spannable.setSpan(ForegroundColorSpan(Color.BLACK), 0, len - 1, 0)
spannable.append(message)
textView.content = spannable
}
}
} else {
textView.content = context.getText(R.string.msg_no_messages_yet)
}
}
private fun bindUnreadMessages(chatRoom: ChatRoom, textView: TextView) {
val totalUnreadMessage = chatRoom.unread
when {
totalUnreadMessage in 1..99 -> {
textView.textContent = totalUnreadMessage.toString()
textView.isVisible = true
}
totalUnreadMessage > 99 -> {
textView.textContent = context.getString(R.string.msg_more_than_ninety_nine_unread_messages)
textView.isVisible = true
}
else -> textView.isVisible = false
}
}
}
}
\ No newline at end of file
package chat.rocket.android.chatrooms.ui
import android.content.Context
import androidx.recyclerview.widget.RecyclerView
import android.util.SparseArray
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import java.util.*
class SimpleSectionedRecyclerViewAdapter(private val context: Context, private val sectionResourceId: Int, private val textResourceId: Int,
val baseAdapter: ChatRoomsAdapter) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var isValid = true
private val sectionsHeaders = SparseArray<Section>()
init {
baseAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
isValid = baseAdapter.itemCount > 0
notifyDataSetChanged()
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
isValid = baseAdapter.itemCount > 0
notifyItemRangeChanged(positionStart, itemCount)
}
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
isValid = baseAdapter.itemCount > 0
notifyItemRangeInserted(positionStart, itemCount)
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
isValid = baseAdapter.itemCount > 0
notifyItemRangeRemoved(positionStart, itemCount)
}
})
}
class SectionViewHolder(view: View, textResourceId: Int) : RecyclerView.ViewHolder(view) {
var title: TextView = view.findViewById<View>(textResourceId) as TextView
}
override fun onCreateViewHolder(parent: ViewGroup, typeView: Int): RecyclerView.ViewHolder {
return if (typeView == SECTION_TYPE) {
val view = LayoutInflater.from(context).inflate(sectionResourceId, parent, false)
SectionViewHolder(view, textResourceId)
} else {
baseAdapter.onCreateViewHolder(parent, typeView - 1)
}
}
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
if (isSectionHeaderPosition(position)) {
(viewHolder as SectionViewHolder).title.text = sectionsHeaders.get(position).title
} else {
baseAdapter.onBindViewHolder(viewHolder as ChatRoomsAdapter.ViewHolder, sectionedPositionToPosition(position))
}
}
override fun getItemViewType(position: Int): Int {
return if (isSectionHeaderPosition(position))
SECTION_TYPE
else
baseAdapter.getItemViewType(sectionedPositionToPosition(position)) + 1
}
class Section(internal var firstPosition: Int, var title: CharSequence) {
internal var sectionedPosition: Int = 0
}
fun setSections(sections: Array<Section>) {
sectionsHeaders.clear()
Arrays.sort(sections) { section1, section2 ->
when {
section1.firstPosition == section2.firstPosition -> 0
section1.firstPosition < section2.firstPosition -> -1
else -> 1
}
}
for ((offset, section) in sections.withIndex()) {
section.sectionedPosition = section.firstPosition + offset
sectionsHeaders.append(section.sectionedPosition, section)
}
notifyDataSetChanged()
}
fun clearSections(){
sectionsHeaders.clear()
notifyDataSetChanged()
}
fun positionToSectionedPosition(position: Int): Int {
var offset = 0
for (i in 0 until sectionsHeaders.size()) {
if (sectionsHeaders.valueAt(i).firstPosition > position) {
break
}
++offset
}
return position + offset
}
private fun sectionedPositionToPosition(sectionedPosition: Int): Int {
if (isSectionHeaderPosition(sectionedPosition)) {
return RecyclerView.NO_POSITION
}
var offset = 0
for (i in 0 until sectionsHeaders.size()) {
if (sectionsHeaders.valueAt(i).sectionedPosition > sectionedPosition) {
break
}
--offset
}
return sectionedPosition + offset
}
private fun isSectionHeaderPosition(position: Int): Boolean {
return sectionsHeaders.get(position) != null
}
override fun getItemId(position: Int): Long {
return when (isSectionHeaderPosition(position)) {
true -> (Integer.MAX_VALUE - sectionsHeaders.indexOfKey(position)).toLong()
false -> baseAdapter.getItemId(sectionedPositionToPosition(position))
}
}
override fun getItemCount(): Int {
return if (isValid) baseAdapter.itemCount + sectionsHeaders.size() else 0
}
companion object {
private const val SECTION_TYPE = 0
}
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="12dp"
android:viewportHeight="12"
android:viewportWidth="12">
<path
android:fillColor="#DE000000"
android:fillType="evenOdd"
android:pathData="M2.4,0h1.2v12h-1.2z" />
<path
android:fillColor="#DE000000"
android:fillType="evenOdd"
android:pathData="M0,2.4h12v1.2h-12z" />
<path
android:fillColor="#DE000000"
android:fillType="evenOdd"
android:pathData="M0,8.4h12v1.2h-12z" />
<path
android:fillColor="#DE000000"
android:fillType="evenOdd"
android:pathData="M8.4,0h1.2v12h-1.2z" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
android:shape="rectangle">
<solid android:color="@color/colorAccent" />
<corners android:radius="4dp" />
</shape>
......@@ -5,19 +5,19 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:paddingBottom="@dimen/chat_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:paddingTop="@dimen/chat_item_top_and_bottom_padding">
android:paddingTop="@dimen/chat_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingBottom="@dimen/chat_item_top_and_bottom_padding">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/image_avatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginTop="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:roundedCornerRadius="3dp" />
app:roundedCornerRadius="4dp" />
<ImageView
android:id="@+id/image_chat_icon"
......@@ -27,25 +27,7 @@
app:layout_constraintBottom_toBottomOf="@+id/text_chat_name"
app:layout_constraintStart_toEndOf="@+id/image_avatar"
app:layout_constraintTop_toTopOf="@+id/text_chat_name"
tools:src="@drawable/ic_hashtag_unread_12dp" />
<TextView
android:id="@+id/text_last_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="2dp"
android:layout_weight="0.8"
android:ellipsize="end"
android:maxLines="2"
android:textDirection="locale"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/image_chat_icon"
app:layout_constraintTop_toBottomOf="@+id/text_chat_name"
tools:text="Filipe de Lima Brito: Type something that is very big and need at least to lines, or maybe even more" />
tools:src="@drawable/ic_hashtag_12dp" />
<TextView
android:id="@+id/text_chat_name"
......@@ -53,39 +35,42 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/text_view_drawable_padding"
android:ellipsize="end"
android:lines="1"
android:maxLines="1"
android:textDirection="locale"
android:textColor="@color/colorSecondaryText"
app:layout_constraintBottom_toTopOf="@+id/text_last_message"
app:layout_constraintEnd_toStartOf="@+id/text_last_message_date_time"
app:layout_constraintStart_toEndOf="@+id/image_chat_icon"
app:layout_constraintTop_toTopOf="parent"
tools:text="general" />
tools:text="Margaret Hanson" />
<TextView
android:id="@+id/text_last_message_date_time"
style="@style/Timestamp.TextView"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:gravity="center"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="@+id/layout_unread_messages_badge"
android:textDirection="locale"
app:layout_constraintBaseline_toBaselineOf="@+id/text_chat_name"
app:layout_constraintEnd_toEndOf="parent"
tools:text="11:45 AM" />
<TextView
android:id="@+id/text_last_message"
style="@style/ChatRoom.LastMessage.TextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:ellipsize="end"
android:maxLines="2"
android:layout_marginEnd="12dp"
android:textDirection="locale"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/layout_unread_messages_badge"
app:layout_constraintTop_toTopOf="@+id/text_chat_name"
tools:text="11:45 AM" />
app:layout_constraintStart_toStartOf="@+id/image_chat_icon"
app:layout_constraintTop_toBottomOf="@+id/text_chat_name"
tools:text="Filipe de Lima Brito: Type something that is very big and need at least to lines, or maybe even more" />
<include
android:id="@+id/layout_unread_messages_badge"
layout="@layout/unread_messages_badge"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_width="21dp"
android:layout_height="21dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/text_chat_name" />
app:layout_constraintTop_toTopOf="@+id/text_last_message" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
......@@ -6,15 +6,12 @@
<TextView
android:id="@+id/text_total_unread_messages"
style="@style/TextAppearance.AppCompat.Caption"
android:layout_width="18dp"
android:layout_height="18dp"
style="@style/Badge.TextView"
android:layout_width="21dp"
android:layout_height="21dp"
android:background="@drawable/style_total_unread_messages"
android:gravity="center"
android:textColor="@color/colorWhite"
android:textSize="10sp"
android:visibility="gone"
tools:text="99+"
tools:text="1"
tools:visibility="visible" />
</LinearLayout>
\ No newline at end of file
......@@ -10,6 +10,8 @@
<color name="colorPrimaryText">#DE000000</color>
<color name="colorSecondaryText">#FF787878</color>
<color name="colorSecondaryTextLight">#FFC1C1C1</color>
<color name="colorTimestampText">#FF5699FF</color>
<color name="colorLastMessageText">#99000000</color>
<!-- User status colors -->
<color name="colorUserStatusOnline">#2FE1A8</color>
......
......@@ -137,9 +137,25 @@
</style>
<style name="ChatRoom.Name.TextView" parent="TextAppearance.AppCompat.Title">
<item name="android:textSize">16sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">@color/colorPrimary</item>
<item name="android:letterSpacing">0.01</item>
<item name="android:lineSpacingExtra">8sp</item>
<item name="android:ellipsize">end</item>
<item name="android:maxLines">1</item>
<item name="android:textSize">16sp</item>
</style>
<style name="ChatRoom.LastMessage.TextView" parent="TextAppearance.AppCompat.Title">
<item name="android:textSize">14sp</item>
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">@color/colorLastMessageText</item>
<item name="android:letterSpacing">0.02</item>
<item name="android:lineSpacingExtra">6sp</item>
<item name="android:ellipsize">end</item>
<item name="android:maxLines">2</item>
</style>
<style name="Sender.Name.TextView" parent="TextAppearance.AppCompat.Title">
......@@ -163,8 +179,25 @@
<item name="android:textColor">@color/colorPrimaryText</item>
</style>
<style name="Timestamp.TextView" parent="TextAppearance.AppCompat.Caption">
<item name="android:textSize">10sp</item>
<style name="Timestamp.TextView" parent="TextAppearance.AppCompat.Title">
<item name="android:textSize">12sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">@color/colorTimestampText</item>
<item name="android:letterSpacing">0.03</item>
<item name="android:lineSpacingExtra">4sp</item>
<item name="android:ellipsize">end</item>
<item name="android:maxLines">1</item>
</style>
<style name="Badge.TextView" parent="TextAppearance.AppCompat.Title">
<item name="android:textSize">14sp</item>
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">@color/colorWhite</item>
<item name="android:letterSpacing">0.04</item>
<item name="android:lineSpacingExtra">2sp</item>
<item name="android:gravity">center</item>
</style>
// REMARK: To be removed.
......
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