diff --git a/src/assets/translations/en.json b/src/assets/translations/en.json index d6d5f39..3e86316 100644 --- a/src/assets/translations/en.json +++ b/src/assets/translations/en.json @@ -90,7 +90,11 @@ "incoming_message_deleted_text": "This message was deleted.", "not_allowed_to_send": "Only admins and moderators are allowed to send to the room", "reaction_count_more": "{reactionCount} more", - "seen_by": "Seen by no members | Seen by 1 member | Seen by {count} members" + "seen_by": "Seen by no members | Seen by 1 member | Seen by {count} members", + "file": "File", + "files": "Files", + "images": "Images", + "send_attachements_dialog_title": "Do you want to send following attachments ?" }, "room": { "invitations": "You have no invitations | You have 1 invitation | You have {count} invitations", diff --git a/src/components/Chat.vue b/src/components/Chat.vue index a068ebd..c2b3ffb 100644 --- a/src/components/Chat.vue +++ b/src/components/Chat.vue @@ -188,35 +188,52 @@ + accept="image/*, audio/*, video/*, .pdf" class="d-none" multiple/> -
- +
+ - - -
- file: {{ currentImageInputPath.name }} - - {{ currentImageInput.scaledDimensions.width }} x {{ currentImageInput.scaledDimensions.height }} - - {{ currentImageInput.dimensions.width }} x {{ currentImageInput.dimensions.height }} - - ({{ formatBytes(currentImageInput.scaledSize) }}) - ({{ formatBytes(currentImageInputPath.size) }}) - -
-
{{ currentSendError }}
-
{{ currentSendProgress }}
-
+ {{ $t('message.send_attachements_dialog_title') }} + + + - - {{ - $t("menu.cancel") - }} + +
{{ currentSendError }}
+
{{ currentSendProgress }}
+
+ + {{ $t("menu.cancel") }} + {{ $t("menu.send") }}
@@ -342,8 +359,8 @@ export default { timelineWindowPaginating: false, scrollPosition: null, - currentImageInput: null, - currentImageInputPath: null, + currentImageInputs: null, + currentFileInputs: null, currentSendOperation: null, currentSendProgress: null, currentSendShowSendButton: true, @@ -444,6 +461,20 @@ export default { }, computed: { + nonImageFiles() { + return this.isCurrentFileInputsAnArray && this.currentFileInputs.filter(file => !file.type.includes("image/")) + }, + isCurrentFileInputsAnArray() { + return Array.isArray(this.currentFileInputs) + }, + currentFileInputsDialog: { + get() { + return this.isCurrentFileInputsAnArray + }, + set() { + this.currentFileInputs = null + } + }, chatContainer() { const container = this.$refs.chatContainer; if (this.useVoiceMode) { @@ -950,64 +981,64 @@ export default { this.$refs.attachment.click(); }, - /** - * Handle picked attachment - */ - handlePickedAttachment(event) { - if (event.target.files && event.target.files[0]) { + optimizeImage(e,event,file) { + let currentImageInput = { + image: e.target.result, + dimensions: null, + }; + try { + currentImageInput.dimensions = sizeOf(dataUriToBuffer(e.target.result)); + + // Need to resize? + const w = currentImageInput.dimensions.width; + const h = currentImageInput.dimensions.height; + if (w > 640 || h > 640) { + var aspect = w / h; + var newWidth = parseInt((w > h ? 640 : 640 * aspect).toFixed()); + var newHeight = parseInt((w > h ? 640 / aspect : 640).toFixed()); + var imageResize = new ImageResize({ + format: "png", + width: newWidth, + height: newHeight, + outputType: "blob", + }); + imageResize + .play(event.target) + .then((img) => { + Vue.set( + currentImageInput, + "scaled", + new File([img], file.name, { + type: img.type, + lastModified: Date.now(), + }) + ); + Vue.set(currentImageInput, "useScaled", true); + Vue.set(currentImageInput, "scaledSize", img.size); + Vue.set(currentImageInput, "scaledDimensions", { + width: newWidth, + height: newHeight, + }); + }) + .catch((err) => { + console.error("Resize failed:", err); + }); + } + } catch (error) { + console.error("Failed to get image dimensions: " + error); + } + return currentImageInput + }, + handleFileReader(event, file) { + if (file) { var reader = new FileReader(); reader.onload = (e) => { - const file = event.target.files[0]; if (file.type.startsWith("image/")) { - this.currentImageInput = { - image: e.target.result, - dimensions: null, - }; - try { - this.currentImageInput.dimensions = sizeOf(dataUriToBuffer(e.target.result)); - - // Need to resize? - const w = this.currentImageInput.dimensions.width; - const h = this.currentImageInput.dimensions.height; - if (w > 640 || h > 640) { - var aspect = w / h; - var newWidth = parseInt((w > h ? 640 : 640 * aspect).toFixed()); - var newHeight = parseInt((w > h ? 640 / aspect : 640).toFixed()); - var imageResize = new ImageResize({ - format: "png", - width: newWidth, - height: newHeight, - outputType: "blob", - }); - imageResize - .play(event.target) - .then((img) => { - Vue.set( - this.currentImageInput, - "scaled", - new File([img], file.name, { - type: img.type, - lastModified: Date.now(), - }) - ); - Vue.set(this.currentImageInput, "useScaled", true); - Vue.set(this.currentImageInput, "scaledSize", img.size); - Vue.set(this.currentImageInput, "scaledDimensions", { - width: newWidth, - height: newHeight, - }); - }) - .catch((err) => { - console.error("Resize failed:", err); - }); - } - } catch (error) { - console.error("Failed to get image dimensions: " + error); - } + const currentImageInput = this.optimizeImage(e, event, file) + this.currentImageInputs = Array.isArray(this.currentImageInputs) ? [...this.currentImageInputs, currentImageInput] : [currentImageInput] } - console.log(this.currentImageInput); this.$matrix.matrixClient.getMediaConfig().then((config) => { - this.currentImageInputPath = file; + this.currentFileInputs = Array.isArray(this.currentFileInputs) ? [...this.currentFileInputs, file] : [file]; if (config["m.upload.size"] && file.size > config["m.upload.size"]) { this.currentSendError = this.$t("message.upload_file_too_large"); this.currentSendShowSendButton = false; @@ -1016,9 +1047,15 @@ export default { } }); }; - reader.readAsDataURL(event.target.files[0]); + reader.readAsDataURL(file); } }, + /** + * Handle picked attachment + */ + handlePickedAttachment(event) { + Object.values(event.target.files).forEach(file => this.handleFileReader(event, file)); + }, showStickerPicker() { this.$refs.stickerPickerSheet.open(); @@ -1036,41 +1073,35 @@ export default { }); } }, - sendAttachment(withText) { this.$refs.attachment.value = null; - if (this.currentImageInputPath) { - var inputFile = this.currentImageInputPath; - if (this.currentImageInput && this.currentImageInput.scaled && this.currentImageInput.useScaled) { + if (this.isCurrentFileInputsAnArray) { + let inputFiles = this.currentFileInputs; + if (Array.isArray(this.currentImageInputs) && this.currentImageInputs.scaled && this.currentImageInputs.useScaled) { // Send scaled version of image instead! - inputFile = this.currentImageInput.scaled; + inputFiles = this.currentImageInputs.map(({scaled}) => scaled) } + + const promises = inputFiles.map(inputFile => util.sendImage(this.$matrix.matrixClient, this.roomId, inputFile, this.onUploadProgress)); + + Promise.all(promises).then(() => { + this.currentSendOperation = null; + this.currentImageInputs = null; + this.currentFileInputs = null; this.currentSendProgress = null; - this.currentSendOperation = util.sendImage( - this.$matrix.matrixClient, - this.roomId, - inputFile, - this.onUploadProgress - ); - this.currentSendOperation - .then(() => { - this.currentSendOperation = null; - this.currentImageInput = null; - this.currentImageInputPath = null; - this.currentSendProgress = null; - if (withText) { - this.sendMessage(withText); - } - }) - .catch((err) => { - if (err.name === "AbortError" || err === "Abort") { - this.currentSendError = null; - } else { - this.currentSendError = err.LocaleString(); - } - this.currentSendOperation = null; - this.currentSendProgress = null; - }); + if (withText) { + this.sendMessage(withText); + } + }) + .catch((err) => { + if (err.name === "AbortError" || err === "Abort") { + this.currentSendError = null; + } else { + this.currentSendError = err.LocaleString(); + } + this.currentSendOperation = null; + this.currentSendProgress = null; + }); } }, @@ -1080,8 +1111,8 @@ export default { this.currentSendOperation.abort(); } this.currentSendOperation = null; - this.currentImageInput = null; - this.currentImageInputPath = null; + this.currentImageInputs = null; + this.currentFileInputs = null; this.currentSendProgress = null; this.currentSendError = null; }, @@ -1461,7 +1492,7 @@ export default { onVoiceRecording(event) { this.currentSendShowSendButton = false; - this.currentImageInputPath = event.file; + this.currentFileInputs = Array.isArray(this.currentFileInputs) ? [...this.currentFileInputs, event.file] : [event.file]; var text = undefined; if (this.currentInput && this.currentInput.length > 0) { text = this.currentInput;