mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 21:32:34 +00:00
Dismiss mark as unread button eagerly
This commit is contained in:
+14
-2
@@ -138,6 +138,12 @@ class TimelinePresenter(
|
|||||||
val newEventState = remember { mutableStateOf<NewEventState>(NewEventState.None) }
|
val newEventState = remember { mutableStateOf<NewEventState>(NewEventState.None) }
|
||||||
val messageShieldDialogData: MutableState<MessageShieldData?> = remember { mutableStateOf(null) }
|
val messageShieldDialogData: MutableState<MessageShieldData?> = remember { mutableStateOf(null) }
|
||||||
|
|
||||||
|
// Forces [JumpToUnreadState.Hidden] until the next RoomInfo push. Set after a
|
||||||
|
// [TimelineEvent.MarkAllAsRead] await completes so the FAB hides without waiting for
|
||||||
|
// the SDK to push a refreshed fully-read marker; the after-await ordering means any
|
||||||
|
// RoomInfo update racing the mark-as-read call has already landed and can't undo this.
|
||||||
|
val suppressJumpToUnread = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailurePresenter.present()
|
val resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailurePresenter.present()
|
||||||
val isSendPublicReadReceiptsEnabled by remember {
|
val isSendPublicReadReceiptsEnabled by remember {
|
||||||
sessionPreferencesStore.isSendPublicReadReceiptsEnabled()
|
sessionPreferencesStore.isSendPublicReadReceiptsEnabled()
|
||||||
@@ -234,6 +240,7 @@ class TimelinePresenter(
|
|||||||
null
|
null
|
||||||
} ?: return@launch
|
} ?: return@launch
|
||||||
markAsFullyRead(room.roomId, latestEventId)
|
markAsFullyRead(room.roomId, latestEventId)
|
||||||
|
suppressJumpToUnread.value = true
|
||||||
}
|
}
|
||||||
is TimelineEvent.ShowShieldDialog -> messageShieldDialogData.value = event.messageShieldData
|
is TimelineEvent.ShowShieldDialog -> messageShieldDialogData.value = event.messageShieldData
|
||||||
is TimelineEvent.ComputeVerifiedUserSendFailure -> {
|
is TimelineEvent.ComputeVerifiedUserSendFailure -> {
|
||||||
@@ -300,8 +307,13 @@ class TimelinePresenter(
|
|||||||
// - Hidden: feature flag off, no marker, caught-up (marker loaded but no virtual item),
|
// - Hidden: feature flag off, no marker, caught-up (marker loaded but no virtual item),
|
||||||
// or initial load (no items yet).
|
// or initial load (no items yet).
|
||||||
val jumpToUnread = remember { mutableStateOf<JumpToUnreadState>(JumpToUnreadState.Hidden) }
|
val jumpToUnread = remember { mutableStateOf<JumpToUnreadState>(JumpToUnreadState.Hidden) }
|
||||||
LaunchedEffect(timelineItems, displayJumpToUnread, roomInfo.fullyReadEventId) {
|
// The SDK is authoritative again once it pushes a new fully-read marker, so drop the
|
||||||
if (!displayJumpToUnread) {
|
// post-mark-as-read suppression and let the recompute below pick up the new value.
|
||||||
|
LaunchedEffect(roomInfo.fullyReadEventId) {
|
||||||
|
suppressJumpToUnread.value = false
|
||||||
|
}
|
||||||
|
LaunchedEffect(timelineItems, displayJumpToUnread, roomInfo.fullyReadEventId, suppressJumpToUnread.value) {
|
||||||
|
if (!displayJumpToUnread || suppressJumpToUnread.value) {
|
||||||
jumpToUnread.value = JumpToUnreadState.Hidden
|
jumpToUnread.value = JumpToUnreadState.Hidden
|
||||||
return@LaunchedEffect
|
return@LaunchedEffect
|
||||||
}
|
}
|
||||||
|
|||||||
+38
@@ -754,6 +754,44 @@ class TimelinePresenterTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - jumpToUnread hides eagerly after MarkAllAsRead even before a new RoomInfo arrives`() = runTest {
|
||||||
|
val timelineItems = MutableStateFlow(emptyList<MatrixTimelineItem>())
|
||||||
|
val timeline = FakeTimeline(
|
||||||
|
timelineItems = timelineItems,
|
||||||
|
getLatestEventIdResult = { Result.success(AN_EVENT_ID_2) },
|
||||||
|
)
|
||||||
|
val fullyReadEventId = EventId("\$older-than-loaded-window")
|
||||||
|
val room = FakeJoinedRoom(
|
||||||
|
liveTimeline = timeline,
|
||||||
|
baseRoom = FakeBaseRoom(
|
||||||
|
roomPermissions = roomPermissions(),
|
||||||
|
initialRoomInfo = aRoomInfo(fullyReadEventId = fullyReadEventId),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val presenter = createTimelinePresenter(
|
||||||
|
timeline = timeline,
|
||||||
|
room = room,
|
||||||
|
featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to true)),
|
||||||
|
)
|
||||||
|
presenter.test {
|
||||||
|
awaitFirstItem()
|
||||||
|
timelineItems.emit(
|
||||||
|
listOf(
|
||||||
|
MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(eventId = AN_EVENT_ID, content = aMessageContent())),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val outOfWindow = consumeItemsUntilPredicate { it.jumpToUnread is JumpToUnreadState.OutOfWindow }.last()
|
||||||
|
assertThat(outOfWindow.jumpToUnread).isEqualTo(JumpToUnreadState.OutOfWindow(eventId = fullyReadEventId))
|
||||||
|
|
||||||
|
outOfWindow.eventSink(TimelineEvent.MarkAllAsRead)
|
||||||
|
// RoomInfo is intentionally NOT updated — eager hide must fire on the await alone.
|
||||||
|
val afterMark = consumeItemsUntilPredicate { it.jumpToUnread == JumpToUnreadState.Hidden }.last()
|
||||||
|
assertThat(afterMark.jumpToUnread).isEqualTo(JumpToUnreadState.Hidden)
|
||||||
|
cancelAndIgnoreRemainingEvents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - reaction ordering`() = runTest {
|
fun `present - reaction ordering`() = runTest {
|
||||||
val timelineItems = MutableStateFlow(emptyList<MatrixTimelineItem>())
|
val timelineItems = MutableStateFlow(emptyList<MatrixTimelineItem>())
|
||||||
|
|||||||
Reference in New Issue
Block a user