NewChatSheet: render filtered contact list inside SectionView card

The "Contacts" header was a SectionView with empty content lambda, and
the actual contact rows were rendered as separate LazyColumn items
OUTSIDE the SectionView — so they sat on canvas without card chrome.

Move filteredContactChats.forEachIndexed { ContactListNavLinkView }
INSIDE the SectionView lambda in both OneHandLazyColumn and
NonOneHandLazyColumn so the contacts read as a single card matching
the iOS-style facelift.

Same trade-off as GroupChatInfoView members fix (fa29bb7a): lazy
rendering of contact rows replaced with eager composition inside a
Column. For typical contact lists (<100) imperceptible; very long
lists may compose slower on open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
another-simple-pixel
2026-05-16 09:24:35 -07:00
parent b187cf1f85
commit 3a9ece8d1e
@@ -325,20 +325,20 @@ private fun ModalData.NewChatSheetLayout(
item { item {
if (filteredContactChats.isNotEmpty() && searchText.value.text.isEmpty()) { if (filteredContactChats.isNotEmpty() && searchText.value.text.isEmpty()) {
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false)
SectionView(stringResource(MR.strings.contact_list_header_title).uppercase(), headerBottomPadding = DEFAULT_PADDING_HALF) {} SectionView(stringResource(MR.strings.contact_list_header_title).uppercase(), headerBottomPadding = DEFAULT_PADDING_HALF) {
Spacer(Modifier.height(DEFAULT_PADDING_HALF)) filteredContactChats.forEachIndexed { index, chat ->
} val nextChatSelected = remember(chat.id, filteredContactChats) {
} derivedStateOf {
item { chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
NoFilteredContactsItem() }
} }
itemsIndexed(filteredContactChats) { index, chat -> ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = true)
val nextChatSelected = remember(chat.id, filteredContactChats) { }
derivedStateOf {
chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
} }
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
} else {
NoFilteredContactsItem()
} }
ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = true)
} }
if (appPlatform.isAndroid) { if (appPlatform.isAndroid) {
item { item {
@@ -410,19 +410,19 @@ private fun ModalData.NewChatSheetLayout(
item { item {
if (filteredContactChats.isNotEmpty() && searchText.value.text.isEmpty()) { if (filteredContactChats.isNotEmpty() && searchText.value.text.isEmpty()) {
SectionDividerSpaced() SectionDividerSpaced()
SectionView(stringResource(MR.strings.contact_list_header_title).uppercase(), headerBottomPadding = DEFAULT_PADDING_HALF) {} SectionView(stringResource(MR.strings.contact_list_header_title).uppercase(), headerBottomPadding = DEFAULT_PADDING_HALF) {
} filteredContactChats.forEachIndexed { index, chat ->
} val nextChatSelected = remember(chat.id, filteredContactChats) {
item { derivedStateOf {
NoFilteredContactsItem() chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
} }
itemsIndexed(filteredContactChats) { index, chat -> }
val nextChatSelected = remember(chat.id, filteredContactChats) { ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = true)
derivedStateOf { }
chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
} }
} else {
NoFilteredContactsItem()
} }
ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = true)
} }
if (appPlatform.isAndroid) { if (appPlatform.isAndroid) {
item { item {