diff --git a/src/components/views/messages/MAudioBody.js b/src/components/views/messages/MAudioBody.js index ff753621c7..393bf549ae 100644 --- a/src/components/views/messages/MAudioBody.js +++ b/src/components/views/messages/MAudioBody.js @@ -29,6 +29,7 @@ export default class MAudioBody extends React.Component { this.state = { playing: false, decryptedUrl: null, + error: null, } } onPlayToggle() { @@ -51,27 +52,38 @@ export default class MAudioBody extends React.Component { if (content.file !== undefined && this.state.decryptedUrl === null) { decryptFile(content.file).done((url) => { this.setState({ - decryptedUrl: url + decryptedUrl: url, }); }, (err) => { - console.warn("Unable to decrypt attachment: ", err) - // Set a placeholder image when we can't decrypt the image. - this.refs.image.src = "img/warning.svg"; + console.warn("Unable to decrypt attachment: ", err); + this.setState({ + error: err, + }); }); } } render() { + const content = this.props.mxEvent.getContent(); + if (this.state.error !== null) { + return ( + + + Error decrypting audio + + ); + } + if (content.file !== undefined && this.state.decryptedUrl === null) { // Need to decrypt the attachment // The attachment is decrypted in componentDidMount. - // For now add an img tag with a spinner. + // For now add an img tag with a 16x16 spinner. + // Not sure how tall the audio player is so not sure how tall it should actually be. return ( - {content.body} + {content.body} ); } diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index 60b0653f1f..32b53e3b7d 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -24,6 +24,8 @@ import {decryptFile} from '../../../utils/DecryptFile'; import Tinter from '../../../Tinter'; import 'isomorphic-fetch'; import q from 'q'; +import Modal from '../../../Modal'; + // A cached tinted copy of "img/download.svg" var tintedDownloadImageURL; @@ -110,19 +112,6 @@ module.exports = React.createClass({ this.id = nextMountId++; mounts[this.id] = this; this.tint(); - // Check whether we need to decrypt the file content. - const content = this.props.mxEvent.getContent(); - if (content.file !== undefined && this.state.decryptedUrl === null) { - decryptFile(content.file).done((url) => { - this.setState({ - decryptedUrl: url, - }); - }, (err) => { - console.warn("Unable to decrypt attachment: ", err) - // Set a placeholder image when we can't decrypt the image. - this.refs.image.src = "img/warning.svg"; - }); - } }, componentWillUnmount: function() { @@ -141,16 +130,42 @@ module.exports = React.createClass({ const content = this.props.mxEvent.getContent(); const text = this.presentableTextForFile(content); + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); if (content.file !== undefined && this.state.decryptedUrl === null) { + var decrypting = false; + const decrypt = () => { + if (decrypting) { + return false; + } + decrypting = true; + decryptFile(content.file).then((url) => { + this.setState({ + decryptedUrl: url, + }); + }).catch((err) => { + console.warn("Unable to decrypt attachment: ", err) + // Set a placeholder image when we can't decrypt the image + Modal.createDialog(ErrorDialog, { + description: "Error decrypting attachment" + }); + }).finally(function() { + decrypting = false; + }).done(); + return false; + }; + // Need to decrypt the attachment // The attachment is decrypted in componentDidMount. // For now add an img tag with a spinner. return ( - {content.body} +
+ + Decrypt {text} + +
); } diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index 6f46544bf4..63fd119335 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -38,6 +38,7 @@ module.exports = React.createClass({ return { decryptedUrl: null, decryptedThumbnailUrl: null, + error: null }; }, @@ -124,9 +125,11 @@ module.exports = React.createClass({ }); }); }).catch((err) => { - console.warn("Unable to decrypt attachment: ", err) + console.warn("Unable to decrypt attachment: ", err); // Set a placeholder image when we can't decrypt the image. - this.refs.image.src = "img/warning.svg"; + this.setState({ + error: err, + }); }).done(); } }, @@ -165,6 +168,15 @@ module.exports = React.createClass({ const TintableSvg = sdk.getComponent("elements.TintableSvg"); const content = this.props.mxEvent.getContent(); + if (this.state.error !== null) { + return ( + + + Error decrypting image + + ); + } + if (content.file !== undefined && this.state.decryptedUrl === null) { // Need to decrypt the attachment @@ -172,8 +184,14 @@ module.exports = React.createClass({ // For now add an img tag with a spinner. return ( - {content.body} +
+ {content.body} +
); } diff --git a/src/components/views/messages/MVideoBody.js b/src/components/views/messages/MVideoBody.js index a32348ea1a..a0dbb141ac 100644 --- a/src/components/views/messages/MVideoBody.js +++ b/src/components/views/messages/MVideoBody.js @@ -31,6 +31,7 @@ module.exports = React.createClass({ return { decryptedUrl: null, decryptedThumbnailUrl: null, + error: null, }; }, @@ -95,7 +96,9 @@ module.exports = React.createClass({ }).catch((err) => { console.warn("Unable to decrypt attachment: ", err) // Set a placeholder image when we can't decrypt the image. - this.refs.image.src = "img/warning.svg"; + this.setState({ + error: err, + }); }).done(); } }, @@ -103,14 +106,29 @@ module.exports = React.createClass({ render: function() { const content = this.props.mxEvent.getContent(); + if (this.state.error !== null) { + return ( + + + Error decrypting video + + ); + } + if (content.file !== undefined && this.state.decryptedUrl === null) { // Need to decrypt the attachment // The attachment is decrypted in componentDidMount. // For now add an img tag with a spinner. return ( - - {content.body} + +
+ {content.body} +
); }