feat: smooth af scrolling in channel

- typing indicator doesnt go in front of messages
- scrolling has been made so much smoother
- loading older messages is literally seamless
- FAB for scrolling back down is now in proper FAB position
This commit is contained in:
Infi 2023-01-26 01:05:15 +01:00
parent 95b6b17353
commit 0e001033e4
1 changed files with 21 additions and 16 deletions

View File

@ -138,7 +138,7 @@ class ChannelScreenViewModel : ViewModel() {
addUserIfUnknown(message.author!!)
}
_renderableMessages.add(message)
_renderableMessages.add(0, message)
}
override fun onStartTyping(typing: ChannelStartTypingFrame) {
@ -178,7 +178,7 @@ class ChannelScreenViewModel : ViewModel() {
viewModelScope.launch {
val messages = arrayListOf<MessageSchema>()
fetchMessagesFromChannel(channel!!.id!!, limit = 50, false).let {
it.messages!!.reversed().forEach { message ->
it.messages!!.forEach { message ->
addUserIfUnknown(message.author ?: return@forEach)
if (!RevoltAPI.messageCache.containsKey(message.id)) {
RevoltAPI.messageCache[message.id!!] = message
@ -201,7 +201,7 @@ class ChannelScreenViewModel : ViewModel() {
channel!!.id!!,
limit = 20,
true,
before = renderableMessages.first().id
before = renderableMessages.last().id
).let {
it.messages!!.forEach { message ->
addUserIfUnknown(message.author ?: return@forEach)
@ -211,7 +211,7 @@ class ChannelScreenViewModel : ViewModel() {
messages.add(message)
}
}
setRenderableMessages(messages + renderableMessages)
setRenderableMessages(renderableMessages + messages)
}
}
@ -453,21 +453,27 @@ fun ChannelScreen(
val isScrolledToBottom = remember(lazyListState) {
derivedStateOf {
(lazyListState.layoutInfo.visibleItemsInfo.lastOrNull()?.index
?: 0) >= viewModel.renderableMessages.size - 5
lazyListState.firstVisibleItemIndex <= 5
}
}
LaunchedEffect(viewModel.renderableMessages.size) {
if (isScrolledToBottom.value) {
coroutineScope.launch {
lazyListState.scrollToItem(viewModel.renderableMessages.size)
lazyListState.animateScrollToItem(0)
}
}
}
Box(modifier = Modifier.weight(1f)) {
LazyColumn(state = lazyListState) {
Box(
modifier = Modifier.weight(1f),
contentAlignment = Alignment.BottomEnd
) {
LazyColumn(state = lazyListState, reverseLayout = true) {
items(viewModel.renderableMessages) { message ->
Message(message)
}
item {
Button(
onClick = {
@ -482,21 +488,20 @@ fun ChannelScreen(
Text("Load older")
}
}
items(viewModel.renderableMessages) { message ->
Message(message)
}
}
androidx.compose.animation.AnimatedVisibility(
!isScrolledToBottom.value,
enter = slideInHorizontally(
animationSpec = RevoltTweenInt,
initialOffsetX = { -it },
initialOffsetX = { it },
) + fadeIn(animationSpec = RevoltTweenFloat),
exit = slideOutHorizontally(
animationSpec = RevoltTweenInt,
targetOffsetX = { -it },
) + fadeOut(animationSpec = RevoltTweenFloat)
targetOffsetX = { it },
) + fadeOut(animationSpec = RevoltTweenFloat),
modifier = Modifier
.align(Alignment.BottomEnd)
) {
ExtendedFloatingActionButton(
modifier = Modifier
@ -513,7 +518,7 @@ fun ChannelScreen(
},
onClick = {
coroutineScope.launch {
lazyListState.animateScrollToItem(viewModel.renderableMessages.size)
lazyListState.animateScrollToItem(0)
}
},
contentColor = MaterialTheme.colorScheme.onPrimary,