From 0d9ef4e56740e5e7405a0e93a50ffed4501f6057 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Tue, 17 Sep 2024 23:51:18 +0400 Subject: [PATCH] ui: support CRChatItemsStatusesUpdated response (#4890) * ui: support new CRChatItemsStatusesUpdated api * ios * refactor --- apps/ios/Shared/Model/SimpleXAPI.swift | 36 ++++++++++--------- .../Shared/Views/Call/ActiveCallView.swift | 10 +++--- apps/ios/SimpleX SE/ShareModel.swift | 3 +- apps/ios/SimpleXChat/APITypes.swift | 8 +++-- apps/ios/SimpleXChat/ChatTypes.swift | 14 ++++++++ .../chat/simplex/common/model/SimpleXAPI.kt | 21 +++++------ .../simplex/common/views/call/CallView.kt | 9 ++--- .../simplex/common/views/chat/ChatView.kt | 4 +-- 8 files changed, 64 insertions(+), 41 deletions(-) diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 7312b42b1b..6bbacea245 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -1821,23 +1821,25 @@ func processReceivedMsg(_ res: ChatResponse) async { NtfManager.shared.notifyMessageReceived(user, cInfo, cItem) } } - case let .chatItemStatusUpdated(user, aChatItem): - let cInfo = aChatItem.chatInfo - let cItem = aChatItem.chatItem - if !cItem.isDeletedContent && active(user) { - await MainActor.run { m.updateChatItem(cInfo, cItem, status: cItem.meta.itemStatus) } - } - if let endTask = m.messageDelivery[cItem.id] { - switch cItem.meta.itemStatus { - case .sndNew: () - case .sndSent: endTask() - case .sndRcvd: endTask() - case .sndErrorAuth: endTask() - case .sndError: endTask() - case .sndWarning: endTask() - case .rcvNew: () - case .rcvRead: () - case .invalid: () + case let .chatItemsStatusesUpdated(user, chatItems): + for chatItem in chatItems { + let cInfo = chatItem.chatInfo + let cItem = chatItem.chatItem + if !cItem.isDeletedContent && active(user) { + await MainActor.run { m.updateChatItem(cInfo, cItem, status: cItem.meta.itemStatus) } + } + if let endTask = m.messageDelivery[cItem.id] { + switch cItem.meta.itemStatus { + case .sndNew: () + case .sndSent: endTask() + case .sndRcvd: endTask() + case .sndErrorAuth: endTask() + case .sndError: endTask() + case .sndWarning: endTask() + case .rcvNew: () + case .rcvRead: () + case .invalid: () + } } } case let .chatItemUpdated(user, aChatItem): diff --git a/apps/ios/Shared/Views/Call/ActiveCallView.swift b/apps/ios/Shared/Views/Call/ActiveCallView.swift index d238c2dbae..049ee95a09 100644 --- a/apps/ios/Shared/Views/Call/ActiveCallView.swift +++ b/apps/ios/Shared/Views/Call/ActiveCallView.swift @@ -214,10 +214,12 @@ struct ActiveCallView: View { ChatReceiver.shared.messagesChannel = nil return } - if case let .chatItemStatusUpdated(_, msg) = msg, - msg.chatInfo.id == call.contact.id, - case .sndCall = msg.chatItem.content, - case .sndRcvd = msg.chatItem.meta.itemStatus { + if case let .chatItemsStatusesUpdated(_, chatItems) = msg, + chatItems.contains(where: { ci in + ci.chatInfo.id == call.contact.id && + ci.chatItem.content.isSndCall && + ci.chatItem.meta.itemStatus.isSndRcvd + }) { CallSoundsPlayer.shared.startInCallSound() ChatReceiver.shared.messagesChannel = nil } diff --git a/apps/ios/SimpleX SE/ShareModel.swift b/apps/ios/SimpleX SE/ShareModel.swift index e73aeee13c..807f2c9903 100644 --- a/apps/ios/SimpleX SE/ShareModel.swift +++ b/apps/ios/SimpleX SE/ShareModel.swift @@ -320,7 +320,8 @@ class ShareModel: ObservableObject { } await ch.completeFile() if await !ch.isRunning { break } - case let .chatItemStatusUpdated(_, ci): + case let .chatItemsStatusesUpdated(_, chatItems): + guard let ci = chatItems.last else { continue } guard isMessage(for: ci) else { continue } if let (title, message) = ci.chatItem.meta.itemStatus.statusInfo { // `title` and `message` already localized and interpolated diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index 3cc2202bff..c210431d12 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -601,7 +601,7 @@ public enum ChatResponse: Decodable, Error { case groupEmpty(user: UserRef, groupInfo: GroupInfo) case userContactLinkSubscribed case newChatItems(user: UserRef, chatItems: [AChatItem]) - case chatItemStatusUpdated(user: UserRef, chatItem: AChatItem) + case chatItemsStatusesUpdated(user: UserRef, chatItems: [AChatItem]) case chatItemUpdated(user: UserRef, chatItem: AChatItem) case chatItemNotChanged(user: UserRef, chatItem: AChatItem) case chatItemReaction(user: UserRef, added: Bool, reaction: ACIReaction) @@ -772,7 +772,7 @@ public enum ChatResponse: Decodable, Error { case .groupEmpty: return "groupEmpty" case .userContactLinkSubscribed: return "userContactLinkSubscribed" case .newChatItems: return "newChatItems" - case .chatItemStatusUpdated: return "chatItemStatusUpdated" + case .chatItemsStatusesUpdated: return "chatItemsStatusesUpdated" case .chatItemUpdated: return "chatItemUpdated" case .chatItemNotChanged: return "chatItemNotChanged" case .chatItemReaction: return "chatItemReaction" @@ -943,7 +943,9 @@ public enum ChatResponse: Decodable, Error { case let .newChatItems(u, chatItems): let itemsString = chatItems.map { chatItem in String(describing: chatItem) }.joined(separator: "\n") return withUser(u, itemsString) - case let .chatItemStatusUpdated(u, chatItem): return withUser(u, String(describing: chatItem)) + case let .chatItemsStatusesUpdated(u, chatItems): + let itemsString = chatItems.map { chatItem in String(describing: chatItem) }.joined(separator: "\n") + return withUser(u, itemsString) case let .chatItemUpdated(u, chatItem): return withUser(u, String(describing: chatItem)) case let .chatItemNotChanged(u, chatItem): return withUser(u, String(describing: chatItem)) case let .chatItemReaction(u, added, reaction): return withUser(u, "added: \(added)\n\(String(describing: reaction))") diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 84bf445601..6b03833d08 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -2856,6 +2856,13 @@ public enum CIStatus: Decodable, Hashable { ) } } + + public var isSndRcvd: Bool { + switch self { + case .sndRcvd: return true + default: return false + } + } } public enum SndError: Decodable, Hashable { @@ -3152,6 +3159,13 @@ public enum CIContent: Decodable, ItemContent, Hashable { default: return false } } + + public var isSndCall: Bool { + switch self { + case .sndCall: return true + default: return false + } + } } public enum MsgDecryptError: String, Decodable, Hashable { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 452e8a704b..de31229697 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -2186,15 +2186,16 @@ object ChatController { } } } - is CR.ChatItemStatusUpdated -> { - val cInfo = r.chatItem.chatInfo - val cItem = r.chatItem.chatItem - if (!cItem.isDeletedContent && active(r.user)) { - withChats { - updateChatItem(cInfo, cItem, status = cItem.meta.itemStatus) + is CR.ChatItemsStatusesUpdated -> + r.chatItems.forEach { chatItem -> + val cInfo = chatItem.chatInfo + val cItem = chatItem.chatItem + if (!cItem.isDeletedContent && active(r.user)) { + withChats { + updateChatItem(cInfo, cItem, status = cItem.meta.itemStatus) + } } } - } is CR.ChatItemUpdated -> chatItemSimpleUpdate(rhId, r.user, r.chatItem) is CR.ChatItemReaction -> { @@ -4831,7 +4832,7 @@ sealed class CR { @Serializable @SerialName("groupEmpty") class GroupEmpty(val user: UserRef, val group: GroupInfo): CR() @Serializable @SerialName("userContactLinkSubscribed") class UserContactLinkSubscribed: CR() @Serializable @SerialName("newChatItems") class NewChatItems(val user: UserRef, val chatItems: List): CR() - @Serializable @SerialName("chatItemStatusUpdated") class ChatItemStatusUpdated(val user: UserRef, val chatItem: AChatItem): CR() + @Serializable @SerialName("chatItemsStatusesUpdated") class ChatItemsStatusesUpdated(val user: UserRef, val chatItems: List): CR() @Serializable @SerialName("chatItemUpdated") class ChatItemUpdated(val user: UserRef, val chatItem: AChatItem): CR() @Serializable @SerialName("chatItemNotChanged") class ChatItemNotChanged(val user: UserRef, val chatItem: AChatItem): CR() @Serializable @SerialName("chatItemReaction") class ChatItemReaction(val user: UserRef, val added: Boolean, val reaction: ACIReaction): CR() @@ -5008,7 +5009,7 @@ sealed class CR { is GroupEmpty -> "groupEmpty" is UserContactLinkSubscribed -> "userContactLinkSubscribed" is NewChatItems -> "newChatItems" - is ChatItemStatusUpdated -> "chatItemStatusUpdated" + is ChatItemsStatusesUpdated -> "chatItemsStatusesUpdated" is ChatItemUpdated -> "chatItemUpdated" is ChatItemNotChanged -> "chatItemNotChanged" is ChatItemReaction -> "chatItemReaction" @@ -5177,7 +5178,7 @@ sealed class CR { is GroupEmpty -> withUser(user, json.encodeToString(group)) is UserContactLinkSubscribed -> noDetails() is NewChatItems -> withUser(user, chatItems.joinToString("\n") { json.encodeToString(it) }) - is ChatItemStatusUpdated -> withUser(user, json.encodeToString(chatItem)) + is ChatItemsStatusesUpdated -> withUser(user, chatItems.joinToString("\n") { json.encodeToString(it) }) is ChatItemUpdated -> withUser(user, json.encodeToString(chatItem)) is ChatItemNotChanged -> withUser(user, json.encodeToString(chatItem)) is ChatItemReaction -> withUser(user, "added: $added\n${json.encodeToString(reaction)}") diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/CallView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/CallView.kt index e4a6691d49..ae020ea3a1 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/CallView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/CallView.kt @@ -15,10 +15,11 @@ fun activeCallWaitDeliveryReceipt(scope: CoroutineScope) = scope.launch(Dispatch if (call == null || call.callState > CallState.InvitationSent) break val msg = apiResp.resp if (apiResp.remoteHostId == call.remoteHostId && - msg is CR.ChatItemStatusUpdated && - msg.chatItem.chatInfo.id == call.contact.id && - msg.chatItem.chatItem.content is CIContent.SndCall && - msg.chatItem.chatItem.meta.itemStatus is CIStatus.SndRcvd) { + msg is CR.ChatItemsStatusesUpdated && + msg.chatItems.any { + it.chatInfo.id == call.contact.id && it.chatItem.content is CIContent.SndCall && it.chatItem.meta.itemStatus is CIStatus.SndRcvd + } + ) { CallSoundsPlayer.startInCallSound(scope) break } 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 511230cc83..2bef0bdca7 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 @@ -444,8 +444,8 @@ fun ChatView(staleChatId: State, onComposed: suspend (chatId: String) - for (apiResp in controller.messagesChannel) { val msg = apiResp.resp if (apiResp.remoteHostId == chatRh && - msg is CR.ChatItemStatusUpdated && - msg.chatItem.chatItem.id == cItem.id + msg is CR.ChatItemsStatusesUpdated && + msg.chatItems.any { it.chatItem.id == cItem.id } ) { ciInfo = loadChatItemInfo() ?: return@withContext initialCiInfo = ciInfo