diff --git a/src/domain/session/room/RoomViewModel.js b/src/domain/session/room/RoomViewModel.js index a979be09..2586f2b2 100644 --- a/src/domain/session/room/RoomViewModel.js +++ b/src/domain/session/room/RoomViewModel.js @@ -182,6 +182,36 @@ export class RoomViewModel extends ViewModel { // TODO: dispose file.blob (in the attachment, after upload) } + async _sendPicture() { + if (!this.platform.hasReadPixelPermission()) { + alert("Please allow canvas image data access, so we can scale your images down."); + return; + } + let file; + try { + file = await this.platform.openFile("image/*"); + } catch (err) { + return; + } + const image = await this.platform.loadImage(file.blob); + const content = { + body: file.name, + msgtype: "m.image", + info: imageToInfo(image) + }; + const attachments = { + "url": this._room.createAttachment(file.blob, file.name), + }; + if (image.maxDimension > 600) { + const thumbnail = await image.scale(400); + content.info.thumbnail_info = imageToInfo(thumbnail); + attachments["info.thumbnail_url"] = + this._room.createAttachment(thumbnail.blob, file.name); + } + await this._room.sendEvent("m.room.message", content, attachments); + } + + get composerViewModel() { return this._composerVM; } @@ -207,7 +237,11 @@ class ComposerViewModel extends ViewModel { return success; } - sendAttachment() { + sendPicture() { + this._roomVM._sendPicture(); + } + + sendFile() { this._roomVM._sendFile(); } @@ -226,3 +260,12 @@ class ComposerViewModel extends ViewModel { } } } + +function imageToInfo(image) { + return { + w: image.width, + h: image.height, + mimetype: image.blob.mimeType, + size: image.blob.size + }; +} diff --git a/src/platform/web/dom/ImageHandle.js b/src/platform/web/dom/ImageHandle.js index 691ead22..dcead27c 100644 --- a/src/platform/web/dom/ImageHandle.js +++ b/src/platform/web/dom/ImageHandle.js @@ -30,6 +30,10 @@ export class ImageHandle { this._imgElement = imgElement; } + get maxDimension() { + return Math.max(this.width, this.height); + } + async _getImgElement() { if (!this._imgElement) { this._imgElement = await loadImgFromBlob(this.blob); diff --git a/src/platform/web/ui/session/room/MessageComposer.js b/src/platform/web/ui/session/room/MessageComposer.js index 62b55b15..0609285b 100644 --- a/src/platform/web/ui/session/room/MessageComposer.js +++ b/src/platform/web/ui/session/room/MessageComposer.js @@ -15,6 +15,8 @@ limitations under the License. */ import {TemplateView} from "../../general/TemplateView.js"; +import {Popup} from "../../general/Popup.js"; +import {Menu} from "../../general/Menu.js"; export class MessageComposer extends TemplateView { constructor(viewModel) { @@ -32,8 +34,8 @@ export class MessageComposer extends TemplateView { this._input, t.button({ className: "sendFile", - title: vm.i18n`Send file`, - onClick: () => vm.sendAttachment(), + title: vm.i18n`Pick attachment`, + onClick: evt => this._showAttachmentMenu(evt), }, vm.i18n`Send file`), t.button({ className: "send", @@ -56,4 +58,25 @@ export class MessageComposer extends TemplateView { this._trySend(); } } + + _showAttachmentMenu(evt) { + const vm = this.value; + const popup = new Popup(new Menu([ + Menu.option(vm.i18n`Send picture`, () => vm.sendPicture()).setIcon("picture"), + Menu.option(vm.i18n`Send file`, () => vm.sendFile()).setIcon("file"), + ])); + popup.trackInTemplateView(this); + popup.showRelativeTo(evt.target, { + horizontal: { + relativeTo: "end", + align: "start", + after: 0 + }, + vertical: { + relativeTo: "end", + align: "start", + before: 8, + } + }); + } }