Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1375 from matrix-org/dbkr/active_room_observer
Browse files Browse the repository at this point in the history
Avoid re-rendering RoomList on room switch
  • Loading branch information
dbkr authored Sep 11, 2017
2 parents 7e1886c + be8f099 commit 3c70b86
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 4 deletions.
77 changes: 77 additions & 0 deletions src/ActiveRoomObserver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Copyright 2017 New Vector 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.
*/

import RoomViewStore from './stores/RoomViewStore';

/**
* Consumes changes from the RoomViewStore and notifies specific things
* about when the active room changes. Unlike listening for RoomViewStore
* changes, you can subscribe to only changes relevant to a particular
* room.
*
* TODO: If we introduce an observer for something else, factor out
* the adding / removing of listeners & emitting into a common class.
*/
class ActiveRoomObserver {
constructor() {
this._listeners = {};

this._activeRoomId = RoomViewStore.getRoomId();
// TODO: We could self-destruct when the last listener goes away, or at least
// stop listening.
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate.bind(this));
}

addListener(roomId, listener) {
if (!this._listeners[roomId]) this._listeners[roomId] = [];
this._listeners[roomId].push(listener);
}

removeListener(roomId, listener) {
if (this._listeners[roomId]) {
const i = this._listeners[roomId].indexOf(listener);
if (i > -1) {
this._listeners[roomId].splice(i, 1);
}
} else {
console.warn("Unregistering unrecognised listener (roomId=" + roomId + ")");
}
}

_emit(roomId) {
if (!this._listeners[roomId]) return;

for (const l of this._listeners[roomId]) {
l.call();
}
}

_onRoomViewStoreUpdate() {
// emit for the old room ID
if (this._activeRoomId) this._emit(this._activeRoomId);

// update our cache
this._activeRoomId = RoomViewStore.getRoomId();

// and emit for the new one
if (this._activeRoomId) this._emit(this._activeRoomId);
}
}

if (global.mx_ActiveRoomObserver === undefined) {
global.mx_ActiveRoomObserver = new ActiveRoomObserver();
}
export default global.mx_ActiveRoomObserver;
1 change: 0 additions & 1 deletion src/components/views/rooms/RoomList.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ module.exports = React.createClass({
propTypes: {
ConferenceHandler: React.PropTypes.any,
collapsed: React.PropTypes.bool.isRequired,
currentRoom: React.PropTypes.string,
searchFilter: React.PropTypes.string,
},

Expand Down
17 changes: 14 additions & 3 deletions src/components/views/rooms/RoomTile.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -27,6 +28,8 @@ var RoomNotifs = require('../../../RoomNotifs');
var FormattingUtils = require('../../../utils/FormattingUtils');
import AccessibleButton from '../elements/AccessibleButton';
var UserSettingsStore = require('../../../UserSettingsStore');
import ActiveRoomObserver from '../../../ActiveRoomObserver';
import RoomViewStore from '../../../stores/RoomViewStore';

module.exports = React.createClass({
displayName: 'RoomTile',
Expand All @@ -39,7 +42,6 @@ module.exports = React.createClass({

room: React.PropTypes.object.isRequired,
collapsed: React.PropTypes.bool.isRequired,
selected: React.PropTypes.bool.isRequired,
unread: React.PropTypes.bool.isRequired,
highlight: React.PropTypes.bool.isRequired,
isInvite: React.PropTypes.bool.isRequired,
Expand All @@ -58,6 +60,7 @@ module.exports = React.createClass({
badgeHover : false,
menuDisplayed: false,
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
});
},

Expand Down Expand Up @@ -87,15 +90,23 @@ module.exports = React.createClass({
}
},

_onActiveRoomChange: function() {
this.setState({
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
});
},

componentWillMount: function() {
MatrixClientPeg.get().on("accountData", this.onAccountData);
ActiveRoomObserver.addListener(this.props.room.roomId, this._onActiveRoomChange);
},

componentWillUnmount: function() {
var cli = MatrixClientPeg.get();
if (cli) {
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
}
ActiveRoomObserver.removeListener(this.props.room.roomId, this._onActiveRoomChange);
},

onClick: function(ev) {
Expand Down Expand Up @@ -174,7 +185,7 @@ module.exports = React.createClass({

var classes = classNames({
'mx_RoomTile': true,
'mx_RoomTile_selected': this.props.selected,
'mx_RoomTile_selected': this.state.selected,
'mx_RoomTile_unread': this.props.unread,
'mx_RoomTile_unreadNotify': notifBadges,
'mx_RoomTile_highlight': mentionBadges,
Expand Down Expand Up @@ -221,7 +232,7 @@ module.exports = React.createClass({
'mx_RoomTile_badgeShown': badges || this.state.badgeHover || this.state.menuDisplayed,
});

if (this.props.selected) {
if (this.state.selected) {
let nameSelected = <EmojiText>{name}</EmojiText>;

label = <div title={ name } className={ nameClasses } dir="auto">{ nameSelected }</div>;
Expand Down
97 changes: 97 additions & 0 deletions src/components/views/voip/CallPreview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
Copyright 2017 New Vector 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.
*/

import React from 'react';
import RoomViewStore from '../../../stores/RoomViewStore';
import CallHandler from '../../../CallHandler';
import dis from '../../../dispatcher';
import sdk from '../../../index';

module.exports = React.createClass({
displayName: 'CallPreview',

propTypes: {
// A Conference Handler implementation
// Must have a function signature:
// getConferenceCallForRoom(roomId: string): MatrixCall
ConferenceHandler: React.PropTypes.object,
},

getInitialState: function() {
return {
roomId: RoomViewStore.getRoomId(),
activeCall: CallHandler.getAnyActiveCall(),
};
},

componentWillMount: function() {
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this.dispatcherRef = dis.register(this._onAction);
},

componentWillUnmount: function() {
if (this._roomStoreToken) {
this._roomStoreToken.remove();
}
dis.unregister(this.dispatcherRef);
},

_onRoomViewStoreUpdate: function(payload) {
if (RoomViewStore.getRoomId() === this.state.roomId) return;
this.setState({
roomId: RoomViewStore.getRoomId(),
});
},

_onAction: function(payload) {
switch (payload.action) {
// listen for call state changes to prod the render method, which
// may hide the global CallView if the call it is tracking is dead
case 'call_state':
this.setState({
activeCall: CallHandler.getAnyActiveCall(),
});
break;
}
},

_onCallViewClick: function() {
const call = CallHandler.getAnyActiveCall();
if (call) {
dis.dispatch({
action: 'view_room',
room_id: call.groupRoomId || call.roomId,
});
}
},

render: function() {
const callForRoom = CallHandler.getCallForRoom(this.state.roomId);
const showCall = (this.state.activeCall && this.state.activeCall.call_state === 'connected' && !callForRoom);

if (showCall) {
const CallView = sdk.getComponent('voip.CallView');
return (
<CallView
className="mx_LeftPanel_callView" showVoice={true} onClick={this._onCallViewClick}
ConferenceHandler={this.props.ConferenceHandler}
/>
);
}
return null;
},
});

0 comments on commit 3c70b86

Please sign in to comment.