diff --git a/src/components/structures/FilePanel.js b/src/components/structures/FilePanel.js
index 6c4a63c24b..0dd16a7e99 100644
--- a/src/components/structures/FilePanel.js
+++ b/src/components/structures/FilePanel.js
@@ -103,6 +103,7 @@ var FilePanel = React.createClass({
manageReadMarkers={false}
timelineSet={this.state.timelineSet}
showUrlPreview = { false }
+ tileShape="file_grid"
opacity={ this.props.opacity }
/>
);
diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js
index 4dd4a488f9..6f2d8f038b 100644
--- a/src/components/structures/MessagePanel.js
+++ b/src/components/structures/MessagePanel.js
@@ -79,6 +79,9 @@ module.exports = React.createClass({
// className for the panel
className: React.PropTypes.string.isRequired,
+
+ // shape parameter to be passed to EventTiles
+ tileShape: React.PropTypes.string,
},
componentWillMount: function() {
@@ -392,6 +395,7 @@ module.exports = React.createClass({
showUrlPreview={this.props.showUrlPreview}
checkUnmounting={this._isUnmounting}
eventSendStatus={mxEv.status}
+ tileShape={this.props.tileShape}
last={last} isSelectedEvent={highlight}/>
);
diff --git a/src/components/structures/NotificationPanel.js b/src/components/structures/NotificationPanel.js
index e1b7d72002..7d9e752657 100644
--- a/src/components/structures/NotificationPanel.js
+++ b/src/components/structures/NotificationPanel.js
@@ -47,6 +47,7 @@ var NotificationPanel = React.createClass({
timelineSet={timelineSet}
showUrlPreview = { false }
opacity={ this.props.opacity }
+ tileShape="notif"
/>
);
}
diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js
index 8fbe4334c8..be35e9cbdd 100644
--- a/src/components/structures/TimelinePanel.js
+++ b/src/components/structures/TimelinePanel.js
@@ -93,6 +93,9 @@ var TimelinePanel = React.createClass({
// classname to use for the messagepanel
className: React.PropTypes.string,
+
+ // shape property to be passed to EventTiles
+ tileShape: React.PropTypes.string,
},
statics: {
@@ -979,6 +982,7 @@ var TimelinePanel = React.createClass({
onFillRequest={ this.onMessageListFillRequest }
opacity={ this.props.opacity }
className={ this.props.className }
+ tileShape={ this.props.tileShape }
/>
);
},
diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js
index dbad084024..c37cd32c4e 100644
--- a/src/components/views/messages/MFileBody.js
+++ b/src/components/views/messages/MFileBody.js
@@ -57,18 +57,34 @@ module.exports = React.createClass({
var TintableSvg = sdk.getComponent("elements.TintableSvg");
if (httpUrl) {
- return (
-
-
-
- );
+ if (this.props.tileShape === "file_grid") {
+ return (
+
+
+
+ );
+ }
+ else {
+ return (
+
+
+
+ );
+ }
} else {
- var extra = text ? ': '+text : '';
+ var extra = text ? (': ' + text) : '';
return
Invalid file{extra}
diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js
index ec594af2ce..526fc6a3a5 100644
--- a/src/components/views/messages/MImageBody.js
+++ b/src/components/views/messages/MImageBody.js
@@ -123,6 +123,30 @@ module.exports = React.createClass({
var content = this.props.mxEvent.getContent();
var cli = MatrixClientPeg.get();
+ var download;
+ if (this.props.tileShape === "file_grid") {
+ download = (
+
+
+ {content.body}
+
+
+ { content.info && content.info.size ? filesize(content.info.size) : "" }
+
+
+ );
+ }
+ else {
+ download = (
+
+ );
+ }
+
var thumbUrl = this._getThumbUrl();
if (thumbUrl) {
return (
@@ -133,12 +157,7 @@ module.exports = React.createClass({
onMouseEnter={this.onImageEnter}
onMouseLeave={this.onImageLeave} />
-
+ { download }
);
} else if (content.body) {
diff --git a/src/components/views/messages/MVideoBody.js b/src/components/views/messages/MVideoBody.js
index c8327a71ae..2494ab9499 100644
--- a/src/components/views/messages/MVideoBody.js
+++ b/src/components/views/messages/MVideoBody.js
@@ -69,12 +69,37 @@ module.exports = React.createClass({
}
}
+ var download;
+ if (this.props.tileShape === "file_grid") {
+ download = (
+
+
+ {content.body}
+
+
+ { content.info && content.info.size ? filesize(content.info.size) : "" }
+
+
+ );
+ }
+ else {
+ download = (
+
+ );
+ }
+
return (
+ { download }
);
},
diff --git a/src/components/views/messages/MessageEvent.js b/src/components/views/messages/MessageEvent.js
index 26658c3005..4ac0c0dabb 100644
--- a/src/components/views/messages/MessageEvent.js
+++ b/src/components/views/messages/MessageEvent.js
@@ -37,6 +37,9 @@ module.exports = React.createClass({
/* callback called when dynamic content in events are loaded */
onWidgetLoad: React.PropTypes.func,
+
+ /* the shsape of the tile, used */
+ tileShape: React.PropTypes.string,
},
getEventTileOps: function() {
@@ -69,6 +72,7 @@ module.exports = React.createClass({
return ;
},
});
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index b1df3f3267..f3ae3dff7f 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -128,6 +128,15 @@ module.exports = React.createClass({
/* the status of this event - ie, mxEvent.status. Denormalised to here so
* that we can tell when it changes. */
eventSendStatus: React.PropTypes.string,
+
+ /* the shape of the tile. by default, the layout is intended for the
+ * normal room timeline. alternative values are: "file_list", "file_grid"
+ * and "notif". This could be done by CSS, but it'd be horribly inefficient.
+ * It could also be done by subclassing EventTile, but that'd be quite
+ * boiilerplatey. So just make the necessary render decisions conditional
+ * for now.
+ */
+ tileShape: React.PropTypes.string,
},
getInitialState: function() {
@@ -382,18 +391,16 @@ module.exports = React.createClass({
this.props.eventSendStatus
) !== -1,
mx_EventTile_notSent: this.props.eventSendStatus == 'not_sent',
- mx_EventTile_highlight: this.shouldHighlight(),
+ mx_EventTile_highlight: this.props.tileShape === 'notif' ? false : this.shouldHighlight(),
mx_EventTile_selected: this.props.isSelectedEvent,
- mx_EventTile_continuation: this.props.continuation,
+ mx_EventTile_continuation: this.props.tileShape ? '' : this.props.continuation,
mx_EventTile_last: this.props.last,
mx_EventTile_contextual: this.props.contextual,
menu: this.state.menu,
mx_EventTile_verified: this.state.verified == true,
mx_EventTile_unverified: this.state.verified == false,
});
- var timestamp =
-
-
+ var permalink = "#/room/" + this.props.mxEvent.getRoomId() +"/"+ this.props.mxEvent.getId();
var readAvatars = this.getReadAvatars();
@@ -401,7 +408,10 @@ module.exports = React.createClass({
let avatarSize;
let needsSenderProfile;
- if (isInfoMessage) {
+ if (this.props.tileShape === "notif") {
+ avatarSize = 24;
+ needsSenderProfile = true;
+ } else if (isInfoMessage) {
// a small avatar, with no sender profile, for emotes and
// joins/parts/etc
avatarSize = 14;
@@ -428,35 +438,93 @@ module.exports = React.createClass({
if (needsSenderProfile) {
let aux = null;
- if (msgtype === 'm.image') aux = "sent an image";
- else if (msgtype === 'm.video') aux = "sent a video";
- else if (msgtype === 'm.file') aux = "uploaded a file";
+ if (!this.props.tileShape) {
+ if (msgtype === 'm.image') aux = "sent an image";
+ else if (msgtype === 'm.video') aux = "sent a video";
+ else if (msgtype === 'm.file') aux = "uploaded a file";
+ sender = ;
+ }
+ else {
+ sender = ;
+ }
- sender = ;
}
var editButton = (
);
- return (
-
-
- { readAvatars }
+ if (this.props.tileShape === "notif") {
+ var room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
+
+ return (
+
- { avatar }
- { sender }
-
- { timestamp }
-
- { editButton }
+ );
+ }
+ else if (this.props.tileShape === "file_grid") {
+ return (
+
-
- );
+ );
+ }
+ else {
+ return (
+
+
+ { readAvatars }
+
+ { avatar }
+ { sender }
+
+
+
+
+
+ { editButton }
+
+
+ );
+ }
},
});