feat: use QuotedMessage object for replies to better show the replies

Fixes #7754
ok
This commit is contained in:
Jonathan Rainville 2023-01-12 14:23:26 -05:00 committed by Iuri Matias
parent c16e4fe3d2
commit 91c2e6d257
13 changed files with 201 additions and 153 deletions

View File

@ -99,7 +99,11 @@ proc createMessageItemFromDto(self: Module, message: MessageDto, chatDetails: Ch
contactDetails.details.ensVerified,
message.discordMessage,
resendError = "",
message.mentioned
message.mentioned,
message.quotedMessage.`from`,
message.quotedMessage.text,
self.controller.getRenderedText( message.quotedMessage.parsedText),
message.quotedMessage.contentType
))
method convertToItems*(

View File

@ -103,7 +103,11 @@ proc createFetchMoreMessagesItem(self: Module): Item =
senderEnsVerified = false,
DiscordMessage(),
resendError = "",
mentioned = false
mentioned = false,
quotedMessageFrom = "",
quotedMessageText = "",
quotedMessageParsedText = "",
quotedMessageContentType = -1
)
proc createChatIdentifierItem(self: Module): Item =
@ -146,7 +150,11 @@ proc createChatIdentifierItem(self: Module): Item =
senderEnsVerified = false,
DiscordMessage(),
resendError = "",
mentioned = false
mentioned = false,
quotedMessageFrom = "",
quotedMessageText = "",
quotedMessageParsedText = "",
quotedMessageContentType = -1
)
proc checkIfMessageLoadedAndScrollToItIfItIs(self: Module) =
@ -228,7 +236,11 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
sender.details.ensVerified,
m.discordMessage,
resendError = "",
m.mentioned
m.mentioned,
m.quotedMessage.`from`,
m.quotedMessage.text,
self.controller.getRenderedText(m.quotedMessage.parsedText),
m.quotedMessage.contentType
)
for r in reactions:
@ -329,7 +341,11 @@ method messageAdded*(self: Module, message: MessageDto) =
sender.details.ensVerified,
message.discordMessage,
resendError = "",
message.mentioned
message.mentioned,
message.quotedMessage.`from`,
message.quotedMessage.text,
self.controller.getRenderedText(message.quotedMessage.parsedText),
message.quotedMessage.contentType
)
self.view.model().insertItemBasedOnClock(item)
@ -483,11 +499,12 @@ method onMessageEdited*(self: Module, message: MessageDto) =
return
let mentionedUsersPks = itemBeforeChange.mentionedUsersPks
let renderedMessageText = self.controller.getRenderedText(message.parsedText)
self.view.model().updateEditedMsg(
message.id,
renderedMessageText,
self.controller.getRenderedText(message.parsedText),
message.text,
message.contentType,
message.containsContactMentions(),
message.links,
message.mentionedUsersPks
@ -496,13 +513,6 @@ method onMessageEdited*(self: Module, message: MessageDto) =
# ask service to send SIGNAL_MENTIONED_IN_EDITED_MESSAGE signal if there is a new user's mention
self.controller.checkEditedMessageForMentions(self.getChatId(), message, mentionedUsersPks)
let messagesIds = self.view.model().findIdsOfTheMessagesWhichRespondedToMessageWithId(message.id)
for msgId in messagesIds:
# refreshing an item calling `self.view.model().refreshItemWithId(msgId)` doesn't work from some very weird reason
# and that would be the correct way of updating item instead sending this signal. We should check this once we refactor
# qml part.
self.view.emitRefreshAMessageUserRespondedToSignal(msgId)
method onHistoryCleared*(self: Module) =
self.view.model().clear()
@ -616,7 +626,11 @@ method getMessageById*(self: Module, messageId: string): message_item.Item =
sender.details.ensVerified,
m.discordMessage,
resendError = "",
m.mentioned
m.mentioned,
m.quotedMessage.`from`,
m.quotedMessage.text,
self.controller.getRenderedText(m.quotedMessage.parsedText),
m.quotedMessage.contentType
)
return item
return nil

View File

