Skip to content
10 changes: 10 additions & 0 deletions app/src/main/java/otus/gpb/recyclerview/Chat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package otus.gpb.recyclerview

data class Chat(
val id: Int,
val title: String,
val author: String,
val message: String,
val time: String,
val icon: Int
)
94 changes: 94 additions & 0 deletions app/src/main/java/otus/gpb/recyclerview/DataSource.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package otus.gpb.recyclerview

class DataSource {
private val messagesList = listOf(
Chat(
id = 1,
title = "Title1",
author = "User1",
message = "Message1",
time = "12:00",
icon = R.drawable.cat
),
Chat(
id = 2,
title = "Title2",
author = "User2",
message = "Message2",
time = "13:05",
icon = R.drawable.dog
),
Chat(
id = 3,
title = "Title3",
author = "User3",
message = "Message3",
time = "9:13",
icon = R.drawable.fox
),
Chat(
id = 4,
title = "Title4",
author = "User4",
message = "Message4",
time = "4:17",
icon = R.drawable.giraffe
),
Chat(
id = 5,
title = "Title5",
author = "User5",
message = "Message5",
time = "10:00",
icon = R.drawable.koala
),
Chat(
id = 6,
title = "Title6",
author = "User6",
message = "Message6",
time = "10:35",
icon = R.drawable.lion
),
Chat(
id = 7,
title = "Title7",
author = "User7",
message = "Message7",
time = "15:16",
icon = R.drawable.owl
),
Chat(
id = 8,
title = "Title8",
author = "User8",
message = "Message8",
time = "16:22",
icon = R.drawable.panda
),
Chat(
id = 9,
title = "Title9",
author = "User9",
message = "Message9",
time = "21:18",
icon = R.drawable.rabbit
),
Chat(
id = 10,
title = "Title10",
author = "User10",
message = "Message10",
time = "22:45",
icon = R.drawable.wolf
)
)

fun getMessages(page: Int, pageSize: Int): List<Chat> {
val fromIndex = page * pageSize
val toIndex = minOf(fromIndex + pageSize, messagesList.size)
if (fromIndex >= messagesList.size) return emptyList()

return messagesList.subList(fromIndex, toIndex)
}
}
31 changes: 31 additions & 0 deletions app/src/main/java/otus/gpb/recyclerview/ItemTouchHelperCallback.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package otus.gpb.recyclerview

import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView

class ItemTouchHelperCallback(private val listener: MessagesAdapterListener) : ItemTouchHelper.Callback() {
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 onSwiped(
viewHolder: RecyclerView.ViewHolder,
direction: Int
) {
listener.onItemSwipe(viewHolder.adapterPosition)
}
}
74 changes: 73 additions & 1 deletion app/src/main/java/otus/gpb/recyclerview/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,83 @@ package otus.gpb.recyclerview

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {
class MainActivity : AppCompatActivity(), MessagesAdapterListener {

private lateinit var recycleView: RecyclerView
private lateinit var layoutManager: LinearLayoutManager

private val messagesAdapter by lazy { MessagesAdapter() }
private val messagesListDataSource = DataSource()

private val pageSize = 7
private var currentPage = 0
private var isLastPage = false

private lateinit var scrollListener: ScrollListener

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

recycleView = findViewById(R.id.recyclerView)
layoutManager = LinearLayoutManager(this)

recycleView.layoutManager = layoutManager
recycleView.adapter = messagesAdapter
recycleView
.addItemDecoration(
DividerItemDecoration(
this,
DividerItemDecoration.VERTICAL
)
)

ItemTouchHelper(ItemTouchHelperCallback(this))
.attachToRecyclerView(recycleView)

loadFirstPage()

scrollListener = ScrollListener(layoutManager) {
loadNextPage()
}

recycleView.addOnScrollListener(scrollListener)

}

private fun loadFirstPage() {
val firstPage = messagesListDataSource.getMessages(page = currentPage, pageSize = pageSize)
messagesAdapter.submitList(firstPage)
currentPage++
}

private fun loadNextPage() {
if (isLastPage) return

val nextPage = messagesListDataSource.getMessages(page = currentPage, pageSize = pageSize)

if (nextPage.isEmpty()) {
isLastPage = true
scrollListener.onLoadFinished()
return
}

val newList = messagesAdapter.currentList.toMutableList()
newList.addAll(nextPage)
messagesAdapter.submitList(newList)
currentPage++

scrollListener.onLoadFinished()
}

override fun onItemSwipe(position: Int) {
val newList = messagesAdapter.currentList.toMutableList()
newList.removeAt(position)
messagesAdapter.submitList(newList)
}
}
26 changes: 26 additions & 0 deletions app/src/main/java/otus/gpb/recyclerview/MessageViewHolder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package otus.gpb.recyclerview

import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.res.ResourcesCompat
import androidx.recyclerview.widget.RecyclerView

class MessageViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
private val title: TextView = view.findViewById(R.id.title)
private val author: TextView = view.findViewById(R.id.author)
private val message: TextView = view.findViewById(R.id.message)
private val time: TextView = view.findViewById(R.id.time)
private val icon: ImageView = view.findViewById(R.id.icon)

fun bind(chat: Chat) {
val drawableImage = ResourcesCompat
.getDrawable(view.resources, chat.icon, null)
icon.setImageDrawable(drawableImage)

title.text = chat.title
author.text = chat.author
message.text = chat.message
time.text = chat.time
}
}
25 changes: 25 additions & 0 deletions app/src/main/java/otus/gpb/recyclerview/MessagesAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package otus.gpb.recyclerview

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter

class MessagesAdapter() :
ListAdapter<Chat, MessageViewHolder>(MessagesDiffCallback()) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): MessageViewHolder {
val view = LayoutInflater
.from(parent.context)
.inflate(R.layout.chat_item, parent, false)
return MessageViewHolder(view)
}

override fun onBindViewHolder(
holder: MessageViewHolder,
position: Int
) {
holder.bind(getItem(position))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package otus.gpb.recyclerview

interface MessagesAdapterListener {
fun onItemSwipe(position: Int)
}
14 changes: 14 additions & 0 deletions app/src/main/java/otus/gpb/recyclerview/MessagesDiffCallback.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package otus.gpb.recyclerview

import androidx.recyclerview.widget.DiffUtil

class MessagesDiffCallback : DiffUtil.ItemCallback<Chat>() {

override fun areContentsTheSame(oldItem: Chat, newItem: Chat): Boolean {
return oldItem == newItem
}

override fun areItemsTheSame(oldItem: Chat, newItem: Chat): Boolean {
return oldItem.id == newItem.id
}
}
30 changes: 30 additions & 0 deletions app/src/main/java/otus/gpb/recyclerview/ScrollListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package otus.gpb.recyclerview

import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class ScrollListener(
private val layoutManager: LinearLayoutManager,
private val loadMore: () -> Unit
) : RecyclerView.OnScrollListener() {

private var isLoading = false

override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
if (dy <= 0) return

val totalItemCount = layoutManager.itemCount
val lastVisibleItem = layoutManager.findLastVisibleItemPosition()

val isAtEnd = lastVisibleItem >= totalItemCount - 1

if (!isLoading && isAtEnd) {
isLoading = true
loadMore()
}
}

fun onLoadFinished() {
isLoading = false
}
}
Binary file added app/src/main/res/drawable/cat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/dog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/fox.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/giraffe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/koala.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/lion.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/owl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/panda.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/rabbit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/wolf.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
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">

<androidx.recyclerview.widget.RecyclerView
Expand Down
Loading