mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-25 14:40:41 +01:00
Merge pull request #4136 from nextcloud/bugfix/noid/fixUnreadMessageScrollOnEnterChat
fix to scroll to last read message
This commit is contained in:
commit
822af2c967
@ -832,6 +832,14 @@ class ChatActivity :
|
||||
.collect()
|
||||
}
|
||||
|
||||
this.lifecycleScope.launch {
|
||||
chatViewModel.getLastReadMessageFlow
|
||||
.onEach { lastRead ->
|
||||
scrollToAndCenterMessageWithId(lastRead.toString())
|
||||
}
|
||||
.collect()
|
||||
}
|
||||
|
||||
chatViewModel.reactionDeletedViewState.observe(this) { state ->
|
||||
when (state) {
|
||||
is ChatViewModel.ReactionDeletedSuccessState -> {
|
||||
@ -2059,6 +2067,18 @@ class ChatActivity :
|
||||
}
|
||||
}
|
||||
|
||||
private fun scrollToAndCenterMessageWithId(messageId: String) {
|
||||
adapter?.let {
|
||||
val position = it.getMessagePositionByIdInReverse(messageId)
|
||||
if (position != -1) {
|
||||
layoutManager?.scrollToPositionWithOffset(
|
||||
position,
|
||||
binding.messagesListView.height / 2
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeContactToVcfFile(cursor: Cursor, file: File) {
|
||||
val lookupKey = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.LOOKUP_KEY))
|
||||
val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey)
|
||||
@ -2492,34 +2512,11 @@ class ChatActivity :
|
||||
|
||||
private fun processMessagesFromTheFuture(chatMessageList: List<ChatMessage>) {
|
||||
val newMessagesAvailable = (adapter?.itemCount ?: 0) > 0 && chatMessageList.isNotEmpty()
|
||||
val insertNewMessagesNotice = if (newMessagesAvailable) {
|
||||
chatMessageList.any { it.actorId != conversationUser!!.userId }
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
val scrollToEndOnUpdate = layoutManager?.findFirstVisibleItemPosition() == 0
|
||||
val insertNewMessagesNotice = shouldInsertNewMessagesNotice(newMessagesAvailable, chatMessageList)
|
||||
val scrollToEndOnUpdate = isScrolledToBottom()
|
||||
|
||||
if (insertNewMessagesNotice) {
|
||||
val unreadChatMessage = ChatMessage()
|
||||
unreadChatMessage.jsonMessageId = -1
|
||||
unreadChatMessage.actorId = "-1"
|
||||
unreadChatMessage.timestamp = chatMessageList[0].timestamp
|
||||
unreadChatMessage.message = context.getString(R.string.nc_new_messages)
|
||||
adapter?.addToStart(unreadChatMessage, false)
|
||||
|
||||
if (scrollToEndOnUpdate) {
|
||||
binding.scrollDownButton.visibility = View.GONE
|
||||
newMessagesCount = 0
|
||||
} else {
|
||||
if (binding.unreadMessagesPopup.isShown) {
|
||||
newMessagesCount++
|
||||
} else {
|
||||
newMessagesCount = 1
|
||||
binding.scrollDownButton.visibility = View.GONE
|
||||
binding.unreadMessagesPopup.show()
|
||||
}
|
||||
}
|
||||
updateUnreadMessageInfos(chatMessageList, scrollToEndOnUpdate)
|
||||
}
|
||||
|
||||
for (chatMessage in chatMessageList) {
|
||||
@ -2544,6 +2541,42 @@ class ChatActivity :
|
||||
}
|
||||
}
|
||||
|
||||
private fun isScrolledToBottom() = layoutManager?.findFirstVisibleItemPosition() == 0
|
||||
|
||||
private fun shouldInsertNewMessagesNotice(
|
||||
newMessagesAvailable: Boolean,
|
||||
chatMessageList: List<ChatMessage>
|
||||
) = if (newMessagesAvailable) {
|
||||
chatMessageList.any { it.actorId != conversationUser!!.userId }
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
private fun updateUnreadMessageInfos(
|
||||
chatMessageList: List<ChatMessage>,
|
||||
scrollToEndOnUpdate: Boolean
|
||||
) {
|
||||
val unreadChatMessage = ChatMessage()
|
||||
unreadChatMessage.jsonMessageId = -1
|
||||
unreadChatMessage.actorId = "-1"
|
||||
unreadChatMessage.timestamp = chatMessageList[0].timestamp
|
||||
unreadChatMessage.message = context.getString(R.string.nc_new_messages)
|
||||
adapter?.addToStart(unreadChatMessage, false)
|
||||
|
||||
if (scrollToEndOnUpdate) {
|
||||
binding.scrollDownButton.visibility = View.GONE
|
||||
newMessagesCount = 0
|
||||
} else {
|
||||
if (binding.unreadMessagesPopup.isShown) {
|
||||
newMessagesCount++
|
||||
} else {
|
||||
newMessagesCount = 1
|
||||
binding.scrollDownButton.visibility = View.GONE
|
||||
binding.unreadMessagesPopup.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processMessagesNotFromTheFuture(chatMessageList: List<ChatMessage>) {
|
||||
var countGroupedMessages = 0
|
||||
|
||||
@ -2579,10 +2612,7 @@ class ChatActivity :
|
||||
|
||||
private fun scrollToFirstUnreadMessage() {
|
||||
adapter?.let {
|
||||
layoutManager?.scrollToPositionWithOffset(
|
||||
it.getMessagePositionByIdInReverse("-1"),
|
||||
binding.messagesListView.height / 2
|
||||
)
|
||||
scrollToAndCenterMessageWithId("-1")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,8 @@ interface ChatMessageRepository : LifecycleAwareManager {
|
||||
|
||||
val lastCommonReadFlow: Flow<Int>
|
||||
|
||||
val lastReadMessageFlow: Flow<Int>
|
||||
|
||||
fun setData(conversationModel: ConversationModel, credentials: String, urlForChatting: String)
|
||||
|
||||
fun loadInitialMessages(withNetworkParams: Bundle): Job
|
||||
|
@ -81,6 +81,13 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
private val _lastCommonReadFlow:
|
||||
MutableSharedFlow<Int> = MutableSharedFlow()
|
||||
|
||||
override val lastReadMessageFlow:
|
||||
Flow<Int>
|
||||
get() = _lastReadMessageFlow
|
||||
|
||||
private val _lastReadMessageFlow:
|
||||
MutableSharedFlow<Int> = MutableSharedFlow()
|
||||
|
||||
private var newXChatLastCommonRead: Int? = null
|
||||
private var itIsPaused = false
|
||||
private val scope = CoroutineScope(Dispatchers.IO)
|
||||
@ -114,25 +121,33 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
|
||||
sync(withNetworkParams)
|
||||
|
||||
Log.d(TAG, "newestMessageId after sync: " + chatDao.getNewestMessageId(internalConversationId))
|
||||
val newestMessageId = chatDao.getNewestMessageId(internalConversationId)
|
||||
Log.d(TAG, "newestMessageId after sync: $newestMessageId")
|
||||
|
||||
showLast100MessagesBeforeAndEqual(
|
||||
internalConversationId,
|
||||
chatDao.getNewestMessageId(internalConversationId)
|
||||
)
|
||||
updateUiForLastCommonRead(200)
|
||||
|
||||
// delay is a dirty workaround to make sure messages are added to adapter on initial load before dealing
|
||||
// with them (otherwise there is a race condition).
|
||||
delay(DELAY_TO_ENSURE_MESSAGES_ARE_ADDED)
|
||||
|
||||
updateUiForLastCommonRead()
|
||||
updateUiForLastReadMessage(newestMessageId)
|
||||
|
||||
initMessagePolling()
|
||||
}
|
||||
|
||||
private fun updateUiForLastCommonRead(delay: Long) {
|
||||
private suspend fun updateUiForLastReadMessage(newestMessageId: Long) {
|
||||
val scrollToLastRead = conversationModel.lastReadMessage.toLong() < newestMessageId
|
||||
if (scrollToLastRead) {
|
||||
_lastReadMessageFlow.emit(conversationModel.lastReadMessage)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateUiForLastCommonRead() {
|
||||
scope.launch {
|
||||
// delay is a dirty workaround to make sure messages are added to adapter on initial load before setting
|
||||
// their read status(otherwise there is a race condition between adding messages and setting their read
|
||||
// status).
|
||||
if (delay > 0) {
|
||||
delay(delay)
|
||||
}
|
||||
newXChatLastCommonRead?.let {
|
||||
_lastCommonReadFlow.emit(it)
|
||||
}
|
||||
@ -163,7 +178,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
}
|
||||
|
||||
showLast100MessagesBefore(internalConversationId, beforeMessageId)
|
||||
updateUiForLastCommonRead(0)
|
||||
updateUiForLastCommonRead()
|
||||
}
|
||||
|
||||
override fun initMessagePolling(): Job =
|
||||
@ -195,7 +210,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
_messageFlow.emit(pair)
|
||||
}
|
||||
|
||||
updateUiForLastCommonRead(0)
|
||||
updateUiForLastCommonRead()
|
||||
|
||||
val newestMessage = chatDao.getNewestMessageId(internalConversationId).toInt()
|
||||
|
||||
@ -612,5 +627,6 @@ class OfflineFirstChatRepository @Inject constructor(
|
||||
private const val HTTP_CODE_OK: Int = 200
|
||||
private const val HTTP_CODE_NOT_MODIFIED = 304
|
||||
private const val HTTP_CODE_PRECONDITION_FAILED = 412
|
||||
private const val DELAY_TO_ENSURE_MESSAGES_ARE_ADDED: Long = 100
|
||||
}
|
||||
}
|
||||
|
@ -122,6 +122,8 @@ class ChatViewModel @Inject constructor(
|
||||
|
||||
val getLastCommonReadFlow = chatRepository.lastCommonReadFlow
|
||||
|
||||
val getLastReadMessageFlow = chatRepository.lastReadMessageFlow
|
||||
|
||||
val getConversationFlow = conversationRepository.conversationFlow
|
||||
.onEach {
|
||||
_getRoomViewState.value = GetRoomSuccessState
|
||||
|
Loading…
Reference in New Issue
Block a user