diff --git a/src/app/boot/app_controller.nim b/src/app/boot/app_controller.nim
index b700addad4..7c872c295a 100644
--- a/src/app/boot/app_controller.nim
+++ b/src/app/boot/app_controller.nim
@@ -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,
diff --git a/src/app/modules/main/activity_center/controller.nim b/src/app/modules/main/activity_center/controller.nim
index 7bce1bdb16..e144a24890 100644
--- a/src/app/modules/main/activity_center/controller.nim
+++ b/src/app/modules/main/activity_center/controller.nim
@@ -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)
\ No newline at end of file
+ return self.activityCenterService.dismissActivityCenterNotifications(notificationIds)
+
+method getRenderedText*(self: Controller, parsedTextArray: seq[ParsedText]): string =
+ return self.messageService.getRenderedText(parsedTextArray)
\ No newline at end of file
diff --git a/src/app/modules/main/activity_center/controller_interface.nim b/src/app/modules/main/activity_center/controller_interface.nim
index 71fbd89422..440e303ea3 100644
--- a/src/app/modules/main/activity_center/controller_interface.nim
+++ b/src/app/modules/main/activity_center/controller_interface.nim
@@ -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.
diff --git a/src/app/modules/main/activity_center/module.nim b/src/app/modules/main/activity_center/module.nim
index 01e43406be..89e5e660a4 100644
--- a/src/app/modules/main/activity_center/module.nim
+++ b/src/app/modules/main/activity_center/module.nim
@@ -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),
diff --git a/src/app/modules/main/chat_section/chat_content/controller.nim b/src/app/modules/main/chat_section/chat_content/controller.nim
index 57e7e86b57..1ea7d7b62b 100644
--- a/src/app/modules/main/chat_section/chat_content/controller.nim
+++ b/src/app/modules/main/chat_section/chat_content/controller.nim
@@ -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()
\ No newline at end of file
+ return self.settingsService.getFleetAsString()
+
+method getRenderedText*(self: Controller, parsedTextArray: seq[ParsedText]): string =
+ return self.messageService.getRenderedText(parsedTextArray)
\ No newline at end of file
diff --git a/src/app/modules/main/chat_section/chat_content/controller_interface.nim b/src/app/modules/main/chat_section/chat_content/controller_interface.nim
index 670f361275..0a9f28e691 100644
--- a/src/app/modules/main/chat_section/chat_content/controller_interface.nim
+++ b/src/app/modules/main/chat_section/chat_content/controller_interface.nim
@@ -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")
\ No newline at end of file
diff --git a/src/app/modules/main/chat_section/chat_content/messages/controller.nim b/src/app/modules/main/chat_section/chat_content/messages/controller.nim
index f42ab9cb94..2f3308604a 100644
--- a/src/app/modules/main/chat_section/chat_content/messages/controller.nim
+++ b/src/app/modules/main/chat_section/chat_content/messages/controller.nim
@@ -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)
\ No newline at end of file
+ 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)
\ No newline at end of file
diff --git a/src/app/modules/main/chat_section/chat_content/messages/controller_interface.nim b/src/app/modules/main/chat_section/chat_content/messages/controller_interface.nim
index 6be3b2bb8b..151b3d59fa 100644
--- a/src/app/modules/main/chat_section/chat_content/messages/controller_interface.nim
+++ b/src/app/modules/main/chat_section/chat_content/messages/controller_interface.nim
@@ -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")
\ No newline at end of file
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 bbf5608412..3ac033d782 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
@@ -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)
\ No newline at end of file
+ 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()
+
+
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 3f195b3254..6aa8542118 100644
--- a/src/app/modules/main/chat_section/chat_content/module.nim
+++ b/src/app/modules/main/chat_section/chat_content/module.nim
@@ -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)
diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim
index 6b6e853e7b..83ffd2fc21 100644
--- a/src/app/modules/main/module.nim
+++ b/src/app/modules/main/module.nim
@@ -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)
diff --git a/src/app/modules/shared_models/message_item.nim b/src/app/modules/shared_models/message_item.nim
index 734699df02..9cc854f891 100644
--- a/src/app/modules/shared_models/message_item.nim
+++ b/src/app/modules/shared_models/message_item.nim
@@ -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,
diff --git a/src/app/modules/shared_models/message_model.nim b/src/app/modules/shared_models/message_model.nim
index 6071026c67..a13b9c95fc 100644
--- a/src/app/modules/shared_models/message_model.nim
+++ b/src/app/modules/shared_models/message_model.nim
@@ -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)
diff --git a/src/app_service/service/message/dto/message.nim b/src/app_service/service/message/dto/message.nim
index c0cfbc2886..cfcbe7b61a 100644
--- a/src/app_service/service/message/dto/message.nim
+++ b/src/app_service/service/message/dto/message.nim
@@ -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)
\ No newline at end of file
+ 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
\ No newline at end of file
diff --git a/src/app_service/service/message/service.nim b/src/app_service/service/message/service.nim
index f56e7c10b8..8c3b0cf90f 100644
--- a/src/app_service/service/message/service.nim
+++ b/src/app_service/service/message/service.nim
@@ -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]
\ No newline at end of file
+ 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", "
"))
+ .multiReplace(("\n", "
"))
+ .multiReplace((" ", " "))
+
+ case parsedTextChild.type:
+ of "":
+ result = value
+ of PARSED_TEXT_CHILD_TYPE_CODE:
+ result = fmt("{value}
")
+ of PARSED_TEXT_CHILD_TYPE_EMPH:
+ result = fmt("{value}")
+ of PARSED_TEXT_CHILD_TYPE_STRONG:
+ result = fmt("{value}")
+ of PARSED_TEXT_CHILD_TYPE_STRONG_EMPH:
+ result = fmt(" {value} ")
+ of PARSED_TEXT_CHILD_TYPE_MENTION:
+ let contactDto = self.contactService.getContactById(value)
+ result = fmt("{contactDto.userNameOrAlias()}")
+ of PARSED_TEXT_CHILD_TYPE_STATUS_TAG:
+ result = fmt("#{value}")
+ of PARSED_TEXT_CHILD_TYPE_DEL:
+ result = fmt("{value}")
+ 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 & "
" + for child in parsedText.children: + result = result & self.renderInline(child) + result = result & "
" + 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] & "" & + " | {blockquote} | " & + "
" & escape_html(parsedText.literal) & "
"
+ result = result.strip()
\ No newline at end of file
diff --git a/ui/imports/shared/views/chat/ChatTextView.qml b/ui/imports/shared/views/chat/ChatTextView.qml
index fbb5a6ff3b..4a901fa0ea 100644
--- a/ui/imports/shared/views/chat/ChatTextView.qml
+++ b/ui/imports/shared/views/chat/ChatTextView.qml
@@ -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: {