fix(chat): Sent images with text correctly

Fixes: #9564 #6374
This commit is contained in:
Boris Melnik 2023-03-06 15:47:35 +06:00
parent 6c3d5c3ab5
commit 30b4d9eb5c
18 changed files with 191 additions and 39 deletions

View File

@ -130,7 +130,10 @@ proc createMessageItemFromDto(self: Module, message: MessageDto, chatDetails: Ch
message.quotedMessage.contentType,
message.quotedMessage.deleted,
message.quotedMessage.discordMessage,
quotedMessageAuthorDetails
quotedMessageAuthorDetails,
message.albumId,
if (len(message.albumId) == 0): @[] else: @[message.image],
if (len(message.albumId) == 0): @[] else: @[message.id],
))
method convertToItems*(

View File

@ -76,8 +76,8 @@ proc getChatId*(self: Controller): string =
proc belongsToCommunity*(self: Controller): bool =
return self.belongsToCommunity
proc sendImages*(self: Controller, imagePathsAndDataJson: string): string =
self.chatService.sendImages(self.chatId, imagePathsAndDataJson)
proc sendImages*(self: Controller, imagePathsAndDataJson: string, msg: string): string =
self.chatService.sendImages(self.chatId, imagePathsAndDataJson, msg)
proc sendChatMessage*(
self: Controller,

View File

@ -20,7 +20,7 @@ method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
method sendChatMessage*(self: AccessInterface, msg: string, replyTo: string, contentType: int) {.base.} =
raise newException(ValueError, "No implementation available")
method sendImages*(self: AccessInterface, imagePathsJson: string): string {.base.} =
method sendImages*(self: AccessInterface, imagePathsJson: string, msg: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method requestAddressForTransaction*(self: AccessInterface, fromAddress: string, amount: string, tokenAddress: string) {.base.} =

View File

@ -62,8 +62,8 @@ method getModuleAsVariant*(self: Module): QVariant =
method getChatId*(self: Module): string =
return self.controller.getChatId()
method sendImages*(self: Module, imagePathsAndDataJson: string): string =
self.controller.sendImages(imagePathsAndDataJson)
method sendImages*(self: Module, imagePathsAndDataJson: string, msg: string): string =
self.controller.sendImages(imagePathsAndDataJson, msg)
method sendChatMessage*(
self: Module,

View File

@ -38,8 +38,8 @@ QtObject:
contentType: int) {.slot.} =
self.delegate.sendChatMessage(msg, replyTo, contentType)
proc sendImages*(self: View, imagePathsAndDataJson: string): string {.slot.} =
self.delegate.sendImages(imagePathsAndDataJson)
proc sendImages*(self: View, imagePathsAndDataJson: string, msg: string): string {.slot.} =
self.delegate.sendImages(imagePathsAndDataJson, msg)
proc acceptAddressRequest*(self: View, messageId: string , address: string) {.slot.} =
self.delegate.acceptRequestAddressForTransaction(messageId, address)

View File

@ -49,6 +49,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitt
proc createChatIdentifierItem(self: Module): Item
proc createFetchMoreMessagesItem(self: Module): Item
proc setChatDetails(self: Module, chatDetails: ChatDto)
proc updateItemsByAlbum(self: Module, items: var seq[Item], message: MessageDto): bool
method delete*(self: Module) =
self.controller.delete
@ -117,7 +118,10 @@ proc createFetchMoreMessagesItem(self: Module): Item =
quotedMessageContentType = -1,
quotedMessageDeleted = false,
quotedMessageDiscordMessage = DiscordMessage(),
quotedMessageAuthorDetails = ContactDetails()
quotedMessageAuthorDetails = ContactDetails(),
albumId = "",
albumMessageImages = @[],
albumMessageIds = @[],
)
proc createChatIdentifierItem(self: Module): Item =
@ -172,7 +176,10 @@ proc createChatIdentifierItem(self: Module): Item =
quotedMessageContentType = -1,
quotedMessageDeleted = false,
quotedMessageDiscordMessage = DiscordMessage(),
quotedMessageAuthorDetails = ContactDetails()
quotedMessageAuthorDetails = ContactDetails(),
albumId = "",
albumMessageImages = @[],
albumMessageIds = @[],
)
proc checkIfMessageLoadedAndScrollToItIfItIs(self: Module) =
@ -201,7 +208,6 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
pinnedMessages: seq[PinnedMessageDto]) =
var viewItems: seq[Item]
var prevMessage = Item()
if(messages.len > 0):
for message in messages:
# https://github.com/status-im/status-desktop/issues/7632 will introduce deleteFroMe feature.
@ -225,9 +231,13 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
var renderedMessageText = self.controller.getRenderedText(message.parsedText, communityChats)
# Skipping duplication text from image messages whith same text
if (prevMessage.contentType.ContentType == ContentType.Image and prevMessage.messageText == renderedMessageText):
renderedMessageText = ""
# Add image to album if album already exists
if (message.contentType.ContentType == ContentType.Image and len(message.albumId) != 0):
if (self.view.model().updateAlbumIfExists(message.albumId, message.image, message.id)):
continue
if (self.updateItemsByAlbum(viewItems, message)):
continue
var transactionContract = message.transactionParameters.contract
var transactionValue = message.transactionParameters.value
@ -282,11 +292,12 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
message.quotedMessage.contentType,
message.quotedMessage.deleted,
message.quotedMessage.discordMessage,
quotedMessageAuthorDetails
quotedMessageAuthorDetails,
message.albumId,
if (len(message.albumId) == 0): @[] else: @[message.image],
if (len(message.albumId) == 0): @[] else: @[message.id],
)
prevMessage = item
for r in reactions:
if(r.messageId == message.id):
var emojiIdAsEnum: EmojiId
@ -360,6 +371,14 @@ method messagesAdded*(self: Module, messages: seq[MessageDto]) =
if message.deleted or message.deletedForMe:
continue
# Add image to album if album already exists
if (message.contentType.ContentType == ContentType.Image and len(message.albumId) != 0):
if (self.view.model().updateAlbumIfExists(message.albumId, message.image, message.id)):
continue
if (self.updateItemsByAlbum(items, message)):
continue
var item = initItem(
message.id,
message.communityId,
@ -407,6 +426,9 @@ method messagesAdded*(self: Module, messages: seq[MessageDto]) =
message.quotedMessage.deleted,
message.quotedMessage.discordMessage,
quotedMessageAuthorDetails,
message.albumId,
if (len(message.albumId) == 0): @[] else: @[message.image],
if (len(message.albumId) == 0): @[] else: @[message.id],
)
items.add(item)
@ -680,3 +702,22 @@ proc setChatDetails(self: Module, chatDetails: ChatDto) =
self.view.setChatColor(chatDetails.color)
self.view.setChatIcon(chatDetails.icon)
self.view.setChatType(chatDetails.chatType.int)
proc updateItemsByAlbum(self: Module, items: var seq[Item], message: MessageDto): bool =
for i in 0 ..< items.len:
let item = items[i]
if item.albumId == message.albumId:
# Check if message already in album
for j in 0 ..< item.albumMessageIds.len:
if item.albumMessageIds[j] == message.id:
return true
var albumImages = item.albumMessageImages
var albumMessagesIds = item.albumMessageIds
albumMessagesIds.add(message.id)
albumImages.add(message.image)
item.albumMessageImages = albumImages
item.albumMessageIds = albumMessagesIds
items[i] = item
return true
return false

