From 5759fb33bf0ea719f8a2daf300cde30c490ed869 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Fri, 12 Dec 2025 14:22:16 -0600 Subject: [PATCH] feat: Optimize message list node lookup (#3981) Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com> --- .../feature/messaging/MessageListPaged.kt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/feature/messaging/src/main/kotlin/org/meshtastic/feature/messaging/MessageListPaged.kt b/feature/messaging/src/main/kotlin/org/meshtastic/feature/messaging/MessageListPaged.kt index 2a5fe6c7b..b4896ed32 100644 --- a/feature/messaging/src/main/kotlin/org/meshtastic/feature/messaging/MessageListPaged.kt +++ b/feature/messaging/src/main/kotlin/org/meshtastic/feature/messaging/MessageListPaged.kt @@ -108,6 +108,9 @@ internal fun MessageListPaged( val haptics = LocalHapticFeedback.current val inSelectionMode by remember { derivedStateOf { state.selectedIds.value.isNotEmpty() } } + // Optimization: Pre-calculate map for O(1) lookup in list items to avoid O(N) linear search during scrolling. + val nodeMap = remember(state.nodes) { state.nodes.associateBy { it.num } } + var showStatusDialog by remember { mutableStateOf(null) } showStatusDialog?.let { message -> MessageStatusDialog( @@ -145,6 +148,7 @@ internal fun MessageListPaged( MessageListPagedContent( listState = listState, state = state, + nodeMap = nodeMap, handlers = handlers, inSelectionMode = inSelectionMode, coroutineScope = coroutineScope, @@ -159,6 +163,7 @@ internal fun MessageListPaged( private fun MessageListPagedContent( listState: LazyListState, state: MessageListPagedState, + nodeMap: Map, handlers: MessageListHandlers, inSelectionMode: Boolean, coroutineScope: CoroutineScope, @@ -185,6 +190,7 @@ private fun MessageListPagedContent( renderPagedChatMessageRow( message = message, state = state, + nodeMap = nodeMap, handlers = handlers, inSelectionMode = inSelectionMode, coroutineScope = coroutineScope, @@ -224,6 +230,7 @@ private fun MessageListPagedContent( private fun LazyItemScope.renderPagedChatMessageRow( message: Message, state: MessageListPagedState, + nodeMap: Map, handlers: MessageListHandlers, inSelectionMode: Boolean, coroutineScope: CoroutineScope, @@ -237,10 +244,7 @@ private fun LazyItemScope.renderPagedChatMessageRow( remember(message.uuid, state.selectedIds.value) { derivedStateOf { state.selectedIds.value.contains(message.uuid) } } - val node by - remember(message.node.num, state.nodes) { - derivedStateOf { state.nodes.find { it.num == message.node.num } ?: message.node } - } + val node = nodeMap[message.node.num] ?: message.node MessageItem( modifier = Modifier.animateItem(), @@ -253,7 +257,6 @@ private fun LazyItemScope.renderPagedChatMessageRow( state.selectedIds.toggle(message.uuid) haptics.performHapticFeedback(HapticFeedbackType.LongPress) }, - onDoubleClick = { if (!inSelectionMode) handlers.onSendReaction("👍", message.packetId) }, onClickChip = handlers.onClickChip, onStatusClick = { onShowStatusDialog(message) }, onReply = { handlers.onReply(message) }, @@ -364,8 +367,8 @@ private fun UpdateUnreadCountPaged( val observer = androidx.lifecycle.LifecycleEventObserver { _, event -> when (event) { - androidx.lifecycle.Lifecycle.Event.ON_RESUME -> isResumed = true - androidx.lifecycle.Lifecycle.Event.ON_PAUSE -> isResumed = false + Lifecycle.Event.ON_RESUME -> isResumed = true + Lifecycle.Event.ON_PAUSE -> isResumed = false else -> {} } }