From 491ba942308041feebe6e2813113dd4f4695b29c Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 18 Jan 2016 17:39:23 +0000 Subject: [PATCH 01/23] WIP: try to support non-guest room peek. Rename visibility permissions in room settings a bit, and fix how they are persisted. --- src/components/structures/MatrixChat.js | 5 + src/components/structures/RoomView.js | 119 ++++++++++++++----- src/components/views/rooms/RoomPreviewBar.js | 42 +++++-- src/components/views/rooms/RoomSettings.js | 7 +- 4 files changed, 132 insertions(+), 41 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 462933cbc6..71910b6f31 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -65,6 +65,7 @@ module.exports = React.createClass({ collapse_rhs: false, ready: false, width: 10000, + autoPeek: true, // by default, we peek into rooms when we try to join them }; if (s.logged_in) { if (MatrixClientPeg.get().getRooms().length) { @@ -304,6 +305,9 @@ module.exports = React.createClass({ }); break; case 'view_room': + // by default we autoPeek rooms, unless we were called explicitly with + // autoPeek=false by something like RoomDirectory who has already peeked + this.setState({ autoPeek : payload.auto_peek === false ? false : true }); this._viewRoom(payload.room_id, payload.show_settings); break; case 'view_prev_room': @@ -787,6 +791,7 @@ module.exports = React.createClass({ ); diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 5604565dd7..b4986e7a33 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -57,7 +57,9 @@ if (DEBUG_SCROLL) { module.exports = React.createClass({ displayName: 'RoomView', propTypes: { - ConferenceHandler: React.PropTypes.any + ConferenceHandler: React.PropTypes.any, + roomId: React.PropTypes.string, + autoPeek: React.PropTypes.bool, // should we try to peek the room on mount, or has whoever invoked us already initiated a peek? }, /* properties in RoomView objects include: @@ -78,7 +80,9 @@ module.exports = React.createClass({ syncState: MatrixClientPeg.get().getSyncState(), hasUnsentMessages: this._hasUnsentMessages(room), callState: null, + autoPeekDone: false, // track whether our autoPeek (if any) has completed) guestsCanJoin: false, + canPeek: false, readMarkerEventId: room ? room.getEventReadUpTo(MatrixClientPeg.get().credentials.userId) : null, readMarkerGhostEventId: undefined } @@ -86,6 +90,7 @@ module.exports = React.createClass({ componentWillMount: function() { this.dispatcherRef = dis.register(this.onAction); + MatrixClientPeg.get().on("Room", this.onNewRoom); MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline); MatrixClientPeg.get().on("Room.name", this.onRoomName); MatrixClientPeg.get().on("Room.accountData", this.onRoomAccountData); @@ -110,9 +115,13 @@ module.exports = React.createClass({ // We can't try to /join because this may implicitly accept invites (!) // We can /peek though. If it fails then we present the join UI. If it // succeeds then great, show the preview (but we still may be able to /join!). - if (!this.state.room) { + if (!this.state.room && this.props.autoPeek) { console.log("Attempting to peek into room %s", this.props.roomId); MatrixClientPeg.get().peekInRoom(this.props.roomId).done(() => { + this.setState({ + autoPeekDone: true; + }); + // we don't need to do anything - JS SDK will emit Room events // which will update the UI. We *do* however need to know if we // can join the room so we can fiddle with the UI appropriately. @@ -120,15 +129,20 @@ module.exports = React.createClass({ if (!peekedRoom) { return; } + var guestAccessEvent = peekedRoom.currentState.getStateEvents("m.room.guest_access", ""); - if (!guestAccessEvent) { - return; - } - if (guestAccessEvent.getContent().guest_access === "can_join") { + if (guestAccessEvent && guestAccessEvent.getContent().guest_access === "can_join") { this.setState({ guestsCanJoin: true }); } + + var historyVisibility = peekedRoom.currentState.getStateEvents("m.room.history_visibility", ""); + if (historyVisibility && historyVisibility.getContent().history_visibility === "world_readable") { + this.setState({ + canPeek: true + }); + } }, function(err) { console.error("Failed to peek into room: %s", err); }); @@ -155,6 +169,7 @@ module.exports = React.createClass({ } dis.unregister(this.dispatcherRef); if (MatrixClientPeg.get()) { + MatrixClientPeg.get().removeListener("Room", this.onNewRoom); MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); MatrixClientPeg.get().removeListener("Room.name", this.onRoomName); MatrixClientPeg.get().removeListener("Room.accountData", this.onRoomAccountData); @@ -278,6 +293,14 @@ module.exports = React.createClass({ }); }, + onNewRoom: function(room) { + if (room.roomId == this.props.roomId) { + this.setState({ + room: room + }); + } + }, + onRoomName: function(room) { if (room.roomId == this.props.roomId) { this.setState({ @@ -929,9 +952,10 @@ module.exports = React.createClass({ ); } + var visibilityDeferred; if (old_history_visibility != newVals.history_visibility && newVals.history_visibility != undefined) { - deferreds.push( + visibilityDeferred = MatrixClientPeg.get().sendStateEvent( this.state.room.roomId, "m.room.history_visibility", { history_visibility: newVals.history_visibility, @@ -940,6 +964,27 @@ module.exports = React.createClass({ ); } + if (old_guest_read != newVals.guest_read || + old_guest_join != newVals.guest_join) + { + var guestDeferred = + MatrixClientPeg.get().setGuestAccess(this.state.room.roomId, { + allowRead: newVals.guest_read, + allowJoin: newVals.guest_join + }); + + if (visibilityDeferred) { + visibilityDeferred = visibilityDeferred.then(guestDeferred); + } + else { + visibilityDeferred = guestDeferred; + } + } + + if (visibilityDeferred) { + deferreds.push(visibilityDeferred); + } + if (newVals.power_levels) { deferreds.push( MatrixClientPeg.get().sendStateEvent( @@ -1033,17 +1078,6 @@ module.exports = React.createClass({ ); } - if (old_guest_read != newVals.guest_read || - old_guest_join != newVals.guest_join) - { - deferreds.push( - MatrixClientPeg.get().setGuestAccess(this.state.room.roomId, { - allowRead: newVals.guest_read, - allowJoin: newVals.guest_join - }) - ); - } - if (deferreds.length) { var self = this; q.allSettled(deferreds).then( @@ -1391,12 +1425,28 @@ module.exports = React.createClass({ if (!this.state.room) { if (this.props.roomId) { - return ( -
- -
- ); - } else { + if (this.props.autoPeek && !this.state.autoPeekDone) { + return ( +
+ +
+ ); + } + else { + var joinErrorText = this.state.joinError ? "Failed to join room!" : ""; + return ( +
+ +
+ +
{joinErrorText}
+
+
+ ); + } + } + else { return (
); @@ -1417,16 +1467,21 @@ module.exports = React.createClass({ var inviteEvent = myMember.events.member; var inviterName = inviteEvent.sender ? inviteEvent.sender.name : inviteEvent.getSender(); // XXX: Leaving this intentionally basic for now because invites are about to change totally + // FIXME: This comment is now outdated - what do we need to fix? ^ var joinErrorText = this.state.joinError ? "Failed to join room!" : ""; var rejectErrorText = this.state.rejectError ? "Failed to reject invite!" : ""; + + // We deliberately don't try to peek into invites, even if we have permission to peek + // as they could be a spam vector. + // XXX: in future we could give the option of a 'Preview' button which lets them view anyway. return (
-
-
{inviterName} has invited you to a room
-
- - +
+
{joinErrorText}
{rejectErrorText}
@@ -1544,6 +1599,12 @@ module.exports = React.createClass({ ); } + else if (this.state.canPeek && + (!myMember || myMember.membership !== "join")) { + aux = ( + + ); + } var conferenceCallNotification = null; if (this.state.displayConfCallNotification) { diff --git a/src/components/views/rooms/RoomPreviewBar.js b/src/components/views/rooms/RoomPreviewBar.js index 2f12c4c8e2..657aa6a4d9 100644 --- a/src/components/views/rooms/RoomPreviewBar.js +++ b/src/components/views/rooms/RoomPreviewBar.js @@ -23,33 +23,57 @@ module.exports = React.createClass({ propTypes: { onJoinClick: React.PropTypes.func, - canJoin: React.PropTypes.bool + onRejectClick: React.PropTypes.func, + inviterName: React.PropTypes.string, + canJoin: React.PropTypes.bool, + canPreview: React.PropTypes.bool, }, getDefaultProps: function() { return { onJoinClick: function() {}, - canJoin: false + canJoin: false, + canPreview: true, }; }, render: function() { - var joinBlock; + var joinBlock, previewBlock; - if (this.props.canJoin) { + if (this.props.inviter) { + joinBlock = ( +
+
+ You have been invited to join this room by { this.props.inviterName } +
+
+ Would you like to accept or + decline this invitation? +
+
+ ); + + } + else if (this.props.canJoin) { joinBlock = (
- Would you like to join this room? + Would you like to join this room? +
+ ); + } + + if (this.props.canPreview) { + previewBlock = ( +
+ This is a preview of this room. Room interactions have been disabled.
); } return (
-
- This is a preview of this room. Room interactions have been disabled. -
- {joinBlock} + { previewBlock } + { joinBlock }
); } diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index 0ff15a4f43..f41e30091b 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -660,12 +660,13 @@ module.exports = React.createClass({ }
+ // FIXME: disable guests_read if the user hasn't turned on shared history return (

-
-
-
+
+
+
{ tags_section } From 7b91d3c5f84c59875ced881ddfc0ab6124e446c0 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 18 Jan 2016 19:56:38 +0000 Subject: [PATCH 02/23] wording changes from Amandine to settings --- src/components/views/rooms/RoomSettings.js | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index 07751ee4da..808e703b52 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -482,7 +482,7 @@ module.exports = React.createClass({ remote_aliases_section =
- This room can be found elsewhere as: + Remote addresses for this room:
{ remote_domains.map(function(state_key, i) { @@ -513,7 +513,7 @@ module.exports = React.createClass({ return }); })} - + } else { @@ -522,11 +522,12 @@ module.exports = React.createClass({ var aliases_section =
-

Directory

+

Addresses

+
The main address for this room is: { canonical_alias_section }
{ this.state.aliases[domain].length - ? "This room can be found on " + domain + " as:" - : "This room is not findable on " + domain } + ? "Local addresses for this room:" + : "This room has no local addresses" }
{ this.state.aliases[domain].map(function(alias, i) { @@ -539,7 +540,7 @@ module.exports = React.createClass({ The official way to refer to this room is: { canonical_alias_section }
; var room_colors_section = @@ -676,23 +676,23 @@ module.exports = React.createClass({ // FIXME: disable guests_read if the user hasn't turned on shared history return (
-
-
-
-
- { tags_section } +
+ + + + + + +
+ + { room_colors_section } { aliases_section } -

Notifications

-
- -
-

Permissions

@@ -736,7 +736,7 @@ module.exports = React.createClass({ { unfederatable_section }
-

Users

+

Privileged Users

Your role in this room is currently . From 0a79b0f9e28002d3925be7b982f10e76a99b6c0b Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 18 Jan 2016 19:56:47 +0000 Subject: [PATCH 03/23] fix NPE from kegan's memberlist branch --- src/components/views/rooms/MemberList.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index ff76e64c56..abcd3f83da 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -319,6 +319,8 @@ module.exports = React.createClass({ } else { // TODO: Cache this calculation var room = MatrixClientPeg.get().getRoom(this.props.roomId); + if (!room) return
; + var allUsers = MatrixClientPeg.get().getUsers(); // only add Users if they are not joined allUsers = allUsers.filter(function(u) { From eb7144ef8515875fb3be11930d029c7a7a7c419f Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 18 Jan 2016 19:56:56 +0000 Subject: [PATCH 04/23] improve layout --- src/components/views/rooms/RoomPreviewBar.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/views/rooms/RoomPreviewBar.js b/src/components/views/rooms/RoomPreviewBar.js index 657aa6a4d9..6c39e67510 100644 --- a/src/components/views/rooms/RoomPreviewBar.js +++ b/src/components/views/rooms/RoomPreviewBar.js @@ -56,8 +56,10 @@ module.exports = React.createClass({ } else if (this.props.canJoin) { joinBlock = ( -
- Would you like to join this room? +
+
+ Would you like to join this room? +
); } @@ -72,8 +74,10 @@ module.exports = React.createClass({ return (
- { previewBlock } - { joinBlock } +
+ { joinBlock } + { previewBlock } +
); } From f22519f10c66d200943028f9e55cfbfd7196fc19 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 18 Jan 2016 20:05:33 +0000 Subject: [PATCH 05/23] factor out the peek rule calculation so that we can do it both onNewRoom and if there's a room already. I guess we could do it in react's onStateUpdate too --- src/components/structures/RoomView.js | 63 +++++++++++++++------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index f8511bce6b..9c8dc42eca 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -115,23 +115,26 @@ module.exports = React.createClass({ // We can't try to /join because this may implicitly accept invites (!) // We can /peek though. If it fails then we present the join UI. If it // succeeds then great, show the preview (but we still may be able to /join!). - if (!this.state.room && this.props.autoPeek) { - console.log("Attempting to peek into room %s", this.props.roomId); - MatrixClientPeg.get().peekInRoom(this.props.roomId).done(() => { - this.setState({ - autoPeekDone: true - }); + if (!this.state.room) { + if (this.props.autoPeek) { + console.log("Attempting to peek into room %s", this.props.roomId); + MatrixClientPeg.get().peekInRoom(this.props.roomId).done(() => { + this.setState({ + autoPeekDone: true + }); - // we don't need to do anything - JS SDK will emit Room events - // which will update the UI. We *do* however need to know if we - // can join the room so we can fiddle with the UI appropriately. - var peekedRoom = MatrixClientPeg.get().getRoom(this.props.roomId); - if (!peekedRoom) { - return; - } - }, function(err) { - console.error("Failed to peek into room: %s", err); - }); + // we don't need to do anything - JS SDK will emit Room events + // which will update the UI. We *do* however need to know if we + // can join the room so we can fiddle with the UI appropriately. + + // ...XXX: or do we? can't we just do them onNewRoom? + }, function(err) { + console.error("Failed to peek into room: %s", err); + }); + } + } + else { + this._calculatePeekRules(this.state.room); } }, @@ -284,20 +287,24 @@ module.exports = React.createClass({ this.setState({ room: room }); + } - var guestAccessEvent = room.currentState.getStateEvents("m.room.guest_access", ""); - if (guestAccessEvent && guestAccessEvent.getContent().guest_access === "can_join") { - this.setState({ - guestsCanJoin: true - }); - } + this._calculatePeekRules(room); + }, - var historyVisibility = room.currentState.getStateEvents("m.room.history_visibility", ""); - if (historyVisibility && historyVisibility.getContent().history_visibility === "world_readable") { - this.setState({ - canPeek: true - }); - } + _calculatePeekRules: function(room) { + var guestAccessEvent = room.currentState.getStateEvents("m.room.guest_access", ""); + if (guestAccessEvent && guestAccessEvent.getContent().guest_access === "can_join") { + this.setState({ + guestsCanJoin: true + }); + } + + var historyVisibility = room.currentState.getStateEvents("m.room.history_visibility", ""); + if (historyVisibility && historyVisibility.getContent().history_visibility === "world_readable") { + this.setState({ + canPeek: true + }); } }, From c29ec28dfd19143feca5457f1b4700b6ce505abf Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 18 Jan 2016 20:15:12 +0000 Subject: [PATCH 06/23] fix layout for blunt join msgs --- src/components/structures/RoomView.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 9c8dc42eca..a8c2cca56d 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1457,6 +1457,7 @@ module.exports = React.createClass({ canJoin={ true } canPreview={ false }/>
{joinErrorText}
+
); } @@ -1489,6 +1490,7 @@ module.exports = React.createClass({ // We deliberately don't try to peek into invites, even if we have permission to peek // as they could be a spam vector. // XXX: in future we could give the option of a 'Preview' button which lets them view anyway. + return (
@@ -1500,6 +1502,7 @@ module.exports = React.createClass({
{joinErrorText}
{rejectErrorText}
+
); } From 2274cb3f7fb698c629dbc966d791c97ddaa89524 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 18 Jan 2016 20:18:46 +0000 Subject: [PATCH 07/23] fix invite prompt --- src/components/views/rooms/RoomPreviewBar.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/views/rooms/RoomPreviewBar.js b/src/components/views/rooms/RoomPreviewBar.js index 6c39e67510..52e6639f13 100644 --- a/src/components/views/rooms/RoomPreviewBar.js +++ b/src/components/views/rooms/RoomPreviewBar.js @@ -40,15 +40,14 @@ module.exports = React.createClass({ render: function() { var joinBlock, previewBlock; - if (this.props.inviter) { + if (this.props.inviterName) { joinBlock = (
You have been invited to join this room by { this.props.inviterName }
- Would you like to accept or - decline this invitation? + Would you like to accept or decline this invitation?
); From db7d863ce4f5f5fce4b09b4289358a6b48e8e648 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 19 Jan 2016 15:18:16 +0000 Subject: [PATCH 08/23] set autoPeekDone on finally --- src/components/structures/RoomView.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index a8c2cca56d..4dc6c33eef 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -119,10 +119,6 @@ module.exports = React.createClass({ if (this.props.autoPeek) { console.log("Attempting to peek into room %s", this.props.roomId); MatrixClientPeg.get().peekInRoom(this.props.roomId).done(() => { - this.setState({ - autoPeekDone: true - }); - // we don't need to do anything - JS SDK will emit Room events // which will update the UI. We *do* however need to know if we // can join the room so we can fiddle with the UI appropriately. @@ -130,6 +126,10 @@ module.exports = React.createClass({ // ...XXX: or do we? can't we just do them onNewRoom? }, function(err) { console.error("Failed to peek into room: %s", err); + }).finally((() => { + this.setState({ + autoPeekDone: true + }); }); } } From 84608ba156b2e5ea9a3df9bfeef813168059fbbf Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 19 Jan 2016 16:18:08 +0000 Subject: [PATCH 09/23] Fix syntax error --- src/components/structures/RoomView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 4dc6c33eef..3cf3f4aafc 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -126,7 +126,7 @@ module.exports = React.createClass({ // ...XXX: or do we? can't we just do them onNewRoom? }, function(err) { console.error("Failed to peek into room: %s", err); - }).finally((() => { + }).finally(() => { this.setState({ autoPeekDone: true }); From 8dc21ec83721bf8b7b9b8289d9d9e1867e28e5fd Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 20 Jan 2016 15:25:40 +0000 Subject: [PATCH 10/23] Fix race condition when joining rooms Problem: Hitting join on a room invite would show spinner, then join room screen then the messages. Cause: The UI to show a spinner is set via the "joining" flag. This flag was only set for the duration of the /join HTTP request. This is insufficient because it races with actual room info arriving from /sync. If this info does not arrive before the /join HTTP request returns, "joining" is false but the current membership state of the user is still invite. Fix: The "joining" flag is still set when the /join HTTP request is made, but it is only turned off when the join event arrives from /sync. Extras: This fix should also work when joining a room not from an invite. --- src/components/structures/RoomView.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 3cf3f4aafc..951a9a5ec1 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -379,6 +379,14 @@ module.exports = React.createClass({ if (member.roomId === this.props.roomId) { // a member state changed in this room, refresh the tab complete list this._updateTabCompleteList(this.state.room); + + var room = MatrixClientPeg.get().getRoom(this.props.roomId); + var me = MatrixClientPeg.get().credentials.userId; + if (this.state.joining && room.hasMembershipState(me, "join")) { + this.setState({ + joining: false + }); + } } if (!this.props.ConferenceHandler) { @@ -552,10 +560,17 @@ module.exports = React.createClass({ onJoinButtonClicked: function(ev) { var self = this; - MatrixClientPeg.get().joinRoom(this.props.roomId).then(function() { + MatrixClientPeg.get().joinRoom(this.props.roomId).done(function() { + // It is possible that there is no Room yet if state hasn't come down + // from /sync - joinRoom will resolve when the HTTP request to join succeeds, + // NOT when it comes down /sync. If there is no room, we'll keep the + // joining flag set until we see it. Likewise, if our state is not + // "join" we'll keep this flag set until it comes down /sync. + var room = MatrixClientPeg.get().getRoom(self.props.roomId); + var me = MatrixClientPeg.get().credentials.userId; self.setState({ - joining: false, - room: MatrixClientPeg.get().getRoom(self.props.roomId) + joining: room ? !room.hasMembershipState(me, "join") : true, + room: room }); }, function(error) { self.setState({ From b296d05b350ad4d4a915e983e2a95630d4e12d79 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 20 Jan 2016 15:38:34 +0000 Subject: [PATCH 11/23] Fix finally NPE --- src/components/structures/RoomView.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 951a9a5ec1..e2a9f8b730 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -118,15 +118,11 @@ module.exports = React.createClass({ if (!this.state.room) { if (this.props.autoPeek) { console.log("Attempting to peek into room %s", this.props.roomId); - MatrixClientPeg.get().peekInRoom(this.props.roomId).done(() => { - // we don't need to do anything - JS SDK will emit Room events - // which will update the UI. We *do* however need to know if we - // can join the room so we can fiddle with the UI appropriately. - - // ...XXX: or do we? can't we just do them onNewRoom? - }, function(err) { + MatrixClientPeg.get().peekInRoom(this.props.roomId).catch((err) => { console.error("Failed to peek into room: %s", err); }).finally(() => { + // we don't need to do anything - JS SDK will emit Room events + // which will update the UI. this.setState({ autoPeekDone: true }); From 4d2608017b9a2fc829297c9218ac74f8e29cd851 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jan 2016 15:39:56 +0000 Subject: [PATCH 12/23] fix CSS for ChangeAvatar placeholder --- src/components/views/settings/ChangeAvatar.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/views/settings/ChangeAvatar.js b/src/components/views/settings/ChangeAvatar.js index 7bd3d7754b..8fd0f20def 100644 --- a/src/components/views/settings/ChangeAvatar.js +++ b/src/components/views/settings/ChangeAvatar.js @@ -122,8 +122,7 @@ module.exports = React.createClass({ height: this.props.height, objectFit: 'cover', }; - // FIXME: surely we should be using MemberAvatar or UserAvatar or something here... - avatarImg = ; + avatarImg = ; } var uploadSection; From dbcbd2aad8be4f7616bced2027eec8e9d0d92816 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jan 2016 15:52:34 +0000 Subject: [PATCH 13/23] fix badge layout --- src/components/views/rooms/EntityTile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/EntityTile.js b/src/components/views/rooms/EntityTile.js index 55629aa8b0..d20329fcd8 100644 --- a/src/components/views/rooms/EntityTile.js +++ b/src/components/views/rooms/EntityTile.js @@ -128,10 +128,10 @@ module.exports = React.createClass({ onClick={ this.props.onClick } onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave }>
- {av} + { av } + { power }
{ nameEl } - { power } { inviteButton }
); From 14c2d945d686cc50ed55fea86f620816621677d7 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jan 2016 15:58:17 +0000 Subject: [PATCH 14/23] oops, use right class --- src/components/views/settings/ChangeAvatar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/settings/ChangeAvatar.js b/src/components/views/settings/ChangeAvatar.js index 8fd0f20def..89303856b2 100644 --- a/src/components/views/settings/ChangeAvatar.js +++ b/src/components/views/settings/ChangeAvatar.js @@ -122,7 +122,7 @@ module.exports = React.createClass({ height: this.props.height, objectFit: 'cover', }; - avatarImg = ; + avatarImg = ; } var uploadSection; From 76279e29409093c5600a9bbb4a7f783135404376 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jan 2016 16:39:26 +0000 Subject: [PATCH 15/23] fix roomsettings a bit --- src/components/views/rooms/RoomSettings.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index 808e703b52..3a444707a9 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -295,8 +295,8 @@ module.exports = React.createClass({ else { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Invalid alias format", - description: "'" + alias + "' is not a valid format for an alias", + title: "Invalid address format", + description: "'" + alias + "' is not a valid format for an address", }); } }, @@ -533,7 +533,8 @@ module.exports = React.createClass({ { this.state.aliases[domain].map(function(alias, i) { var deleteButton; if (can_set_room_aliases) { - deleteButton = Delete; + deleteButton = Delete; } return (
@@ -561,7 +562,8 @@ module.exports = React.createClass({ blurToCancel={ false } onValueChanged={ self.onAliasAdded } />
- Add + Add
@@ -659,7 +661,7 @@ module.exports = React.createClass({ var tags_section =
- This room is tagged as + Tagged as: { can_set_tag ? tags.map(function(tag, i) { return (
{ remote_domains.map(function(state_key, i) { - self.state.aliases[state_key].map(function(alias, j) { + return self.state.aliases[state_key].map(function(alias, j) { return (
-
-
); }); @@ -558,7 +556,7 @@ module.exports = React.createClass({ ref="add_alias" className="mx_RoomSettings_alias mx_RoomSettings_editable" placeholderClassName="mx_RoomSettings_aliasPlaceholder" - placeholder={ "New alias (e.g. #foo:" + domain + ")" } + placeholder={ "New address (e.g. #foo:" + domain + ")" } blurToCancel={ false } onValueChanged={ self.onAliasAdded } />
From 76b7788ba6a12e218464bee8e3515337254aa137 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jan 2016 17:07:00 +0000 Subject: [PATCH 17/23] usersettings rhs button --- src/components/structures/UserSettings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 488e7368d1..859be592e2 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -306,7 +306,7 @@ module.exports = React.createClass({ rowClassName="mx_UserSettings_profileTableRow" rowLabelClassName="mx_UserSettings_profileLabelCell" rowInputClassName="mx_UserSettings_profileInputCell" - buttonClassName="mx_UserSettings_button" + buttonClassName="mx_UserSettings_button mx_UserSettings_rhsButton" onError={this.onPasswordChangeError} onFinished={this.onPasswordChanged} /> ); @@ -353,7 +353,7 @@ module.exports = React.createClass({
-
+
Log out
From 442e090f37c7aacf790cf6d415665afdb12c973f Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jan 2016 17:09:46 +0000 Subject: [PATCH 18/23] button layout --- src/components/structures/UserSettings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 859be592e2..d1bb66356c 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -306,7 +306,7 @@ module.exports = React.createClass({ rowClassName="mx_UserSettings_profileTableRow" rowLabelClassName="mx_UserSettings_profileLabelCell" rowInputClassName="mx_UserSettings_profileInputCell" - buttonClassName="mx_UserSettings_button mx_UserSettings_rhsButton" + buttonClassName="mx_UserSettings_button mx_UserSettings_changePasswordButton" onError={this.onPasswordChangeError} onFinished={this.onPasswordChanged} /> ); @@ -353,7 +353,7 @@ module.exports = React.createClass({
-
+
Log out
From 705730d450b1517d31e606bd197662bb183ebae2 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jan 2016 17:12:55 +0000 Subject: [PATCH 19/23] fix user_levels --- src/components/views/rooms/RoomSettings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index e5a1d05da2..fab843cefa 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -597,7 +597,7 @@ module.exports = React.createClass({
; var user_levels_section; - if (user_levels.length) { + if (Object.keys(user_levels).length) { user_levels_section =
From 964e7c3739ff723632b771285d218538ef554707 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jan 2016 17:15:01 +0000 Subject: [PATCH 20/23] fix user_levels some more --- src/components/views/rooms/RoomSettings.js | 28 +++++++--------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index fab843cefa..74b7ba7e7c 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -599,21 +599,15 @@ module.exports = React.createClass({ var user_levels_section; if (Object.keys(user_levels).length) { user_levels_section = -
-
- Users with specific roles are: -
-
- {Object.keys(user_levels).map(function(user, i) { - return ( -
- { user } is a - -
- ); - })} -
-
; +
    + {Object.keys(user_levels).map(function(user, i) { + return ( +
  • + { user } is a +
  • + ); + })} +
; } else { user_levels_section =
No users have specific privileges in this room.
@@ -738,10 +732,6 @@ module.exports = React.createClass({

Privileged Users

-
- Your role in this room is currently . -
- { user_levels_section }
From 161cdef36ed2fe86e4d9d7b21b4b36ece7acddfb Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jan 2016 17:24:09 +0000 Subject: [PATCH 21/23] tint bottom borders --- src/Tinter.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tinter.js b/src/Tinter.js index 3e7949b65d..3612be5b10 100644 --- a/src/Tinter.js +++ b/src/Tinter.js @@ -63,6 +63,7 @@ var cssAttrs = [ "backgroundColor", "borderColor", "borderTopColor", + "borderBottomColor", ]; var svgAttrs = [ From 3aaf934c978d9b258baf75e87d1eafbd85619bae Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jan 2016 22:04:49 +0000 Subject: [PATCH 22/23] implement the correct design for memberlist, modulo gemini --- src/components/views/rooms/EntityTile.js | 2 +- src/components/views/rooms/MemberList.js | 10 +++++----- src/components/views/rooms/SearchableEntityList.js | 13 ++++++++----- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/components/views/rooms/EntityTile.js b/src/components/views/rooms/EntityTile.js index d20329fcd8..ed0e5cbc41 100644 --- a/src/components/views/rooms/EntityTile.js +++ b/src/components/views/rooms/EntityTile.js @@ -72,7 +72,7 @@ module.exports = React.createClass({ }, render: function() { - var presenceClass = PRESENCE_CLASS[this.props.presenceState]; + var presenceClass = PRESENCE_CLASS[this.props.presenceState] || "mx_EntityTile_offline"; var mainClassName = "mx_EntityTile "; mainClassName += presenceClass; if (this.state.hover) { diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index e38d6ae41d..69cd6ef9af 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -362,7 +362,7 @@ module.exports = React.createClass({ invitedSection = (

Invited

-
+
{invitedMemberTiles}
@@ -370,15 +370,15 @@ module.exports = React.createClass({ } return (
- {this.inviteTile()} -
+
{this.makeMemberTiles('join', this.state.searchQuery)}
+ {invitedSection} +
+
- {invitedSection} -
); } diff --git a/src/components/views/rooms/SearchableEntityList.js b/src/components/views/rooms/SearchableEntityList.js index b6232362ac..7617a237dc 100644 --- a/src/components/views/rooms/SearchableEntityList.js +++ b/src/components/views/rooms/SearchableEntityList.js @@ -104,13 +104,16 @@ var SearchableEntityList = React.createClass({ } return ( -
+
{inputBox} -
- {this.state.results.map((entity) => { - return entity.getJsx(); - })} +
+
+ {this.state.results.map((entity) => { + return entity.getJsx(); + })} +
+ { this.state.results.length ?

: '' }
); } From c0aa15aa09c4646906f1fa32278e89d761decc89 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 20 Jan 2016 22:11:58 +0000 Subject: [PATCH 23/23] now with gemini --- src/components/views/rooms/MemberList.js | 4 ++-- src/components/views/rooms/SearchableEntityList.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index 69cd6ef9af..64bebdeca3 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -371,12 +371,12 @@ module.exports = React.createClass({ return (
{this.inviteTile()} -
+
{this.makeMemberTiles('join', this.state.searchQuery)}
{invitedSection} -
+
diff --git a/src/components/views/rooms/SearchableEntityList.js b/src/components/views/rooms/SearchableEntityList.js index 7617a237dc..506a8ba92d 100644 --- a/src/components/views/rooms/SearchableEntityList.js +++ b/src/components/views/rooms/SearchableEntityList.js @@ -106,13 +106,13 @@ var SearchableEntityList = React.createClass({ return (
{inputBox} -
+
{this.state.results.map((entity) => { return entity.getJsx(); })}
-
+ { this.state.results.length ?

: '' }
);