fix: jump to messages from the proper direction
This commit is contained in:
parent
46987baec9
commit
da79c219b7
|
|
@ -154,6 +154,64 @@ class ChannelHistoryScrollTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun reversedListCanCenterAnOlderItemFromTheTopEdge() {
|
||||
val messages = (0 until 100).map { "message-$it" }
|
||||
lateinit var state: LazyListState
|
||||
|
||||
composeRule.setContent {
|
||||
state = rememberLazyListState()
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.width(200.dp)
|
||||
.height(240.dp),
|
||||
state = state,
|
||||
reverseLayout = true,
|
||||
) {
|
||||
items(messages, key = { it }) { message ->
|
||||
Text(
|
||||
text = message,
|
||||
modifier = Modifier.height(48.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
composeRule.runOnIdle {
|
||||
runBlocking {
|
||||
state.scrollToItem(20)
|
||||
}
|
||||
}
|
||||
composeRule.runOnIdle {
|
||||
runBlocking {
|
||||
state.scrollToItem(40)
|
||||
}
|
||||
|
||||
val viewportCenter =
|
||||
(state.layoutInfo.viewportStartOffset + state.layoutInfo.viewportEndOffset) / 2
|
||||
val targetCenter = state.itemCenter("message-40")
|
||||
runBlocking {
|
||||
state.scrollBy((targetCenter - viewportCenter) * 2f)
|
||||
}
|
||||
}
|
||||
composeRule.runOnIdle {
|
||||
val viewportCenter =
|
||||
(state.layoutInfo.viewportStartOffset + state.layoutInfo.viewportEndOffset) / 2
|
||||
assertTrue(state.itemCenter("message-40") > viewportCenter)
|
||||
|
||||
runBlocking {
|
||||
state.scrollBy(
|
||||
(state.itemCenter("message-40") - viewportCenter).toFloat()
|
||||
)
|
||||
}
|
||||
}
|
||||
composeRule.runOnIdle {
|
||||
val viewportCenter =
|
||||
(state.layoutInfo.viewportStartOffset + state.layoutInfo.viewportEndOffset) / 2
|
||||
assertEquals(viewportCenter, state.itemCenter("message-40"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListState.currentAnchor(): Pair<Any, Int> {
|
||||
val firstVisibleItem = layoutInfo.visibleItemsInfo
|
||||
.first { it.index == firstVisibleItemIndex }
|
||||
|
|
|
|||
|
|
@ -520,22 +520,40 @@ fun ChannelScreen(
|
|||
val visibleItemsBeforeJump = lazyListState.layoutInfo.visibleItemsInfo
|
||||
val targetIsVisible = visibleItemsBeforeJump
|
||||
.any { it.key == request.messageId }
|
||||
val targetWasAboveViewport =
|
||||
visibleItemsBeforeJump.isNotEmpty() &&
|
||||
lazyItemIndex > visibleItemsBeforeJump.maxOf { it.index }
|
||||
if (!targetIsVisible) {
|
||||
// Off-screen lazy items must be measured before exact centering
|
||||
// so we snap the target into the viewport, then animate the centering distance
|
||||
lazyListState.scrollToItem(lazyItemIndex)
|
||||
}
|
||||
val target = checkNotNull(
|
||||
var target = checkNotNull(
|
||||
snapshotFlow {
|
||||
lazyListState.layoutInfo.visibleItemsInfo
|
||||
.firstOrNull { it.key == request.messageId }
|
||||
}.first { it != null }
|
||||
)
|
||||
val viewportCenter =
|
||||
var viewportCenter =
|
||||
(lazyListState.layoutInfo.viewportStartOffset +
|
||||
lazyListState.layoutInfo.viewportEndOffset) / 2
|
||||
val targetCenter = target.offset + target.size / 2
|
||||
val centerOffset = (targetCenter - viewportCenter).toFloat()
|
||||
var targetCenter = target.offset + target.size / 2
|
||||
var centerOffset = (targetCenter - viewportCenter).toFloat()
|
||||
if (request.animated && !targetIsVisible && targetWasAboveViewport) {
|
||||
// scrollToItem anchors at the bottom in this reversed list. Here we mirror
|
||||
// an older target to the top so its centering animation comes from the same
|
||||
// side of the viewport where the message was located.
|
||||
lazyListState.scrollBy(centerOffset * 2)
|
||||
target = checkNotNull(
|
||||
lazyListState.layoutInfo.visibleItemsInfo
|
||||
.firstOrNull { it.key == request.messageId }
|
||||
)
|
||||
viewportCenter =
|
||||
(lazyListState.layoutInfo.viewportStartOffset +
|
||||
lazyListState.layoutInfo.viewportEndOffset) / 2
|
||||
targetCenter = target.offset + target.size / 2
|
||||
centerOffset = (targetCenter - viewportCenter).toFloat()
|
||||
}
|
||||
if (request.animated) {
|
||||
lazyListState.animateScrollBy(
|
||||
value = centerOffset,
|
||||
|
|
|
|||
Loading…
Reference in New Issue