mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-08-08 06:46:11 +00:00
Fix first Wear message auto-scroll
This commit is contained in:
parent
efeb9b54b5
commit
44b2b8cb79
@ -113,9 +113,21 @@ fun ChatScaffold(
|
||||
val followNewest = remember(messages.size) { atNewest }
|
||||
LaunchedEffect(columnState, messages.size) {
|
||||
if (messages.isNotEmpty() && followNewest) {
|
||||
val expectedSingleMessageKey = messages.singleOrNull()?.id
|
||||
scrollToNewestAfterItemsMeasured(
|
||||
expectedItemCount = messages.size,
|
||||
measuredItemCounts = snapshotFlow { columnState.layoutInfo.totalItemsCount }
|
||||
expectedSingleMessageKey = expectedSingleMessageKey,
|
||||
measuredLayouts = snapshotFlow {
|
||||
val layoutInfo = columnState.layoutInfo
|
||||
MeasuredChatLayout(
|
||||
itemCount = layoutInfo.totalItemsCount,
|
||||
singleVisibleItemKey = if (expectedSingleMessageKey != null) {
|
||||
layoutInfo.visibleItems.singleOrNull()?.key
|
||||
} else {
|
||||
null
|
||||
}
|
||||
)
|
||||
}
|
||||
) {
|
||||
// scrollBy to the end of the range: animateScrollToItem stops as soon as the
|
||||
// item is partially visible, which left the last message cropped.
|
||||
@ -138,12 +150,22 @@ fun ChatScaffold(
|
||||
)
|
||||
}
|
||||
|
||||
internal data class MeasuredChatLayout(
|
||||
val itemCount: Int,
|
||||
val singleVisibleItemKey: Any?
|
||||
)
|
||||
|
||||
internal suspend fun scrollToNewestAfterItemsMeasured(
|
||||
expectedItemCount: Int,
|
||||
measuredItemCounts: Flow<Int>,
|
||||
expectedSingleMessageKey: Any?,
|
||||
measuredLayouts: Flow<MeasuredChatLayout>,
|
||||
scrollToEnd: suspend () -> Unit
|
||||
) {
|
||||
measuredItemCounts.first { it >= expectedItemCount }
|
||||
measuredLayouts.first { layout ->
|
||||
layout.itemCount >= expectedItemCount &&
|
||||
(expectedSingleMessageKey == null ||
|
||||
layout.singleVisibleItemKey == expectedSingleMessageKey)
|
||||
}
|
||||
scrollToEnd()
|
||||
}
|
||||
|
||||
|
||||
@ -12,13 +12,14 @@ class ChatAutoScrollTest {
|
||||
|
||||
@Test
|
||||
fun `newest scroll waits until appended message is measured`() = runTest {
|
||||
val measuredItemCount = MutableStateFlow(3)
|
||||
val measuredLayouts = MutableStateFlow(MeasuredChatLayout(3, null))
|
||||
var scrollCount = 0
|
||||
|
||||
val scrollJob = launch(start = CoroutineStart.UNDISPATCHED) {
|
||||
scrollToNewestAfterItemsMeasured(
|
||||
expectedItemCount = 4,
|
||||
measuredItemCounts = measuredItemCount
|
||||
expectedSingleMessageKey = null,
|
||||
measuredLayouts = measuredLayouts
|
||||
) {
|
||||
scrollCount += 1
|
||||
}
|
||||
@ -27,7 +28,7 @@ class ChatAutoScrollTest {
|
||||
assertFalse(scrollJob.isCompleted)
|
||||
assertEquals(0, scrollCount)
|
||||
|
||||
measuredItemCount.value = 4
|
||||
measuredLayouts.value = MeasuredChatLayout(4, null)
|
||||
scrollJob.join()
|
||||
|
||||
assertEquals(1, scrollCount)
|
||||
@ -35,16 +36,47 @@ class ChatAutoScrollTest {
|
||||
|
||||
@Test
|
||||
fun `newest scroll runs immediately when messages are already measured`() = runTest {
|
||||
val measuredItemCount = MutableStateFlow(4)
|
||||
val measuredLayouts = MutableStateFlow(MeasuredChatLayout(4, null))
|
||||
var scrollCount = 0
|
||||
|
||||
scrollToNewestAfterItemsMeasured(
|
||||
expectedItemCount = 4,
|
||||
measuredItemCounts = measuredItemCount
|
||||
expectedSingleMessageKey = null,
|
||||
measuredLayouts = measuredLayouts
|
||||
) {
|
||||
scrollCount += 1
|
||||
}
|
||||
|
||||
assertEquals(1, scrollCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `first message waits past stale empty placeholder layout`() = runTest {
|
||||
val messageKey = "first-message"
|
||||
val measuredLayouts = MutableStateFlow(
|
||||
MeasuredChatLayout(itemCount = 1, singleVisibleItemKey = "empty-placeholder")
|
||||
)
|
||||
var scrollCount = 0
|
||||
|
||||
val scrollJob = launch(start = CoroutineStart.UNDISPATCHED) {
|
||||
scrollToNewestAfterItemsMeasured(
|
||||
expectedItemCount = 1,
|
||||
expectedSingleMessageKey = messageKey,
|
||||
measuredLayouts = measuredLayouts
|
||||
) {
|
||||
scrollCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
assertFalse(scrollJob.isCompleted)
|
||||
assertEquals(0, scrollCount)
|
||||
|
||||
measuredLayouts.value = MeasuredChatLayout(
|
||||
itemCount = 1,
|
||||
singleVisibleItemKey = messageKey
|
||||
)
|
||||
scrollJob.join()
|
||||
|
||||
assertEquals(1, scrollCount)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user