View File

@ -220,7 +220,10 @@ proc buildPinnedMessageItem(self: Module, messageId: string, actionInitiatedBy:
message.quotedMessage.contentType,
message.quotedMessage.deleted,
message.quotedMessage.discordMessage,
quotedMessageAuthorDetails
quotedMessageAuthorDetails,
message.albumId,
if (len(message.albumId) == 0): @[] else: @[message.image],
if (len(message.albumId) == 0): @[] else: @[message.id],
)
item.pinned = true
item.pinnedBy = actionInitiatedBy

View File

@ -56,6 +56,9 @@ type
quotedMessageAuthorDisplayName: string
quotedMessageAuthorAvatar: string
quotedMessageAuthorDetails: ContactDetails
albumId: string
albumMessageImages: seq[string]
albumMessageIds: seq[string]
proc initItem*(
id,
@ -97,6 +100,9 @@ proc initItem*(
quotedMessageDeleted: bool,
quotedMessageDiscordMessage: DiscordMessage,
quotedMessageAuthorDetails: ContactDetails,
albumId: string,
albumMessageImages: seq[string],
albumMessageIds: seq[string],
): Item =
result = Item()
result.id = id
@ -143,6 +149,9 @@ proc initItem*(
result.quotedMessageContentType = quotedMessageContentType
result.quotedMessageDeleted = quotedMessageDeleted
result.quotedMessageAuthorDetails = quotedMessageAuthorDetails
result.albumId = albumId
result.albumMessageImages = albumMessageImages
result.albumMessageIds = albumMessageIds
if quotedMessageContentType == ContentType.DiscordMessage.int:
result.quotedMessageAuthorDisplayName = quotedMessageDiscordMessage.author.name
@ -214,6 +223,9 @@ proc initNewMessagesMarkerItem*(clock, timestamp: int64): Item =
quotedMessageDeleted = false,
quotedMessageDiscordMessage = DiscordMessage(),
quotedMessageAuthorDetails = ContactDetails(),
albumId = "",
albumMessageImages = @[],
albumMessageIds = @[],
)
proc `$`*(self: Item): string =
@ -339,6 +351,21 @@ proc `parsedText=`*(self: Item, value: seq[ParsedText]) {.inline.} =
proc messageImage*(self: Item): string {.inline.} =
self.messageImage
proc albumId*(self: Item): string {.inline.} =
self.albumId
proc albumMessageImages*(self: Item): seq[string] {.inline.} =
self.albumMessageImages
proc `albumMessageImages=`*(self: Item, value: seq[string]) {.inline.} =
self.albumMessageImages = value
proc albumMessageIds*(self: Item): seq[string] {.inline.} =
self.albumMessageIds
proc `albumMessageIds=`*(self: Item, value: seq[string]) {.inline.} =
self.albumMessageIds = value
proc messageContainsMentions*(self: Item): bool {.inline.} =
self.messageContainsMentions
@ -461,6 +488,9 @@ proc toJsonNode*(self: Item): JsonNode =
"quotedMessageDeleted": self.quotedMessageDeleted,
"quotedMessageAuthorDisplayName": self.quotedMessageAuthorDisplayName,
"quotedMessageAuthorAvatar": self.quotedMessageAuthorAvatar,
"albumId": self.albumId,
"albumMessageImages": self.albumMessageImages,
"albumMessageIds": self.albumMessageIds,
}
proc editMode*(self: Item): bool {.inline.} =

