From d782d5bbc757f271892b81608e3173d0426a8f78 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 5 Sep 2016 17:03:10 +0100 Subject: [PATCH 01/11] Fix error dialog on conf call error --- src/CallHandler.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CallHandler.js b/src/CallHandler.js index 4c68718709..c2ee05b22c 100644 --- a/src/CallHandler.js +++ b/src/CallHandler.js @@ -276,6 +276,7 @@ function _onAction(payload) { ).done(function(call) { placeCall(call); }, function(err) { + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { title: "Failed to set up conference call", description: "Conference call failed: " + err, From 50ef6957406d32db0d38b1b374ad070825493668 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 5 Sep 2016 17:42:22 +0100 Subject: [PATCH 02/11] Fix: conference rooms were no longer hidden --- src/MatrixTools.js | 48 ++++++++++++++++++-------- src/components/views/rooms/RoomList.js | 5 ++- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/MatrixTools.js b/src/MatrixTools.js index 3bc7f28e20..f442904862 100644 --- a/src/MatrixTools.js +++ b/src/MatrixTools.js @@ -26,30 +26,48 @@ module.exports = { return room.getCanonicalAlias() || room.getAliases()[0]; }, - isDirectMessageRoom: function(room, me, ConferenceHandler, hideConferenceChans) { + /** + * If the room contains only two members including the logged-in user, + * return the other one. Otherwise, return null. + */ + getOnlyOtherMember(room, me) { + const joinedMembers = room.getJoinedMembers(); + + if (joinedMembers.length === 2) { + return joinedMembers.filter(function(m) { + return m.userId !== me.userId + })[0]; + } + + return null; + }, + + isConfCallRoom: function(room, me, conferenceHandler) { + if (!conferenceHandler) return false; + + const otherMember = this.getOnlyOtherMember(room, me); + if (otherMember === null) { + return false; + } + + if (conferenceHandler.isConferenceUser(otherMember.userId)) { + return true; + } + }, + + isDirectMessageRoom: function(room, me) { if (me.membership == "join" || me.membership === "ban" || (me.membership === "leave" && me.events.member.getSender() !== me.events.member.getStateKey())) { // Used to split rooms via tags - var tagNames = Object.keys(room.tags); + const tagNames = Object.keys(room.tags); // Used for 1:1 direct chats - var joinedMembers = room.getJoinedMembers(); + const joinedMembers = room.getJoinedMembers(); // Show 1:1 chats in seperate "Direct Messages" section as long as they haven't // been moved to a different tag section if (joinedMembers.length === 2 && !tagNames.length) { - var otherMember = joinedMembers.filter(function(m) { - return m.userId !== me.userId - })[0]; - - if (ConferenceHandler && ConferenceHandler.isConferenceUser(otherMember.userId)) { - // console.log("Hiding conference 1:1 room %s", room.roomId); - if (!hideConferenceChans) { - return true; - } - } else { - return true; - } + return true; } } return false; diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 206bf8504e..4fef4ff0a4 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -221,7 +221,10 @@ module.exports = React.createClass({ if (me.membership == "invite") { s.lists["im.vector.fake.invite"].push(room); } - else if (MatrixTools.isDirectMessageRoom(room, me, self.props.ConferenceHandler, HIDE_CONFERENCE_CHANS)) { + else if (HIDE_CONFERENCE_CHANS && MatrixTools.isConfCallRoom(room, me, self.props.ConferenceHandler)) { + // skip past this room & don't put it in any lists + } + else if (MatrixTools.isDirectMessageRoom(room, me)) { // "Direct Message" rooms s.lists["im.vector.fake.direct"].push(room); } From 04889a89ecd732e84ad541348bf60b241636bdd1 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 5 Sep 2016 18:35:32 +0100 Subject: [PATCH 03/11] Only count rooms we're in as DM rooms --- src/MatrixTools.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/MatrixTools.js b/src/MatrixTools.js index f442904862..b95e21a4af 100644 --- a/src/MatrixTools.js +++ b/src/MatrixTools.js @@ -45,6 +45,10 @@ module.exports = { isConfCallRoom: function(room, me, conferenceHandler) { if (!conferenceHandler) return false; + if (me.membership != "join") { + return false; + } + const otherMember = this.getOnlyOtherMember(room, me); if (otherMember === null) { return false; From 840132315672b906b9d2a0aa30d1341899364340 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 6 Sep 2016 16:39:21 +0100 Subject: [PATCH 04/11] Hopefully read DM rooms from account data --- src/DMRoomMap.js | 46 ++++++++++++++++++++++++++ src/MatrixTools.js | 2 +- src/components/views/rooms/RoomList.js | 24 ++++++++++++-- 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/DMRoomMap.js diff --git a/src/DMRoomMap.js b/src/DMRoomMap.js new file mode 100644 index 0000000000..d92ae87e64 --- /dev/null +++ b/src/DMRoomMap.js @@ -0,0 +1,46 @@ +/* +Copyright 2016 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/** + * Class that takes a Matrix Client and flips the m.direct map + * so the operation of mapping a room ID to which user it's a DM + * with can be performed efficiently. + */ +export default class DMRoomMap { + constructor(matrixClient) { + const mDirectEvent = matrixClient.getAccountData('m.direct'); + if (!mDirectEvent) { + this.userToRooms = {}; + this.roomToUser = {}; + } else { + this.userToRooms = mDirectEvent.getContent(); + this.roomToUser = {}; + for (const user of Object.keys(this.userToRooms)) { + for (const roomId of this.userToRooms[user]) { + this.roomToUser[roomId] = user; + } + } + } + } + + getDMRoomsForUserId(userId) { + return this.userToRooms[userId]; + } + + getUserIdForRoomId(roomId) { + return this.roomToUser[roomId]; + } +} diff --git a/src/MatrixTools.js b/src/MatrixTools.js index b95e21a4af..f3c0cd6949 100644 --- a/src/MatrixTools.js +++ b/src/MatrixTools.js @@ -59,7 +59,7 @@ module.exports = { } }, - isDirectMessageRoom: function(room, me) { + looksLikeDirectMessageRoom: function(room, me) { if (me.membership == "join" || me.membership === "ban" || (me.membership === "leave" && me.events.member.getSender() !== me.events.member.getStateKey())) { diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 4fef4ff0a4..6ce85af82b 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -26,6 +26,7 @@ var dis = require("../../../dispatcher"); var sdk = require('../../../index'); var rate_limited_func = require('../../../ratelimitedfunc'); var MatrixTools = require('../../../MatrixTools'); +var DMRoomMap = require('../../../DMRoomMap'); var HIDE_CONFERENCE_CHANS = true; @@ -209,8 +210,10 @@ module.exports = React.createClass({ s.lists["m.lowpriority"] = []; s.lists["im.vector.fake.archived"] = []; + const dmRoomMap = new DMRoomMap(MatrixClientPeg.get()); + MatrixClientPeg.get().getRooms().forEach(function(room) { - var me = room.getMember(MatrixClientPeg.get().credentials.userId); + const me = room.getMember(MatrixClientPeg.get().credentials.userId); if (!me) return; // console.log("room = " + room.name + ", me.membership = " + me.membership + @@ -224,7 +227,7 @@ module.exports = React.createClass({ else if (HIDE_CONFERENCE_CHANS && MatrixTools.isConfCallRoom(room, me, self.props.ConferenceHandler)) { // skip past this room & don't put it in any lists } - else if (MatrixTools.isDirectMessageRoom(room, me)) { + else if (dmRoomMap.getUserIdForRoomId(room.roomId)) { // "Direct Message" rooms s.lists["im.vector.fake.direct"].push(room); } @@ -253,6 +256,23 @@ module.exports = React.createClass({ } }); + if (s.lists["im.vector.fake.direct"].length == 0 && MatrixClientPeg.get().getAccountData('m.direct') === undefined) { + // scan through the 'recents' list for any rooms which look like DM rooms + // and make them DM rooms + const oldRecents = s.lists["im.vector.fake.recent"]; + s.lists["im.vector.fake.recent"] = []; + + for (const room of oldRecents) { + const me = room.getMember(MatrixClientPeg.get().credentials.userId); + + if (!me || MatrixTools.looksLikeDirectMessageRoom(room, me)) { + s.lists["im.vector.fake.recent"].push(room); + } else { + s.lists["im.vector.fake.direct"].push(room); + } + } + } + //console.log("calculated new roomLists; im.vector.fake.recent = " + s.lists["im.vector.fake.recent"]); // we actually apply the sorting to this when receiving the prop in RoomSubLists. From d5b23e9e0eed0e4095299b0e994c8cfac0aa511e Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 6 Sep 2016 17:43:39 +0100 Subject: [PATCH 05/11] Save guessed DM rooms to account data Also bugfix --- src/components/views/rooms/RoomList.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 6ce85af82b..5067cdc92e 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -265,12 +265,27 @@ module.exports = React.createClass({ for (const room of oldRecents) { const me = room.getMember(MatrixClientPeg.get().credentials.userId); - if (!me || MatrixTools.looksLikeDirectMessageRoom(room, me)) { - s.lists["im.vector.fake.recent"].push(room); - } else { + if (me && MatrixTools.looksLikeDirectMessageRoom(room, me)) { s.lists["im.vector.fake.direct"].push(room); + } else { + s.lists["im.vector.fake.recent"].push(room); } } + + // save these new guessed DM rooms into the account data + const newMDirectEvent = {}; + for (const room of s.lists["im.vector.fake.direct"]) { + const me = room.getMember(MatrixClientPeg.get().credentials.userId); + const otherPerson = MatrixTools.getOnlyOtherMember(room, me); + if (!otherPerson) continue; + + const roomList = newMDirectEvent[otherPerson.userId] || []; + roomList.push(room.roomId); + newMDirectEvent[otherPerson.userId] = roomList; + } + + // if this fails, fine, we'll just do the same thing next time we get the room lists + MatrixClientPeg.get().setAccountData('m.direct', newMDirectEvent).done(); } //console.log("calculated new roomLists; im.vector.fake.recent = " + s.lists["im.vector.fake.recent"]); From 8f6d413ebd1df168b167bd1f46fbb606bb05a540 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 7 Sep 2016 10:07:43 +0100 Subject: [PATCH 06/11] Move DMRoomMap to a util subdir --- src/{ => utils}/DMRoomMap.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{ => utils}/DMRoomMap.js (100%) diff --git a/src/DMRoomMap.js b/src/utils/DMRoomMap.js similarity index 100% rename from src/DMRoomMap.js rename to src/utils/DMRoomMap.js From 094080629dca35ec38ea24a94e2eb90315a6eb29 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 7 Sep 2016 10:19:39 +0100 Subject: [PATCH 07/11] Actually commit changed path --- src/components/views/rooms/RoomList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 5067cdc92e..bdb1ea3c8c 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -26,7 +26,7 @@ var dis = require("../../../dispatcher"); var sdk = require('../../../index'); var rate_limited_func = require('../../../ratelimitedfunc'); var MatrixTools = require('../../../MatrixTools'); -var DMRoomMap = require('../../../DMRoomMap'); +var DMRoomMap = require('../../../utils/DMRoomMap'); var HIDE_CONFERENCE_CHANS = true; From db42d629aa3e6820fb61d14d9c53174b637f7f3e Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 7 Sep 2016 11:30:09 +0100 Subject: [PATCH 08/11] Rename MatrixTools to Rooms Since all the functions therein are to do with rooms, so this name is probably more helpful --- src/{MatrixTools.js => Rooms.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{MatrixTools.js => Rooms.js} (100%) diff --git a/src/MatrixTools.js b/src/Rooms.js similarity index 100% rename from src/MatrixTools.js rename to src/Rooms.js From df1cc8748f151f80a0e60b903c0b866756b6dfba Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 7 Sep 2016 11:33:58 +0100 Subject: [PATCH 09/11] Change references to MatrixTools to Rooms or remove where they were unused --- src/SlashCommands.js | 1 - src/autocomplete/RoomProvider.js | 2 +- src/components/structures/MatrixChat.js | 6 +++--- src/components/structures/RoomView.js | 1 - src/components/views/rooms/RoomList.js | 8 ++++---- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 759a95c8ff..be007496dd 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -15,7 +15,6 @@ limitations under the License. */ var MatrixClientPeg = require("./MatrixClientPeg"); -var MatrixTools = require("./MatrixTools"); var dis = require("./dispatcher"); var Tinter = require("./Tinter"); diff --git a/src/autocomplete/RoomProvider.js b/src/autocomplete/RoomProvider.js index 39cf1179d7..ac7f1b418a 100644 --- a/src/autocomplete/RoomProvider.js +++ b/src/autocomplete/RoomProvider.js @@ -4,7 +4,7 @@ import Q from 'q'; import MatrixClientPeg from '../MatrixClientPeg'; import Fuse from 'fuse.js'; import {PillCompletion} from './Components'; -import {getDisplayAliasForRoom} from '../MatrixTools'; +import {getDisplayAliasForRoom} from '../Rooms'; import sdk from '../index'; const ROOM_REGEX = /(?=#)([^\s]*)/g; diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index e1e622af65..251f3f1dc8 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -36,7 +36,7 @@ var PostRegistration = require("./login/PostRegistration"); var Modal = require("../../Modal"); var Tinter = require("../../Tinter"); var sdk = require('../../index'); -var MatrixTools = require('../../MatrixTools'); +var Rooms = require('../../Rooms'); var linkifyMatrix = require("../../linkify-matrix"); var KeyCode = require('../../KeyCode'); var Lifecycle = require('../../Lifecycle'); @@ -479,7 +479,7 @@ module.exports = React.createClass({ var presentedId = room_info.room_alias || room_info.room_id; var room = MatrixClientPeg.get().getRoom(room_info.room_id); if (room) { - var theAlias = MatrixTools.getDisplayAliasForRoom(room); + var theAlias = Rooms.getDisplayAliasForRoom(room); if (theAlias) presentedId = theAlias; // No need to do this given RoomView triggers it itself... @@ -592,7 +592,7 @@ module.exports = React.createClass({ var presentedId = self.state.currentRoomId; var room = MatrixClientPeg.get().getRoom(self.state.currentRoomId); if (room) { - var theAlias = MatrixTools.getDisplayAliasForRoom(room); + var theAlias = Rooms.getDisplayAliasForRoom(room); if (theAlias) presentedId = theAlias; } diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 3d0bcf7445..041493d420 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -36,7 +36,6 @@ var dis = require("../../dispatcher"); var Tinter = require("../../Tinter"); var rate_limited_func = require('../../ratelimitedfunc'); var ObjectUtils = require('../../ObjectUtils'); -var MatrixTools = require('../../MatrixTools'); import UserProvider from '../../autocomplete/UserProvider'; diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index bdb1ea3c8c..d679a1f4c6 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -25,7 +25,7 @@ var Unread = require('../../../Unread'); var dis = require("../../../dispatcher"); var sdk = require('../../../index'); var rate_limited_func = require('../../../ratelimitedfunc'); -var MatrixTools = require('../../../MatrixTools'); +var Rooms = require('../../../Rooms'); var DMRoomMap = require('../../../utils/DMRoomMap'); var HIDE_CONFERENCE_CHANS = true; @@ -224,7 +224,7 @@ module.exports = React.createClass({ if (me.membership == "invite") { s.lists["im.vector.fake.invite"].push(room); } - else if (HIDE_CONFERENCE_CHANS && MatrixTools.isConfCallRoom(room, me, self.props.ConferenceHandler)) { + else if (HIDE_CONFERENCE_CHANS && Rooms.isConfCallRoom(room, me, self.props.ConferenceHandler)) { // skip past this room & don't put it in any lists } else if (dmRoomMap.getUserIdForRoomId(room.roomId)) { @@ -265,7 +265,7 @@ module.exports = React.createClass({ for (const room of oldRecents) { const me = room.getMember(MatrixClientPeg.get().credentials.userId); - if (me && MatrixTools.looksLikeDirectMessageRoom(room, me)) { + if (me && Rooms.looksLikeDirectMessageRoom(room, me)) { s.lists["im.vector.fake.direct"].push(room); } else { s.lists["im.vector.fake.recent"].push(room); @@ -276,7 +276,7 @@ module.exports = React.createClass({ const newMDirectEvent = {}; for (const room of s.lists["im.vector.fake.direct"]) { const me = room.getMember(MatrixClientPeg.get().credentials.userId); - const otherPerson = MatrixTools.getOnlyOtherMember(room, me); + const otherPerson = Rooms.getOnlyOtherMember(room, me); if (!otherPerson) continue; const roomList = newMDirectEvent[otherPerson.userId] || []; From 8a4606cfbf81061c01b4f6afaf1624fb597d7549 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 7 Sep 2016 11:34:55 +0100 Subject: [PATCH 10/11] Remove unused import --- src/Rooms.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Rooms.js b/src/Rooms.js index f3c0cd6949..be3420b507 100644 --- a/src/Rooms.js +++ b/src/Rooms.js @@ -13,7 +13,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -var CallHandler = require('./CallHandler'); module.exports = { /** From 66b2944011f090e0fdc622dce0c92f17dff95b1f Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 7 Sep 2016 11:45:32 +0100 Subject: [PATCH 11/11] Convert Rooms.js to ES6 --- src/Rooms.js | 118 +++++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/src/Rooms.js b/src/Rooms.js index be3420b507..7f4564b439 100644 --- a/src/Rooms.js +++ b/src/Rooms.js @@ -14,66 +14,64 @@ See the License for the specific language governing permissions and limitations under the License. */ -module.exports = { - /** - * Given a room object, return the alias we should use for it, - * if any. This could be the canonical alias if one exists, otherwise - * an alias selected arbitrarily but deterministically from the list - * of aliases. Otherwise return null; - */ - getDisplayAliasForRoom: function(room) { - return room.getCanonicalAlias() || room.getAliases()[0]; - }, - /** - * If the room contains only two members including the logged-in user, - * return the other one. Otherwise, return null. - */ - getOnlyOtherMember(room, me) { - const joinedMembers = room.getJoinedMembers(); - - if (joinedMembers.length === 2) { - return joinedMembers.filter(function(m) { - return m.userId !== me.userId - })[0]; - } - - return null; - }, - - isConfCallRoom: function(room, me, conferenceHandler) { - if (!conferenceHandler) return false; - - if (me.membership != "join") { - return false; - } - - const otherMember = this.getOnlyOtherMember(room, me); - if (otherMember === null) { - return false; - } - - if (conferenceHandler.isConferenceUser(otherMember.userId)) { - return true; - } - }, - - looksLikeDirectMessageRoom: function(room, me) { - if (me.membership == "join" || me.membership === "ban" || - (me.membership === "leave" && me.events.member.getSender() !== me.events.member.getStateKey())) - { - // Used to split rooms via tags - const tagNames = Object.keys(room.tags); - // Used for 1:1 direct chats - const joinedMembers = room.getJoinedMembers(); - - // Show 1:1 chats in seperate "Direct Messages" section as long as they haven't - // been moved to a different tag section - if (joinedMembers.length === 2 && !tagNames.length) { - return true; - } - } - return false; - }, +/** + * Given a room object, return the alias we should use for it, + * if any. This could be the canonical alias if one exists, otherwise + * an alias selected arbitrarily but deterministically from the list + * of aliases. Otherwise return null; + */ +export function getDisplayAliasForRoom(room) { + return room.getCanonicalAlias() || room.getAliases()[0]; } +/** + * If the room contains only two members including the logged-in user, + * return the other one. Otherwise, return null. + */ +export function getOnlyOtherMember(room, me) { + const joinedMembers = room.getJoinedMembers(); + + if (joinedMembers.length === 2) { + return joinedMembers.filter(function(m) { + return m.userId !== me.userId + })[0]; + } + + return null; +} + +export function isConfCallRoom(room, me, conferenceHandler) { + if (!conferenceHandler) return false; + + if (me.membership != "join") { + return false; + } + + const otherMember = getOnlyOtherMember(room, me); + if (otherMember === null) { + return false; + } + + if (conferenceHandler.isConferenceUser(otherMember.userId)) { + return true; + } +} + +export function looksLikeDirectMessageRoom(room, me) { + if (me.membership == "join" || me.membership === "ban" || + (me.membership === "leave" && me.events.member.getSender() !== me.events.member.getStateKey())) + { + // Used to split rooms via tags + const tagNames = Object.keys(room.tags); + // Used for 1:1 direct chats + const joinedMembers = room.getJoinedMembers(); + + // Show 1:1 chats in seperate "Direct Messages" section as long as they haven't + // been moved to a different tag section + if (joinedMembers.length === 2 && !tagNames.length) { + return true; + } + } + return false; +}