Merge pull request #4390 from nextcloud/bugfix/4380/fixMessagesNotShownAndImproveUnreadMarker

fix messages not shown + improve unread marker behavior
This commit is contained in:
Marcel Hibbe 2024-11-05 13:46:47 +01:00 committed by GitHub
commit 967c3aedd3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 93 additions and 120 deletions

View file

@ -24,7 +24,6 @@ public class UnreadNoticeMessageViewHolder extends MessageHolders.SystemMessageV
@Override @Override
public void viewDetached() { public void viewDetached() {
messagesListAdapter.deleteById("-1");
} }
@Override @Override

View file

@ -296,7 +296,6 @@ class ChatActivity :
var mentionAutocomplete: Autocomplete<*>? = null var mentionAutocomplete: Autocomplete<*>? = null
var layoutManager: LinearLayoutManager? = null var layoutManager: LinearLayoutManager? = null
var pullChatMessagesPending = false var pullChatMessagesPending = false
var newMessagesCount = 0
var startCallFromNotification: Boolean = false var startCallFromNotification: Boolean = false
var startCallFromRoomSwitch: Boolean = false var startCallFromRoomSwitch: Boolean = false
@ -756,8 +755,10 @@ class ChatActivity :
is MessageInputViewModel.SendChatMessageSuccessState -> { is MessageInputViewModel.SendChatMessageSuccessState -> {
myFirstMessage = state.message myFirstMessage = state.message
if (binding.unreadMessagesPopup.isShown == true) { removeUnreadMessagesMarker()
binding.unreadMessagesPopup.hide()
if (binding.unreadMessagesPopup.isShown) {
binding.unreadMessagesPopup.visibility = View.GONE
} }
binding.messagesListView.smoothScrollToPosition(0) binding.messagesListView.smoothScrollToPosition(0)
} }
@ -768,8 +769,8 @@ class ChatActivity :
if (code.toString().startsWith("2")) { if (code.toString().startsWith("2")) {
myFirstMessage = state.message myFirstMessage = state.message
if (binding.unreadMessagesPopup.isShown == true) { if (binding.unreadMessagesPopup.isShown) {
binding.unreadMessagesPopup.hide() binding.unreadMessagesPopup.visibility = View.GONE
} }
binding.messagesListView.smoothScrollToPosition(0) binding.messagesListView.smoothScrollToPosition(0)
@ -853,9 +854,10 @@ class ChatActivity :
this.lifecycleScope.launch { this.lifecycleScope.launch {
chatViewModel.getMessageFlow chatViewModel.getMessageFlow
.onEach { pair -> .onEach { triple ->
val lookIntoFuture = pair.first val lookIntoFuture = triple.first
var chatMessageList = pair.second val setUnreadMessagesMarker = triple.second
var chatMessageList = triple.third
chatMessageList = handleSystemMessages(chatMessageList) chatMessageList = handleSystemMessages(chatMessageList)
@ -871,7 +873,8 @@ class ChatActivity :
} }
if (lookIntoFuture) { if (lookIntoFuture) {
processMessagesFromTheFuture(chatMessageList) Log.d(TAG, "chatMessageList.size in getMessageFlow:" + chatMessageList.size)
processMessagesFromTheFuture(chatMessageList, setUnreadMessagesMarker)
} else { } else {
processMessagesNotFromTheFuture(chatMessageList) processMessagesNotFromTheFuture(chatMessageList)
collapseSystemMessages() collapseSystemMessages()
@ -1011,6 +1014,13 @@ class ChatActivity :
} }
} }
private fun removeUnreadMessagesMarker() {
val index = adapter?.getMessagePositionById(UNREAD_MESSAGES_MARKER_ID.toString())
if (index != null && index != -1) {
adapter?.items?.removeAt(index)
}
}
@Suppress("Detekt.TooGenericExceptionCaught") @Suppress("Detekt.TooGenericExceptionCaught")
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
@ -1030,22 +1040,9 @@ class ChatActivity :
setupSwipeToReply() setupSwipeToReply()
binding.unreadMessagesPopup.setRecyclerView(binding.messagesListView) binding.unreadMessagesPopup.setOnClickListener {
binding.messagesListView.smoothScrollToPosition(0)
binding.unreadMessagesPopup.setPopupBubbleListener { _ -> binding.unreadMessagesPopup.visibility = View.GONE
if (newMessagesCount != 0) {
val scrollPosition = if (newMessagesCount - 1 < 0) {
0
} else {
newMessagesCount - 1
}
Handler().postDelayed(
{
binding.messagesListView.smoothScrollToPosition(scrollPosition)
},
NEW_MESSAGES_POPUP_BUBBLE_DELAY
)
}
} }
binding.scrollDownButton.setOnClickListener { binding.scrollDownButton.setOnClickListener {
@ -1064,21 +1061,14 @@ class ChatActivity :
super.onScrollStateChanged(recyclerView, newState) super.onScrollStateChanged(recyclerView, newState)
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) { if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
if (layoutManager!!.findFirstCompletelyVisibleItemPosition() > 0 && if (isScrolledToBottom()) {
!binding.unreadMessagesPopup.isShown binding.unreadMessagesPopup.visibility = View.GONE
) {
binding.scrollDownButton.visibility = View.VISIBLE
} else {
binding.scrollDownButton.visibility = View.GONE binding.scrollDownButton.visibility = View.GONE
} } else {
if (newMessagesCount != 0 && layoutManager != null) {
if (layoutManager!!.findFirstCompletelyVisibleItemPosition() < newMessagesCount) {
newMessagesCount = 0
if (binding.unreadMessagesPopup.isShown) { if (binding.unreadMessagesPopup.isShown) {
binding.unreadMessagesPopup.hide() binding.scrollDownButton.visibility = View.GONE
} } else {
binding.scrollDownButton.visibility = View.VISIBLE
} }
} }
} }
@ -2653,13 +2643,22 @@ class ChatActivity :
} }
} }
private fun processMessagesFromTheFuture(chatMessageList: List<ChatMessage>) { private fun processMessagesFromTheFuture(chatMessageList: List<ChatMessage>, setUnreadMessagesMarker: Boolean) {
val newMessagesAvailable = (adapter?.itemCount ?: 0) > 0 && chatMessageList.isNotEmpty() binding.scrollDownButton.visibility = View.GONE
val insertNewMessagesNotice = shouldInsertNewMessagesNotice(newMessagesAvailable, chatMessageList)
val scrollToEndOnUpdate = isScrolledToBottom()
if (insertNewMessagesNotice) { val scrollToBottom: Boolean
updateUnreadMessageInfos(chatMessageList, scrollToEndOnUpdate)
if (setUnreadMessagesMarker) {
scrollToBottom = false
setUnreadMessageMarker(chatMessageList)
} else {
if (isScrolledToBottom()) {
scrollToBottom = true
} else {
scrollToBottom = false
binding.unreadMessagesPopup.visibility = View.VISIBLE
// here we have the problem that the chat jumps for every update
}
} }
for (chatMessage in chatMessageList) { for (chatMessage in chatMessageList) {
@ -2674,44 +2673,26 @@ class ChatActivity :
(currentConversation?.type == ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) (currentConversation?.type == ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL)
chatMessage.isFormerOneToOneConversation = chatMessage.isFormerOneToOneConversation =
(currentConversation?.type == ConversationEnums.ConversationType.FORMER_ONE_TO_ONE) (currentConversation?.type == ConversationEnums.ConversationType.FORMER_ONE_TO_ONE)
it.addToStart(chatMessage, scrollToEndOnUpdate) Log.d(TAG, "chatMessage to add:" + chatMessage.message)
it.addToStart(chatMessage, scrollToBottom)
} }
} }
if (insertNewMessagesNotice && scrollToEndOnUpdate && adapter != null) { // workaround to jump back to unread messages marker
if (setUnreadMessagesMarker) {
scrollToFirstUnreadMessage() scrollToFirstUnreadMessage()
} }
} }
private fun isScrolledToBottom() = layoutManager?.findFirstVisibleItemPosition() == 0 private fun isScrolledToBottom() = layoutManager?.findFirstVisibleItemPosition() == 0
private fun shouldInsertNewMessagesNotice(newMessagesAvailable: Boolean, chatMessageList: List<ChatMessage>) = private fun setUnreadMessageMarker(chatMessageList: List<ChatMessage>) {
if (newMessagesAvailable) {
chatMessageList.any { it.actorId != conversationUser!!.userId }
} else {
false
}
private fun updateUnreadMessageInfos(chatMessageList: List<ChatMessage>, scrollToEndOnUpdate: Boolean) {
val unreadChatMessage = ChatMessage() val unreadChatMessage = ChatMessage()
unreadChatMessage.jsonMessageId = -1 unreadChatMessage.jsonMessageId = UNREAD_MESSAGES_MARKER_ID
unreadChatMessage.actorId = "-1" unreadChatMessage.actorId = "-1"
unreadChatMessage.timestamp = chatMessageList[0].timestamp unreadChatMessage.timestamp = chatMessageList[0].timestamp
unreadChatMessage.message = context.getString(R.string.nc_new_messages) unreadChatMessage.message = context.getString(R.string.nc_new_messages)
adapter?.addToStart(unreadChatMessage, false) 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>) { private fun processMessagesNotFromTheFuture(chatMessageList: List<ChatMessage>) {
@ -2739,7 +2720,7 @@ class ChatActivity :
private fun scrollToFirstUnreadMessage() { private fun scrollToFirstUnreadMessage() {
adapter?.let { adapter?.let {
scrollToAndCenterMessageWithId("-1") scrollToAndCenterMessageWithId(UNREAD_MESSAGES_MARKER_ID.toString())
} }
} }
@ -2754,7 +2735,8 @@ class ChatActivity :
return false return false
} }
if (!message1IsSystem && ( if (!message1IsSystem &&
(
(message1.actorType != message2.actorType) || (message1.actorType != message2.actorType) ||
(message2.actorId != message1.actorId) (message2.actorId != message1.actorId)
) )
@ -2863,9 +2845,8 @@ class ChatActivity :
TextUtils.isEmpty(messageRight.systemMessage) && TextUtils.isEmpty(messageRight.systemMessage) &&
DateFormatter.isSameDay(messageLeft.createdAt, messageRight.createdAt) DateFormatter.isSameDay(messageLeft.createdAt, messageRight.createdAt)
private fun isSameDayMessages(message1: ChatMessage, message2: ChatMessage): Boolean { private fun isSameDayMessages(message1: ChatMessage, message2: ChatMessage): Boolean =
return DateFormatter.isSameDay(message1.createdAt, message2.createdAt) DateFormatter.isSameDay(message1.createdAt, message2.createdAt)
}
override fun onLoadMore(page: Int, totalItemsCount: Int) { override fun onLoadMore(page: Int, totalItemsCount: Int) {
val id = ( val id = (
@ -3555,7 +3536,7 @@ class ChatActivity :
CONTENT_TYPE_POLL -> message.isPoll() CONTENT_TYPE_POLL -> message.isPoll()
CONTENT_TYPE_LINK_PREVIEW -> message.isLinkPreview() CONTENT_TYPE_LINK_PREVIEW -> message.isLinkPreview()
CONTENT_TYPE_SYSTEM_MESSAGE -> !TextUtils.isEmpty(message.systemMessage) CONTENT_TYPE_SYSTEM_MESSAGE -> !TextUtils.isEmpty(message.systemMessage)
CONTENT_TYPE_UNREAD_NOTICE_MESSAGE -> message.id == "-1" CONTENT_TYPE_UNREAD_NOTICE_MESSAGE -> message.id == UNREAD_MESSAGES_MARKER_ID.toString()
CONTENT_TYPE_CALL_STARTED -> message.id == "-2" CONTENT_TYPE_CALL_STARTED -> message.id == "-2"
CONTENT_TYPE_TEMP -> message.id == "-3" CONTENT_TYPE_TEMP -> message.id == "-3"
CONTENT_TYPE_DECK_CARD -> message.isDeckCard() CONTENT_TYPE_DECK_CARD -> message.isDeckCard()
@ -3765,28 +3746,16 @@ class ChatActivity :
private const val CONTENT_TYPE_LINK_PREVIEW: Byte = 7 private const val CONTENT_TYPE_LINK_PREVIEW: Byte = 7
private const val CONTENT_TYPE_DECK_CARD: Byte = 8 private const val CONTENT_TYPE_DECK_CARD: Byte = 8
private const val CONTENT_TYPE_TEMP: Byte = 9 private const val CONTENT_TYPE_TEMP: Byte = 9
private const val NEW_MESSAGES_POPUP_BUBBLE_DELAY: Long = 200 private const val UNREAD_MESSAGES_MARKER_ID = -1
private const val CALL_STARTED_ID = -2
private const val GET_ROOM_INFO_DELAY_NORMAL: Long = 30000 private const val GET_ROOM_INFO_DELAY_NORMAL: Long = 30000
private const val GET_ROOM_INFO_DELAY_LOBBY: Long = 5000 private const val GET_ROOM_INFO_DELAY_LOBBY: Long = 5000
private const val HTTP_CODE_OK: Int = 200
private const val AGE_THRESHOLD_FOR_DELETE_MESSAGE: Int = 21600000 // (6 hours in millis = 6 * 3600 * 1000) private const val AGE_THRESHOLD_FOR_DELETE_MESSAGE: Int = 21600000 // (6 hours in millis = 6 * 3600 * 1000)
private const val REQUEST_SHARE_FILE_PERMISSION: Int = 221 private const val REQUEST_SHARE_FILE_PERMISSION: Int = 221
private const val REQUEST_RECORD_AUDIO_PERMISSION = 222 private const val REQUEST_RECORD_AUDIO_PERMISSION = 222
private const val REQUEST_READ_CONTACT_PERMISSION = 234 private const val REQUEST_READ_CONTACT_PERMISSION = 234
private const val REQUEST_CAMERA_PERMISSION = 223 private const val REQUEST_CAMERA_PERMISSION = 223
private const val OBJECT_MESSAGE: String = "{object}"
private const val MINIMUM_VOICE_RECORD_DURATION: Int = 1000
private const val MINIMUM_VOICE_RECORD_TO_STOP: Int = 200
private const val VOICE_RECORD_CANCEL_SLIDER_X: Int = -50
private const val VOICE_RECORD_LOCK_BUTTON_Y: Int = -130
private const val VOICE_MESSAGE_META_DATA = "{\"messageType\":\"voice-message\"}" private const val VOICE_MESSAGE_META_DATA = "{\"messageType\":\"voice-message\"}"
private const val VOICE_MESSAGE_FILE_SUFFIX = ".mp3"
// Samplingrate 22050 was chosen because somehow 44100 failed to playback on safari when recorded on android.
// Please test with firefox, chrome, safari and mobile clients if changing anything regarding the sound.
private const val VOICE_MESSAGE_SAMPLING_RATE = 22050
private const val VOICE_MESSAGE_ENCODING_BIT_RATE = 32000
private const val VOICE_MESSAGE_CHANNELS = 1
private const val FILE_DATE_PATTERN = "yyyy-MM-dd HH-mm-ss" private const val FILE_DATE_PATTERN = "yyyy-MM-dd HH-mm-ss"
private const val VIDEO_SUFFIX = ".mp4" private const val VIDEO_SUFFIX = ".mp4"
private const val FULLY_OPAQUE_INT: Int = 255 private const val FULLY_OPAQUE_INT: Int = 255
@ -3795,40 +3764,21 @@ class ChatActivity :
private const val NO_PREVIOUS_MESSAGE_ID: Int = -1 private const val NO_PREVIOUS_MESSAGE_ID: Int = -1
private const val TOOLBAR_AVATAR_RATIO = 1.5 private const val TOOLBAR_AVATAR_RATIO = 1.5
private const val STATUS_SIZE_IN_DP = 9f private const val STATUS_SIZE_IN_DP = 9f
private const val HTTP_CODE_NOT_MODIFIED = 304
private const val HTTP_CODE_PRECONDITION_FAILED = 412
private const val HTTP_BAD_REQUEST = 400 private const val HTTP_BAD_REQUEST = 400
private const val HTTP_FORBIDDEN = 403 private const val HTTP_FORBIDDEN = 403
private const val HTTP_NOT_FOUND = 404 private const val HTTP_NOT_FOUND = 404
private const val QUOTED_MESSAGE_IMAGE_MAX_HEIGHT = 96f
private const val MENTION_AUTO_COMPLETE_ELEVATION = 6f
private const val MESSAGE_PULL_LIMIT = 100 private const val MESSAGE_PULL_LIMIT = 100
private const val PAGE_SIZE = 100
private const val INVITE_LENGTH = 6 private const val INVITE_LENGTH = 6
private const val ACTOR_LENGTH = 6 private const val ACTOR_LENGTH = 6
private const val ANIMATION_DURATION: Long = 750
private const val LOOKING_INTO_FUTURE_TIMEOUT = 30
private const val CHUNK_SIZE: Int = 10 private const val CHUNK_SIZE: Int = 10
private const val ONE_SECOND_IN_MILLIS = 1000 private const val ONE_SECOND_IN_MILLIS = 1000
private const val SAMPLE_RATE = 8000
private const val VOICE_RECORDING_LOCK_ANIMATION_DURATION = 500
private const val AUDIO_VALUE_MAX = 40
private const val AUDIO_VALUE_MIN = 20
private const val AUDIO_VALUE_SLEEP: Long = 50
private const val WHITESPACE = " " private const val WHITESPACE = " "
private const val COMMA = ", " private const val COMMA = ", "
private const val TYPING_INDICATOR_ANIMATION_DURATION = 200L private const val TYPING_INDICATOR_ANIMATION_DURATION = 200L
private const val TYPING_INDICATOR_MAX_NAME_LENGTH = 14 private const val TYPING_INDICATOR_MAX_NAME_LENGTH = 14
private const val TYPING_INDICATOR_POSITION_VISIBLE = -18f private const val TYPING_INDICATOR_POSITION_VISIBLE = -18f
private const val TYPING_INDICATOR_POSITION_HIDDEN = -1f private const val TYPING_INDICATOR_POSITION_HIDDEN = -1f
private const val TYPING_DURATION_TO_SEND_NEXT_TYPING_MESSAGE = 10000L
private const val TYPING_INTERVAL_TO_SEND_NEXT_TYPING_MESSAGE = 1000L
private const val TYPING_STARTED_SIGNALING_MESSAGE_TYPE = "startedTyping"
private const val TYPING_STOPPED_SIGNALING_MESSAGE_TYPE = "stoppedTyping"
private const val CALL_STARTED_ID = -2
private const val MILISEC_15: Long = 15 private const val MILISEC_15: Long = 15
private const val LINEBREAK = "\n"
private const val CURSOR_KEY = "_cursor"
private const val CURRENT_AUDIO_MESSAGE_KEY = "CURRENT_AUDIO_MESSAGE" private const val CURRENT_AUDIO_MESSAGE_KEY = "CURRENT_AUDIO_MESSAGE"
private const val CURRENT_AUDIO_POSITION_KEY = "CURRENT_AUDIO_POSITION" private const val CURRENT_AUDIO_POSITION_KEY = "CURRENT_AUDIO_POSITION"
private const val CURRENT_AUDIO_WAS_PLAYING_KEY = "CURRENT_AUDIO_PLAYING" private const val CURRENT_AUDIO_WAS_PLAYING_KEY = "CURRENT_AUDIO_PLAYING"

View file

@ -22,7 +22,8 @@ interface ChatMessageRepository : LifecycleAwareManager {
*/ */
val messageFlow: val messageFlow:
Flow< Flow<
Pair< Triple<
Boolean,
Boolean, Boolean,
List<ChatMessage> List<ChatMessage>
> >

View file

@ -53,7 +53,8 @@ class OfflineFirstChatRepository @Inject constructor(
override val messageFlow: override val messageFlow:
Flow< Flow<
Pair< Triple<
Boolean,
Boolean, Boolean,
List<ChatMessage> List<ChatMessage>
> >
@ -62,7 +63,8 @@ class OfflineFirstChatRepository @Inject constructor(
private val _messageFlow: private val _messageFlow:
MutableSharedFlow< MutableSharedFlow<
Pair< Triple<
Boolean,
Boolean, Boolean,
List<ChatMessage> List<ChatMessage>
> >
@ -142,6 +144,7 @@ class OfflineFirstChatRepository @Inject constructor(
// set up field map to load the newest messages // set up field map to load the newest messages
val fieldMap = getFieldMap( val fieldMap = getFieldMap(
lookIntoFuture = false, lookIntoFuture = false,
timeout = 0,
includeLastKnown = true, includeLastKnown = true,
setReadMarker = true, setReadMarker = true,
lastKnown = null lastKnown = null
@ -229,6 +232,7 @@ class OfflineFirstChatRepository @Inject constructor(
val fieldMap = getFieldMap( val fieldMap = getFieldMap(
lookIntoFuture = false, lookIntoFuture = false,
timeout = 0,
includeLastKnown = false, includeLastKnown = false,
setReadMarker = true, setReadMarker = true,
lastKnown = beforeMessageId.toInt() lastKnown = beforeMessageId.toInt()
@ -254,6 +258,9 @@ class OfflineFirstChatRepository @Inject constructor(
var fieldMap = getFieldMap( var fieldMap = getFieldMap(
lookIntoFuture = true, lookIntoFuture = true,
// timeout for first longpoll is 0, so "unread message" info is not shown if there were
// initially no messages but someone writes us in the first 30 seconds.
timeout = 0,
includeLastKnown = false, includeLastKnown = false,
setReadMarker = true, setReadMarker = true,
lastKnown = initialMessageId.toInt() lastKnown = initialMessageId.toInt()
@ -261,6 +268,8 @@ class OfflineFirstChatRepository @Inject constructor(
val networkParams = Bundle() val networkParams = Bundle()
var showUnreadMessagesMarker = true
while (true) { while (true) {
if (!monitor.isOnline.first() || itIsPaused) { if (!monitor.isOnline.first() || itIsPaused) {
Thread.sleep(HALF_SECOND) Thread.sleep(HALF_SECOND)
@ -272,8 +281,14 @@ class OfflineFirstChatRepository @Inject constructor(
val resultsFromSync = sync(networkParams) val resultsFromSync = sync(networkParams)
if (!resultsFromSync.isNullOrEmpty()) { if (!resultsFromSync.isNullOrEmpty()) {
val chatMessages = resultsFromSync.map(ChatMessageEntity::asModel) val chatMessages = resultsFromSync.map(ChatMessageEntity::asModel)
val pair = Pair(true, chatMessages)
_messageFlow.emit(pair) val weHaveMessagesFromOurself = chatMessages.any { it.actorId == currentUser.userId }
showUnreadMessagesMarker = showUnreadMessagesMarker && !weHaveMessagesFromOurself
val triple = Triple(true, showUnreadMessagesMarker, chatMessages)
_messageFlow.emit(triple)
} else {
Log.d(TAG, "resultsFromSync are null or empty")
} }
updateUiForLastCommonRead() updateUiForLastCommonRead()
@ -283,10 +298,13 @@ class OfflineFirstChatRepository @Inject constructor(
// update field map vars for next cycle // update field map vars for next cycle
fieldMap = getFieldMap( fieldMap = getFieldMap(
lookIntoFuture = true, lookIntoFuture = true,
timeout = 30,
includeLastKnown = false, includeLastKnown = false,
setReadMarker = true, setReadMarker = true,
lastKnown = newestMessage lastKnown = newestMessage
) )
showUnreadMessagesMarker = false
} }
} }
} }
@ -325,6 +343,7 @@ class OfflineFirstChatRepository @Inject constructor(
private fun getFieldMap( private fun getFieldMap(
lookIntoFuture: Boolean, lookIntoFuture: Boolean,
timeout: Int,
includeLastKnown: Boolean, includeLastKnown: Boolean,
setReadMarker: Boolean, setReadMarker: Boolean,
lastKnown: Int?, lastKnown: Int?,
@ -342,7 +361,7 @@ class OfflineFirstChatRepository @Inject constructor(
fieldMap["lastCommonReadId"] = it fieldMap["lastCommonReadId"] = it
} }
fieldMap["timeout"] = if (lookIntoFuture) 30 else 0 fieldMap["timeout"] = timeout
fieldMap["limit"] = limit fieldMap["limit"] = limit
fieldMap["lookIntoFuture"] = if (lookIntoFuture) 1 else 0 fieldMap["lookIntoFuture"] = if (lookIntoFuture) 1 else 0
fieldMap["setReadMarker"] = if (setReadMarker) 1 else 0 fieldMap["setReadMarker"] = if (setReadMarker) 1 else 0
@ -357,6 +376,7 @@ class OfflineFirstChatRepository @Inject constructor(
if (loadFromServer) { if (loadFromServer) {
val fieldMap = getFieldMap( val fieldMap = getFieldMap(
lookIntoFuture = false, lookIntoFuture = false,
timeout = 0,
includeLastKnown = true, includeLastKnown = true,
setReadMarker = false, setReadMarker = false,
lastKnown = messageId.toInt(), lastKnown = messageId.toInt(),
@ -664,8 +684,8 @@ class OfflineFirstChatRepository @Inject constructor(
) )
if (list.isNotEmpty()) { if (list.isNotEmpty()) {
val pair = Pair(false, list) val triple = Triple(false, false, list)
_messageFlow.emit(pair) _messageFlow.emit(triple)
} }
} }
@ -690,8 +710,8 @@ class OfflineFirstChatRepository @Inject constructor(
) )
if (list.isNotEmpty()) { if (list.isNotEmpty()) {
val pair = Pair(false, list) val triple = Triple(false, false, list)
_messageFlow.emit(pair) _messageFlow.emit(triple)
} }
} }

View file

@ -157,8 +157,9 @@
app:textAutoLink="all" app:textAutoLink="all"
tools:visibility="visible" /> tools:visibility="visible" />
<com.nextcloud.ui.popupbubble.PopupBubble <com.google.android.material.button.MaterialButton
android:id="@+id/unreadMessagesPopup" android:id="@+id/unreadMessagesPopup"
style="@style/Widget.AppTheme.Button.ElevatedButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignBottom="@id/typing_indicator_wrapper" android:layout_alignBottom="@id/typing_indicator_wrapper"
@ -172,6 +173,8 @@
android:minHeight="@dimen/min_size_clickable_area" android:minHeight="@dimen/min_size_clickable_area"
android:text="@string/nc_new_messages" android:text="@string/nc_new_messages"
android:theme="@style/Button.Primary" android:theme="@style/Button.Primary"
android:visibility="gone"
tools:visibility="visible"
app:background="@color/colorPrimary" app:background="@color/colorPrimary"
app:cornerRadius="@dimen/button_corner_radius" app:cornerRadius="@dimen/button_corner_radius"
app:icon="@drawable/ic_baseline_arrow_downward_24px" /> app:icon="@drawable/ic_baseline_arrow_downward_24px" />