feat: introduce ability to @everyone

Closes #8479

This needs: status-im/status-go#3026
This commit is contained in:
Pascal Precht 2022-12-19 15:55:44 +01:00 committed by r4bbit
parent bf324f273a
commit 865ed32deb
14 changed files with 82 additions and 17 deletions

View File

@ -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
return $jsonObject

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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] =

View File

@ -703,10 +703,18 @@ proc renderInline(self: Service, parsedText: ParsedText): string =
result = fmt(" <strong><em>{value}</em></strong> ")
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("<a href=\"//{id}\" class=\"mention\">{contactDto.userDefaultDisplayName()}</a>")
if isSystemMention(id):
var tag = id
for pair in SystemTagMapping:
if pair[1] == "@" & id:
tag = pair[0]
break
result = fmt("<a href=\"\" class=\"mention\">{tag}</a>")
else:
if isCompressedPubKey(id):
id = status_accounts.decompressPk(id).result
let contactDto = self.contactService.getContactById(id)
result = fmt("<a href=\"//{id}\" class=\"mention\">{contactDto.userDefaultDisplayName()}</a>")
of PARSED_TEXT_CHILD_TYPE_STATUS_TAG:
result = fmt("<a href=\"#{value}\" class=\"status-tag\">#{value}</a>")
of PARSED_TEXT_CHILD_TYPE_DEL:

View File

@ -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() {

View File

@ -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

View File

@ -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

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 4a0eb56574a3cfd8f5732f0069cc62cb04f9dd29
Subproject commit b4bdfd3df6cf5fb91ab2d0e9f3b38e8d1b9703e5