View File

@ -61,6 +61,7 @@ type
QuotedMessageAuthorEnsVerified
QuotedMessageAuthorIsContact
QuotedMessageAuthorColorHash
AlbumMessageImages
QtObject:
type
@ -161,6 +162,7 @@ QtObject:
ModelRole.QuotedMessageAuthorEnsVerified.int: "quotedMessageAuthorEnsVerified",
ModelRole.QuotedMessageAuthorIsContact.int: "quotedMessageAuthorIsContact",
ModelRole.QuotedMessageAuthorColorHash.int: "quotedMessageAuthorColorHash",
ModelRole.AlbumMessageImages.int: "albumMessageImages",
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
@ -305,6 +307,8 @@ QtObject:
result = newQVariant(item.senderEnsVerified)
of ModelRole.MessageAttachments:
result = newQVariant(item.messageAttachments.join(" "))
of ModelRole.AlbumMessageImages:
result = newQVariant(item.albumMessageImages.join(" "))
proc updateItemAtIndex(self: Model, index: int) =
let ind = self.createIndex(index, 0, nil)
@ -698,3 +702,23 @@ QtObject:
item.seen = true
let index = self.createIndex(i, 0, nil)
self.dataChanged(index, index, @[ModelRole.Seen.int])
proc updateAlbumIfExists*(self: Model, albumId: string, messageImage: string, messageId: string): bool =
for i in 0 ..< self.items.len:
let item = self.items[i]
if item.albumId == albumId:
# Check if message already in album
for j in 0 ..< item.albumMessageIds.len:
if item.albumMessageIds[j] == messageId:
return true
var albumImages = item.albumMessageImages
var albumMessagesIds = item.albumMessageIds
albumMessagesIds.add(messageId)
albumImages.add(messageImage)
item.albumMessageImages = albumImages
item.albumMessageIds = albumMessagesIds
let index = self.createIndex(i, 0, nil)
self.dataChanged(index, index, @[ModelRole.AlbumMessageImages.int])
return true
return false

