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 fa2095e7a8..542e9e6184 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 @@ -192,6 +192,11 @@ fun ChatSection.excessItemCount(): Int { return max(boundary.maxIndex.minus(boundary.minIndex) + 1 - MAX_SECTION_SIZE, 0) } +fun landingSectionToArea(chatLandingSection: ChatLandingSection) = when (chatLandingSection) { + ChatLandingSection.Latest -> ChatSectionArea.Bottom + ChatLandingSection.Unread -> ChatSectionArea.Current +} + suspend fun apiLoadMessagesAroundItem(chatInfo: ChatInfo, chatModel: ChatModel, aroundItemId: Long, rhId: Long?, chatSectionLoad: ChatSectionLoad) { val pagination = ChatPagination.Around(aroundItemId, ChatPagination.PRELOAD_COUNT * 2) val (chat) = chatModel.controller.apiGetChat(rhId, chatInfo.chatType, chatInfo.apiId, pagination) ?: return 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 8248702ec8..7da9082e88 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 @@ -94,7 +94,6 @@ fun ChatView(staleChatId: State, onComposed: suspend (chatId: String) - showSearch.value = false searchText.value = "" selectedChatItems.value = null - chatModel.chatItemsSectionArea = mutableMapOf().also { it.putAll(chatModel.chatItems.value.associate { it.id to ChatSectionArea.Bottom }) } } } } @@ -1009,8 +1008,10 @@ 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) } PreloadItems(chatInfo.id, listState, ChatPagination.UNTIL_PRELOAD_COUNT, preloadItemsEnabled, boundaries, loadMessages) + val maxHeightRounded = with(LocalDensity.current) { maxHeight.roundToPx() } LaunchedEffect(Unit) { launch { @@ -1019,13 +1020,15 @@ fun BoxWithConstraintsScope.ChatItemsList( .collect { revealedItems.value = setOf() preloadItemsEnabled.value = true + val firstUnreadItemIndex = chatModel.chatItems.value.indexOfFirst { it.isRcvNew } + if (firstUnreadItemIndex != -1) { + listState.scrollToItem(scrollPosition(reversedChatItems.size - 1 - firstUnreadItemIndex), -maxHeightRounded) + } } } } - val maxHeightRounded = with(LocalDensity.current) { maxHeight.roundToPx() } val scrollToItem: (Long) -> Unit = { itemId: Long -> - val scrollPosition: (Int) -> Int = { idx -> min(reversedChatItems.lastIndex, idx + 1) } val index = reversedChatItems.indexOfFirst { it.id == itemId } preloadItemsEnabled.value = false diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt index 4c65c26247..02e32c3d54 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt @@ -207,28 +207,29 @@ suspend fun noteFolderChatAction(rhId: Long?, noteFolder: NoteFolder) { suspend fun openDirectChat(rhId: Long?, contactId: Long, chatModel: ChatModel) = coroutineScope { val chat = chatModel.controller.apiGetChat(rhId, ChatType.Direct, contactId, ChatPagination.Initial(ChatPagination.INITIAL_COUNT)) if (chat != null && isActive) { - openLoadedChat(chat.first, chatModel) + openLoadedChat(chat.first, chatModel, chat.second) } } suspend fun openGroupChat(rhId: Long?, groupId: Long, chatModel: ChatModel) = coroutineScope { val chat = chatModel.controller.apiGetChat(rhId, ChatType.Group, groupId, ChatPagination.Initial(ChatPagination.INITIAL_COUNT)) if (chat != null && isActive) { - openLoadedChat(chat.first, chatModel) + openLoadedChat(chat.first, chatModel, chat.second) } } suspend fun openChat(rhId: Long?, chatInfo: ChatInfo, chatModel: ChatModel) = coroutineScope { val chat = chatModel.controller.apiGetChat(rhId, chatInfo.chatType, chatInfo.apiId, ChatPagination.Initial(ChatPagination.INITIAL_COUNT)) if (chat != null && isActive) { - openLoadedChat(chat.first, chatModel) + openLoadedChat(chat.first, chatModel, chat.second) } } -fun openLoadedChat(chat: Chat, chatModel: ChatModel) { +fun openLoadedChat(chat: Chat, chatModel: ChatModel, landingSection: ChatLandingSection = ChatLandingSection.Latest) { chatModel.chatItemStatuses.clear() chatModel.chatItems.replaceAll(chat.chatItems) chatModel.chatId.value = chat.chatInfo.id + chatModel.chatItemsSectionArea = mutableMapOf().also { map -> map.putAll(chatModel.chatItems.value.associate { it.id to landingSectionToArea(landingSection) }) } } suspend fun apiLoadPrevMessages(ch: Chat, chatModel: ChatModel, beforeChatItemId: Long, search: String, chatSectionLoad: ChatSectionLoad) {