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 504e5af012..2124ed3c42 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 @@ -290,14 +290,20 @@ fun ChatView(staleChatId: State, onComposed: suspend (chatId: String) - } } }, - loadPrevMessages = { chatId -> + loadMessages = { chatId, scrollDirection -> val c = chatModel.getChat(chatId) if (chatModel.chatId.value != chatId) return@ChatLayout - val firstId = chatModel.chatItems.value.firstOrNull()?.id - if (c != null && firstId != null) { - withBGApi { - apiLoadPrevMessages(c, chatModel, firstId, searchText.value) + when (scrollDirection) { + ScrollDirection.Up -> { + val firstId = chatModel.chatItems.value.firstOrNull()?.id + if (c != null && firstId != null) { + withBGApi { + apiLoadPrevMessages(c, chatModel, firstId, searchText.value) + } + } } + ScrollDirection.Down -> {} + else -> {} } }, deleteMessage = { itemId, mode -> @@ -604,7 +610,7 @@ fun ChatLayout( back: () -> Unit, info: () -> Unit, showMemberInfo: (GroupInfo, GroupMember) -> Unit, - loadPrevMessages: (ChatId) -> Unit, + loadMessages: (ChatId, ScrollDirection) -> Unit, deleteMessage: (Long, CIDeleteMode) -> Unit, deleteMessages: (List) -> Unit, receiveFile: (Long) -> Unit, @@ -710,7 +716,7 @@ fun ChatLayout( if (chatInfo != null) { ChatItemsList( remoteHostId, chatInfo, unreadCount, composeState, searchValue, - useLinkPreviews, linkMode, selectedChatItems, showMemberInfo, loadPrevMessages, deleteMessage, deleteMessages, + useLinkPreviews, linkMode, selectedChatItems, showMemberInfo, loadMessages, deleteMessage, deleteMessages, receiveFile, cancelFile, joinGroup, acceptCall, acceptFeature, openDirectChat, forwardItem, updateContactStats, updateMemberStats, syncContactConnection, syncMemberConnection, findModelChat, findModelMember, setReaction, showItemDetails, markRead, setFloatingButton, onComposed, developerTools, showViaProxy, @@ -944,7 +950,7 @@ fun BoxWithConstraintsScope.ChatItemsList( linkMode: SimplexLinkMode, selectedChatItems: MutableState?>, showMemberInfo: (GroupInfo, GroupMember) -> Unit, - loadPrevMessages: (ChatId) -> Unit, + loadMessages: (ChatId, ScrollDirection) -> Unit, deleteMessage: (Long, CIDeleteMode) -> Unit, deleteMessages: (List) -> Unit, receiveFile: (Long) -> Unit, @@ -984,8 +990,7 @@ fun BoxWithConstraintsScope.ChatItemsList( } } val preloadItems = remember { mutableStateOf(true) } - - PreloadItems(chatInfo.id, listState, ChatPagination.UNTIL_PRELOAD_COUNT, preloadItems.value, loadPrevMessages) + PreloadItems(chatInfo.id, listState, ChatPagination.UNTIL_PRELOAD_COUNT, preloadItems.value, loadMessages) Spacer(Modifier.size(8.dp)) val reversedChatItems by remember { derivedStateOf { chatModel.chatItems.asReversed() } } @@ -1000,14 +1005,13 @@ fun BoxWithConstraintsScope.ChatItemsList( } else { preloadItems.value = false withBGApi { + try { apiLoadMessagesAroundItem(rhId = remoteHostId, chatModel = chatModel, chatInfo = chatInfo, aroundItemId = itemId) - println("there") - - val idx = reversedChatItems.indexOfFirst { it.id == itemId } + val idx = reversedChatItems.indexOfFirst { it.id == itemId } scope.launch { listState.animateScrollToItem(kotlin.math.min(reversedChatItems.lastIndex, idx + 1), -maxHeightRounded) } -// } finally { -// preloadItems.value = true -// } + } finally { + preloadItems.value = true + } } } } @@ -1434,12 +1438,33 @@ fun PreloadItems( listState: LazyListState, remaining: Int = 10, enabled: Boolean, - onLoadMore: (ChatId) -> Unit, + onLoadMore: (ChatId, ScrollDirection) -> Unit, ) { // Prevent situation when initial load and load more happens one after another after selecting a chat with long scroll position from previous selection val allowLoad = remember { mutableStateOf(false) } val chatId = rememberUpdatedState(chatId) val onLoadMore = rememberUpdatedState(onLoadMore) + var scrollDirection by remember { mutableStateOf(ScrollDirection.Idle) } + var previousIndex by remember { mutableStateOf(0) } + var previousScrollOffset by remember { mutableStateOf(0) } + + LaunchedEffect(listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) { + val currentIndex = listState.firstVisibleItemIndex + val currentScrollOffset = listState.firstVisibleItemScrollOffset + val threshold = 25 + + scrollDirection = when { + currentIndex > previousIndex -> ScrollDirection.Up + currentIndex < previousIndex -> ScrollDirection.Down + currentScrollOffset > previousScrollOffset + threshold -> ScrollDirection.Up + currentScrollOffset < previousScrollOffset - threshold -> ScrollDirection.Down + currentScrollOffset == previousScrollOffset -> ScrollDirection.Idle + else -> scrollDirection + } + + previousIndex = currentIndex + previousScrollOffset = currentScrollOffset + } LaunchedEffect(Unit) { snapshotFlow { chatId.value } .filterNotNull() @@ -1462,7 +1487,7 @@ fun PreloadItems( .filter { it > 0 } .collect { if (enabled) { - onLoadMore.value(chatId.value) + onLoadMore.value(chatId.value, scrollDirection) } } } @@ -2116,7 +2141,7 @@ fun PreviewChatLayout() { back = {}, info = {}, showMemberInfo = { _, _ -> }, - loadPrevMessages = {}, + loadMessages = { _, _ -> }, deleteMessage = { _, _ -> }, deleteMessages = { _ -> }, receiveFile = { _ -> }, @@ -2188,7 +2213,7 @@ fun PreviewGroupChatLayout() { back = {}, info = {}, showMemberInfo = { _, _ -> }, - loadPrevMessages = {}, + loadMessages = { _, _ -> }, deleteMessage = { _, _ -> }, deleteMessages = {}, receiveFile = { _ -> },