From 34bb37aaba4c4401b6096d46b61dff00a088c077 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 11 Sep 2016 02:14:27 +0100 Subject: [PATCH] layout for file & notif panel --- src/components/structures/FilePanel.js | 1 + src/components/structures/MessagePanel.js | 4 + .../structures/NotificationPanel.js | 1 + src/components/structures/TimelinePanel.js | 4 + src/components/views/messages/MFileBody.js | 38 ++++-- src/components/views/messages/MImageBody.js | 31 ++++- src/components/views/messages/MVideoBody.js | 25 ++++ src/components/views/messages/MessageEvent.js | 4 + src/components/views/rooms/EventTile.js | 122 ++++++++++++++---- 9 files changed, 186 insertions(+), 44 deletions(-) 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 ( - -
- - - Download {text} - -
-
- ); + if (this.props.tileShape === "file_grid") { + return ( + +
+ + { content.body && content.body.length > 0 ? content.body : "Attachment" } + +
+ { content.info && content.info.size ? filesize(content.info.size) : "" } +
+
+
+ ); + } + else { + return ( + +
+ + + Download {text} + +
+
+ ); + } } 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 = ( +
+ + + Download {content.body} ({ content.info && content.info.size ? filesize(content.info.size) : "Unknown size" }) + +
+ ); + } + var thumbUrl = this._getThumbUrl(); if (thumbUrl) { return ( @@ -133,12 +157,7 @@ module.exports = React.createClass({ onMouseEnter={this.onImageEnter} onMouseLeave={this.onImageLeave} /> -
- - - Download {content.body} ({ content.info && content.info.size ? filesize(content.info.size) : "Unknown size" }) - -
+ { 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 = ( +
+ + + Download {content.body} ({ content.info && content.info.size ? filesize(content.info.size) : "Unknown size" }) + +
+ ); + } + 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 = ( Options ); - return ( -
-
- { readAvatars } + if (this.props.tileShape === "notif") { + var room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId()); + + return ( +
+ +
+ { avatar } + + { sender } + + +
+
+ +
- { avatar } - { sender } -
- { timestamp } - - { editButton } + ); + } + else if (this.props.tileShape === "file_grid") { + return ( + -
- ); + ); + } + else { + return ( +
+
+ { readAvatars } +
+ { avatar } + { sender } +
+ + + + + { editButton } +
+
+ ); + } }, });