View File

@ -394,7 +394,7 @@ QtObject:
error "Error deleting channel", chatId, msg = e.msg
return
proc sendImages*(self: Service, chatId: string, imagePathsAndDataJson: string): string =
proc sendImages*(self: Service, chatId: string, imagePathsAndDataJson: string, msg: string): string =
result = ""
try:
var images = Json.decode(imagePathsAndDataJson, seq[string])
@ -430,7 +430,7 @@ QtObject:
imagePaths.add(imagePath)
let response = status_chat.sendImages(chatId, imagePaths)
let response = status_chat.sendImages(chatId, imagePaths, msg)
for imagePath in imagePaths:
removeFile(imagePath)

View File

@ -103,6 +103,7 @@ type MessageDto* = object
ensName*: string
sticker*: Sticker
image*: string
albumId*: string
gapParameters*: GapParameters
timestamp*: int64
contentType*: int
@ -222,6 +223,7 @@ proc toMessageDto*(jsonObj: JsonNode): MessageDto =
discard jsonObj.getProp("messageType", result.messageType)
discard jsonObj.getProp("contactRequestState", result.contactRequestState)
discard jsonObj.getProp("image", result.image)
discard jsonObj.getProp("albumId", result.albumId)
discard jsonObj.getProp("editedAt", result.editedAt)
discard jsonObj.getProp("deleted", result.deleted)
discard jsonObj.getProp("deletedForMe", result.deletedForMe)

View File

