Scroll to first unread message instead of bottom + load enough events to have all unread messages
This commit is contained in:
parent
c2b06e5cfd
commit
db45a2bb78
3 changed files with 72 additions and 22 deletions
|
@ -173,6 +173,10 @@ class ChatMessagesListAdapter(
|
|||
firstUnreadMessagePosition = -1
|
||||
}
|
||||
|
||||
fun getFirstUnreadMessagePosition(): Int {
|
||||
return firstUnreadMessagePosition
|
||||
}
|
||||
|
||||
private fun computeFirstUnreadMessagePosition() {
|
||||
if (unreadMessagesCount > 0) {
|
||||
var messageCount = 0
|
||||
|
|
|
@ -27,6 +27,7 @@ import android.os.Bundle
|
|||
import android.os.Parcelable
|
||||
import android.provider.MediaStore
|
||||
import android.view.*
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener
|
||||
import android.widget.PopupWindow
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.view.doOnPreDraw
|
||||
|
@ -75,13 +76,18 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||
adapter.notifyItemChanged(positionStart - 1) // For grouping purposes
|
||||
|
||||
// Scroll to newly added messages automatically
|
||||
if (positionStart == adapter.itemCount - itemCount) {
|
||||
// But only if user hasn't initiated a scroll up in the messages history
|
||||
if (viewModel.isUserScrollingUp.value == false) {
|
||||
scrollToBottom()
|
||||
} else {
|
||||
Log.w("[Chat Room] User has scrolled up manually in the messages history, don't scroll to the newly added message at the bottom & don't mark the chat room as read")
|
||||
if (positionStart == 0 && adapter.itemCount == itemCount) {
|
||||
// First time we fill the list with messages
|
||||
Log.i("[Chat Room] History first $itemCount messages loaded")
|
||||
} else {
|
||||
// Scroll to newly added messages automatically
|
||||
if (positionStart == adapter.itemCount - itemCount) {
|
||||
// But only if user hasn't initiated a scroll up in the messages history
|
||||
if (viewModel.isUserScrollingUp.value == false) {
|
||||
scrollToFirstUnreadMessageOrBottom(false)
|
||||
} else {
|
||||
Log.w("[Chat Room] User has scrolled up manually in the messages history, don't scroll to the newly added message at the bottom & don't mark the chat room as read")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,8 +176,8 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
_adapter = ChatMessagesListAdapter(listSelectionViewModel, viewLifecycleOwner)
|
||||
// SubmitList is done on a background thread
|
||||
// We need this adapter data observer to know when to scroll
|
||||
binding.chatMessagesList.adapter = adapter
|
||||
adapter.registerAdapterDataObserver(observer)
|
||||
binding.chatMessagesList.adapter = adapter
|
||||
|
||||
val layoutManager = LinearLayoutManager(activity)
|
||||
layoutManager.stackFromEnd = true
|
||||
|
@ -181,6 +187,21 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
val headerItemDecoration = RecyclerViewHeaderDecoration(requireContext(), adapter)
|
||||
binding.chatMessagesList.addItemDecoration(headerItemDecoration)
|
||||
|
||||
// Wait for items to be displayed before scrolling for the first time
|
||||
binding.chatMessagesList
|
||||
.viewTreeObserver
|
||||
.addOnGlobalLayoutListener(
|
||||
object : OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
binding.chatMessagesList
|
||||
.viewTreeObserver
|
||||
.removeOnGlobalLayoutListener(this)
|
||||
Log.i("[Chat Room] Messages have been displayed, scrolling to first unread message if any")
|
||||
scrollToFirstUnreadMessageOrBottom(false)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// Swipe action
|
||||
/*val swipeConfiguration = RecyclerViewSwipeConfiguration()
|
||||
swipeConfiguration.leftToRightAction = RecyclerViewSwipeConfiguration.Action(icon = R.drawable.menu_reply_default)
|
||||
|
@ -205,6 +226,7 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
|
||||
val chatScrollListener = object : ChatScrollListener(layoutManager) {
|
||||
override fun onLoadMore(totalItemsCount: Int) {
|
||||
Log.i("[Chat Room] User has scrolled up far enough, load more items from history (currently there are $totalItemsCount messages displayed)")
|
||||
listViewModel.loadMoreData(totalItemsCount)
|
||||
}
|
||||
|
||||
|
@ -214,8 +236,10 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
|
||||
override fun onScrolledToEnd() {
|
||||
viewModel.isUserScrollingUp.value = false
|
||||
Log.i("[Chat Room] User has scrolled to the latest message, mark chat room as read")
|
||||
viewModel.chatRoom.markAsRead()
|
||||
if (viewModel.unreadMessagesCount.value != 0) {
|
||||
Log.i("[Chat Room] User has scrolled to the latest message, mark chat room as read")
|
||||
viewModel.chatRoom.markAsRead()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.chatMessagesList.addOnScrollListener(chatScrollListener)
|
||||
|
@ -468,7 +492,7 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
}
|
||||
|
||||
binding.setScrollToBottomClickListener {
|
||||
smoothScrollToPosition()
|
||||
scrollToFirstUnreadMessageOrBottom(true)
|
||||
}
|
||||
|
||||
if (textToShare?.isNotEmpty() == true) {
|
||||
|
@ -746,18 +770,21 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
popupWindow.showAsDropDown(binding.menu, 0, 0, Gravity.BOTTOM)
|
||||
}
|
||||
|
||||
private fun scrollToBottom() {
|
||||
private fun scrollToFirstUnreadMessageOrBottom(smooth: Boolean) {
|
||||
if (_adapter != null && adapter.itemCount > 0) {
|
||||
binding.chatMessagesList.scrollToPosition(adapter.itemCount - 1)
|
||||
}
|
||||
}
|
||||
|
||||
private fun smoothScrollToPosition() {
|
||||
if (_adapter != null && adapter.itemCount > 0) {
|
||||
if (corePreferences.enableAnimations) {
|
||||
binding.chatMessagesList.smoothScrollToPosition(adapter.itemCount - 1)
|
||||
// Scroll to first unread message if any
|
||||
val firstUnreadMessagePosition = adapter.getFirstUnreadMessagePosition()
|
||||
val indexToScrollTo = if (firstUnreadMessagePosition != -1) {
|
||||
firstUnreadMessagePosition
|
||||
} else {
|
||||
binding.chatMessagesList.scrollToPosition(adapter.itemCount - 1)
|
||||
adapter.itemCount - 1
|
||||
}
|
||||
|
||||
Log.i("[Chat Room] Scrolling to position $indexToScrollTo, first unread message is at $firstUnreadMessagePosition")
|
||||
if (smooth && corePreferences.enableAnimations) {
|
||||
binding.chatMessagesList.smoothScrollToPosition(indexToScrollTo)
|
||||
} else {
|
||||
binding.chatMessagesList.scrollToPosition(indexToScrollTo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,12 +214,31 @@ class ChatMessagesListViewModel(private val chatRoom: ChatRoom) : ViewModel() {
|
|||
private fun getEvents(): ArrayList<EventLogData> {
|
||||
val list = arrayListOf<EventLogData>()
|
||||
val unreadCount = chatRoom.unreadMessagesCount
|
||||
val loadCount = max(MESSAGES_PER_PAGE, unreadCount)
|
||||
var loadCount = max(MESSAGES_PER_PAGE, unreadCount)
|
||||
Log.i("[Chat Messages] $unreadCount unread messages in this chat room, loading $loadCount from history")
|
||||
|
||||
val history = chatRoom.getHistoryEvents(loadCount)
|
||||
var messageCount = 0
|
||||
for (eventLog in history) {
|
||||
list.add(EventLogData(eventLog))
|
||||
if (eventLog.type == EventLog.Type.ConferenceChatMessage) {
|
||||
messageCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
// Load enough events to have at least all unread messages
|
||||
while (unreadCount > 0 && messageCount < unreadCount) {
|
||||
Log.w("[Chat Messages] There is only $messageCount messages in the last $loadCount events, loading $MESSAGES_PER_PAGE more")
|
||||
val moreHistory = chatRoom.getHistoryRangeEvents(loadCount, loadCount + MESSAGES_PER_PAGE)
|
||||
loadCount += MESSAGES_PER_PAGE
|
||||
for (eventLog in moreHistory) {
|
||||
list.add(EventLogData(eventLog))
|
||||
if (eventLog.type == EventLog.Type.ConferenceChatMessage) {
|
||||
messageCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue