From 8ff2f66bb924667c0532a5c5015bce172e1be9e1 Mon Sep 17 00:00:00 2001 From: Diogo Date: Thu, 31 Oct 2024 14:58:45 +0000 Subject: [PATCH] disable auto scroll when loading bottom section --- .../simplex/common/views/chat/ChatSections.kt | 23 +++++++++++++ .../simplex/common/views/chat/ChatView.kt | 34 +++++++------------ 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatSections.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatSections.kt index be0bd36cac..6dd7dfdb4c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatSections.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatSections.kt @@ -1,6 +1,8 @@ package chat.simplex.common.views.chat +import androidx.compose.runtime.toMutableStateList import chat.simplex.common.model.* +import chat.simplex.common.platform.chatController import chat.simplex.common.platform.chatModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -229,3 +231,24 @@ suspend fun apiLoadMessagesAroundItem(chatInfo: ChatInfo, chatModel: ChatModel, } } } + +suspend fun apiLoadBottomSection(chatInfo: ChatInfo, chatModel: ChatModel, rhId: Long?) { + val chat = chatController.apiGetChat(rh = rhId, type = chatInfo.chatType, id = chatInfo.apiId) + if (chatModel.chatId.value != chatInfo.id || chat == null) return + withContext(Dispatchers.Main) { + val updatedItems = chatModel.chatItems.value.toMutableStateList() + var insertIndex = updatedItems.size + + for (cItem in chat.first.chatItems.asReversed()) { + if (chatModel.chatItemsSectionArea[cItem.id] == null) { + updatedItems.add(insertIndex, cItem) + chatModel.chatItemsSectionArea[cItem.id] = ChatSectionArea.Bottom + } else { + chatModel.chatItemsSectionArea[cItem.id] = ChatSectionArea.Bottom + insertIndex = max(0, insertIndex - 1) + } + } + + chatModel.chatItems.replaceAll(updatedItems) + } +} \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index a90e051eb4..a25afda5a4 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -988,7 +988,8 @@ fun BoxWithConstraintsScope.ChatItemsList( ) { val listState = rememberLazyListState() val scope = rememberCoroutineScope() - ScrollToBottom(chatInfo.id, listState, chatModel.chatItems) + val scrollAdjustmentEnabled = remember { mutableStateOf(true) } + ScrollToBottom(chatInfo.id, listState, chatModel.chatItems, scrollAdjustmentEnabled) var prevSearchEmptiness by rememberSaveable { mutableStateOf(searchValue.value.isEmpty()) } // Scroll to bottom when search value changes from something to nothing and back LaunchedEffect(searchValue.value.isEmpty()) { @@ -1008,7 +1009,7 @@ fun BoxWithConstraintsScope.ChatItemsList( val sections by remember { derivedStateOf { reversedChatItems.putIntoSections(revealedItems.value) } } val preloadItemsEnabled = remember { mutableStateOf(true) } val boundaries = remember { derivedStateOf { sections.map { it.boundary } } } - val scrollPosition: (Int) -> Int = { idx -> min(reversedChatItems.lastIndex, idx + 1) } + val scrollPosition: (Int) -> Int = { idx -> min(listState.layoutInfo.totalItemsCount - 1, idx + 1 ) } PreloadItems(chatInfo.id, listState, ChatPagination.UNTIL_PRELOAD_COUNT, preloadItemsEnabled, boundaries, loadMessages) val maxHeightRounded = with(LocalDensity.current) { maxHeight.roundToPx() } @@ -1022,30 +1023,19 @@ fun BoxWithConstraintsScope.ChatItemsList( preloadItemsEnabled.value = true val firstUnreadItem = reversedChatItems.findLast { it.isRcvNew } if (firstUnreadItem != null) { - val firstUnreadItemIndexIdx = sections.find { it.area == ChatSectionArea.Current }?.itemPositions?.get(firstUnreadItem.id) + val firstUnreadItemIndexIdx = sections.chatItemPosition(firstUnreadItem.id) if (firstUnreadItemIndexIdx != null) { listState.scrollToItem(scrollPosition(firstUnreadItemIndexIdx), -maxHeightRounded) } if (chatModel.chatItemsSectionArea[firstUnreadItem.id] != ChatSectionArea.Bottom) { withBGApi { - val chat = chatController.apiGetChat(rh = remoteHostId, type = chatInfo.chatType, id = chatInfo.apiId) - if (chatModel.chatId.value != chatInfo.id || chat == null) return@withBGApi - withContext(Dispatchers.Main) { - val updatedItems = chatModel.chatItems.value.toMutableStateList() - var insertIndex = updatedItems.size - - for (cItem in chat.first.chatItems.asReversed()) { - if (chatModel.chatItemsSectionArea[cItem.id] == null) { - updatedItems.add(insertIndex, cItem) - chatModel.chatItemsSectionArea[cItem.id] = ChatSectionArea.Bottom - } else { - chatModel.chatItemsSectionArea[cItem.id] = ChatSectionArea.Bottom - insertIndex = max(0, insertIndex - 1) - } - } - - chatModel.chatItems.replaceAll(updatedItems) + scrollAdjustmentEnabled.value = false + try { + apiLoadBottomSection(chatInfo, chatModel, remoteHostId) + } finally { + delay(600) + scrollAdjustmentEnabled.value = true } } } @@ -1418,7 +1408,7 @@ fun BoxWithConstraintsScope.ChatItemsList( } @Composable -private fun ScrollToBottom(chatId: ChatId, listState: LazyListState, chatItems: State>) { +private fun ScrollToBottom(chatId: ChatId, listState: LazyListState, chatItems: State>, enabled: State) { val scope = rememberCoroutineScope() // Helps to scroll to bottom after moving from Group to Direct chat // and prevents scrolling to bottom on orientation change @@ -1438,7 +1428,7 @@ private fun ScrollToBottom(chatId: ChatId, listState: LazyListState, chatItems: LaunchedEffect(Unit) { snapshotFlow { chatItems.value.lastOrNull()?.id } .distinctUntilChanged() - .filter { listState.layoutInfo.visibleItemsInfo.firstOrNull()?.key != it } + .filter { listState.layoutInfo.visibleItemsInfo.firstOrNull()?.key != it && enabled.value } .collect { try { if (listState.firstVisibleItemIndex == 0 || (listState.firstVisibleItemIndex == 1 && listState.layoutInfo.totalItemsCount == chatItems.value.size)) {