mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-08-08 06:46:11 +00:00
Fix Wear chat auto-scroll timing
This commit is contained in:
parent
cb6d68958d
commit
efeb9b54b5
@ -42,6 +42,8 @@ import com.bitchat.android.model.BitchatMessage
|
||||
import com.bitchat.watch.ui.theme.BitchatMotion
|
||||
import com.bitchat.watch.ui.theme.ChatVisualTokens
|
||||
import com.bitchat.watch.ui.theme.LocalBitchatPalette
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
/**
|
||||
* The shared chat body for global chat and DM threads, following the classic messenger
|
||||
@ -106,11 +108,19 @@ fun ChatScaffold(
|
||||
}
|
||||
|
||||
// Stick to bottom: follow new messages while resting at the newest.
|
||||
// Capture this when the message count changes, before the new layout can temporarily make
|
||||
// canScrollForward true and report that the user is browsing history.
|
||||
val followNewest = remember(messages.size) { atNewest }
|
||||
LaunchedEffect(columnState, messages.size) {
|
||||
if (messages.isNotEmpty() && atNewest) {
|
||||
// scrollBy to the end of the range: animateScrollToItem stops as soon as the
|
||||
// item is partially visible, which left the last message cropped.
|
||||
columnState.scroll { scrollBy(Float.MAX_VALUE) }
|
||||
if (messages.isNotEmpty() && followNewest) {
|
||||
scrollToNewestAfterItemsMeasured(
|
||||
expectedItemCount = messages.size,
|
||||
measuredItemCounts = snapshotFlow { columnState.layoutInfo.totalItemsCount }
|
||||
) {
|
||||
// scrollBy to the end of the range: animateScrollToItem stops as soon as the
|
||||
// item is partially visible, which left the last message cropped.
|
||||
columnState.scroll { scrollBy(Float.MAX_VALUE) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,6 +138,15 @@ fun ChatScaffold(
|
||||
)
|
||||
}
|
||||
|
||||
internal suspend fun scrollToNewestAfterItemsMeasured(
|
||||
expectedItemCount: Int,
|
||||
measuredItemCounts: Flow<Int>,
|
||||
scrollToEnd: suspend () -> Unit
|
||||
) {
|
||||
measuredItemCounts.first { it >= expectedItemCount }
|
||||
scrollToEnd()
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChatBody(
|
||||
messages: List<BitchatMessage>,
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
package com.bitchat.watch.ui
|
||||
|
||||
import kotlinx.coroutines.CoroutineStart
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Test
|
||||
|
||||
class ChatAutoScrollTest {
|
||||
|
||||
@Test
|
||||
fun `newest scroll waits until appended message is measured`() = runTest {
|
||||
val measuredItemCount = MutableStateFlow(3)
|
||||
var scrollCount = 0
|
||||
|
||||
val scrollJob = launch(start = CoroutineStart.UNDISPATCHED) {
|
||||
scrollToNewestAfterItemsMeasured(
|
||||
expectedItemCount = 4,
|
||||
measuredItemCounts = measuredItemCount
|
||||
) {
|
||||
scrollCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
assertFalse(scrollJob.isCompleted)
|
||||
assertEquals(0, scrollCount)
|
||||
|
||||
measuredItemCount.value = 4
|
||||
scrollJob.join()
|
||||
|
||||
assertEquals(1, scrollCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `newest scroll runs immediately when messages are already measured`() = runTest {
|
||||
val measuredItemCount = MutableStateFlow(4)
|
||||
var scrollCount = 0
|
||||
|
||||
scrollToNewestAfterItemsMeasured(
|
||||
expectedItemCount = 4,
|
||||
measuredItemCounts = measuredItemCount
|
||||
) {
|
||||
scrollCount += 1
|
||||
}
|
||||
|
||||
assertEquals(1, scrollCount)
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user