From 5843e1c90f11adbbdfba18c67cc221fe19d75156 Mon Sep 17 00:00:00 2001 From: iamwhoiam0 Date: Tue, 15 Jul 2025 20:47:48 +0300 Subject: [PATCH] done --- app/build.gradle | 8 +- app/src/main/AndroidManifest.xml | 2 +- .../otus/gpb/recyclerview/MainActivity.kt | 48 ++++++- .../otus/gpb/recyclerview/data/ChatItem.kt | 6 + .../otus/gpb/recyclerview/data/GroupChat.kt | 81 ++++++++++++ .../otus/gpb/recyclerview/data/UserChat.kt | 57 +++++++++ .../otus/gpb/recyclerview/ui/ChatAdapter.kt | 101 +++++++++++++++ .../gpb/recyclerview/ui/ChatDiffCallback.kt | 19 +++ .../gpb/recyclerview/ui/CustomDecorator.kt | 50 ++++++++ .../recyclerview/ui/SwipeToDeleteCallback.kt | 73 +++++++++++ .../main/res/drawable/circle_shape_blue.xml | 16 +++ app/src/main/res/drawable/ic_avatar.png | Bin 0 -> 19090 bytes app/src/main/res/drawable/ic_delete.xml | 18 +++ app/src/main/res/drawable/ic_mention.xml | 15 +++ app/src/main/res/drawable/ic_mute.xml | 13 ++ app/src/main/res/drawable/ic_scam.xml | 26 ++++ .../main/res/drawable/ic_vector_mention.xml | 12 ++ app/src/main/res/drawable/ic_verified.xml | 10 ++ app/src/main/res/drawable/ic_voipe.xml | 21 +++ .../res/drawable/shape_avatar_imageview.xml | 5 + app/src/main/res/layout/item_group_chat.xml | 120 ++++++++++++++++++ app/src/main/res/layout/item_user_chat.xml | 100 +++++++++++++++ app/src/main/res/values/colors.xml | 2 + app/src/main/res/values/integers.xml | 4 + 24 files changed, 802 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/otus/gpb/recyclerview/data/ChatItem.kt create mode 100644 app/src/main/java/otus/gpb/recyclerview/data/GroupChat.kt create mode 100644 app/src/main/java/otus/gpb/recyclerview/data/UserChat.kt create mode 100644 app/src/main/java/otus/gpb/recyclerview/ui/ChatAdapter.kt create mode 100644 app/src/main/java/otus/gpb/recyclerview/ui/ChatDiffCallback.kt create mode 100644 app/src/main/java/otus/gpb/recyclerview/ui/CustomDecorator.kt create mode 100644 app/src/main/java/otus/gpb/recyclerview/ui/SwipeToDeleteCallback.kt create mode 100644 app/src/main/res/drawable/circle_shape_blue.xml create mode 100644 app/src/main/res/drawable/ic_avatar.png create mode 100644 app/src/main/res/drawable/ic_delete.xml create mode 100644 app/src/main/res/drawable/ic_mention.xml create mode 100644 app/src/main/res/drawable/ic_mute.xml create mode 100644 app/src/main/res/drawable/ic_scam.xml create mode 100644 app/src/main/res/drawable/ic_vector_mention.xml create mode 100644 app/src/main/res/drawable/ic_verified.xml create mode 100644 app/src/main/res/drawable/ic_voipe.xml create mode 100644 app/src/main/res/drawable/shape_avatar_imageview.xml create mode 100644 app/src/main/res/layout/item_group_chat.xml create mode 100644 app/src/main/res/layout/item_user_chat.xml create mode 100644 app/src/main/res/values/integers.xml diff --git a/app/build.gradle b/app/build.gradle index 54e4eac..2d0be58 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,7 +4,7 @@ plugins { } android { - compileSdk 34 + compileSdk 35 namespace "otus.gpb.recyclerview" defaultConfig { @@ -30,14 +30,18 @@ android { kotlinOptions { jvmTarget = '1.8' } + buildFeatures { + viewBinding = true + } } dependencies { - + implementation('com.github.bumptech.glide:glide:4.16.0') implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'com.google.android.material:material:1.7.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.compose.ui:ui-graphics-android:1.8.3' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ef75335..9ed9ff2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - + = + (groupChats.map { ChatItem.Group(it) } + + userChats.map { ChatItem.User(it) }).toMutableList() + + private lateinit var binding: ActivityMainBinding + private lateinit var adapter: ChatAdapter + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + binding.recyclerView.addItemDecoration(CustomDecorator(this).apply { + setColor(R.color.color_chat_divider_light) + setOffset(R.integer.dividerOffset) + }) + + binding.recyclerView.layoutManager = LinearLayoutManager(this) + adapter = ChatAdapter() { id -> + println(id) + } + + binding.recyclerView.adapter = adapter + + adapter.submitList(chatItems.toList()) + + val itemTouchHelper = ItemTouchHelper( + SwipeToDeleteCallback ({ position -> removeItem(position)}, this) + ) + itemTouchHelper.attachToRecyclerView(binding.recyclerView) + } + + private fun removeItem(position: Int) { + chatItems.removeAt(position) + adapter.submitList(chatItems.toList()) + } + } \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/data/ChatItem.kt b/app/src/main/java/otus/gpb/recyclerview/data/ChatItem.kt new file mode 100644 index 0000000..44ee951 --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/data/ChatItem.kt @@ -0,0 +1,6 @@ +package otus.gpb.recyclerview.data + +sealed class ChatItem() { + data class Group(val chat: GroupChat) : ChatItem() + data class User(val chat: UserChat) : ChatItem() +} \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/data/GroupChat.kt b/app/src/main/java/otus/gpb/recyclerview/data/GroupChat.kt new file mode 100644 index 0000000..46c7e87 --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/data/GroupChat.kt @@ -0,0 +1,81 @@ +package otus.gpb.recyclerview.data + +data class GroupChat( + val id: Int, + val groupName: String, + val lastUsername: String, + val lastMessage: String, + val avatarUrl: String, + val lastUserUrl: String, + var isVerified: Boolean, + var isMuted: Boolean, + var isRead: Boolean, + var isVoip: Boolean, + var counterMessages: Int, + var isMentioned: Boolean, + val messageTime: String +) + + +val groupChats = listOf( + GroupChat( + id = 1, + groupName = "Labubu fans", + lastUsername = "Teodor", + lastMessage = "Hi, how are you?", + avatarUrl = "https://media.geeksforgeeks.org/wp-content/uploads/20210101144014/gfglogo.png", + lastUserUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Moscow_%288351271825%29.jpg/500px-Moscow_%288351271825%29.jpg", + isVerified = false, + isMuted = false, + isRead = true, + isVoip = false, + counterMessages = 0, + isMentioned = false, + messageTime = "06.07.2025 10:00", + ), + GroupChat( + id = 2, + groupName = "Top Gear", + lastUsername = "Patrick", + lastMessage = "Yes, I know this, but what you want to do?", + avatarUrl = "https://media.geeksforgeeks.org/wp-content/uploads/20210101144014/gfglogo.png", + lastUserUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Moscow_%288351271825%29.jpg/500px-Moscow_%288351271825%29.jpg", + isVerified = false, + isMuted = false, + isRead = true, + isVoip = false, + counterMessages = 0, + isMentioned = false, + messageTime = "10.06.2025 15:23", + ), + GroupChat( + id = 3, + groupName = "Karena Makarena", + lastUsername = "Tereza", + lastMessage = "Whaaaaaaat??", + avatarUrl = "https://i.imgur.com/DvpvklR.png", + lastUserUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Moscow_%288351271825%29.jpg/500px-Moscow_%288351271825%29.jpg", + isVerified = false, + isMuted = false, + isRead = false, + isVoip = true, + counterMessages = 3, + isMentioned = false, + messageTime = "06.07.2025 10:00", + ), + GroupChat( + id = 4, + groupName = "Eric Davidich", + lastUsername = "Magomed", + lastMessage = "Shaize", + avatarUrl = "https://i.imgur.com/DvpvklR.png", + lastUserUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Moscow_%288351271825%29.jpg/500px-Moscow_%288351271825%29.jpg", + isVerified = false, + isMuted = true, + isRead = false, + isVoip = false, + counterMessages = 69, + isMentioned = true, + messageTime = "05.07.2025 17:56", + ), +) \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/data/UserChat.kt b/app/src/main/java/otus/gpb/recyclerview/data/UserChat.kt new file mode 100644 index 0000000..e2eca6f --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/data/UserChat.kt @@ -0,0 +1,57 @@ +package otus.gpb.recyclerview.data + +data class UserChat( + val id: Int, + val username: String, + val lastMessage: String, + val avatarUrl: String, + var isVerified: Boolean, + var isMuted: Boolean, + var isRead: Boolean, + var isScam: Boolean, + var isOnline: Boolean, + var counterMessages: Int, + val messageTime: String +) + +val userChats = listOf( + UserChat( + id = 1, + username = "Павел Дуров", + lastMessage = "Пойдём сегодня на футбол?", + avatarUrl = "https://upload.wikimedia.org/wikipedia/commons/3/33/Espaguetis_carbonara.jpg", + isVerified = true, + isMuted = false, + isRead = false, + isScam = false, + isOnline = true, + counterMessages = 1, + messageTime = "06.07.2025 13:05" + ), + UserChat( + id = 2, + username = "Бадави", + lastMessage = "Сроооочно зайди да", + avatarUrl = "https://upload.wikimedia.org/wikipedia/commons/3/33/Espaguetis_carbonara.jpg", + isVerified = false, + isMuted = true, + isRead = false, + isScam = false, + isOnline = false, + counterMessages = 10, + messageTime = "02.07.2025 13:46" + ), + UserChat( + id = 3, + username = "Олег Тинькофф", + lastMessage = "Скинь 3 цифры на обороте карты", + avatarUrl = "https://upload.wikimedia.org/wikipedia/commons/3/33/Espaguetis_carbonara.jpg", + isVerified = false, + isMuted = false, + isRead = false, + isScam = true, + isOnline = true, + counterMessages = 5, + messageTime = "25.01.2024 16:18" + ), +) diff --git a/app/src/main/java/otus/gpb/recyclerview/ui/ChatAdapter.kt b/app/src/main/java/otus/gpb/recyclerview/ui/ChatAdapter.kt new file mode 100644 index 0000000..31a4945 --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/ui/ChatAdapter.kt @@ -0,0 +1,101 @@ +package otus.gpb.recyclerview.ui + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import otus.gpb.recyclerview.data.ChatItem +import otus.gpb.recyclerview.databinding.ItemGroupChatBinding +import otus.gpb.recyclerview.databinding.ItemUserChatBinding +import java.util.Locale + +class ChatAdapter(private val onItemClick: (Int) -> Unit): + ListAdapter(ChatDiffCallback()) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val inflater = LayoutInflater.from(parent.context) + + return when(viewType){ + VIEW_TYPE_GROUP -> { + val binding = ItemGroupChatBinding.inflate(inflater, parent, false) + GroupChatViewHolder(binding) + } + VIEW_TYPE_USER -> { + val binding = ItemUserChatBinding.inflate(inflater, parent, false) + UserChatViewHolder(binding) + } + else -> throw RuntimeException("RuntimeException") + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (val item = getItem(position)) { + is ChatItem.Group -> (holder as GroupChatViewHolder).bind(item) + is ChatItem.User -> (holder as UserChatViewHolder).bind(item) + } + } + + override fun getItemViewType(position: Int): Int { + return when (getItem(position)){ + is ChatItem.Group -> VIEW_TYPE_GROUP + is ChatItem.User -> VIEW_TYPE_USER + } + } + + inner class GroupChatViewHolder(private val binding: ItemGroupChatBinding) : RecyclerView.ViewHolder(binding.root) { + fun bind(item: ChatItem.Group) { + binding.groupName.text = item.chat.groupName + binding.lastUsername.text = item.chat.lastUsername + Glide.with(binding.root.context) + .load(item.chat.avatarUrl) + .centerCrop() + .into(binding.avatarUrl) + binding.lastMessage.text = item.chat.lastMessage + binding.verification.visibility = if (item.chat.isVerified) View.VISIBLE else View.GONE + binding.mute.visibility = if (item.chat.isMuted){ + binding.badge.isActivated = true + View.VISIBLE + } else { + binding.badge.isActivated = false + View.GONE + } + binding.voip.visibility = if (item.chat.isVoip) View.VISIBLE else View.GONE + + binding.badge.visibility = if (item.chat.isMentioned) View.VISIBLE else View.GONE + binding.badge.text = String.format(Locale("ru", "RU"), "%d", item.chat.counterMessages) + binding.messageTime.text = item.chat.messageTime + binding.root.setOnClickListener { onItemClick(item.chat.id) } + } + } + + inner class UserChatViewHolder(private val binding: ItemUserChatBinding) : RecyclerView.ViewHolder(binding.root) { + fun bind(item: ChatItem.User) { + binding.usernameField.text = item.chat.username + Glide.with(binding.root.context) + .load(item.chat.avatarUrl) + .centerCrop() + .into(binding.avatarUrl) + binding.lastMessage.text = item.chat.lastMessage + binding.verification.visibility = if (item.chat.isVerified) View.VISIBLE else View.GONE + binding.mute.visibility = if (item.chat.isMuted){ + binding.badge.isActivated = true + View.VISIBLE + } else { + binding.badge.isActivated = false + View.GONE + } + binding.scam.visibility = if (item.chat.isScam) View.VISIBLE else View.GONE + binding.badge.visibility = if (item.chat.counterMessages>0) View.VISIBLE else View.GONE + binding.badge.text = String.format(Locale("ru", "RU"), "%d", item.chat.counterMessages) + binding.messageTime.text = item.chat.messageTime + binding.root.setOnClickListener { onItemClick(item.chat.id) } + } + } + + companion object{ + private const val VIEW_TYPE_GROUP = 1 + private const val VIEW_TYPE_USER = 2 + } +} \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/ui/ChatDiffCallback.kt b/app/src/main/java/otus/gpb/recyclerview/ui/ChatDiffCallback.kt new file mode 100644 index 0000000..368d842 --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/ui/ChatDiffCallback.kt @@ -0,0 +1,19 @@ +package otus.gpb.recyclerview.ui + +import androidx.recyclerview.widget.DiffUtil +import otus.gpb.recyclerview.data.ChatItem + +class ChatDiffCallback : DiffUtil.ItemCallback() { + + override fun areContentsTheSame(oldItem: ChatItem, newItem: ChatItem): Boolean { + return oldItem == newItem + } + + override fun areItemsTheSame(oldItem: ChatItem, newItem: ChatItem): Boolean { + return when{ + oldItem is ChatItem.Group && newItem is ChatItem.Group -> oldItem.chat.id == newItem.chat.id + oldItem is ChatItem.User && newItem is ChatItem.User -> oldItem.chat.id == newItem.chat.id + else -> false + } + } +} \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/ui/CustomDecorator.kt b/app/src/main/java/otus/gpb/recyclerview/ui/CustomDecorator.kt new file mode 100644 index 0000000..8f4edfd --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/ui/CustomDecorator.kt @@ -0,0 +1,50 @@ +package otus.gpb.recyclerview.ui + +import android.content.Context +import android.content.res.Resources +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.Rect +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.RecyclerView + +class CustomDecorator(private val context: Context) : DividerItemDecoration(context, VERTICAL){ + + private val bounds = Rect() + private val paint = Paint() + private var offset = 0 + private var color = 0xFF000000.toInt() + + override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { + paint.color = color + + val childCount = parent.childCount + for (index: Int in 0 until childCount) { + val child = parent.getChildAt(index) + parent.getDecoratedBoundsWithMargins(child, bounds) + bounds.left += offset + + val positionCurrent = parent.getChildAdapterPosition(child) + if (positionCurrent != RecyclerView.NO_POSITION) { + val lastElementPosition = parent.adapter?.itemCount?.minus(1) + if (positionCurrent != lastElementPosition) { + c.drawLine( + (bounds.left).toFloat(), + bounds.bottom.toFloat(), + bounds.right.toFloat(), + bounds.bottom.toFloat(), + paint + ) + } + } + } + } + + fun setColor(id: Int) { + color = context.getColor(id) + } + + fun setOffset(id: Int) { + offset = (context.resources.getInteger(id) * Resources.getSystem().displayMetrics.density).toInt() + } +} \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/ui/SwipeToDeleteCallback.kt b/app/src/main/java/otus/gpb/recyclerview/ui/SwipeToDeleteCallback.kt new file mode 100644 index 0000000..5bc5d44 --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/ui/SwipeToDeleteCallback.kt @@ -0,0 +1,73 @@ +package otus.gpb.recyclerview.ui + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.RectF +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import otus.gpb.recyclerview.R + +class SwipeToDeleteCallback( + private val onItemRemoved: (Int) -> Unit, + context: Context +) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { + + private val deleteIcon = ContextCompat.getDrawable(context, R.drawable.ic_delete)!! + private val backgroundPaint = Paint().apply { + color = 0xFFE64646.toInt() + } + + override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float { + return 0.85f + } + + override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder) = false + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + onItemRemoved(viewHolder.adapterPosition) + } + + override fun onChildDraw( + c: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { + val itemView = viewHolder.itemView + val itemHeight = itemView.bottom - itemView.top + + if (dX != 0f) { + val backgroundRect = if (dX > 0) { + RectF(itemView.left.toFloat(), itemView.top.toFloat(), itemView.left + dX, itemView.bottom.toFloat()) + } else { + RectF(itemView.right + dX, itemView.top.toFloat(), itemView.right.toFloat(), itemView.bottom.toFloat()) + } + c.drawRect(backgroundRect, backgroundPaint) + } + + val icon = deleteIcon + val iconTop = itemView.top + (itemHeight - icon.intrinsicHeight) / 2 + + if (dX > 0) { + val iconLeft = itemView.left + dX.toInt() - icon.intrinsicWidth - 32 + val iconRight = iconLeft + icon.intrinsicWidth + icon.setBounds(iconLeft, iconTop, iconRight, iconTop + icon.intrinsicHeight) + icon.draw(c) + } else if (dX < 0) { + val iconRight = itemView.right + dX.toInt() + icon.intrinsicWidth + 32 + val iconLeft = iconRight - icon.intrinsicWidth + icon.setBounds(iconLeft, iconTop, iconRight, iconTop + icon.intrinsicHeight) + icon.draw(c) + } + + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) + } + +} + diff --git a/app/src/main/res/drawable/circle_shape_blue.xml b/app/src/main/res/drawable/circle_shape_blue.xml new file mode 100644 index 0000000..cca1cd9 --- /dev/null +++ b/app/src/main/res/drawable/circle_shape_blue.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_avatar.png b/app/src/main/res/drawable/ic_avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..1f5e89dfc651a473d3241a66dd7b55d78577a9c7 GIT binary patch literal 19090 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 B6D|M% literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000..3d6007e --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_mention.xml b/app/src/main/res/drawable/ic_mention.xml new file mode 100644 index 0000000..ca45d79 --- /dev/null +++ b/app/src/main/res/drawable/ic_mention.xml @@ -0,0 +1,15 @@ + + + + diff --git a/app/src/main/res/drawable/ic_mute.xml b/app/src/main/res/drawable/ic_mute.xml new file mode 100644 index 0000000..ca48517 --- /dev/null +++ b/app/src/main/res/drawable/ic_mute.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_scam.xml b/app/src/main/res/drawable/ic_scam.xml new file mode 100644 index 0000000..f6d9704 --- /dev/null +++ b/app/src/main/res/drawable/ic_scam.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_vector_mention.xml b/app/src/main/res/drawable/ic_vector_mention.xml new file mode 100644 index 0000000..6e60993 --- /dev/null +++ b/app/src/main/res/drawable/ic_vector_mention.xml @@ -0,0 +1,12 @@ + + + diff --git a/app/src/main/res/drawable/ic_verified.xml b/app/src/main/res/drawable/ic_verified.xml new file mode 100644 index 0000000..52ec8f3 --- /dev/null +++ b/app/src/main/res/drawable/ic_verified.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_voipe.xml b/app/src/main/res/drawable/ic_voipe.xml new file mode 100644 index 0000000..c2b0bbd --- /dev/null +++ b/app/src/main/res/drawable/ic_voipe.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/app/src/main/res/drawable/shape_avatar_imageview.xml b/app/src/main/res/drawable/shape_avatar_imageview.xml new file mode 100644 index 0000000..a9a5983 --- /dev/null +++ b/app/src/main/res/drawable/shape_avatar_imageview.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_group_chat.xml b/app/src/main/res/layout/item_group_chat.xml new file mode 100644 index 0000000..1dbc18a --- /dev/null +++ b/app/src/main/res/layout/item_group_chat.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_user_chat.xml b/app/src/main/res/layout/item_user_chat.xml new file mode 100644 index 0000000..150bc07 --- /dev/null +++ b/app/src/main/res/layout/item_user_chat.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index f8c6127..5fbf9d4 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,4 +7,6 @@ #FF018786 #FF000000 #FFFFFFFF + + #FFD9D9D9 \ No newline at end of file diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml new file mode 100644 index 0000000..d19e039 --- /dev/null +++ b/app/src/main/res/values/integers.xml @@ -0,0 +1,4 @@ + + + 73 + \ No newline at end of file