mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-22 03:28:52 +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.contactsService = contacts_service.newService(statusFoundation.events, statusFoundation.threadpool)
|
||||||
result.chatService = chat_service.newService(statusFoundation.events, result.contactsService)
|
result.chatService = chat_service.newService(statusFoundation.events, result.contactsService)
|
||||||
result.communityService = community_service.newService(statusFoundation.events, result.chatService)
|
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,
|
result.activityCenterService = activity_center_service.newService(statusFoundation.events,
|
||||||
statusFoundation.threadpool, result.chatService)
|
statusFoundation.threadpool, result.chatService)
|
||||||
result.tokenService = token_service.newService(statusFoundation.events, statusFoundation.threadpool,
|
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/activity_center/service as activity_center_service
|
||||||
import ../../../../app_service/service/contacts/service as contacts_service
|
import ../../../../app_service/service/contacts/service as contacts_service
|
||||||
import ../../../../app_service/service/chat/service as chat_service
|
import ../../../../app_service/service/chat/service as chat_service
|
||||||
|
import ../../../../app_service/service/message/service as message_service
|
||||||
|
|
||||||
export controller_interface
|
export controller_interface
|
||||||
|
|
||||||
@ -16,18 +17,21 @@ type
|
|||||||
events: EventEmitter
|
events: EventEmitter
|
||||||
activityCenterService: activity_center_service.Service
|
activityCenterService: activity_center_service.Service
|
||||||
contactsService: contacts_service.Service
|
contactsService: contacts_service.Service
|
||||||
|
messageService: message_service.Service
|
||||||
|
|
||||||
proc newController*[T](
|
proc newController*[T](
|
||||||
delegate: io_interface.AccessInterface,
|
delegate: io_interface.AccessInterface,
|
||||||
events: EventEmitter,
|
events: EventEmitter,
|
||||||
activityCenterService: activity_center_service.Service,
|
activityCenterService: activity_center_service.Service,
|
||||||
contactsService: contacts_service.Service
|
contactsService: contacts_service.Service,
|
||||||
|
messageService: message_service.Service
|
||||||
): Controller[T] =
|
): Controller[T] =
|
||||||
result = Controller[T]()
|
result = Controller[T]()
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
result.events = events
|
result.events = events
|
||||||
result.activityCenterService = activityCenterService
|
result.activityCenterService = activityCenterService
|
||||||
result.contactsService = contactsService
|
result.contactsService = contactsService
|
||||||
|
result.messageService = messageService
|
||||||
|
|
||||||
method delete*[T](self: Controller[T]) =
|
method delete*[T](self: Controller[T]) =
|
||||||
discard
|
discard
|
||||||
@ -103,3 +107,6 @@ method acceptActivityCenterNotifications*[T](self: Controller[T], notificationId
|
|||||||
|
|
||||||
method dismissActivityCenterNotifications*[T](self: Controller[T], notificationIds: seq[string]): string =
|
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/contacts/service as contacts_service
|
||||||
import ../../../../app_service/service/activity_center/service as activity_center_service
|
import ../../../../app_service/service/activity_center/service as activity_center_service
|
||||||
|
import ../../../../app_service/service/message/dto/[message]
|
||||||
|
|
||||||
type
|
type
|
||||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
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.} =
|
method dismissActivityCenterNotifications*(self: AccessInterface, notificationIds: seq[string]): string {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method getRenderedText*(self: AccessInterface, parsedTextArray: seq[ParsedText]): string {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
## Abstract class (concept) which must be implemented by object/s used in this
|
## Abstract class (concept) which must be implemented by object/s used in this
|
||||||
## module.
|
## module.
|
||||||
|
@ -8,6 +8,7 @@ import ../../../global/global_singleton
|
|||||||
import ../../../core/eventemitter
|
import ../../../core/eventemitter
|
||||||
import ../../../../app_service/service/activity_center/service as activity_center_service
|
import ../../../../app_service/service/activity_center/service as activity_center_service
|
||||||
import ../../../../app_service/service/contacts/service as contacts_service
|
import ../../../../app_service/service/contacts/service as contacts_service
|
||||||
|
import ../../../../app_service/service/message/service as message_service
|
||||||
|
|
||||||
export io_interface
|
export io_interface
|
||||||
|
|
||||||
@ -23,7 +24,8 @@ proc newModule*[T](
|
|||||||
delegate: T,
|
delegate: T,
|
||||||
events: EventEmitter,
|
events: EventEmitter,
|
||||||
activityCenterService: activity_center_service.Service,
|
activityCenterService: activity_center_service.Service,
|
||||||
contactsService: contacts_service.Service
|
contactsService: contacts_service.Service,
|
||||||
|
messageService: message_service.Service
|
||||||
): Module[T] =
|
): Module[T] =
|
||||||
result = Module[T]()
|
result = Module[T]()
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
@ -33,7 +35,8 @@ proc newModule*[T](
|
|||||||
result,
|
result,
|
||||||
events,
|
events,
|
||||||
activityCenterService,
|
activityCenterService,
|
||||||
contactsService
|
contactsService,
|
||||||
|
messageService
|
||||||
)
|
)
|
||||||
result.moduleLoaded = false
|
result.moduleLoaded = false
|
||||||
|
|
||||||
@ -78,8 +81,9 @@ method convertToItems*[T](
|
|||||||
contactDetails.isIdenticon,
|
contactDetails.isIdenticon,
|
||||||
contactDetails.isCurrentUser,
|
contactDetails.isCurrentUser,
|
||||||
n.message.outgoingStatus,
|
n.message.outgoingStatus,
|
||||||
n.message.text,
|
self.controller.getRenderedText(n.message.parsedText),
|
||||||
n.message.image,
|
n.message.image,
|
||||||
|
n.message.containsContactMentions(),
|
||||||
n.message.seen,
|
n.message.seen,
|
||||||
n.message.timestamp,
|
n.message.timestamp,
|
||||||
ContentType(n.message.contentType),
|
ContentType(n.message.contentType),
|
||||||
|
@ -150,3 +150,6 @@ method getContactDetails*(self: Controller, contactId: string): ContactDetails =
|
|||||||
|
|
||||||
method getCurrentFleet*(self: Controller): string =
|
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)
|
@ -66,3 +66,6 @@ method getContactDetails*(self: AccessInterface, contactId: string): ContactDeta
|
|||||||
|
|
||||||
method getCurrentFleet*(self: AccessInterface): string {.base.} =
|
method getCurrentFleet*(self: AccessInterface): string {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method getRenderedText*(self: AccessInterface, parsedTextArray: seq[ParsedText]): string {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
@ -140,3 +140,10 @@ method getContactDetails*(self: Controller, contactId: string): ContactDetails =
|
|||||||
|
|
||||||
method getNumOfPinnedMessages*(self: Controller): int =
|
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/contacts/dto/[contacts, contact_details]
|
||||||
import ../../../../../../app_service/service/community/dto/[community]
|
import ../../../../../../app_service/service/community/dto/[community]
|
||||||
import ../../../../../../app_service/service/chat/dto/[chat]
|
import ../../../../../../app_service/service/chat/dto/[chat]
|
||||||
|
import ../../../../../../app_service/service/message/dto/[message, reaction]
|
||||||
|
|
||||||
type
|
type
|
||||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||||
@ -51,3 +52,10 @@ method getContactDetails*(self: AccessInterface, contactId: string): ContactDeta
|
|||||||
|
|
||||||
method getNumOfPinnedMessages*(self: AccessInterface): int {.base.} =
|
method getNumOfPinnedMessages*(self: AccessInterface): int {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
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()
|
(chatName, chatIcon, isIdenticon) = self.controller.getOneToOneChatNameAndImage()
|
||||||
|
|
||||||
result = initItem(CHAT_IDENTIFIER_MESSAGE_ID, "", chatDto.id, chatName, "", chatIcon, isIdenticon, false, "", "", "",
|
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],
|
method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: seq[ReactionDto],
|
||||||
pinnedMessages: seq[PinnedMessageDto]) =
|
pinnedMessages: seq[PinnedMessageDto]) =
|
||||||
@ -83,9 +83,10 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
|
|||||||
for m in messages:
|
for m in messages:
|
||||||
let sender = self.controller.getContactDetails(m.`from`)
|
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,
|
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,
|
sender.isIdenticon, sender.isCurrentUser, m.outgoingStatus, renderedMessageText, m.image,
|
||||||
m.contentType.ContentType, m.messageType)
|
m.containsContactMentions(), m.seen, m.timestamp, m.contentType.ContentType, m.messageType)
|
||||||
|
|
||||||
for r in reactions:
|
for r in reactions:
|
||||||
if(r.messageId == m.id):
|
if(r.messageId == m.id):
|
||||||
@ -121,9 +122,10 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
|
|||||||
method messageAdded*(self: Module, message: MessageDto) =
|
method messageAdded*(self: Module, message: MessageDto) =
|
||||||
let sender = self.controller.getContactDetails(message.`from`)
|
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,
|
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,
|
sender.icon, sender.isIdenticon, sender.isCurrentUser, message.outgoingStatus, renderedMessageText, message.image,
|
||||||
message.seen, message.timestamp, message.contentType.ContentType, message.messageType)
|
message.containsContactMentions(), message.seen, message.timestamp, message.contentType.ContentType, message.messageType)
|
||||||
|
|
||||||
self.view.model().insertItemBasedOnTimestamp(item)
|
self.view.model().insertItemBasedOnTimestamp(item)
|
||||||
|
|
||||||
@ -199,5 +201,16 @@ method getNumberOfPinnedMessages*(self: Module): int =
|
|||||||
|
|
||||||
method updateContactDetails*(self: Module, contactId: string) =
|
method updateContactDetails*(self: Module, contactId: string) =
|
||||||
let updatedContact = self.controller.getContactDetails(contactId)
|
let updatedContact = self.controller.getContactDetails(contactId)
|
||||||
self.view.model().updateSenderDetails(contactId, updatedContact.displayName, updatedContact.details.localNickname,
|
for item in self.view.model().modelContactUpdateIterator(contactId):
|
||||||
updatedContact.icon, updatedContact.isIdenticon)
|
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.isIdenticon,
|
||||||
contactDetails.isCurrentUser,
|
contactDetails.isCurrentUser,
|
||||||
m.outgoingStatus,
|
m.outgoingStatus,
|
||||||
m.text,
|
self.controller.getRenderedText(m.parsedText),
|
||||||
m.image,
|
m.image,
|
||||||
|
m.containsContactMentions(),
|
||||||
m.seen,
|
m.seen,
|
||||||
m.timestamp,
|
m.timestamp,
|
||||||
m.contentType.ContentType,
|
m.contentType.ContentType,
|
||||||
@ -250,8 +251,18 @@ method amIChatAdmin*(self: Module): bool =
|
|||||||
|
|
||||||
method onContactDetailsUpdated*(self: Module, contactId: string) =
|
method onContactDetailsUpdated*(self: Module, contactId: string) =
|
||||||
let updatedContact = self.controller.getContactDetails(contactId)
|
let updatedContact = self.controller.getContactDetails(contactId)
|
||||||
self.view.pinnedModel().updateSenderDetails(contactId, updatedContact.displayName, updatedContact.details.localNickname,
|
for item in self.view.pinnedModel().modelContactUpdateIterator(contactId):
|
||||||
updatedContact.icon, updatedContact.isIdenticon)
|
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):
|
if(self.controller.getMyChatId() == contactId):
|
||||||
self.view.updateChatDetailsNameAndIcon(updatedContact.displayName, updatedContact.icon, updatedContact.isIdenticon)
|
self.view.updateChatDetailsNameAndIcon(updatedContact.displayName, updatedContact.icon, updatedContact.isIdenticon)
|
||||||
|
|
||||||
|
@ -125,7 +125,8 @@ proc newModule*[T](
|
|||||||
profileService, contactsService, aboutService, languageService, privacyService, nodeConfigurationService,
|
profileService, contactsService, aboutService, languageService, privacyService, nodeConfigurationService,
|
||||||
devicesService, mailserversService, chatService)
|
devicesService, mailserversService, chatService)
|
||||||
result.stickersModule = stickers_module.newModule(result, events, stickersService)
|
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.communitiesModule = communities_module.newModule(result, events, communityService)
|
||||||
result.appSearchModule = app_search_module.newModule(result, events, contactsService, chatService, communityService,
|
result.appSearchModule = app_search_module.newModule(result, events, contactsService, chatService, communityService,
|
||||||
messageService)
|
messageService)
|
||||||
|
@ -18,6 +18,7 @@ type
|
|||||||
outgoingStatus: string
|
outgoingStatus: string
|
||||||
messageText: string
|
messageText: string
|
||||||
messageImage: string
|
messageImage: string
|
||||||
|
messageContainsMentions: bool
|
||||||
stickerHash: string
|
stickerHash: string
|
||||||
stickerPack: int
|
stickerPack: int
|
||||||
gapFrom: int64
|
gapFrom: int64
|
||||||
@ -30,8 +31,8 @@ type
|
|||||||
pinnedBy: string
|
pinnedBy: string
|
||||||
|
|
||||||
proc initItem*(id, responseToMessageWithId, senderId, senderDisplayName, senderLocalName, senderIcon: string,
|
proc initItem*(id, responseToMessageWithId, senderId, senderDisplayName, senderLocalName, senderIcon: string,
|
||||||
isSenderIconIdenticon, amISender: bool, outgoingStatus, text, image: string, seen: bool, timestamp: int64,
|
isSenderIconIdenticon, amISender: bool, outgoingStatus, text, image: string, messageContainsMentions, seen: bool,
|
||||||
contentType: ContentType, messageType: int): Item =
|
timestamp: int64, contentType: ContentType, messageType: int): Item =
|
||||||
result = Item()
|
result = Item()
|
||||||
result.id = id
|
result.id = id
|
||||||
result.responseToMessageWithId = responseToMessageWithId
|
result.responseToMessageWithId = responseToMessageWithId
|
||||||
@ -45,6 +46,7 @@ proc initItem*(id, responseToMessageWithId, senderId, senderDisplayName, senderL
|
|||||||
result.outgoingStatus = outgoingStatus
|
result.outgoingStatus = outgoingStatus
|
||||||
result.messageText = text
|
result.messageText = text
|
||||||
result.messageImage = image
|
result.messageImage = image
|
||||||
|
result.messageContainsMentions = messageContainsMentions
|
||||||
result.timestamp = timestamp
|
result.timestamp = timestamp
|
||||||
result.contentType = contentType
|
result.contentType = contentType
|
||||||
result.messageType = messageType
|
result.messageType = messageType
|
||||||
@ -63,6 +65,7 @@ proc `$`*(self: Item): string =
|
|||||||
seen: {$self.seen},
|
seen: {$self.seen},
|
||||||
outgoingStatus:{$self.outgoingStatus},
|
outgoingStatus:{$self.outgoingStatus},
|
||||||
messageText:{self.messageText},
|
messageText:{self.messageText},
|
||||||
|
messageContainsMentions:{self.messageContainsMentions},
|
||||||
timestamp:{$self.timestamp},
|
timestamp:{$self.timestamp},
|
||||||
contentType:{$self.contentType.int},
|
contentType:{$self.contentType.int},
|
||||||
messageType:{$self.messageType},
|
messageType:{$self.messageType},
|
||||||
@ -113,9 +116,18 @@ proc outgoingStatus*(self: Item): string {.inline.} =
|
|||||||
proc messageText*(self: Item): string {.inline.} =
|
proc messageText*(self: Item): string {.inline.} =
|
||||||
self.messageText
|
self.messageText
|
||||||
|
|
||||||
|
proc `messageText=`*(self: Item, value: string) {.inline.} =
|
||||||
|
self.messageText = value
|
||||||
|
|
||||||
proc messageImage*(self: Item): string {.inline.} =
|
proc messageImage*(self: Item): string {.inline.} =
|
||||||
self.messageImage
|
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.} =
|
proc stickerPack*(self: Item): int {.inline.} =
|
||||||
self.stickerPack
|
self.stickerPack
|
||||||
|
|
||||||
@ -176,6 +188,7 @@ proc toJsonNode*(self: Item): JsonNode =
|
|||||||
"outgoingStatus": self.outgoingStatus,
|
"outgoingStatus": self.outgoingStatus,
|
||||||
"messageText": self.messageText,
|
"messageText": self.messageText,
|
||||||
"messageImage": self.messageImage,
|
"messageImage": self.messageImage,
|
||||||
|
"messageContainsMentions": self.messageContainsMentions,
|
||||||
"stickerHash": self.stickerHash,
|
"stickerHash": self.stickerHash,
|
||||||
"stickerPack": self.stickerPack,
|
"stickerPack": self.stickerPack,
|
||||||
"gapFrom": self.gapFrom,
|
"gapFrom": self.gapFrom,
|
||||||
|
@ -16,6 +16,8 @@ type
|
|||||||
OutgoingStatus
|
OutgoingStatus
|
||||||
MessageText
|
MessageText
|
||||||
MessageImage
|
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
|
Timestamp
|
||||||
ContentType
|
ContentType
|
||||||
MessageType
|
MessageType
|
||||||
@ -73,6 +75,7 @@ QtObject:
|
|||||||
ModelRole.OutgoingStatus.int:"outgoingStatus",
|
ModelRole.OutgoingStatus.int:"outgoingStatus",
|
||||||
ModelRole.MessageText.int:"messageText",
|
ModelRole.MessageText.int:"messageText",
|
||||||
ModelRole.MessageImage.int:"messageImage",
|
ModelRole.MessageImage.int:"messageImage",
|
||||||
|
ModelRole.MessageContainsMentions.int:"messageContainsMentions",
|
||||||
ModelRole.Timestamp.int:"timestamp",
|
ModelRole.Timestamp.int:"timestamp",
|
||||||
ModelRole.ContentType.int:"contentType",
|
ModelRole.ContentType.int:"contentType",
|
||||||
ModelRole.MessageType.int:"messageType",
|
ModelRole.MessageType.int:"messageType",
|
||||||
@ -120,6 +123,8 @@ QtObject:
|
|||||||
result = newQVariant(item.messageText)
|
result = newQVariant(item.messageText)
|
||||||
of ModelRole.MessageImage:
|
of ModelRole.MessageImage:
|
||||||
result = newQVariant(item.messageImage)
|
result = newQVariant(item.messageImage)
|
||||||
|
of ModelRole.MessageContainsMentions:
|
||||||
|
result = newQVariant(item.messageContainsMentions)
|
||||||
of ModelRole.Timestamp:
|
of ModelRole.Timestamp:
|
||||||
result = newQVariant(item.timestamp)
|
result = newQVariant(item.timestamp)
|
||||||
of ModelRole.ContentType:
|
of ModelRole.ContentType:
|
||||||
@ -272,18 +277,18 @@ QtObject:
|
|||||||
return
|
return
|
||||||
self.items[index].toJsonNode()
|
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:
|
for i in 0 ..< self.items.len:
|
||||||
|
yield self.items[i]
|
||||||
|
|
||||||
var roles: seq[int]
|
var roles: seq[int]
|
||||||
if(self.items[i].senderId == contactId):
|
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,
|
roles = @[ModelRole.SenderDisplayName.int, ModelRole.SenderLocalName.int, ModelRole.SenderIcon.int,
|
||||||
ModelRole.IsSenderIconIdenticon.int]
|
ModelRole.IsSenderIconIdenticon.int]
|
||||||
if(self.items[i].pinnedBy == contactId):
|
if(self.items[i].pinnedBy == contactId):
|
||||||
roles.add(ModelRole.PinnedBy.int)
|
roles.add(ModelRole.PinnedBy.int)
|
||||||
|
if(self.items[i].messageContainsMentions):
|
||||||
|
roles.add(@[ModelRole.MessageText.int, ModelRole.MessageContainsMentions.int])
|
||||||
|
|
||||||
if(roles.len > 0):
|
if(roles.len > 0):
|
||||||
let index = self.createIndex(i, 0, nil)
|
let index = self.createIndex(i, 0, nil)
|
||||||
|
@ -4,10 +4,32 @@ import json
|
|||||||
|
|
||||||
include ../../../common/json_utils
|
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
|
type QuotedMessage* = object
|
||||||
`from`*: string
|
`from`*: string
|
||||||
text*: string
|
text*: string
|
||||||
#parsedText*: Not sure if we use it
|
parsedText*: seq[ParsedText]
|
||||||
|
|
||||||
type Sticker* = object
|
type Sticker* = object
|
||||||
hash*: string
|
hash*: string
|
||||||
@ -27,7 +49,7 @@ type MessageDto* = object
|
|||||||
outgoingStatus*: string
|
outgoingStatus*: string
|
||||||
quotedMessage*: QuotedMessage
|
quotedMessage*: QuotedMessage
|
||||||
rtl*: bool
|
rtl*: bool
|
||||||
#parsedText*: Not sure if we use it
|
parsedText*: seq[ParsedText]
|
||||||
lineCount*: int
|
lineCount*: int
|
||||||
text*: string
|
text*: string
|
||||||
chatId*: string
|
chatId*: string
|
||||||
@ -44,11 +66,32 @@ type MessageDto* = object
|
|||||||
messageType*: int
|
messageType*: int
|
||||||
links*: seq[string]
|
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 =
|
proc toQuotedMessage*(jsonObj: JsonNode): QuotedMessage =
|
||||||
result = QuotedMessage()
|
result = QuotedMessage()
|
||||||
discard jsonObj.getProp("from", result.from)
|
discard jsonObj.getProp("from", result.from)
|
||||||
discard jsonObj.getProp("text", result.text)
|
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 =
|
proc toSticker*(jsonObj: JsonNode): Sticker =
|
||||||
result = Sticker()
|
result = Sticker()
|
||||||
discard jsonObj.getProp("hash", result.hash)
|
discard jsonObj.getProp("hash", result.hash)
|
||||||
@ -98,3 +141,15 @@ proc toMessageDto*(jsonObj: JsonNode): MessageDto =
|
|||||||
if(jsonObj.getProp("links", linksArr)):
|
if(jsonObj.getProp("links", linksArr)):
|
||||||
for link in 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/tasks/[qt, threadpool]
|
||||||
import ../../../app/core/signals/types
|
import ../../../app/core/signals/types
|
||||||
import ../../../app/core/eventemitter
|
import ../../../app/core/eventemitter
|
||||||
import status/statusgo_backend_new/messages as status_go
|
import status/statusgo_backend_new/messages as status_go
|
||||||
|
import ../contacts/service as contact_service
|
||||||
import ./dto/message as message_dto
|
import ./dto/message as message_dto
|
||||||
import ./dto/pinned_message as pinned_msg_dto
|
import ./dto/pinned_message as pinned_msg_dto
|
||||||
import ./dto/reaction as reaction_dto
|
import ./dto/reaction as reaction_dto
|
||||||
@ -17,6 +17,7 @@ export reaction_dto
|
|||||||
logScope:
|
logScope:
|
||||||
topics = "messages-service"
|
topics = "messages-service"
|
||||||
|
|
||||||
|
let NEW_LINE = re"\n|\r" #must be defined as let, not const
|
||||||
const MESSAGES_PER_PAGE = 20
|
const MESSAGES_PER_PAGE = 20
|
||||||
const CURSOR_VALUE_IGNORE = "ignore"
|
const CURSOR_VALUE_IGNORE = "ignore"
|
||||||
|
|
||||||
@ -66,6 +67,7 @@ QtObject:
|
|||||||
type Service* = ref object of QObject
|
type Service* = ref object of QObject
|
||||||
events: EventEmitter
|
events: EventEmitter
|
||||||
threadpool: ThreadPool
|
threadpool: ThreadPool
|
||||||
|
contactService: contact_service.Service
|
||||||
msgCursor: Table[string, string]
|
msgCursor: Table[string, string]
|
||||||
lastUsedMsgCursor: Table[string, string]
|
lastUsedMsgCursor: Table[string, string]
|
||||||
pinnedMsgCursor: Table[string, string]
|
pinnedMsgCursor: Table[string, string]
|
||||||
@ -75,11 +77,12 @@ QtObject:
|
|||||||
proc delete*(self: Service) =
|
proc delete*(self: Service) =
|
||||||
self.QObject.delete
|
self.QObject.delete
|
||||||
|
|
||||||
proc newService*(events: EventEmitter, threadpool: ThreadPool): Service =
|
proc newService*(events: EventEmitter, threadpool: ThreadPool, contactService: contact_service.Service): Service =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
result.QObject.setup
|
result.QObject.setup
|
||||||
result.events = events
|
result.events = events
|
||||||
result.threadpool = threadpool
|
result.threadpool = threadpool
|
||||||
|
result.contactService = contactService
|
||||||
result.msgCursor = initTable[string, string]()
|
result.msgCursor = initTable[string, string]()
|
||||||
result.lastUsedMsgCursor = initTable[string, string]()
|
result.lastUsedMsgCursor = initTable[string, string]()
|
||||||
result.pinnedMsgCursor = initTable[string, string]()
|
result.pinnedMsgCursor = initTable[string, string]()
|
||||||
@ -482,3 +485,61 @@ QtObject:
|
|||||||
|
|
||||||
proc getNumOfPinnedMessages*(self: Service, chatId: string): int =
|
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
|
height: root.veryLongChatText && !root.readMore ? Math.min(implicitHeight, 200) : implicitHeight
|
||||||
clip: height < implicitHeight
|
clip: height < implicitHeight
|
||||||
onLinkActivated: {
|
onLinkActivated: {
|
||||||
|
root.linkActivated(link)
|
||||||
|
|
||||||
// Not Refactored Yet
|
// Not Refactored Yet
|
||||||
// root.linkActivated(link)
|
|
||||||
// if(link.startsWith("#")) {
|
// if(link.startsWith("#")) {
|
||||||
// const channelName = link.substring(1);
|
// const channelName = link.substring(1);
|
||||||
// const foundChannelObj = root.store.chatsModelInst.getChannel(channelName);
|
// const foundChannelObj = root.store.chatsModelInst.getChannel(channelName);
|
||||||
@ -90,19 +91,20 @@ Item {
|
|||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if (link.startsWith('//')) {
|
if (link.startsWith('//')) {
|
||||||
// let pk = link.replace("//", "");
|
let pk = link.replace("//", "");
|
||||||
// Global.openProfilePopup(pk)
|
Global.openProfilePopup(pk)
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
// Not Refactored Yet
|
||||||
// const data = Utils.getLinkDataForStatusLinks(link)
|
// const data = Utils.getLinkDataForStatusLinks(link)
|
||||||
// if (data && data.callback) {
|
// if (data && data.callback) {
|
||||||
// return data.callback()
|
// return data.callback()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
// Global.openLink(link)
|
Global.openLink(link)
|
||||||
}
|
}
|
||||||
|
|
||||||
onLinkHovered: {
|
onLinkHovered: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user