refactor(@desktop/chat): mentioning a user in chat reveals his public key instead of user name

This fix also includes mention users name update according to their
local/ens names, in app runtime.

Fixes #4403
This commit is contained in:
Sale Djenic 2022-01-13 15:45:34 +01:00
parent 35568d1d6b
commit f7e8b68715
16 changed files with 239 additions and 40 deletions

View File

@ -128,7 +128,8 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.contactsService = contacts_service.newService(statusFoundation.events, statusFoundation.threadpool)
result.chatService = chat_service.newService(statusFoundation.events, result.contactsService)
result.communityService = community_service.newService(statusFoundation.events, result.chatService)
result.messageService = message_service.newService(statusFoundation.events, statusFoundation.threadpool)
result.messageService = message_service.newService(statusFoundation.events, statusFoundation.threadpool,
result.contactsService)
result.activityCenterService = activity_center_service.newService(statusFoundation.events,
statusFoundation.threadpool, result.chatService)
result.tokenService = token_service.newService(statusFoundation.events, statusFoundation.threadpool,

View File

@ -7,6 +7,7 @@ import ../../../core/signals/types
import ../../../../app_service/service/activity_center/service as activity_center_service
import ../../../../app_service/service/contacts/service as contacts_service
import ../../../../app_service/service/chat/service as chat_service
import ../../../../app_service/service/message/service as message_service
export controller_interface
@ -16,18 +17,21 @@ type
events: EventEmitter
activityCenterService: activity_center_service.Service
contactsService: contacts_service.Service
messageService: message_service.Service
proc newController*[T](
delegate: io_interface.AccessInterface,
events: EventEmitter,
activityCenterService: activity_center_service.Service,
contactsService: contacts_service.Service
contactsService: contacts_service.Service,
messageService: message_service.Service
): Controller[T] =
result = Controller[T]()
result.delegate = delegate
result.events = events
result.activityCenterService = activityCenterService
result.contactsService = contactsService
result.messageService = messageService
method delete*[T](self: Controller[T]) =
discard
@ -102,4 +106,7 @@ method acceptActivityCenterNotifications*[T](self: Controller[T], notificationId
return self.activityCenterService.acceptActivityCenterNotifications(notificationIds)
method dismissActivityCenterNotifications*[T](self: Controller[T], notificationIds: seq[string]): string =
return self.activityCenterService.dismissActivityCenterNotifications(notificationIds)
return self.activityCenterService.dismissActivityCenterNotifications(notificationIds)
method getRenderedText*(self: Controller, parsedTextArray: seq[ParsedText]): string =
return self.messageService.getRenderedText(parsedTextArray)

View File

@ -1,5 +1,6 @@
import ../../../../app_service/service/contacts/service as contacts_service
import ../../../../app_service/service/activity_center/service as activity_center_service
import ../../../../app_service/service/message/dto/[message]
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -38,6 +39,10 @@ method acceptActivityCenterNotifications*(self: AccessInterface, notificationIds
method dismissActivityCenterNotifications*(self: AccessInterface, notificationIds: seq[string]): string {.base.} =
raise newException(ValueError, "No implementation available")
method getRenderedText*(self: AccessInterface, parsedTextArray: seq[ParsedText]): string {.base.} =
raise newException(ValueError, "No implementation available")
type
## Abstract class (concept) which must be implemented by object/s used in this
## module.

View File

@ -8,6 +8,7 @@ import ../../../global/global_singleton
import ../../../core/eventemitter
import ../../../../app_service/service/activity_center/service as activity_center_service
import ../../../../app_service/service/contacts/service as contacts_service
import ../../../../app_service/service/message/service as message_service
export io_interface
@ -23,7 +24,8 @@ proc newModule*[T](
delegate: T,
events: EventEmitter,
activityCenterService: activity_center_service.Service,
contactsService: contacts_service.Service
contactsService: contacts_service.Service,
messageService: message_service.Service
): Module[T] =
result = Module[T]()
result.delegate = delegate
@ -33,7 +35,8 @@ proc newModule*[T](
result,
events,
activityCenterService,
contactsService
contactsService,
messageService
)
result.moduleLoaded = false
@ -78,8 +81,9 @@ method convertToItems*[T](
contactDetails.isIdenticon,
contactDetails.isCurrentUser,
n.message.outgoingStatus,
n.message.text,
self.controller.getRenderedText(n.message.parsedText),
n.message.image,
n.message.containsContactMentions(),
n.message.seen,
n.message.timestamp,
ContentType(n.message.contentType),

View File

@ -149,4 +149,7 @@ method getContactDetails*(self: Controller, contactId: string): ContactDetails =
return self.contactService.getContactDetails(contactId)
method getCurrentFleet*(self: Controller): string =
return self.settingsService.getFleetAsString()
return self.settingsService.getFleetAsString()
method getRenderedText*(self: Controller, parsedTextArray: seq[ParsedText]): string =
return self.messageService.getRenderedText(parsedTextArray)

View File

@ -65,4 +65,7 @@ method getContactDetails*(self: AccessInterface, contactId: string): ContactDeta
raise newException(ValueError, "No implementation available")
method getCurrentFleet*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method getRenderedText*(self: AccessInterface, parsedTextArray: seq[ParsedText]): string {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -139,4 +139,11 @@ method getContactDetails*(self: Controller, contactId: string): ContactDetails =
return self.contactService.getContactDetails(contactId)
method getNumOfPinnedMessages*(self: Controller): int =
return self.messageService.getNumOfPinnedMessages(self.chatId)
return self.messageService.getNumOfPinnedMessages(self.chatId)
method getRenderedText*(self: Controller, parsedTextArray: seq[ParsedText]): string =
return self.messageService.getRenderedText(parsedTextArray)
method getMessageDetails*(self: Controller, messageId: string):
tuple[message: MessageDto, reactions: seq[ReactionDto], error: string] =
return self.messageService.getDetailsForMessage(self.chatId, messageId)

View File

@ -1,6 +1,7 @@
import ../../../../../../app_service/service/contacts/dto/[contacts, contact_details]
import ../../../../../../app_service/service/community/dto/[community]
import ../../../../../../app_service/service/chat/dto/[chat]
import ../../../../../../app_service/service/message/dto/[message, reaction]
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -50,4 +51,11 @@ method getContactDetails*(self: AccessInterface, contactId: string): ContactDeta
raise newException(ValueError, "No implementation available")
method getNumOfPinnedMessages*(self: AccessInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method getRenderedText*(self: AccessInterface, parsedTextArray: seq[ParsedText]): string {.base.} =
raise newException(ValueError, "No implementation available")
method getMessageDetails*(self: AccessInterface, messageId: string):
tuple[message: MessageDto, reactions: seq[ReactionDto], error: string] {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -73,7 +73,7 @@ proc createChatIdentifierItem(self: Module): Item =
(chatName, chatIcon, isIdenticon) = self.controller.getOneToOneChatNameAndImage()
result = initItem(CHAT_IDENTIFIER_MESSAGE_ID, "", chatDto.id, chatName, "", chatIcon, isIdenticon, false, "", "", "",
true, 0, ContentType.ChatIdentifier, -1)
false, true, 0, ContentType.ChatIdentifier, -1)
method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: seq[ReactionDto],
pinnedMessages: seq[PinnedMessageDto]) =
@ -83,9 +83,10 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
for m in messages:
let sender = self.controller.getContactDetails(m.`from`)
let renderedMessageText = self.controller.getRenderedText(m.parsedText)
var item = initItem(m.id, m.responseTo, m.`from`, sender.displayName, sender.details.localNickname, sender.icon,
sender.isIdenticon, sender.isCurrentUser, m.outgoingStatus, m.text, m.image, m.seen, m.timestamp,
m.contentType.ContentType, m.messageType)
sender.isIdenticon, sender.isCurrentUser, m.outgoingStatus, renderedMessageText, m.image,
m.containsContactMentions(), m.seen, m.timestamp, m.contentType.ContentType, m.messageType)
for r in reactions:
if(r.messageId == m.id):
@ -121,9 +122,10 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
method messageAdded*(self: Module, message: MessageDto) =
let sender = self.controller.getContactDetails(message.`from`)
let renderedMessageText = self.controller.getRenderedText(message.parsedText)
var item = initItem(message.id, message.responseTo, message.`from`, sender.displayName, sender.details.localNickname,
sender.icon, sender.isIdenticon, sender.isCurrentUser, message.outgoingStatus, message.text, message.image,
message.seen, message.timestamp, message.contentType.ContentType, message.messageType)
sender.icon, sender.isIdenticon, sender.isCurrentUser, message.outgoingStatus, renderedMessageText, message.image,
message.containsContactMentions(), message.seen, message.timestamp, message.contentType.ContentType, message.messageType)
self.view.model().insertItemBasedOnTimestamp(item)
@ -199,5 +201,16 @@ method getNumberOfPinnedMessages*(self: Module): int =
method updateContactDetails*(self: Module, contactId: string) =
let updatedContact = self.controller.getContactDetails(contactId)
self.view.model().updateSenderDetails(contactId, updatedContact.displayName, updatedContact.details.localNickname,
updatedContact.icon, updatedContact.isIdenticon)
for item in self.view.model().modelContactUpdateIterator(contactId):
if(item.senderId == contactId):
item.senderDisplayName = updatedContact.displayName
item.senderLocalName = updatedContact.details.localNickname
item.senderIcon = updatedContact.icon
item.isSenderIconIdenticon = updatedContact.isIdenticon
if(item.messageContainsMentions):
let (m, _, err) = self.controller.getMessageDetails(item.id)
if(err.len == 0):
item.messageText = self.controller.getRenderedText(m.parsedText)
item.messageContainsMentions = m.containsContactMentions()

View File

@ -142,8 +142,9 @@ proc buildPinnedMessageItem(self: Module, messageId: string, actionInitiatedBy:
contactDetails.isIdenticon,
contactDetails.isCurrentUser,
m.outgoingStatus,
m.text,
self.controller.getRenderedText(m.parsedText),
m.image,
m.containsContactMentions(),
m.seen,
m.timestamp,
m.contentType.ContentType,
@ -250,8 +251,18 @@ method amIChatAdmin*(self: Module): bool =
method onContactDetailsUpdated*(self: Module, contactId: string) =
let updatedContact = self.controller.getContactDetails(contactId)
self.view.pinnedModel().updateSenderDetails(contactId, updatedContact.displayName, updatedContact.details.localNickname,
updatedContact.icon, updatedContact.isIdenticon)
for item in self.view.pinnedModel().modelContactUpdateIterator(contactId):
if(item.senderId == contactId):
item.senderDisplayName = updatedContact.displayName
item.senderLocalName = updatedContact.details.localNickname
item.senderIcon = updatedContact.icon
item.isSenderIconIdenticon = updatedContact.isIdenticon
if(item.messageContainsMentions):
let (m, _, err) = self.controller.getMessageDetails(item.id)
if(err.len == 0):
item.messageText = self.controller.getRenderedText(m.parsedText)
item.messageContainsMentions = m.containsContactMentions()
if(self.controller.getMyChatId() == contactId):
self.view.updateChatDetailsNameAndIcon(updatedContact.displayName, updatedContact.icon, updatedContact.isIdenticon)

View File

@ -125,7 +125,8 @@ proc newModule*[T](
profileService, contactsService, aboutService, languageService, privacyService, nodeConfigurationService,
devicesService, mailserversService, chatService)
result.stickersModule = stickers_module.newModule(result, events, stickersService)
result.activityCenterModule = activity_center_module.newModule(result, events, activityCenterService, contactsService)
result.activityCenterModule = activity_center_module.newModule(result, events, activityCenterService, contactsService,
messageService)
result.communitiesModule = communities_module.newModule(result, events, communityService)
result.appSearchModule = app_search_module.newModule(result, events, contactsService, chatService, communityService,
messageService)

View File

@ -18,6 +18,7 @@ type
outgoingStatus: string
messageText: string
messageImage: string
messageContainsMentions: bool
stickerHash: string
stickerPack: int
gapFrom: int64
@ -30,8 +31,8 @@ type
pinnedBy: string
proc initItem*(id, responseToMessageWithId, senderId, senderDisplayName, senderLocalName, senderIcon: string,
isSenderIconIdenticon, amISender: bool, outgoingStatus, text, image: string, seen: bool, timestamp: int64,
contentType: ContentType, messageType: int): Item =
isSenderIconIdenticon, amISender: bool, outgoingStatus, text, image: string, messageContainsMentions, seen: bool,
timestamp: int64, contentType: ContentType, messageType: int): Item =
result = Item()
result.id = id
result.responseToMessageWithId = responseToMessageWithId
@ -45,6 +46,7 @@ proc initItem*(id, responseToMessageWithId, senderId, senderDisplayName, senderL
result.outgoingStatus = outgoingStatus
result.messageText = text
result.messageImage = image
result.messageContainsMentions = messageContainsMentions
result.timestamp = timestamp
result.contentType = contentType
result.messageType = messageType
@ -63,6 +65,7 @@ proc `$`*(self: Item): string =
seen: {$self.seen},
outgoingStatus:{$self.outgoingStatus},
messageText:{self.messageText},
messageContainsMentions:{self.messageContainsMentions},
timestamp:{$self.timestamp},
contentType:{$self.contentType.int},
messageType:{$self.messageType},
@ -113,9 +116,18 @@ proc outgoingStatus*(self: Item): string {.inline.} =
proc messageText*(self: Item): string {.inline.} =
self.messageText
proc `messageText=`*(self: Item, value: string) {.inline.} =
self.messageText = value
proc messageImage*(self: Item): string {.inline.} =
self.messageImage
proc messageContainsMentions*(self: Item): bool {.inline.} =
self.messageContainsMentions
proc `messageContainsMentions=`*(self: Item, value: bool) {.inline.} =
self.messageContainsMentions = value
proc stickerPack*(self: Item): int {.inline.} =
self.stickerPack
@ -176,6 +188,7 @@ proc toJsonNode*(self: Item): JsonNode =
"outgoingStatus": self.outgoingStatus,
"messageText": self.messageText,
"messageImage": self.messageImage,
"messageContainsMentions": self.messageContainsMentions,
"stickerHash": self.stickerHash,
"stickerPack": self.stickerPack,
"gapFrom": self.gapFrom,

View File

@ -16,6 +16,8 @@ type
OutgoingStatus
MessageText
MessageImage
MessageContainsMentions # Actually we don't need to exposed this to qml since we only used it as an improved way to
# check whether we need to update mentioned contact name or not.
Timestamp
ContentType
MessageType
@ -73,6 +75,7 @@ QtObject:
ModelRole.OutgoingStatus.int:"outgoingStatus",
ModelRole.MessageText.int:"messageText",
ModelRole.MessageImage.int:"messageImage",
ModelRole.MessageContainsMentions.int:"messageContainsMentions",
ModelRole.Timestamp.int:"timestamp",
ModelRole.ContentType.int:"contentType",
ModelRole.MessageType.int:"messageType",
@ -120,6 +123,8 @@ QtObject:
result = newQVariant(item.messageText)
of ModelRole.MessageImage:
result = newQVariant(item.messageImage)
of ModelRole.MessageContainsMentions:
result = newQVariant(item.messageContainsMentions)
of ModelRole.Timestamp:
result = newQVariant(item.timestamp)
of ModelRole.ContentType:
@ -272,18 +277,18 @@ QtObject:
return
self.items[index].toJsonNode()
proc updateSenderDetails*(self: Model, contactId, displayName, localName, icon: string, isIdenticon: bool) =
iterator modelContactUpdateIterator*(self: Model, contactId: string): Item =
for i in 0 ..< self.items.len:
yield self.items[i]
var roles: seq[int]
if(self.items[i].senderId == contactId):
self.items[i].senderDisplayName = displayName
self.items[i].senderLocalName = localName
self.items[i].senderIcon = icon
self.items[i].isSenderIconIdenticon = isIdenticon
roles = @[ModelRole.SenderDisplayName.int, ModelRole.SenderLocalName.int, ModelRole.SenderIcon.int,
ModelRole.IsSenderIconIdenticon.int]
if(self.items[i].pinnedBy == contactId):
roles.add(ModelRole.PinnedBy.int)
if(self.items[i].messageContainsMentions):
roles.add(@[ModelRole.MessageText.int, ModelRole.MessageContainsMentions.int])
if(roles.len > 0):
let index = self.createIndex(i, 0, nil)

View File

@ -4,10 +4,32 @@ import json
include ../../../common/json_utils
const PARSED_TEXT_TYPE_PARAGRAPH* = "paragraph"
const PARSED_TEXT_TYPE_BLOCKQUOTE* = "blockquote"
const PARSED_TEXT_TYPE_CODEBLOCK* = "codeblock"
const PARSED_TEXT_CHILD_TYPE_CODE* = "code"
const PARSED_TEXT_CHILD_TYPE_EMPH* = "emph"
const PARSED_TEXT_CHILD_TYPE_STRONG* = "strong"
const PARSED_TEXT_CHILD_TYPE_STRONG_EMPH* = "strong-emph"
const PARSED_TEXT_CHILD_TYPE_MENTION* = "mention"
const PARSED_TEXT_CHILD_TYPE_STATUS_TAG* = "status-tag"
const PARSED_TEXT_CHILD_TYPE_DEL* = "del"
type ParsedTextChild* = object
`type`*: string
literal*: string
destination*: string
type ParsedText* = object
`type`*: string
literal*: string
children*: seq[ParsedTextChild]
type QuotedMessage* = object
`from`*: string
text*: string
#parsedText*: Not sure if we use it
parsedText*: seq[ParsedText]
type Sticker* = object
hash*: string
@ -27,7 +49,7 @@ type MessageDto* = object
outgoingStatus*: string
quotedMessage*: QuotedMessage
rtl*: bool
#parsedText*: Not sure if we use it
parsedText*: seq[ParsedText]
lineCount*: int
text*: string
chatId*: string
@ -44,10 +66,31 @@ type MessageDto* = object
messageType*: int
links*: seq[string]
proc toParsedTextChild*(jsonObj: JsonNode): ParsedTextChild =
result = ParsedTextChild()
discard jsonObj.getProp("type", result.type)
discard jsonObj.getProp("literal", result.literal)
discard jsonObj.getProp("destination", result.destination)
proc toParsedText*(jsonObj: JsonNode): ParsedText =
result = ParsedText()
discard jsonObj.getProp("type", result.type)
discard jsonObj.getProp("literal", result.literal)
var childrenArr: JsonNode
if(jsonObj.getProp("children", childrenArr) and childrenArr.kind == JArray):
for childObj in childrenArr:
result.children.add(toParsedTextChild(childObj))
proc toQuotedMessage*(jsonObj: JsonNode): QuotedMessage =
result = QuotedMessage()
discard jsonObj.getProp("from", result.from)
discard jsonObj.getProp("text", result.text)
var parsedTextArr: JsonNode
if(jsonObj.getProp("parsedText", parsedTextArr) and parsedTextArr.kind == JArray):
for pTextObj in parsedTextArr:
result.parsedText.add(toParsedText(pTextObj))
proc toSticker*(jsonObj: JsonNode): Sticker =
result = Sticker()
@ -97,4 +140,16 @@ proc toMessageDto*(jsonObj: JsonNode): MessageDto =
var linksArr: JsonNode
if(jsonObj.getProp("links", linksArr)):
for link in linksArr:
result.links.add(link.getStr)
result.links.add(link.getStr)
var parsedTextArr: JsonNode
if(jsonObj.getProp("parsedText", parsedTextArr) and parsedTextArr.kind == JArray):
for pTextObj in parsedTextArr:
result.parsedText.add(toParsedText(pTextObj))
proc containsContactMentions*(self: MessageDto): bool =
for pText in self.parsedText:
for child in pText.children:
if (child.type == PARSED_TEXT_CHILD_TYPE_MENTION):
return true
return false

View File

@ -1,10 +1,10 @@
import NimQml, tables, json, sequtils, chronicles
import NimQml, tables, json, re, sequtils, strformat, strutils, chronicles
import ../../../app/core/tasks/[qt, threadpool]
import ../../../app/core/signals/types
import ../../../app/core/eventemitter
import status/statusgo_backend_new/messages as status_go
import ../contacts/service as contact_service
import ./dto/message as message_dto
import ./dto/pinned_message as pinned_msg_dto
import ./dto/reaction as reaction_dto
@ -17,6 +17,7 @@ export reaction_dto
logScope:
topics = "messages-service"
let NEW_LINE = re"\n|\r" #must be defined as let, not const
const MESSAGES_PER_PAGE = 20
const CURSOR_VALUE_IGNORE = "ignore"
@ -66,6 +67,7 @@ QtObject:
type Service* = ref object of QObject
events: EventEmitter
threadpool: ThreadPool
contactService: contact_service.Service
msgCursor: Table[string, string]
lastUsedMsgCursor: Table[string, string]
pinnedMsgCursor: Table[string, string]
@ -75,11 +77,12 @@ QtObject:
proc delete*(self: Service) =
self.QObject.delete
proc newService*(events: EventEmitter, threadpool: ThreadPool): Service =
proc newService*(events: EventEmitter, threadpool: ThreadPool, contactService: contact_service.Service): Service =
new(result, delete)
result.QObject.setup
result.events = events
result.threadpool = threadpool
result.contactService = contactService
result.msgCursor = initTable[string, string]()
result.lastUsedMsgCursor = initTable[string, string]()
result.pinnedMsgCursor = initTable[string, string]()
@ -481,4 +484,62 @@ QtObject:
self.threadpool.start(arg)
proc getNumOfPinnedMessages*(self: Service, chatId: string): int =
return self.numOfPinnedMessagesPerChat[chatId]
return self.numOfPinnedMessagesPerChat[chatId]
# See render-inline in status-react/src/status_im/ui/screens/chat/message/message.cljs
proc renderInline(self: Service, parsedTextChild: ParsedTextChild): string =
let value = escape_html(parsedTextChild.literal)
.multiReplace(("\r\n", "<br/>"))
.multiReplace(("\n", "<br/>"))
.multiReplace((" ", "&nbsp;&nbsp;"))
case parsedTextChild.type:
of "":
result = value
of PARSED_TEXT_CHILD_TYPE_CODE:
result = fmt("<code>{value}</code>")
of PARSED_TEXT_CHILD_TYPE_EMPH:
result = fmt("<em>{value}</em>")
of PARSED_TEXT_CHILD_TYPE_STRONG:
result = fmt("<strong>{value}</strong>")
of PARSED_TEXT_CHILD_TYPE_STRONG_EMPH:
result = fmt(" <strong><em>{value}</em></strong> ")
of PARSED_TEXT_CHILD_TYPE_MENTION:
let contactDto = self.contactService.getContactById(value)
result = fmt("<a href=\"//{value}\" class=\"mention\">{contactDto.userNameOrAlias()}</a>")
of PARSED_TEXT_CHILD_TYPE_STATUS_TAG:
result = fmt("<a href=\"#{value}\" class=\"status-tag\">#{value}</a>")
of PARSED_TEXT_CHILD_TYPE_DEL:
result = fmt("<del>{value}</del>")
else:
result = fmt(" {value} ")
# See render-block in status-react/src/status_im/ui/screens/chat/message/message.cljs
proc getRenderedText*(self: Service, parsedTextArray: seq[ParsedText]): string =
for parsedText in parsedTextArray:
case parsedText.type:
of PARSED_TEXT_TYPE_PARAGRAPH:
result = result & "<p>"
for child in parsedText.children:
result = result & self.renderInline(child)
result = result & "</p>"
of PARSED_TEXT_TYPE_BLOCKQUOTE:
var
blockquote = escape_html(parsedText.literal)
lines = toSeq(blockquote.split(NEW_LINE))
for i in 0..(lines.len - 1):
if i + 1 >= lines.len:
continue
if lines[i + 1] != "":
lines[i] = lines[i] & "<br/>"
blockquote = lines.join("")
result = result & fmt(
"<table class=\"blockquote\">" &
"<tr>" &
"<td class=\"quoteline\" valign=\"middle\"></td>" &
"<td>{blockquote}</td>" &
"</tr>" &
"</table>")
of PARSED_TEXT_TYPE_CODEBLOCK:
result = result & "<code>" & escape_html(parsedText.literal) & "</code>"
result = result.strip()

View File

@ -52,8 +52,9 @@ Item {
height: root.veryLongChatText && !root.readMore ? Math.min(implicitHeight, 200) : implicitHeight
clip: height < implicitHeight
onLinkActivated: {
root.linkActivated(link)
// Not Refactored Yet
// root.linkActivated(link)
// if(link.startsWith("#")) {
// const channelName = link.substring(1);
// const foundChannelObj = root.store.chatsModelInst.getChannel(channelName);
@ -90,19 +91,20 @@ Item {
// return
// }
// if (link.startsWith('//')) {
// let pk = link.replace("//", "");
// Global.openProfilePopup(pk)
// return;
// }
if (link.startsWith('//')) {
let pk = link.replace("//", "");
Global.openProfilePopup(pk)
return;
}
// Not Refactored Yet
// const data = Utils.getLinkDataForStatusLinks(link)
// if (data && data.callback) {
// return data.callback()
// }
// Global.openLink(link)
Global.openLink(link)
}
onLinkHovered: {