@ -58,19 +58,6 @@ QtObject:
return ""
return $jsonObj
proc getReplyMessageByIdAsJson*(self: View, messageId: string): string {.slot.} =
var jsonObj = self.model.getMessageByIdAsJson(messageId)
if(jsonObj.isNil):
# trying to get message from status-go
let messageItem = self.delegate.getMessageById(messageId)
if messageItem == nil:
return ""
jsonObj = messageItem.toJsonNode();
if(jsonObj.isNil):
return ""
return $jsonObj
proc getSectionId*(self: View): string {.slot.} =
return self.delegate.getSectionId()
@ -159,10 +146,6 @@ QtObject:
proc leaveChat*(self: View) {.slot.} =
self.delegate.leaveChat()
proc refreshAMessageUserRespondedTo(self: View, msgId: string) {.signal.}
proc emitRefreshAMessageUserRespondedToSignal*(self: View, msgId: string) =
self.refreshAMessageUserRespondedTo(msgId)
proc jumpToMessage*(self: View, messageId: string) {.slot.} =
self.delegate.scrollToMessage(messageId)

View File

@ -199,7 +199,11 @@ proc buildPinnedMessageItem(self: Module, messageId: string, actionInitiatedBy:
contactDetails.details.ensVerified,
m.discordMessage,
resendError = "",
m.mentioned
m.mentioned,
m.quotedMessage.`from`,
m.quotedMessage.text,
self.controller.getRenderedText(m.quotedMessage.parsedText),
m.quotedMessage.contentType
)
item.pinned = true
item.pinnedBy = actionInitiatedBy

View File

@ -44,6 +44,12 @@ type
messageAttachments: seq[string]
resendError: string
mentioned: bool
quotedMessageFrom: string
quotedMessageText: string
quotedMessageParsedText: string
quotedMessageContentType: int
# This is only used to update the author's details when author's details change
quotedMessageFromIterator: int
proc initItem*(
id,
@ -74,7 +80,11 @@ proc initItem*(
senderEnsVerified: bool,
discordMessage: DiscordMessage,
resendError: string,
mentioned: bool
mentioned: bool,
quotedMessageFrom: string,
quotedMessageText: string,
quotedMessageParsedText: string,
quotedMessageContentType: int
): Item =
result = Item()
result.id = id
@ -112,6 +122,11 @@ proc initItem*(
result.messageAttachments = @[]
result.resendError = resendError
result.mentioned = mentioned
result.quotedMessageFrom = quotedMessageFrom
result.quotedMessageText = quotedMessageText
result.quotedMessageParsedText = quotedMessageParsedText
result.quotedMessageContentType = quotedMessageContentType
result.quotedMessageFromIterator = 0
if ContentType.DiscordMessage == contentType:
if result.messageText == "":
@ -161,7 +176,11 @@ proc initNewMessagesMarkerItem*(clock, timestamp: int64): Item =
senderEnsVerified = false,
discordMessage = DiscordMessage(),
resendError = "",
mentioned = false
mentioned = false,
quotedMessageFrom = "",
quotedMessageText = "",
quotedMessageParsedText = "",
quotedMessageContentType = -1
)
proc `$`*(self: Item): string =
@ -378,7 +397,12 @@ proc toJsonNode*(self: Item): JsonNode =
"links": self.links,
"mentionedUsersPks": self.mentionedUsersPks,
"senderEnsVerified": self.senderEnsVerified,
"resendError": self.resendError
"resendError": self.resendError,
"mentioned": self.mentioned,
"quotedMessageFrom": self.quotedMessageFrom,
"quotedMessageText": self.quotedMessageText,
"quotedMessageParsedText": self.quotedMessageParsedText,
"quotedMessageContentType": self.quotedMessageContentType,
}
proc editMode*(self: Item): bool {.inline.} =
@ -410,3 +434,28 @@ proc mentioned*(self: Item): bool {.inline.} =
proc `mentioned=`*(self: Item, value: bool) {.inline.} =
self.mentioned = value
proc quotedMessageFrom*(self: Item): string {.inline.} =
self.quotedMessageFrom
proc `quotedMessageFrom=`*(self: Item, value: string) {.inline.} =
self.quotedMessageFrom = value
proc quotedMessageText*(self: Item): string {.inline.} =
self.quotedMessageText
proc `quotedMessageText=`*(self: Item, value: string) {.inline.} =
self.quotedMessageText = value
proc quotedMessageParsedText*(self: Item): string {.inline.} =
self.quotedMessageParsedText
proc `quotedMessageParsedText=`*(self: Item, value: string) {.inline.} =
self.quotedMessageParsedText = value
proc quotedMessageContentType*(self: Item): int {.inline.} =
self.quotedMessageContentType
proc `quotedMessageContentType=`*(self: Item, value: int) {.inline.} =
self.quotedMessageContentType = value
proc quotedMessageFromIterator*(self: Item): int {.inline.} =
self.quotedMessageFromIterator
proc `quotedMessageFromIterator=`*(self: Item, value: int) {.inline.} =
self.quotedMessageFromIterator = value