@ -75,7 +75,7 @@ proc sendChatMessage*(
}
])
proc sendImages*(chatId: string, images: var seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =
proc sendImages*(chatId: string, images: var seq[string], msg: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let imagesJson = %* images.map(image => %*
{
"chatId": chatId,
@ -83,7 +83,7 @@ proc sendImages*(chatId: string, images: var seq[string]): RpcResponse[JsonNode]
"imagePath": image,
# TODO is this still needed
# "ensName": preferredUsername,
"text": "🖼️"
"text": msg
}
)
callPrivateRPC("sendChatMessages".prefix, %* [imagesJson])

View File

@ -49,6 +49,9 @@ proc createTestMessageItem(id: string, clock: int64): Item =
quotedMessageDeleted = false,
quotedMessageDiscordMessage = DiscordMessage(),
quotedMessageAuthorDetails = ContactDetails(),
albumId = "",
albumMessageImages = @[],
albumMessageIds = @[],
)
let message0_chatIdentifier = createTestMessageItem("chat-identifier", -2)

View File

@ -275,7 +275,9 @@ Control {
Loader {
active: root.messageDetails.contentType === StatusMessage.ContentType.Image && !editMode
visible: active
sourceComponent: Column {
id: imagesColumn
spacing: 8
Loader {
active: root.messageDetails.messageText !== ""
@ -288,13 +290,46 @@ Control {
}
}
Loader {
active: true
sourceComponent: messageDetails.album.length > 1 ? albumComp : imageComp
}
}
Component {
id: imageComp
StatusImageMessage {
source: root.messageDetails.messageContent
onClicked: root.imageClicked(image, mouse, imageSource)
shapeType: root.messageDetails.amISender ? StatusImageMessage.ShapeType.RIGHT_ROUNDED : StatusImageMessage.ShapeType.LEFT_ROUNDED
}
}
Component {
id: albumComp
RowLayout {
width: messageLayout.width
spacing: 9
Repeater {
model: root.messageDetails.album
StatusImageMessage {
Layout.alignment: Qt.AlignLeft
imageWidth: Math.min(parent.width / root.messageDetails.album.length - 9 * (root.messageDetails.album.length - 1), 144)
source: modelData
onClicked: root.imageClicked(image, mouse, imageSource)
shapeType: root.messageDetails.amISender ? StatusImageMessage.ShapeType.RIGHT_ROUNDED : StatusImageMessage.ShapeType.LEFT_ROUNDED
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
}
Loader {
active: root.messageAttachments && !editMode
visible: active

View File

@ -12,4 +12,5 @@ QtObject {
property string messageText: ""
property string messageContent: ""
property string messageOriginInfo: ""
property var album: []
}

View File

@ -167,26 +167,31 @@ QtObject {
const chatContentModule = chatCommunitySectionModule.getChatContentModule()
var result = false
if (fileUrlsAndSources.length > 0){
chatContentModule.inputAreaModule.sendImages(JSON.stringify(fileUrlsAndSources))
result = true
}
let textMsg = globalUtils.plainText(StatusQUtils.Emoji.deparse(text))
if (textMsg.trim() !== "") {
textMsg = interpretMessage(textMsg)
let msg = globalUtils.plainText(StatusQUtils.Emoji.deparse(text))
if (msg.trim() !== "") {
msg = interpretMessage(msg)
chatContentModule.inputAreaModule.sendMessage(
msg,
replyMessageId,
Utils.isOnlyEmoji(msg) ? Constants.messageContentType.emojiType : Constants.messageContentType.messageType,
false)
if (event)
if (event) {
event.accepted = true
result = true
}
}
if (fileUrlsAndSources.length > 0) {
chatContentModule.inputAreaModule.sendImages(JSON.stringify(fileUrlsAndSources), textMsg.trim())
result = true
} else {
if (textMsg.trim() !== "") {
chatContentModule.inputAreaModule.sendMessage(
textMsg,
replyMessageId,
Utils.isOnlyEmoji(textMsg) ? Constants.messageContentType.emojiType : Constants.messageContentType.messageType,
false)
result = true
}
}
return result
}

View File

@ -243,6 +243,7 @@ Item {
messageText: model.messageText
unparsedText: model.unparsedText
messageImage: model.messageImage
album: model.albumMessageImages.split(" ")
messageTimestamp: model.timestamp
messageOutgoingStatus: model.outgoingStatus
resendError: model.resendError

View File

@ -76,6 +76,8 @@ Loader {
property bool quotedMessageAuthorDetailsIsContact: false
property var quotedMessageAuthorDetailsColorHash
property var album: []
// 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)
@ -570,6 +572,7 @@ Loader {
case StatusMessage.ContentType.Sticker:
return root.sticker;
case StatusMessage.ContentType.Image:
return root.messageImage;
}
if (root.isDiscordMessage && root.messageImage != "") {
@ -577,6 +580,7 @@ Loader {
}
return "";
}
album: root.album
amISender: root.amISender
sender.id: root.senderIsEnsVerified ? "" : Utils.getCompressedPk(root.senderId)