fix(images): fix second pasted image replaces the first one

Fixes #9966

Uses the validate function to paste images so that it concatenates the previous images.
FIxes the validate function to also accept data images.
Moves the size validation function to Utils to reuse the data path prefix constant and fix the possible crash when we try to get the size of a data image.
This commit is contained in:
Jonathan Rainville 2023-03-27 13:53:17 -04:00
parent b580f0a810
commit e5ff0b4a6a
6 changed files with 34 additions and 20 deletions

View File

@ -32,7 +32,7 @@ DropArea {
} }
// needed because drag.urls is not a normal js array // needed because drag.urls is not a normal js array
rptDraggedPreviews.model = drag.urls.filter(img => Utils.hasDragNDropImageExtension(img)) rptDraggedPreviews.model = drag.urls.filter(img => Utils.isValidDragNDropImage(img))
} }
onPositionChanged: { onPositionChanged: {
rptDraggedPreviews.x = drag.x rptDraggedPreviews.x = drag.x

View File

@ -15,7 +15,7 @@ StatusChatImageValidator {
onImagesChanged: { onImagesChanged: {
let isValid = true let isValid = true
root.validImages = images.filter(img => { root.validImages = images.filter(img => {
const isImage = Utils.hasDragNDropImageExtension(img) const isImage = Utils.isValidDragNDropImage(img)
isValid = isValid && isImage isValid = isValid && isImage
return isImage return isImage
}) })

View File

@ -4,13 +4,11 @@ import utils 1.0
StatusChatImageValidator { StatusChatImageValidator {
id: root id: root
readonly property int maxImgSizeBytes: Constants.maxUploadFilesizeMB * 1048576 /* 1 MB in bytes */
onImagesChanged: { onImagesChanged: {
let isValid = true let isValid = true
root.validImages = images.filter(img => { root.validImages = images.filter(img => {
let size = parseInt(globalUtils.getFileSize(img)) const isSmallEnough = Utils.isFilesizeValid(img)
const isSmallEnough = size <= maxImgSizeBytes
isValid = isValid && isSmallEnough isValid = isValid && isSmallEnough
return isSmallEnough return isSmallEnough
}) })

View File

@ -436,7 +436,7 @@ Rectangle {
if (event.matches(StandardKey.Paste)) { if (event.matches(StandardKey.Paste)) {
if (QClipboardProxy.hasImage) { if (QClipboardProxy.hasImage) {
const clipboardImage = QClipboardProxy.imageBase64 const clipboardImage = QClipboardProxy.imageBase64
showImageArea([clipboardImage]) validateImagesAndShowImageArea([clipboardImage])
event.accepted = true event.accepted = true
} else if (QClipboardProxy.hasText) { } else if (QClipboardProxy.hasText) {
messageInputField.remove(messageInputField.selectionStart, messageInputField.selectionEnd) messageInputField.remove(messageInputField.selectionStart, messageInputField.selectionEnd)
@ -883,11 +883,22 @@ Rectangle {
function showImageArea(imagePathsOrData) { function showImageArea(imagePathsOrData) {
isImage = true; isImage = true;
imageArea.imageSource = imagePathsOrData imageArea.imageSource = imagePathsOrData
control.fileUrlsAndSources = imageArea.imageSource control.fileUrlsAndSources = imageArea.imageSource
} }
// Use this to validate and show the images. The concatanation of previous selected images is done automatically
// Returns true if the images were valid and added
function validateImagesAndShowImageArea(imagePaths) {
const validImages = validateImages(imagePaths)
if (validImages.length > 0) {
showImageArea(validImages)
return true
}
return false
}
function showReplyArea(messageId, userName, message, contentType, image, sticker) { function showReplyArea(messageId, userName, message, contentType, image, sticker) {
isReply = true isReply = true
replyArea.userName = userName replyArea.userName = userName
@ -908,9 +919,7 @@ Rectangle {
target: Global.dragArea target: Global.dragArea
ignoreUnknownSignals: true ignoreUnknownSignals: true
function onDroppedOnValidScreen(drop) { function onDroppedOnValidScreen(drop) {
let validImages = validateImages(drop.urls) if (validateImagesAndShowImageArea(drop.urls)) {
if (validImages.length > 0) {
showImageArea(validImages)
drop.acceptProposedAction() drop.acceptProposedAction()
} }
} }
@ -918,10 +927,7 @@ Rectangle {
// This is used by Squish tests to not have to access the file dialog // This is used by Squish tests to not have to access the file dialog
function selectImageString(filePath) { function selectImageString(filePath) {
let validImages = validateImages([filePath]) validateImagesAndShowImageArea([filePath])
if (validImages.length > 0) {
control.showImageArea(validImages)
}
messageInputField.forceActiveFocus(); messageInputField.forceActiveFocus();
} }
@ -935,10 +941,7 @@ Rectangle {
] ]
onAccepted: { onAccepted: {
imageBtn.highlighted = false imageBtn.highlighted = false
let validImages = validateImages(imageDialog.fileUrls) validateImagesAndShowImageArea(imageDialog.fileUrls)
if (validImages.length > 0) {
control.showImageArea(validImages)
}
messageInputField.forceActiveFocus(); messageInputField.forceActiveFocus();
} }
onRejected: { onRejected: {

View File

@ -797,6 +797,7 @@ QtObject {
readonly property int maxNumberOfPins: 3 readonly property int maxNumberOfPins: 3
readonly property string dataImagePrefix: "data:image"
readonly property var acceptedImageExtensions: [".png", ".jpg", ".jpeg", ".svg", ".gif"] readonly property var acceptedImageExtensions: [".png", ".jpg", ".jpeg", ".svg", ".gif"]
readonly property var acceptedDragNDropImageExtensions: [".png", ".jpg", ".jpeg", ".heif", ".tif", ".tiff"] readonly property var acceptedDragNDropImageExtensions: [".png", ".jpg", ".jpeg", ".heif", ".tif", ".tiff"]

View File

@ -10,6 +10,8 @@ QtObject {
property var mainModuleInst: typeof mainModule !== "undefined" ? mainModule : null property var mainModuleInst: typeof mainModule !== "undefined" ? mainModule : null
property var globalUtilsInst: typeof globalUtils !== "undefined" ? globalUtils : null property var globalUtilsInst: typeof globalUtils !== "undefined" ? globalUtils : null
readonly property int maxImgSizeBytes: Constants.maxUploadFilesizeMB * 1048576 /* 1 MB in bytes */
function isDigit(value) { function isDigit(value) {
return /^\d$/.test(value); return /^\d$/.test(value);
} }
@ -320,8 +322,18 @@ QtObject {
return message.replace(/(?:https?|ftp):\/\/[\n\S]*(\.gif)+/gm, ''); return message.replace(/(?:https?|ftp):\/\/[\n\S]*(\.gif)+/gm, '');
} }
function hasDragNDropImageExtension(url) { function isValidDragNDropImage(url) {
return Constants.acceptedDragNDropImageExtensions.some(ext => url.toLowerCase().includes(ext)) let lowerCaseUrl = url.toLowerCase()
return Constants.acceptedDragNDropImageExtensions.some(ext => lowerCaseUrl.endsWith(ext)) ||
lowerCaseUrl.startsWith(Constants.dataImagePrefix);
}
function isFilesizeValid(img) {
if (img.startsWith(Constants.dataImagePrefix)) {
return img.length < maxImgSizeBytes
}
let size = parseInt(globalUtils.getFileSize(img))
return size <= maxImgSizeBytes
} }
function deduplicate(array) { function deduplicate(array) {