diff --git a/res/css/views/messages/_MImageBody.scss b/res/css/views/messages/_MImageBody.scss
index 86bc022829..8e650eaff4 100644
--- a/res/css/views/messages/_MImageBody.scss
+++ b/res/css/views/messages/_MImageBody.scss
@@ -59,3 +59,36 @@ limitations under the License.
color: $imagebody-giflabel-color;
pointer-events: none;
}
+
+.mx_HiddenImagePlaceholder {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ right: 0;
+
+ // To center the text in the middle of the frame
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+
+ cursor: pointer;
+ background-color: $header-panel-bg-color;
+
+ .mx_HiddenImagePlaceholder_button {
+ color: $accent-color;
+
+ img {
+ margin-right: 8px;
+ }
+
+ span {
+ vertical-align: text-bottom;
+ }
+ }
+}
+
+.mx_EventTile:hover .mx_HiddenImagePlaceholder {
+ background-color: $primary-bg-color;
+}
diff --git a/res/css/views/messages/_MStickerBody.scss b/res/css/views/messages/_MStickerBody.scss
index e4977bcc34..162ee7da86 100644
--- a/res/css/views/messages/_MStickerBody.scss
+++ b/res/css/views/messages/_MStickerBody.scss
@@ -22,3 +22,14 @@ limitations under the License.
position: absolute;
top: 50%;
}
+
+.mx_MStickerBody_hidden {
+ max-width: 220px;
+ text-decoration: none;
+ text-align: center;
+
+ // To center the text in the middle of the frame
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
diff --git a/res/img/feather-customised/eye.svg b/res/img/feather-customised/eye.svg
new file mode 100644
index 0000000000..fd06bf7b21
--- /dev/null
+++ b/res/img/feather-customised/eye.svg
@@ -0,0 +1,6 @@
+
diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js
index de19d0026f..e89c6d2bc9 100644
--- a/src/components/views/messages/MImageBody.js
+++ b/src/components/views/messages/MImageBody.js
@@ -64,6 +64,7 @@ export default class MImageBody extends React.Component {
imgLoaded: false,
loadedImageDimensions: null,
hover: false,
+ showImage: SettingsStore.getValue("showImages"),
};
}
@@ -86,9 +87,19 @@ export default class MImageBody extends React.Component {
}
}
+ showImage() {
+ localStorage.setItem("mx_ShowImage_" + this.props.mxEvent.getId(), "true");
+ this.setState({showImage: true});
+ }
+
onClick(ev) {
if (ev.button === 0 && !ev.metaKey) {
ev.preventDefault();
+ if (!this.state.showImage) {
+ this.showImage();
+ return;
+ }
+
const content = this.props.mxEvent.getContent();
const httpUrl = this._getContentUrl();
const ImageView = sdk.getComponent("elements.ImageView");
@@ -120,7 +131,7 @@ export default class MImageBody extends React.Component {
onImageEnter(e) {
this.setState({ hover: true });
- if (!this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) {
+ if (!this.state.showImage || !this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) {
return;
}
const imgElement = e.target;
@@ -130,7 +141,7 @@ export default class MImageBody extends React.Component {
onImageLeave(e) {
this.setState({ hover: false });
- if (!this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) {
+ if (!this.state.showImage || !this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) {
return;
}
const imgElement = e.target;
@@ -280,6 +291,12 @@ export default class MImageBody extends React.Component {
});
}).done();
}
+
+ // Remember that the user wanted to show this particular image
+ if (!this.state.showImage && localStorage.getItem("mx_ShowImage_" + this.props.mxEvent.getId()) === "true") {
+ this.setState({showImage: true});
+ }
+
this._afterComponentDidMount();
}
@@ -321,13 +338,19 @@ export default class MImageBody extends React.Component {
// By doing this, the image "pops" into the timeline, but is still restricted
// by the same width and height logic below.
if (!this.state.loadedImageDimensions) {
- return this.wrapImage(contentUrl,
- ,
- );
+ let imageElement;
+ if (!this.state.showImage) {
+ imageElement = ;
+ } else {
+ imageElement = (
+
+ );
+ }
+ return this.wrapImage(contentUrl, imageElement);
}
infoWidth = this.state.loadedImageDimensions.naturalWidth;
infoHeight = this.state.loadedImageDimensions.naturalHeight;
@@ -356,19 +379,26 @@ export default class MImageBody extends React.Component {
placeholder = this.getPlaceholder();
}
- const showPlaceholder = Boolean(placeholder);
+ let showPlaceholder = Boolean(placeholder);
if (thumbUrl && !this.state.imgError) {
// Restrict the width of the thumbnail here, otherwise it will fill the container
// which has the same width as the timeline
// mx_MImageBody_thumbnail resizes img to exactly container size
- img = ;
+ img = (
+
+ );
+ }
+
+ if (!this.state.showImage) {
+ img = ;
+ showPlaceholder = false; // because we're hiding the image, so don't show the sticker icon.
}
if (this._isGif() && !SettingsStore.getValue("autoplayGifsAndVideos") && !this.state.hover) {
@@ -454,3 +484,22 @@ export default class MImageBody extends React.Component {
;
}
}
+
+export class HiddenImagePlaceholder extends React.PureComponent {
+ static propTypes = {
+ hover: PropTypes.bool,
+ };
+
+ render() {
+ let className = 'mx_HiddenImagePlaceholder';
+ if (this.props.hover) className += ' mx_HiddenImagePlaceholder_hover';
+ return (
+
+
+
+ {_t("Show image")}
+
+
+ );
+ }
+}
diff --git a/src/components/views/messages/MStickerBody.js b/src/components/views/messages/MStickerBody.js
index 6a4128dfa7..ed82d49576 100644
--- a/src/components/views/messages/MStickerBody.js
+++ b/src/components/views/messages/MStickerBody.js
@@ -14,21 +14,27 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-'use strict';
-
import React from 'react';
import MImageBody from './MImageBody';
import sdk from '../../../index';
export default class MStickerBody extends MImageBody {
- // Empty to prevent default behaviour of MImageBody
- onClick() {
+ // Mostly empty to prevent default behaviour of MImageBody
+ onClick(ev) {
+ ev.preventDefault();
+ if (!this.state.showImage) {
+ this.showImage();
+ }
}
// MStickerBody doesn't need a wrapping ``, but it does need extra padding
// which is added by mx_MStickerBody_wrapper
wrapImage(contentUrl, children) {
- return