Fix read marker update when rm becomes visible last

If the read marker becomes visible after all events, the global most
recent visible event won't be caught unless the user starts scrolling it
out and back in.
To fix, immediately look up the most recently displayed event once the
read marker becomes visible.

Change-Id: I909503801572d50e968610de163e56c05a946d36
This commit is contained in:
SpiritCroc 2022-05-06 10:26:39 +02:00
parent 19402f54a6
commit 3c702b7230
3 changed files with 42 additions and 4 deletions

View file

@ -46,7 +46,7 @@ sealed class RoomDetailAction : VectorViewModelAction {
object AcceptInvite : RoomDetailAction()
object RejectInvite : RoomDetailAction()
object EnterTrackingUnreadMessagesState : RoomDetailAction()
data class EnterTrackingUnreadMessagesState(val mostRecentDisplayedEvent: TimelineEvent?) : RoomDetailAction()
object ExitTrackingUnreadMessagesState : RoomDetailAction()
data class ResendMessage(val eventId: String) : RoomDetailAction()

View file

@ -73,6 +73,7 @@ import com.vanniktech.emoji.EmojiPopup
import de.spiritcroc.matrixsdk.util.DbgUtil
import de.spiritcroc.matrixsdk.util.Dimber
import de.spiritcroc.recyclerview.widget.BetterLinearLayoutManager
import de.spiritcroc.recyclerview.widget.LinearLayoutManager
import im.vector.app.R
import im.vector.app.core.animations.play
import im.vector.app.core.dialogs.ConfirmationDialogBuilder
@ -166,6 +167,7 @@ import im.vector.app.features.home.room.detail.timeline.helper.AudioMessagePlayb
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
import im.vector.app.features.home.room.detail.timeline.image.buildImageContentRendererData
import im.vector.app.features.home.room.detail.timeline.item.AbsMessageItem
import im.vector.app.features.home.room.detail.timeline.item.ItemWithEvents
import im.vector.app.features.home.room.detail.timeline.item.MessageAudioItem
import im.vector.app.features.home.room.detail.timeline.item.MessageFileItem
import im.vector.app.features.home.room.detail.timeline.item.MessageImageVideoItem
@ -224,6 +226,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
@ -2246,7 +2249,37 @@ class TimelineFragment @Inject constructor(
}
override fun onReadMarkerVisible() {
timelineViewModel.handle(RoomDetailAction.EnterTrackingUnreadMessagesState)
var mostRecentDisplayedEvent: TimelineEvent? = timelineViewModel.mostRecentDisplayedEvent()
val lm = views.timelineRecyclerView.layoutManager as? LinearLayoutManager
val room = session.roomService().getRoom(timelineArgs.roomId)
rmDimber.i { "Most recent check: ${mostRecentDisplayedEvent == null} ${lm?.findFirstVisibleItemPosition()}..${lm?.findLastVisibleItemPosition()}" }
if (mostRecentDisplayedEvent == null && lm != null && room != null) {
for (i in lm.findFirstVisibleItemPosition()..lm.findLastVisibleItemPosition()) {
val model = timelineEventController.adapter.getModelAtPosition(i)
rmDimber.i { "Most recent check: ${model.javaClass} / ${(model as? ItemWithEvents)?.isVisible()}" }
if (model is ItemWithEvents) {
if (!model.isVisible()) {
continue
}
rmDimber.i { "Most recent displayed model: ${model.getEventIds().firstOrNull()} - ${model.getEventIds().lastOrNull()}" }
model.getEventIds().reversed().forEach { eventId ->
if (mostRecentDisplayedEvent != null) {
return@forEach
}
val event = room.getTimelineEvent(eventId)
if (event != null) {
rmDimber.i { "Most recent displayed event: $eventId" }
mostRecentDisplayedEvent = event
return@forEach
}
}
}
if (mostRecentDisplayedEvent != null) {
break
}
}
}
timelineViewModel.handle(RoomDetailAction.EnterTrackingUnreadMessagesState(mostRecentDisplayedEvent))
}
override fun onPreviewUrlClicked(url: String) {

View file

@ -172,6 +172,8 @@ class TimelineViewModel @AssistedInject constructor(
}
}
fun mostRecentDisplayedEvent() = mostRecentDisplayedEvent
private var prepareToEncrypt: Async<Unit> = Uninitialized
@AssistedFactory
@ -437,7 +439,7 @@ class TimelineViewModel @AssistedInject constructor(
is RoomDetailAction.MarkAllAsRead -> handleMarkAllAsRead()
is RoomDetailAction.ReportContent -> handleReportContent(action)
is RoomDetailAction.IgnoreUser -> handleIgnoreUser(action)
is RoomDetailAction.EnterTrackingUnreadMessagesState -> startTrackingUnreadMessages()
is RoomDetailAction.EnterTrackingUnreadMessagesState -> startTrackingUnreadMessages(action)
is RoomDetailAction.ExitTrackingUnreadMessagesState -> stopTrackingUnreadMessages()
is RoomDetailAction.VoteToPoll -> handleVoteToPoll(action)
is RoomDetailAction.AcceptVerificationRequest -> handleAcceptVerification(action)
@ -663,8 +665,11 @@ class TimelineViewModel @AssistedInject constructor(
}
}
private fun startTrackingUnreadMessages() {
private fun startTrackingUnreadMessages(action: RoomDetailAction.EnterTrackingUnreadMessagesState? = null) {
trackUnreadMessages.set(true)
if (mostRecentDisplayedEvent == null && action != null) {
mostRecentDisplayedEvent = action.mostRecentDisplayedEvent
}
withState {
_viewEvents.post(RoomDetailViewEvents.ScDbgReadTracking(mostRecentDisplayedEvent, it.unreadState, trackUnreadMessages.get()))
}