From 865ed32deb47bd4a302968b2b86e1234b548a097 Mon Sep 17 00:00:00 2001 From: Pascal Precht <445106+0x-r4bbit@users.noreply.github.com> Date: Mon, 19 Dec 2022 15:55:44 +0100 Subject: [PATCH] feat: introduce ability to @everyone Closes #8479 This needs: status-im/status-go#3026 --- src/app/modules/main/activity_center/module.nim | 5 +++-- .../chat_content/messages/module.nim | 15 ++++++++++----- .../main/chat_section/chat_content/module.nim | 3 ++- src/app/modules/shared_models/message_item.nim | 13 +++++++++++-- .../shared_models/message_item_qobject.nim | 4 ++++ src/app/modules/shared_models/message_model.nim | 4 ++++ src/app_service/common/conversion.nim | 7 +++++++ src/app_service/common/message.nim | 5 +++++ src/app_service/service/message/dto/message.nim | 12 +++++++++++- src/app_service/service/message/service.nim | 16 ++++++++++++---- .../Chat/panels/SuggestionFilterPanel.qml | 10 ++++++++++ ui/app/AppLayouts/Chat/views/ChatContentView.qml | 1 + .../AppLayouts/Chat/views/ChatMessagesView.qml | 2 +- vendor/status-go | 2 +- 14 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/app/modules/main/activity_center/module.nim b/src/app/modules/main/activity_center/module.nim index c01501ad16..43e16a417f 100644 --- a/src/app/modules/main/activity_center/module.nim +++ b/src/app/modules/main/activity_center/module.nim @@ -98,7 +98,8 @@ proc createMessageItemFromDto(self: Module, message: MessageDto, chatDetails: Ch contactDetails.details.trustStatus, contactDetails.details.ensVerified, message.discordMessage, - resendError = "" + resendError = "", + message.mentioned )) method convertToItems*( @@ -257,4 +258,4 @@ method getChatDetailsAsJson*(self: Module, chatId: string): string = jsonObject["icon"] = %* chatDto.icon jsonObject["color"] = %* chatDto.color jsonObject["emoji"] = %* chatDto.emoji - return $jsonObject \ No newline at end of file + return $jsonObject diff --git a/src/app/modules/main/chat_section/chat_content/messages/module.nim b/src/app/modules/main/chat_section/chat_content/messages/module.nim index 2a7c58b312..fb2fcbbc2e 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/module.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/module.nim @@ -100,7 +100,8 @@ proc createFetchMoreMessagesItem(self: Module): Item = senderTrustStatus = TrustStatus.Unknown, senderEnsVerified = false, DiscordMessage(), - resendError = "" + resendError = "", + mentioned = false ) proc createChatIdentifierItem(self: Module): Item = @@ -142,7 +143,8 @@ proc createChatIdentifierItem(self: Module): Item = senderTrustStatus = TrustStatus.Unknown, senderEnsVerified = false, DiscordMessage(), - resendError = "" + resendError = "", + mentioned = false ) proc checkIfMessageLoadedAndScrollToItIfItIs(self: Module) = @@ -223,7 +225,8 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se sender.details.trustStatus, sender.details.ensVerified, m.discordMessage, - resendError = "" + resendError = "", + m.mentioned ) for r in reactions: @@ -323,7 +326,8 @@ method messageAdded*(self: Module, message: MessageDto) = sender.details.trustStatus, sender.details.ensVerified, message.discordMessage, - resendError = "" + resendError = "", + message.mentioned ) self.view.model().insertItemBasedOnClock(item) @@ -609,7 +613,8 @@ method getMessageById*(self: Module, messageId: string): message_item.Item = sender.details.trustStatus, sender.details.ensVerified, m.discordMessage, - resendError = "" + resendError = "", + m.mentioned ) return item return nil diff --git a/src/app/modules/main/chat_section/chat_content/module.nim b/src/app/modules/main/chat_section/chat_content/module.nim index afdfb95bbf..493a4f0b64 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -198,7 +198,8 @@ proc buildPinnedMessageItem(self: Module, messageId: string, actionInitiatedBy: contactDetails.details.trustStatus, contactDetails.details.ensVerified, m.discordMessage, - resendError = "" + resendError = "", + m.mentioned ) item.pinned = true item.pinnedBy = actionInitiatedBy diff --git a/src/app/modules/shared_models/message_item.nim b/src/app/modules/shared_models/message_item.nim index 5cf2a5775f..5b2b2d9c80 100644 --- a/src/app/modules/shared_models/message_item.nim +++ b/src/app/modules/shared_models/message_item.nim @@ -43,6 +43,7 @@ type senderEnsVerified: bool messageAttachments: seq[string] resendError: string + mentioned: bool proc initItem*( id, @@ -72,7 +73,8 @@ proc initItem*( senderTrustStatus: TrustStatus, senderEnsVerified: bool, discordMessage: DiscordMessage, - resendError: string + resendError: string, + mentioned: bool ): Item = result = Item() result.id = id @@ -109,6 +111,7 @@ proc initItem*( result.senderEnsVerified = senderEnsVerified result.messageAttachments = @[] result.resendError = resendError + result.mentioned = mentioned if ContentType.DiscordMessage == contentType: if result.messageText == "": @@ -157,7 +160,8 @@ proc initNewMessagesMarkerItem*(timestamp: int64): Item = senderTrustStatus = TrustStatus.Unknown, senderEnsVerified = false, discordMessage = DiscordMessage(), - resendError = "" + resendError = "", + mentioned = false ) proc `$`*(self: Item): string = @@ -401,3 +405,8 @@ proc gapTo*(self: Item): int64 {.inline.} = proc `gapTo=`*(self: Item, value: int64) {.inline.} = self.gapTo = value +proc mentioned*(self: Item): bool {.inline.} = + self.mentioned + +proc `mentioned=`*(self: Item, value: bool) {.inline.} = + self.mentioned = value diff --git a/src/app/modules/shared_models/message_item_qobject.nim b/src/app/modules/shared_models/message_item_qobject.nim index 89dc24e2c7..0fe7d0b8d3 100644 --- a/src/app/modules/shared_models/message_item_qobject.nim +++ b/src/app/modules/shared_models/message_item_qobject.nim @@ -57,6 +57,10 @@ QtObject: QtProperty[bool] amISender: read = amISender + proc mentioned*(self: MessageItem): bool {.slot.} = result = ?.self.messageItem.mentioned + QtProperty[bool] mentioned: + read = mentioned + proc senderIcon*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.senderIcon QtProperty[string] senderIcon: read = senderIcon diff --git a/src/app/modules/shared_models/message_model.nim b/src/app/modules/shared_models/message_model.nim index 52625616cf..4b18bb32c6 100644 --- a/src/app/modules/shared_models/message_model.nim +++ b/src/app/modules/shared_models/message_model.nim @@ -43,6 +43,7 @@ type SenderEnsVerified MessageAttachments ResendError + Mentioned QtObject: type @@ -103,6 +104,7 @@ QtObject: ModelRole.Seen.int:"seen", ModelRole.OutgoingStatus.int:"outgoingStatus", ModelRole.ResendError.int:"resendError", + ModelRole.Mentioned.int:"mentioned", ModelRole.MessageText.int:"messageText", ModelRole.MessageImage.int:"messageImage", ModelRole.MessageContainsMentions.int:"messageContainsMentions", @@ -173,6 +175,8 @@ QtObject: result = newQVariant(item.outgoingStatus) of ModelRole.ResendError: result = newQVariant(item.resendError) + of ModelRole.Mentioned: + result = newQVariant(item.mentioned) of ModelRole.MessageText: result = newQVariant(item.messageText) of ModelRole.MessageImage: diff --git a/src/app_service/common/conversion.nim b/src/app_service/common/conversion.nim index 49854da19f..ee5ddb3d2d 100644 --- a/src/app_service/common/conversion.nim +++ b/src/app_service/common/conversion.nim @@ -3,9 +3,16 @@ from web3 import Address, fromHex const CompressedKeyChars* = {'0'..'9', 'A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','m','n','o','p','q','r','s','t','u','v','w','x','y','z'} +const SystemMentionChars* = {'0'..'9', 'x'} + +const SystemTagMapping* = [("@everyone", "@0x00001")] + proc isCompressedPubKey*(strPubKey: string): bool = return strPubKey.startsWith("zQ3") and allCharsInSet(strPubKey, CompressedKeyChars) +proc isSystemMention*(mention: string) : bool = + mention.startsWith("0x") and allCharsInSet(mention, SystemMentionChars) + proc parseAddress*(strAddress: string): Address = var hexAddressValue: Address try: diff --git a/src/app_service/common/message.nim b/src/app_service/common/message.nim index 03a67c3e91..cd62d34673 100644 --- a/src/app_service/common/message.nim +++ b/src/app_service/common/message.nim @@ -1,5 +1,6 @@ import sequtils, strutils, sugar, re import ../service/contacts/dto/contacts +from conversion import SystemTagMapping proc replaceMentionsWithPubKeys*(allKnownContacts: seq[ContactsDto], message: string): string = let aliasPattern = re(r"(@[A-z][a-z]+ [A-z][a-z]* [A-z][a-z]*)", flags = {reStudy, reIgnoreCase}) @@ -11,6 +12,10 @@ proc replaceMentionsWithPubKeys*(allKnownContacts: seq[ContactsDto], message: st let nameMentions = findAll(message, namePattern) var updatedMessage = message + # replace system tag with system ID + for pair in SystemTagMapping: + updatedMessage = updatedMessage.replaceWord(pair[0], pair[1]) + # In the following lines we're free to compare to `x.userDefaultDisplayName()` cause that's actually what we're displaying # in the mentions suggestion list. for mention in aliasMentions: diff --git a/src/app_service/service/message/dto/message.nim b/src/app_service/service/message/dto/message.nim index 99d2c6b29a..a0320a16ac 100644 --- a/src/app_service/service/message/dto/message.nim +++ b/src/app_service/service/message/dto/message.nim @@ -4,6 +4,8 @@ import json, strutils include ../../../common/json_utils +from ../../../common/conversion import SystemTagMapping + const PARSED_TEXT_TYPE_PARAGRAPH* = "paragraph" const PARSED_TEXT_TYPE_BLOCKQUOTE* = "blockquote" const PARSED_TEXT_TYPE_CODEBLOCK* = "codeblock" @@ -108,6 +110,7 @@ type MessageDto* = object deleted*: bool deletedForMe*: bool transactionParameters*: TransactionParameters + mentioned*: bool proc toParsedText*(jsonObj: JsonNode): ParsedText = result = ParsedText() @@ -213,6 +216,7 @@ proc toMessageDto*(jsonObj: JsonNode): MessageDto = discard jsonObj.getProp("editedAt", result.editedAt) discard jsonObj.getProp("deleted", result.deleted) discard jsonObj.getProp("deletedForMe", result.deletedForMe) + discard jsonObj.getProp("mentioned", result.mentioned) var quotedMessageObj: JsonNode if(jsonObj.getProp("quotedMessage", quotedMessageObj)): @@ -259,7 +263,13 @@ proc isPersonalMention*(self: MessageDto, publicKey: string): bool = return false proc isGlobalMention*(self: MessageDto): bool = - # TODO: we should check here if message contains global mention. + for pText in self.parsedText: + for child in pText.children: + if child.type == PARSED_TEXT_CHILD_TYPE_MENTION: + for pair in SystemTagMapping: + if child.literal.contains(pair[1]): + return true + return false proc mentionedUsersPks*(self: MessageDto): seq[string] = diff --git a/src/app_service/service/message/service.nim b/src/app_service/service/message/service.nim index 63d57c379a..a2da37c688 100644 --- a/src/app_service/service/message/service.nim +++ b/src/app_service/service/message/service.nim @@ -703,10 +703,18 @@ proc renderInline(self: Service, parsedText: ParsedText): string = result = fmt(" {value} ") of PARSED_TEXT_CHILD_TYPE_MENTION: var id = value - if isCompressedPubKey(id): - id = status_accounts.decompressPk(id).result - let contactDto = self.contactService.getContactById(id) - result = fmt("{contactDto.userDefaultDisplayName()}") + if isSystemMention(id): + var tag = id + for pair in SystemTagMapping: + if pair[1] == "@" & id: + tag = pair[0] + break + result = fmt("{tag}") + else: + if isCompressedPubKey(id): + id = status_accounts.decompressPk(id).result + let contactDto = self.contactService.getContactById(id) + result = fmt("{contactDto.userDefaultDisplayName()}") of PARSED_TEXT_CHILD_TYPE_STATUS_TAG: result = fmt("#{value}") of PARSED_TEXT_CHILD_TYPE_DEL: diff --git a/ui/app/AppLayouts/Chat/panels/SuggestionFilterPanel.qml b/ui/app/AppLayouts/Chat/panels/SuggestionFilterPanel.qml index 0e2bf0ff70..a2f1cf6903 100644 --- a/ui/app/AppLayouts/Chat/panels/SuggestionFilterPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/SuggestionFilterPanel.qml @@ -13,6 +13,7 @@ Item { property int cursorPosition: 0 property int lastAtPosition: 0 property var property: ([]) + property bool addSystemSuggestions: false onFilterChanged: invalidateFilter() onPropertyChanged: invalidateFilter() @@ -78,6 +79,15 @@ Item { filterModel.append(item) } } + + const everyoneItem = { + publicKey: "0x00001", + name: "@everyone", + icon: "" + } + if (suggestionsPanelRoot.addSystemSuggestions && isAcceptedItem(filter, everyoneItem)) { + filterModel.append(everyoneItem) + } } function getFilter() { diff --git a/ui/app/AppLayouts/Chat/views/ChatContentView.qml b/ui/app/AppLayouts/Chat/views/ChatContentView.qml index 637a223209..0aff73a12d 100644 --- a/ui/app/AppLayouts/Chat/views/ChatContentView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatContentView.qml @@ -190,6 +190,7 @@ ColumnLayout { isActiveChannel: root.isActiveChannel anchors.bottom: parent.bottom chatType: chatContentModule? chatContentModule.chatDetails.type : Constants.chatType.unknown + suggestions.suggestionFilter.addSystemSuggestions: chatType == Constants.chatType.communityChat Binding on chatInputPlaceholder { when: root.isBlocked diff --git a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml index 6184c1ca0a..9fb4fea3f8 100644 --- a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml @@ -276,7 +276,7 @@ Item { linkUrls: model.links messageAttachments: model.messageAttachments transactionParams: model.transactionParameters - hasMention: model.mentionedUsersPks.split(" ").includes(root.rootStore.userProfileInst.pubKey) + hasMention: model.mentioned gapFrom: model.gapFrom gapTo: model.gapTo diff --git a/vendor/status-go b/vendor/status-go index 4a0eb56574..b4bdfd3df6 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit 4a0eb56574a3cfd8f5732f0069cc62cb04f9dd29 +Subproject commit b4bdfd3df6cf5fb91ab2d0e9f3b38e8d1b9703e5