diff --git a/app/build.gradle b/app/build.gradle index 54e4eac..3734578 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,7 +38,9 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'com.google.android.material:material:1.7.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'it.xabaras.android:recyclerview-swipedecorator:1.4' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + } \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt index e2cdca7..6338f0f 100644 --- a/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt +++ b/app/src/main/java/otus/gpb/recyclerview/MainActivity.kt @@ -1,12 +1,29 @@ package otus.gpb.recyclerview -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import otus.gpb.recyclerview.chat.ChatListAdapter +import otus.gpb.recyclerview.chat.ChatTouchHelper class MainActivity : AppCompatActivity() { + private val chatAdapter: ChatListAdapter by lazy { ChatListAdapter() } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + createRcViewChat() + } + + private fun createRcViewChat() { + val cardsMessages = findViewById(R.id.cardsMessages) + cardsMessages.adapter = chatAdapter + chatAdapter.createChatCards() + + cardsMessages.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL)) + ItemTouchHelper(ChatTouchHelper(chatAdapter, this)).attachToRecyclerView(cardsMessages) } } \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatData.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatData.kt new file mode 100644 index 0000000..b0bbb3c --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatData.kt @@ -0,0 +1,22 @@ +package otus.gpb.recyclerview.chat + +data class ChatData( + var id: Int, + var avatar: Int, + var avatarActionIcon: Int, + + var lockIcon: Int, + val title: String, + var verifiedIcon: Int, + + var messageAuthor: String, + + var previewIcon: Int, + val message: String, + + var checkIcon: Int, + var timeService: String, + + var mentionBlock: Boolean, + var pinnedIcon: Int, +) \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt new file mode 100644 index 0000000..ca5e5fd --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatDiffutils.kt @@ -0,0 +1,14 @@ +package otus.gpb.recyclerview.chat + +import androidx.recyclerview.widget.DiffUtil + +class ChatDiffutils : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: ChatData, newItem: ChatData): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: ChatData, newItem: ChatData): Boolean { + return oldItem.id == newItem.id + } +} \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatListAdapter.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatListAdapter.kt new file mode 100644 index 0000000..967ce62 --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatListAdapter.kt @@ -0,0 +1,68 @@ +package otus.gpb.recyclerview.chat + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.ListAdapter +import otus.gpb.recyclerview.R + + +class ChatListAdapter : ListAdapter(ChatDiffutils()) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatViewHolder { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.card_chat, parent, false) + return ChatViewHolder(view) + } + + override fun onBindViewHolder(holder: ChatViewHolder, position: Int) { + holder.bind(getItem(position)) + + if (position == currentList.size-1) { + val newChatList= currentList + getChatCard(currentList.last().id+1) + changeChatCard(newChatList) + } + } + + private fun changeChatCard(newChatList: List) { + this.submitList(newChatList) + } + + fun deleteChatCard(position: Int) { + val newChatList = currentList.filterIndexed { index, _ -> index != position } + changeChatCard(newChatList) + } + + override fun onCurrentListChanged( + previousList: MutableList, + currentList: MutableList + ) { + super.onCurrentListChanged(previousList, currentList) + } + + fun createChatCards() { + + val cards = (1..15).map { + getChatCard(it) + }.toMutableList() + changeChatCard(cards) + } + + private fun getChatCard(position: Int): ChatData { + + return ChatData( + id = position, + avatar = R.drawable.avatar_1, + avatarActionIcon = R.drawable.avatar_action_icon, + lockIcon = R.drawable.lock_icon, + title = "Title", + verifiedIcon = R.drawable.verified_icon, + messageAuthor = "messageAuthor", + previewIcon = R.drawable.preview_1, + message = "message", + checkIcon = R.drawable.check_icon, + timeService = "11:00", + mentionBlock = true, + pinnedIcon = R.drawable.pinned_icon + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatTouchHelper.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatTouchHelper.kt new file mode 100644 index 0000000..20b48cc --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatTouchHelper.kt @@ -0,0 +1,60 @@ +package otus.gpb.recyclerview.chat + +import android.content.Context +import otus.gpb.recyclerview.R +import android.graphics.Canvas +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator + + +class ChatTouchHelper(adapter: ChatListAdapter, context: Context) : ItemTouchHelper.Callback() { + private val chatAdapter = adapter + private val _context = context + + override fun getMovementFlags( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder + ): Int { + return makeMovementFlags(0, ItemTouchHelper.LEFT) + } + + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean { + return false + } + + override fun onChildDraw( + canvas: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { + RecyclerViewSwipeDecorator.Builder( + canvas, + recyclerView, + viewHolder, + dX, + dY, + actionState, + isCurrentlyActive + ) + .addBackgroundColor(ContextCompat.getColor(_context, R.color.mentionBg)) + .addActionIcon(R.drawable.archive_icon) + .create() + .decorate() + + super.onChildDraw(canvas, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + chatAdapter.deleteChatCard(viewHolder.absoluteAdapterPosition) + } +} \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/recyclerview/chat/ChatViewHolder.kt b/app/src/main/java/otus/gpb/recyclerview/chat/ChatViewHolder.kt new file mode 100644 index 0000000..39a91e4 --- /dev/null +++ b/app/src/main/java/otus/gpb/recyclerview/chat/ChatViewHolder.kt @@ -0,0 +1,15 @@ +package otus.gpb.recyclerview.chat + +import android.view.View +import android.widget.ImageView +import androidx.recyclerview.widget.RecyclerView +import otus.gpb.recyclerview.R + +class ChatViewHolder(private val cardView: View) : RecyclerView.ViewHolder(cardView) { + + private val image: ImageView by lazy { cardView.findViewById(R.id.avatar) } + + fun bind(items: ChatData) { + image.setImageResource(items.avatar) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-nodpi/avatar_1.png b/app/src/main/res/drawable-nodpi/avatar_1.png new file mode 100644 index 0000000..ff829ec Binary files /dev/null and b/app/src/main/res/drawable-nodpi/avatar_1.png differ diff --git a/app/src/main/res/drawable-nodpi/avatar_cats.png b/app/src/main/res/drawable-nodpi/avatar_cats.png new file mode 100644 index 0000000..fde48a0 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/avatar_cats.png differ diff --git a/app/src/main/res/drawable-nodpi/avatar_cow.png b/app/src/main/res/drawable-nodpi/avatar_cow.png new file mode 100644 index 0000000..be237f9 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/avatar_cow.png differ diff --git a/app/src/main/res/drawable-nodpi/avatar_paintroll.png b/app/src/main/res/drawable-nodpi/avatar_paintroll.png new file mode 100644 index 0000000..809079f Binary files /dev/null and b/app/src/main/res/drawable-nodpi/avatar_paintroll.png differ diff --git a/app/src/main/res/drawable-nodpi/preview_1.png b/app/src/main/res/drawable-nodpi/preview_1.png new file mode 100644 index 0000000..63efd8b Binary files /dev/null and b/app/src/main/res/drawable-nodpi/preview_1.png differ diff --git a/app/src/main/res/drawable-nodpi/preview_2.png b/app/src/main/res/drawable-nodpi/preview_2.png new file mode 100644 index 0000000..ae840c9 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/preview_2.png differ diff --git a/app/src/main/res/drawable-nodpi/preview_3.png b/app/src/main/res/drawable-nodpi/preview_3.png new file mode 100644 index 0000000..af6fd24 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/preview_3.png differ diff --git a/app/src/main/res/drawable/archive_icon.xml b/app/src/main/res/drawable/archive_icon.xml new file mode 100644 index 0000000..7438d9a --- /dev/null +++ b/app/src/main/res/drawable/archive_icon.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/avatar_action_icon.xml b/app/src/main/res/drawable/avatar_action_icon.xml new file mode 100644 index 0000000..dfe3e9a --- /dev/null +++ b/app/src/main/res/drawable/avatar_action_icon.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/border_image.xml b/app/src/main/res/drawable/border_image.xml new file mode 100644 index 0000000..98d96ba --- /dev/null +++ b/app/src/main/res/drawable/border_image.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/check_icon.xml b/app/src/main/res/drawable/check_icon.xml new file mode 100644 index 0000000..314a6bd --- /dev/null +++ b/app/src/main/res/drawable/check_icon.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/lock_icon.xml b/app/src/main/res/drawable/lock_icon.xml new file mode 100644 index 0000000..0efa151 --- /dev/null +++ b/app/src/main/res/drawable/lock_icon.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/mention_icon.xml b/app/src/main/res/drawable/mention_icon.xml new file mode 100644 index 0000000..7c6fbb6 --- /dev/null +++ b/app/src/main/res/drawable/mention_icon.xml @@ -0,0 +1,12 @@ + + + diff --git a/app/src/main/res/drawable/pencil_icon.xml b/app/src/main/res/drawable/pencil_icon.xml new file mode 100644 index 0000000..c9378b0 --- /dev/null +++ b/app/src/main/res/drawable/pencil_icon.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/pinned_icon.xml b/app/src/main/res/drawable/pinned_icon.xml new file mode 100644 index 0000000..e270350 --- /dev/null +++ b/app/src/main/res/drawable/pinned_icon.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/app/src/main/res/drawable/round_shape.xml b/app/src/main/res/drawable/round_shape.xml new file mode 100644 index 0000000..63b62fb --- /dev/null +++ b/app/src/main/res/drawable/round_shape.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/scam_icon.xml b/app/src/main/res/drawable/scam_icon.xml new file mode 100644 index 0000000..e984312 --- /dev/null +++ b/app/src/main/res/drawable/scam_icon.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/sound_icon.xml b/app/src/main/res/drawable/sound_icon.xml new file mode 100644 index 0000000..bd102cc --- /dev/null +++ b/app/src/main/res/drawable/sound_icon.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/verified_icon.xml b/app/src/main/res/drawable/verified_icon.xml new file mode 100644 index 0000000..b1ba800 --- /dev/null +++ b/app/src/main/res/drawable/verified_icon.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 2d026df..371c5a7 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -3,11 +3,15 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".MainActivity"> + android:layout_height="match_parent" + android:orientation="vertical" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + /> \ No newline at end of file diff --git a/app/src/main/res/layout/card_chat.xml b/app/src/main/res/layout/card_chat.xml new file mode 100644 index 0000000..0e83f93 --- /dev/null +++ b/app/src/main/res/layout/card_chat.xml @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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..6c8a020 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,4 +7,5 @@ #FF018786 #FF000000 #FFFFFFFF + #FF3D95D4 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3d78b1f..e917224 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,15 @@ RecyclerView + avatar + title + verified + preview + message + message author + lock Icon + check icon + 11:00 + mention icon + pinned icon + avatar action icon \ No newline at end of file diff --git a/build.gradle b/build.gradle index bd20018..b948b15 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '8.7.2' apply false - id 'com.android.library' version '8.7.2' apply false - id 'org.jetbrains.kotlin.android' version '2.0.21' apply false + id 'com.android.application' version '8.8.0' apply false + id 'com.android.library' version '8.8.0' apply false + id 'org.jetbrains.kotlin.android' version '2.1.0' apply false } task clean(type: Delete) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8c7b120..b426861 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Nov 05 09:40:34 CET 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists