Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -302,12 +302,17 @@ internal fun MessageList(
// Always scroll for own messages; only near-bottom for incoming
val nearBottom = listState.firstVisibleItemIndex <= 5
val newest = messages.peek(0) as? ChatListItem.ContentBubble
if (newest?.isFromSelf == true || nearBottom) {
if (nearBottom) {
listState.animateScrollToItem(0)
} else {
listState.scrollToItem(0)
}
when {
// Own message: anchor the new bubble during the next measure pass
// rather than animating to it. An animated scroll resolves its target
// offset up front, so the previous message's receipt collapsing out
// from under it moves the target mid-flight and the list overshoots
// and corrects — read as the bubble bouncing. iOS never hand-rolls
// this scroll at all: ChatLayout's keepContentOffsetAtBottomOnBatchUpdates
// pins the bottom edge across the one batch that both inserts the new
// cell and reconfigures the old one's receipt away.
newest?.isFromSelf == true -> listState.requestScrollToItem(0, 0)
nearBottom -> listState.animateScrollToItem(0)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,10 @@ internal fun ReceiptLabel(
) {
AnimatedVisibility(
visible = deliveredVisible,
// Expand + opacity, no scale: iOS un-hides the label and cross-fades its text in,
// letting the cell self-size. The line itself never scales.
enter = if (animateEntrance) {
expandVertically() +
scaleIn(deliveredSpec, initialScale = 0.95f) + fadeIn(deliveredSpec)
expandVertically() + fadeIn(deliveredSpec)
} else {
expandVertically(snap()) + fadeIn(snap())
},
Expand Down
Loading