From 5bcba9e0b2fd88f73d24df78390668876636ce8c Mon Sep 17 00:00:00 2001 From: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:31:30 +0000 Subject: [PATCH] android, desktop, ios: simplify pending-invitee preview selection Collapse the four nested branches in addChatItem's preview pick into a single "keep the current preview" predicate: the new item wins by default, and only the comparison criterion changes for a pending invitee. Same behaviour, addresses review feedback (4 branches for 2 outcomes). --- apps/ios/Shared/Model/ChatModel.swift | 27 +++++++---------- .../chat/simplex/common/model/ChatModel.kt | 29 ++++++------------- ...6-13-fix-wrong-chat-preview-addchatitem.md | 11 ++++--- 3 files changed, 26 insertions(+), 41 deletions(-) diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 71534fab20..98d5db9975 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -658,24 +658,17 @@ final class ChatModel: ObservableObject { if let i = getChatIndex(cInfo.id) { // update preview if cInfo.groupChatScope() == nil || cInfo.groupInfo?.membership.memberPending ?? false { - chats[i].chatItems = switch cInfo { - case .group: - if let currentPreviewItem = chats[i].chatItems.first { - // Pending invitee: surface the latest support message (broker vs local itemTs - // aren't comparable); don't let a no-content event re-cover an already-shown message. - if cInfo.groupInfo?.membership.memberPending ?? false { - (cItem.content.msgContent != nil || currentPreviewItem.content.msgContent == nil) ? [cItem] : [currentPreviewItem] - } else if cItem.meta.itemTs >= currentPreviewItem.meta.itemTs { - [cItem] - } else { - [currentPreviewItem] - } - } else { - [cItem] - } - default: - [cItem] + let memberPending = cInfo.groupInfo?.membership.memberPending ?? false + let currentPreviewItem: ChatItem? = if case .group = cInfo { chats[i].chatItems.first } else { nil } + // the new item becomes the preview unless it is older - or, for a pending invitee, unless it is + // a no-content event that would re-cover an already shown support message (broker vs local + // itemTs aren't comparable there, so content presence is the criterion instead) + let keptPreviewItem = currentPreviewItem.flatMap { current in + (memberPending + ? cItem.content.msgContent == nil && current.content.msgContent != nil + : cItem.meta.itemTs < current.meta.itemTs) ? current : nil } + chats[i].chatItems = [keptPreviewItem ?? cItem] if case .rcvNew = cItem.meta.itemStatus { unreadCollector.changeUnreadCounter(cInfo.id, by: 1, unreadMentions: cItem.meta.userMention ? 1 : 0) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt index 8a953ca4f0..2154fc2d83 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt @@ -541,26 +541,15 @@ object ChatModel { chat = chats[i] // update preview (for chat from main scope to show new items for invitee in pending status) if (cInfo.groupChatScope() == null || cInfo.groupInfo_?.membership?.memberPending == true) { - val newPreviewItem = when (cInfo) { - is ChatInfo.Group -> { - val currentPreviewItem = chat.chatItems.firstOrNull() - if (currentPreviewItem != null) { - // Pending invitee: surface the latest support message (broker vs local itemTs aren't - // comparable); don't let a no-content event re-cover an already-shown message. - if (cInfo.groupInfo_?.membership?.memberPending == true) { - if (cItem.content.msgContent != null || currentPreviewItem.content.msgContent == null) cItem else currentPreviewItem - } else if (cItem.meta.itemTs >= currentPreviewItem.meta.itemTs) { - cItem - } else { - currentPreviewItem - } - } else { - cItem - } - } - - else -> cItem - } + val memberPending = cInfo.groupInfo_?.membership?.memberPending == true + val currentPreviewItem = if (cInfo is ChatInfo.Group) chat.chatItems.firstOrNull() else null + // the new item becomes the preview unless it is older - or, for a pending invitee, unless it is + // a no-content event that would re-cover an already shown support message (broker vs local + // itemTs aren't comparable there, so content presence is the criterion instead) + val newPreviewItem = currentPreviewItem?.takeIf { + if (memberPending) cItem.content.msgContent == null && it.content.msgContent != null + else cItem.meta.itemTs < it.meta.itemTs + } ?: cItem val wasUnread = chat.unreadTag chats[i] = chat.copy( chatItems = arrayListOf(newPreviewItem), diff --git a/plans/2026-06-13-fix-wrong-chat-preview-addchatitem.md b/plans/2026-06-13-fix-wrong-chat-preview-addchatitem.md index 61e516ccca..60cde2133c 100644 --- a/plans/2026-06-13-fix-wrong-chat-preview-addchatitem.md +++ b/plans/2026-06-13-fix-wrong-chat-preview-addchatitem.md @@ -158,11 +158,14 @@ Sent items win only because their `itemTs` is the same device's local clock. **Fix (two parts):** for a pending invitee, (1) **bypass the cross-clock comparison** so the support message surfaces, and (2) **prefer a message over a no-content event** so an event can't -re-cover an already-shown message (Kotlin + iOS): +re-cover an already-shown message (Kotlin + iOS). Expressed as a single *keep the current +preview* predicate — the new item wins by default, and only the criterion for keeping the old +one changes with `memberPending` (no extra branches per outcome): ``` -if (memberPending) - if (cItem.content.msgContent != null || currentPreviewItem.content.msgContent == null) cItem else currentPreviewItem -else if (cItem.meta.itemTs >= currentPreviewItem.meta.itemTs) cItem else currentPreviewItem +newPreviewItem = currentPreviewItem?.takeIf { + if (memberPending) cItem.content.msgContent == null && it.content.msgContent != null + else cItem.meta.itemTs < it.meta.itemTs +} ?: cItem ``` Part (2) (`5b37cf881`) fixes a follow-up symptom — **"reviewed by admins" reappearing after the first message**: a pending invitee's member-support no-content events arrive as new chat items in