From 63cb7a75b34f66fb00f3fae8820a4b4bb9a511e7 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Wed, 17 May 2023 10:31:27 +0200 Subject: [PATCH] ios: update reactions api (#2451) --- apps/ios/Shared/Model/SimpleXAPI.swift | 8 ++--- apps/ios/Shared/Views/Chat/ChatView.swift | 12 +++---- apps/ios/SimpleXChat/APITypes.swift | 8 ++--- apps/ios/SimpleXChat/ChatTypes.swift | 44 +++++++++++++---------- 4 files changed, 39 insertions(+), 33 deletions(-) diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 8dcdb8514..33e10bf07 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -345,9 +345,9 @@ func apiUpdateChatItem(type: ChatType, id: Int64, itemId: Int64, msg: MsgContent throw r } -func apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, reaction: MsgReaction, add: Bool) async throws -> ChatItem { - let r = await chatSendCmd(.apiChatItemReaction(type: type, id: id, itemId: itemId, reaction: reaction, add: add), bgDelay: msgDelay) - if case let .chatItemReaction(_, reaction, _) = r { return reaction.chatReaction.chatItem } +func apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, add: Bool, reaction: MsgReaction) async throws -> ChatItem { + let r = await chatSendCmd(.apiChatItemReaction(type: type, id: id, itemId: itemId, add: add, reaction: reaction), bgDelay: msgDelay) + if case let .chatItemReaction(_, _, reaction) = r { return reaction.chatReaction.chatItem } throw r } @@ -1285,7 +1285,7 @@ func processReceivedMsg(_ res: ChatResponse) async { } case let .chatItemUpdated(user, aChatItem): chatItemSimpleUpdate(user, aChatItem) - case let .chatItemReaction(user, r, _): + case let .chatItemReaction(user, _, r): if active(user) { m.updateChatItem(r.chatInfo, r.chatReaction.chatItem) } diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index 5df8d062f..4cbf2ed7a 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -526,7 +526,7 @@ struct ChatView: View { if chat.chatInfo.featureEnabled(.reactions) && (ci.allowAddReaction || r.userReacted) { v.onTapGesture { - setReaction(r.reaction, add: !r.userReacted) + setReaction(add: !r.userReacted, reaction: r.reaction) } } else { v @@ -606,27 +606,27 @@ struct ChatView: View { let rs = MsgReaction.values.compactMap { r in ci.reactions.contains(where: { $0.userReacted && $0.reaction == r }) ? nil - : UIAction(title: r.text) { _ in setReaction(r, add: true) } + : UIAction(title: r.text) { _ in setReaction(add: true, reaction: r) } } if rs.count > 0 { return UIMenu( title: NSLocalizedString("React...", comment: "chat item menu"), - image: UIImage(systemName: "hand.thumbsup"), + image: UIImage(systemName: "face.smiling"), children: rs ) } return nil } - private func setReaction(_ r: MsgReaction, add: Bool) { + private func setReaction(add: Bool, reaction: MsgReaction) { Task { do { let chatItem = try await apiChatItemReaction( type: chat.chatInfo.chatType, id: chat.chatInfo.apiId, itemId: ci.id, - reaction: r, - add: add + add: add, + reaction: reaction ) await MainActor.run { ChatModel.shared.updateChatItem(chat.chatInfo, chatItem) diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index cc1d0183f..be86f32e4 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -41,7 +41,7 @@ public enum ChatCommand { case apiUpdateChatItem(type: ChatType, id: Int64, itemId: Int64, msg: MsgContent, live: Bool) case apiDeleteChatItem(type: ChatType, id: Int64, itemId: Int64, mode: CIDeleteMode) case apiDeleteMemberChatItem(groupId: Int64, groupMemberId: Int64, itemId: Int64) - case apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, reaction: MsgReaction, add: Bool) + case apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, add: Bool, reaction: MsgReaction) case apiGetNtfToken case apiRegisterToken(token: DeviceToken, notificationMode: NotificationsMode) case apiVerifyToken(token: DeviceToken, nonce: String, code: String) @@ -149,7 +149,7 @@ public enum ChatCommand { case let .apiUpdateChatItem(type, id, itemId, mc, live): return "/_update item \(ref(type, id)) \(itemId) live=\(onOff(live)) \(mc.cmdString)" case let .apiDeleteChatItem(type, id, itemId, mode): return "/_delete item \(ref(type, id)) \(itemId) \(mode.rawValue)" case let .apiDeleteMemberChatItem(groupId, groupMemberId, itemId): return "/_delete member item #\(groupId) \(groupMemberId) \(itemId)" - case let .apiChatItemReaction(type, id, itemId, reaction, add): return "/_reaction \(ref(type, id)) \(itemId) \(reaction.cmdString) \(onOff(add))" + case let .apiChatItemReaction(type, id, itemId, add, reaction): return "/_reaction \(ref(type, id)) \(itemId) \(onOff(add)) \(encodeJSON(reaction))" case .apiGetNtfToken: return "/_ntf get " case let .apiRegisterToken(token, notificationMode): return "/_ntf register \(token.cmdString) \(notificationMode.rawValue)" case let .apiVerifyToken(token, nonce, code): return "/_ntf verify \(token.cmdString) \(nonce) \(code)" @@ -433,7 +433,7 @@ public enum ChatResponse: Decodable, Error { case newChatItem(user: User, chatItem: AChatItem) case chatItemStatusUpdated(user: User, chatItem: AChatItem) case chatItemUpdated(user: User, chatItem: AChatItem) - case chatItemReaction(user: User, reaction: ACIReaction, added: Bool) + case chatItemReaction(user: User, added: Bool, reaction: ACIReaction) case chatItemDeleted(user: User, deletedChatItem: AChatItem, toChatItem: AChatItem?, byUser: Bool) case contactsList(user: User, contacts: [Contact]) // group events @@ -668,7 +668,7 @@ public enum ChatResponse: Decodable, Error { case let .newChatItem(u, chatItem): return withUser(u, String(describing: chatItem)) case let .chatItemStatusUpdated(u, chatItem): return withUser(u, String(describing: chatItem)) case let .chatItemUpdated(u, chatItem): return withUser(u, String(describing: chatItem)) - case let .chatItemReaction(u, reaction, added): return withUser(u, "added: \(added)\n\(String(describing: reaction))") + case let .chatItemReaction(u, added, reaction): return withUser(u, "added: \(added)\n\(String(describing: reaction))") case let .chatItemDeleted(u, deletedChatItem, toChatItem, byUser): return withUser(u, "deletedChatItem:\n\(String(describing: deletedChatItem))\ntoChatItem:\n\(String(describing: toChatItem))\nbyUser: \(byUser)") case let .contactsList(u, contacts): return withUser(u, String(describing: contacts)) case let .groupCreated(u, groupInfo): return withUser(u, String(describing: groupInfo)) diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index b3a472f1e..f93d2a5f2 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -561,7 +561,7 @@ public enum ChatFeature: String, Decodable, Feature { switch self { case .timedMessages: return "stopwatch" case .fullDelete: return "trash.slash" - case .reactions: return "hand.thumbsup" + case .reactions: return "face.smiling" case .voice: return "mic" case .calls: return "phone" } @@ -571,7 +571,7 @@ public enum ChatFeature: String, Decodable, Feature { switch self { case .timedMessages: return "stopwatch.fill" case .fullDelete: return "trash.slash.fill" - case .reactions: return "hand.thumbsup.fill" + case .reactions: return "face.smiling.fill" case .voice: return "mic.fill" case .calls: return "phone.fill" } @@ -696,7 +696,7 @@ public enum GroupFeature: String, Decodable, Feature { case .timedMessages: return "stopwatch" case .directMessages: return "arrow.left.and.right.circle" case .fullDelete: return "trash.slash" - case .reactions: return "hand.thumbsup" + case .reactions: return "face.smiling" case .voice: return "mic" } } @@ -706,7 +706,7 @@ public enum GroupFeature: String, Decodable, Feature { case .timedMessages: return "stopwatch.fill" case .directMessages: return "arrow.left.and.right.circle.fill" case .fullDelete: return "trash.slash.fill" - case .reactions: return "hand.thumbsup.fill" + case .reactions: return "face.smiling.fill" case .voice: return "mic.fill" } } @@ -2469,25 +2469,17 @@ public struct CIReactionCount: Decodable { } public enum MsgReaction: Hashable { - case emoji(MREmojiChar) - case unknown + case emoji(emoji: MREmojiChar) + case unknown(type: String) public var text: String { switch self { case let .emoji(emoji): return emoji.rawValue - case .unknown: return "" + case .unknown: return "?" } } - public var cmdString: String { - switch self { - case let .emoji(emoji): return emoji.cmdString - case .unknown: return "" - } - } - - public static var values: [MsgReaction] = - MREmojiChar.allCases.map { .emoji($0) } + public static var values: [MsgReaction] = MREmojiChar.allCases.map { .emoji(emoji: $0) } enum CodingKeys: String, CodingKey { case type @@ -2527,12 +2519,26 @@ extension MsgReaction: Decodable { switch type { case "emoji": let emoji = try container.decode(MREmojiChar.self, forKey: CodingKeys.emoji) - self = .emoji(emoji) + self = .emoji(emoji: emoji) default: - self = .unknown + self = .unknown(type: type) } } catch { - self = .unknown + self = .unknown(type: "") + } + } +} + +extension MsgReaction: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + switch self { + case let .emoji(emoji): + try container.encode("emoji", forKey: .type) + try container.encode(emoji, forKey: .emoji) + // TODO use original JSON and type + case let .unknown(type): + try container.encode(type, forKey: .type) } } }