View File

@ -26,6 +26,22 @@ QtObject:
QtProperty[string] responseToMessageWithId:
read = responseToMessageWithId
proc quotedMessageFrom*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.quotedMessageFrom
QtProperty[string] quotedMessageFrom:
read = quotedMessageFrom
proc quotedMessageText*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.quotedMessageText
QtProperty[string] quotedMessageText:
read = quotedMessageText
proc quotedMessageParsedText*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.quotedMessageParsedText
QtProperty[string] quotedMessageParsedText:
read = quotedMessageParsedText
proc quotedMessageContentType*(self: MessageItem): int {.slot.} = result = ?.self.messageItem.quotedMessageContentType
QtProperty[int] quotedMessageContentType:
read = quotedMessageContentType
proc senderId*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.senderId
QtProperty[string] senderId:
read = senderId

View File

@ -44,6 +44,11 @@ type
MessageAttachments
ResendError
Mentioned
QuotedMessageFrom
QuotedMessageText
QuotedMessageParsedText
QuotedMessageContentType
QuotedMessageFromIterator
QtObject:
type
@ -127,7 +132,12 @@ QtObject:
ModelRole.MentionedUsersPks.int: "mentionedUsersPks",
ModelRole.SenderTrustStatus.int: "senderTrustStatus",
ModelRole.SenderEnsVerified.int: "senderEnsVerified",
ModelRole.MessageAttachments.int: "messageAttachments"
ModelRole.MessageAttachments.int: "messageAttachments",
ModelRole.QuotedMessageFrom.int: "quotedMessageFrom",
ModelRole.QuotedMessageFromIterator.int: "quotedMessageFromIterator",
ModelRole.QuotedMessageText.int: "quotedMessageText",
ModelRole.QuotedMessageParsedText.int: "quotedMessageParsedText",
ModelRole.QuotedMessageContentType.int: "quotedMessageContentType"
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
@ -179,6 +189,16 @@ QtObject:
result = newQVariant(item.resendError)
of ModelRole.Mentioned:
result = newQVariant(item.mentioned)
of ModelRole.QuotedMessageFrom:
result = newQVariant(item.quotedMessageFrom)
of ModelRole.QuotedMessageFromIterator:
result = newQVariant(item.quotedMessageFromIterator)
of ModelRole.QuotedMessageText:
result = newQVariant(item.quotedMessageText)
of ModelRole.QuotedMessageParsedText:
result = newQVariant(item.quotedMessageParsedText)
of ModelRole.QuotedMessageContentType:
result = newQVariant(item.quotedMessageContentType)
of ModelRole.MessageText:
result = newQVariant(item.messageText)
of ModelRole.MessageImage:
@ -279,13 +299,16 @@ QtObject:
for item in items:
self.insertItemBasedOnClock(item)
proc replyDeleted*(self: Model, messageIndex: int) {.signal.}
proc updateMessagesWithResponseTo(self: Model, messageId: string) =
for i in 0 ..< self.items.len:
if(self.items[i].responseToMessageWithId == messageId):
let ind = self.createIndex(i, 0, nil)
self.replyDeleted(i)
var item = self.items[i]
item.quotedMessageText = ""
item.quotedMessageParsedText = ""
item.quotedMessageFrom = ""
self.dataChanged(ind, ind, @[ModelRole.QuotedMessageFrom.int, ModelRole.QuotedMessageParsedText.int, ModelRole.QuotedMessageContentType.int])
proc removeItem*(self: Model, messageId: string) =
let ind = self.findIndexForMessageId(messageId)
@ -393,12 +416,6 @@ QtObject:
return
self.items[index].toJsonNode()
proc updateContactInReplies(self: Model, messageId: string) =
for i in 0 ..< self.items.len:
if (self.items[i].responseToMessageWithId == messageId):
let index = self.createIndex(i, 0, nil)
self.dataChanged(index, index, @[ModelRole.ResponseToMessageWithId.int])
iterator modelContactUpdateIterator*(self: Model, contactId: string): Item =
for i in 0 ..< self.items.len:
yield self.items[i]
@ -416,10 +433,15 @@ QtObject:
if(self.items[i].messageContainsMentions):
roles.add(@[ModelRole.MessageText.int, ModelRole.MessageContainsMentions.int])
if (self.items[i].quotedMessageFrom == contactId):
# If there is a quoted message whom the author changed, increase the iterator to force
# the view to re-fetch the author's details
self.items[i].quotedMessageFromIterator = self.items[i].quotedMessageFromIterator + 1
roles.add(ModelRole.QuotedMessageFromIterator.int)
if(roles.len > 0):
let index = self.createIndex(i, 0, nil)
self.dataChanged(index, index, roles)
self.updateContactInReplies(self.items[i].id)
proc setEditModeOn*(self: Model, messageId: string) =
let ind = self.findIndexForMessageId(messageId)
@ -445,6 +467,8 @@ QtObject:
self: Model,
messageId: string,
updatedMsg: string,
updatedRawMsg: string,
contentType: int,
messageContainsMentions: bool,
links: seq[string],
mentionedUsersPks: seq[string]
@ -468,7 +492,18 @@ QtObject:
ModelRole.MentionedUsersPks.int
])
self.updateContactInReplies(messageId)
# Update replied to messages if there are
for i in 0 ..< self.items.len:
if(self.items[i].responseToMessageWithId == messageId):
self.items[i].quotedMessageParsedText = updatedMsg
self.items[i].quotedMessageText = updatedRawMsg
self.items[i].quotedMessageContentType = contentType
let index = self.createIndex(i, 0, nil)
self.dataChanged(index, index, @[
ModelRole.QuotedMessageText.int,
ModelRole.QuotedMessageParsedText.int,
ModelRole.QuotedMessageContentType.int,
])
proc clear*(self: Model) =
self.beginResetModel()

