diff --git a/src/ContentMessages.js b/src/ContentMessages.js index eba3011917..094eff18d9 100644 --- a/src/ContentMessages.js +++ b/src/ContentMessages.js @@ -18,6 +18,10 @@ limitations under the License. var q = require('q'); var extend = require('./extend'); +var dis = require('./dispatcher'); +var MatrixClientPeg = require('./MatrixClientPeg'); +var sdk = require('./index'); +var Modal = require('./Modal'); function infoForImageFile(imageFile) { var deferred = q.defer(); @@ -48,39 +52,108 @@ function infoForImageFile(imageFile) { return deferred.promise; } -function sendContentToRoom(file, roomId, matrixClient) { - var content = { - body: file.name, - info: { - size: file.size, +class ContentMessages { + constructor() { + this.inprogress = []; + this.nextId = 0; + } + + sendContentToRoom(file, roomId, matrixClient) { + var content = { + body: file.name, + info: { + size: file.size, + } + }; + + // if we have a mime type for the file, add it to the message metadata + if (file.type) { + content.info.mimetype = file.type; } - }; - // if we have a mime type for the file, add it to the message metadata - if (file.type) { - content.info.mimetype = file.type; - } - - var def = q.defer(); - if (file.type.indexOf('image/') == 0) { - content.msgtype = 'm.image'; - infoForImageFile(file).then(function(imageInfo) { - extend(content.info, imageInfo); + var def = q.defer(); + if (file.type.indexOf('image/') == 0) { + content.msgtype = 'm.image'; + infoForImageFile(file).then(function(imageInfo) { + extend(content.info, imageInfo); + def.resolve(); + }); + } else { + content.msgtype = 'm.file'; def.resolve(); + } + + var upload = { + fileName: file.name, + roomId: roomId, + total: 0, + loaded: 0 + }; + this.inprogress.push(upload); + dis.dispatch({action: 'upload_started'}); + + var self = this; + return def.promise.then(function() { + upload.promise = matrixClient.uploadContent(file); + return upload.promise; + }).progress(function(ev) { + if (ev) { + upload.total = ev.total; + upload.loaded = ev.loaded; + dis.dispatch({action: 'upload_progress', upload: upload}); + } + }).then(function(url) { + dis.dispatch({action: 'upload_finished', upload: upload}); + content.url = url; + return matrixClient.sendMessage(roomId, content); + }, function(err) { + dis.dispatch({action: 'upload_failed', upload: upload}); + if (!upload.canceled) { + var desc = "The file '"+upload.fileName+"' failed to upload."; + if (err.http_status == 413) { + desc = "The file '"+upload.fileName+"' exceeds this home server's size limit for uploads"; + } + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createDialog(ErrorDialog, { + title: "Upload Failed", + description: desc + }); + } + }).finally(function() { + var inprogressKeys = Object.keys(self.inprogress); + for (var i = 0; i < self.inprogress.length; ++i) { + var k = inprogressKeys[i]; + if (self.inprogress[k].promise === upload.promise) { + self.inprogress.splice(k, 1); + break; + } + } }); - } else { - content.msgtype = 'm.file'; - def.resolve(); } - return def.promise.then(function() { - return matrixClient.uploadContent(file); - }).then(function(url) { - content.url = url; - return matrixClient.sendMessage(roomId, content); - }); + getCurrentUploads() { + return this.inprogress; + } + + cancelUpload(promise) { + var inprogressKeys = Object.keys(this.inprogress); + var upload; + for (var i = 0; i < this.inprogress.length; ++i) { + var k = inprogressKeys[i]; + if (this.inprogress[k].promise === promise) { + upload = this.inprogress[k]; + break; + } + } + if (upload) { + upload.canceled = true; + MatrixClientPeg.get().cancelUpload(upload.promise); + } + } } -module.exports = { - sendContentToRoom: sendContentToRoom -}; +if (global.mx_ContentMessage === undefined) { + global.mx_ContentMessage = new ContentMessages(); +} + +module.exports = global.mx_ContentMessage; diff --git a/src/component-index.js b/src/component-index.js index b9821b6c56..2f89e6d94b 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -28,6 +28,7 @@ module.exports.components['structures.login.PostRegistration'] = require('./comp module.exports.components['structures.login.Registration'] = require('./components/structures/login/Registration'); module.exports.components['structures.MatrixChat'] = require('./components/structures/MatrixChat'); module.exports.components['structures.RoomView'] = require('./components/structures/RoomView'); +module.exports.components['structures.UploadBar'] = require('./components/structures/UploadBar'); module.exports.components['structures.UserSettings'] = require('./components/structures/UserSettings'); module.exports.components['views.avatars.MemberAvatar'] = require('./components/views/avatars/MemberAvatar'); module.exports.components['views.avatars.RoomAvatar'] = require('./components/views/avatars/RoomAvatar'); diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index dda6da5834..538bf83d03 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -26,7 +26,6 @@ var ReactDOM = require("react-dom"); var GeminiScrollbar = require('react-gemini-scrollbar'); var q = require("q"); var classNames = require("classnames"); -var filesize = require('filesize'); var Matrix = require("matrix-js-sdk"); var MatrixClientPeg = require("../../MatrixClientPeg"); @@ -107,6 +106,9 @@ module.exports = React.createClass({ this.forceUpdate(); break; case 'notifier_enabled': + case 'upload_failed': + case 'upload_started': + case 'upload_finished': this.forceUpdate(); break; case 'call_state': @@ -408,30 +410,10 @@ module.exports = React.createClass({ }, uploadFile: function(file) { - this.setState({ - upload: { - fileName: file.name, - uploadedBytes: 0, - totalBytes: file.size - } - }); var self = this; ContentMessages.sendContentToRoom( file, this.props.roomId, MatrixClientPeg.get() - ).progress(function(ev) { - //console.log("Upload: "+ev.loaded+" / "+ev.total); - self.setState({ - upload: { - fileName: file.name, - uploadedBytes: ev.loaded, - totalBytes: ev.total - } - }); - }).finally(function() { - self.setState({ - upload: undefined - }); - }).done(undefined, function(error) { + ).done(undefined, function(error) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { title: "Failed to upload file", @@ -894,28 +876,9 @@ module.exports = React.createClass({ // fileName: "testing_fooble.jpg", // } - if (this.state.upload) { - var innerProgressStyle = { - width: ((this.state.upload.uploadedBytes / this.state.upload.totalBytes) * 100) + '%' - }; - var uploadedSize = filesize(this.state.upload.uploadedBytes); - var totalSize = filesize(this.state.upload.totalBytes); - if (uploadedSize.replace(/^.* /,'') === totalSize.replace(/^.* /,'')) { - uploadedSize = uploadedSize.replace(/ .*/, ''); - } - statusBar = ( -