mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-19 10:09:38 +00:00
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:
parent
35568d1d6b
commit
f7e8b68715
@ -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,
|
||||
|
@ -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)
|
@ -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.
|
||||
|
@ -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),
|
||||
|
@ -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)
|
@ -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")
|
@ -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)
|
@ -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")
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
@ -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((" ", " "))
|
||||
|
||||
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()
|
@ -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: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user