View File

@ -35,6 +35,7 @@ type QuotedMessage* = object
`from`*: string
text*: string
parsedText*: seq[ParsedText]
contentType*: int
type DiscordMessageAttachment* = object
id*: string
@ -161,8 +162,9 @@ proc toDiscordMessage*(jsonObj: JsonNode): DiscordMessage =
proc toQuotedMessage*(jsonObj: JsonNode): QuotedMessage =
result = QuotedMessage()
discard jsonObj.getProp("from", result.from)
discard jsonObj.getProp("from", result.`from`)
discard jsonObj.getProp("text", result.text)
discard jsonObj.getProp("contentType", result.contentType)
var parsedTextArr: JsonNode
if(jsonObj.getProp("parsedText", parsedTextArr) and parsedTextArr.kind == JArray):

View File

@ -38,7 +38,11 @@ proc createTestMessageItem(id: string, clock: int64): Item =
senderEnsVerified = false,
discordMessage = DiscordMessage(),
resendError = "",
mentioned = false
mentioned = false,
quotedMessageFrom = "",
quotedMessageText = "",
quotedMessageParsedText = "",
quotedMessageContentType = -1
)
let message0_chatIdentifier = createTestMessageItem("chat-identifier", -2)

View File

@ -50,28 +50,6 @@ QtObject {
return obj
}
function getReplyMessageByIdAsJson(messageId: string) {
if (!messageModule) {
console.warn("getReplyMessageByIdAsJson: Failed to parse message, because messageModule is not set")
return false
}
const jsonObj = messageModule.getReplyMessageByIdAsJson(messageId)
if (jsonObj === "") {
console.warn("getReplyMessageByIdAsJson: Failed to get message, returned json is empty")
return undefined
}
const obj = JSON.parse(jsonObj)
if (obj.error) {
// This log is available only in debug mode, if it's annoying we can remove it
console.debug("getReplyMessageByIdAsJson: Failed to parse message for index: ", messageId, " error: ", obj.error)
return false
}
return obj
}
function getMessageByIndexAsJson (index) {
if(!messageModule)
return false

View File

@ -218,25 +218,6 @@ Item {
}
}
Connections {
target: chatLogView.model || null
function onDataChanged(topLeft, bottomRight, roles) {
if (roles.indexOf(Constants.messageModelRoles.responseToMessageWithId) !== -1) {
let item = chatLogView.itemAtIndex(topLeft.row)
if (item) {
item.updateReplyInfo()
}
}
}
function onReplyDeleted(messageIndex) {
let item = chatLogView.itemAtIndex(messageIndex)
if (item) {
item.replyDeleted()
}
}
}
delegate: MessageView {
id: msgDelegate
@ -286,6 +267,10 @@ Item {
messageAttachments: model.messageAttachments
transactionParams: model.transactionParameters
hasMention: model.mentioned
quotedMessageText: model.quotedMessageParsedText
quotedMessageFrom: model.quotedMessageFrom
quotedMessageContentType: model.quotedMessageContentType
quotedMessageFromIterator: model.quotedMessageFromIterator
gapFrom: model.gapFrom
gapTo: model.gapTo

View File

@ -37,7 +37,6 @@ Loader {
property string messageId: ""
property string communityId: ""
property string responseToMessageWithId: ""
property string senderId: ""
property string senderDisplayName: ""
@ -61,6 +60,13 @@ Loader {
property string messageAttachments: ""
property var transactionParams
property string responseToMessageWithId: ""
property string quotedMessageText: ""
property string quotedMessageFrom: ""
property int quotedMessageContentType: Constants.messageContentType.messageType
property int quotedMessageFromIterator: -1
property var quotedMessageAuthorDetails: quotedMessageFromIterator >= 0 && Utils.getContactDetailsAsJson(quotedMessageFrom, false)
// External behavior changers
property bool isInPinnedPopup: false // The pinned popup limits the number of buttons shown
property bool disableHover: false // Used to force the HoverHandler to be active (useful for messages in popups)
@ -151,15 +157,15 @@ Loader {
messageContextMenu.isSticker = isSticker
messageContextMenu.hideEmojiPicker = hideEmojiPicker
if (isReply){
let obj = messageStore.getMessageByIdAsJson(responseToMessageWithId)
if(!obj)
if (isReply) {
if (!quotedMessageFrom) {
// The responseTo message was deleted so we don't eneble to right click the unaviable profile
return
messageContextMenu.messageSenderId = obj.senderId
messageContextMenu.selectedUserPublicKey = obj.senderId
messageContextMenu.selectedUserDisplayName = obj.senderDisplayName
messageContextMenu.selectedUserIcon = obj.senderIcon
}
messageContextMenu.messageSenderId = quotedMessageFrom
messageContextMenu.selectedUserPublicKey = quotedMessageFrom
messageContextMenu.selectedUserDisplayName = quotedMessageAuthorDetails.displayName
messageContextMenu.selectedUserIcon = quotedMessageAuthorDetails.thumbnailImage
}
messageContextMenu.parent = sender;
@ -196,22 +202,6 @@ Loader {
}
}
function updateReplyInfo() {
switch(messageContentType) {
case Constants.messageContentType.chatIdentifier:
case Constants.messageContentType.fetchMoreMessagesButton:
case Constants.messageContentType.systemMessagePrivateGroupType:
case Constants.messageContentType.gapType:
return
default:
item.updateReplyInfo()
}
}
function replyDeleted() {
item.replyDeleted()
}
QtObject {
id: d
@ -359,14 +349,6 @@ Loader {
delegate.startMessageFoundAnimation();
}
function updateReplyInfo() {
delegate.replyMessage = delegate.getReplyMessage()
}
function replyDeleted() {
delegate.replyMessage = null
}
StatusDateGroupLabel {
id: dateGroupLabel
Layout.fillWidth: true
@ -411,18 +393,9 @@ Loader {
readonly property int contentType: convertContentType(root.messageContentType)
readonly property bool isReply: root.responseToMessageWithId !== ""
property var replyMessage: getReplyMessage()
readonly property string replySenderId: replyMessage ? replyMessage.senderId : ""
property string originalMessageText: ""
function getReplyMessage() {
return root.messageStore && isReply
? root.messageStore.getReplyMessageByIdAsJson(root.responseToMessageWithId)
: null
}
function editCancelledHandler() {
root.messageStore.setEditModeOff(root.messageId)
}
@ -636,37 +609,38 @@ Loader {
}
replyDetails: StatusMessageDetails {
messageText: delegate.replyMessage ? delegate.replyMessage.messageText
//: deleted message
: qsTr("&lt;deleted&gt;")
contentType: delegate.replyMessage ? delegate.convertContentType(delegate.replyMessage.contentType) : 0
messageText: root.quotedMessageText ? root.quotedMessageText
: qsTr("Message deleted")
contentType: delegate.convertContentType(root.quotedMessageContentType)
messageContent: {
if (!delegate.replyMessage)
return "";
if (contentType !== StatusMessage.ContentType.Sticker && contentType !== StatusMessage.ContentType.Image) {
return ""
}
let message = root.messageStore.getMessageByIdAsJson(responseToMessageWithId)
switch (contentType) {
case StatusMessage.ContentType.Sticker:
return delegate.replyMessage.sticker;
return message.sticker;
case StatusMessage.ContentType.Image:
return delegate.replyMessage.messageImage;
return message.messageImage;
}
return "";
}
amISender: delegate.replyMessage && delegate.replyMessage.amISender
sender.id: delegate.replyMessage ? delegate.replyMessage.senderId : ""
sender.isContact: delegate.replyMessage && delegate.replyMessage.senderIsAdded
sender.displayName: delegate.replyMessage ? delegate.replyMessage.senderDisplayName: ""
sender.isEnsVerified: delegate.replyMessage && delegate.replyMessage.senderEnsVerified
sender.secondaryName: delegate.replyMessage ? delegate.replyMessage.senderOptionalName : ""
amISender: root.quotedMessageFrom === userProfile.pubKey
sender.id: root.quotedMessageFrom
sender.isContact: quotedMessageAuthorDetails.isContact
sender.displayName: quotedMessageAuthorDetails.displayName
sender.isEnsVerified: quotedMessageAuthorDetails.ensVerified
sender.secondaryName: quotedMessageAuthorDetails.name || ""
sender.profileImage {
width: 20
height: 20
name: delegate.replyMessage ? delegate.replyMessage.senderIcon : ""
assetSettings.isImage: delegate.replyMessage && (delegate.replyMessage.contentType === Constants.messageContentType.discordMessageType || delegate.replyMessage.senderIcon.startsWith("data"))
showRing: (delegate.replyMessage && delegate.replyMessage.contentType !== Constants.messageContentType.discordMessageType) && !sender.isEnsVerified
pubkey: delegate.replySenderId
colorId: Utils.colorIdForPubkey(delegate.replySenderId)
colorHash: Utils.getColorHashAsJson(delegate.replySenderId, sender.isEnsVerified)
name: quotedMessageAuthorDetails.thumbnailImage
assetSettings.isImage: quotedMessageAuthorDetails.thumbnailImage !== ""
showRing: (root.quotedMessageContentType !== Constants.messageContentType.discordMessageType) && !sender.isEnsVerified
pubkey: sender.id
colorId: Utils.colorIdForPubkey(sender.id)
colorHash: Utils.getColorHashAsJson(sender.id, sender.isEnsVerified)
}
}

View File

@ -538,7 +538,7 @@ QtObject {
incomingVerificationStatus: Constants.verificationStatus.unverified
}
if (!mainModuleInst)
if (!mainModuleInst || !publicKey)
return defaultValue
const jsonObj = mainModuleInst.getContactDetailsAsJson(publicKey, getVerificationRequest)