Merge remote-tracking branch 'origin/develop' into dbkr/group_userlist

This commit is contained in:
David Baker 2017-09-13 16:35:37 +01:00
commit 06fe240be2
38 changed files with 1083 additions and 184 deletions

View file

@ -30,13 +30,14 @@ import VectorConferenceHandler from '../../VectorConferenceHandler';
var LeftPanel = React.createClass({
displayName: 'LeftPanel',
// NB. If you add props, don't forget to update
// shouldComponentUpdate!
propTypes: {
collapsed: React.PropTypes.bool.isRequired,
},
getInitialState: function() {
return {
showCallElement: null,
searchFilter: '',
};
},
@ -45,26 +46,25 @@ var LeftPanel = React.createClass({
this.focusedElement = null;
},
componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction);
},
componentWillReceiveProps: function(newProps) {
this._recheckCallElement(newProps.selectedRoom);
},
componentWillUnmount: function() {
dis.unregister(this.dispatcherRef);
},
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._recheckCallElement(this.props.selectedRoom);
break;
shouldComponentUpdate: function(nextProps, nextState) {
// MatrixChat will update whenever the user switches
// rooms, but propagating this change all the way down
// the react tree is quite slow, so we cut this off
// here. The RoomTiles listen for the room change
// events themselves to know when to update.
// We just need to update if any of these things change.
if (
this.props.collapsed !== nextProps.collapsed ||
this.props.opacity !== nextProps.opacity
) {
return true;
}
if (this.state.searchFilter !== nextState.searchFilter) {
return true;
}
return false;
},
_onFocus: function(ev) {
@ -152,74 +152,41 @@ var LeftPanel = React.createClass({
}
},
_recheckCallElement: function(selectedRoomId) {
// if we aren't viewing a room with an ongoing call, but there is an
// active call, show the call element - we need to do this to make
// audio/video not crap out
var activeCall = CallHandler.getAnyActiveCall();
var callForRoom = CallHandler.getCallForRoom(selectedRoomId);
var showCall = (activeCall && activeCall.call_state === 'connected' && !callForRoom);
this.setState({
showCallElement: showCall
});
},
onHideClick: function() {
dis.dispatch({
action: 'hide_left_panel',
});
},
onCallViewClick: function() {
var call = CallHandler.getAnyActiveCall();
if (call) {
dis.dispatch({
action: 'view_room',
room_id: call.groupRoomId || call.roomId,
});
}
},
onSearch: function(term) {
this.setState({ searchFilter: term });
},
render: function() {
var RoomList = sdk.getComponent('rooms.RoomList');
var BottomLeftMenu = sdk.getComponent('structures.BottomLeftMenu');
const RoomList = sdk.getComponent('rooms.RoomList');
const BottomLeftMenu = sdk.getComponent('structures.BottomLeftMenu');
const CallPreview = sdk.getComponent('voip.CallPreview');
var topBox;
let topBox;
if (MatrixClientPeg.get().isGuest()) {
var LoginBox = sdk.getComponent('structures.LoginBox');
const LoginBox = sdk.getComponent('structures.LoginBox');
topBox = <LoginBox collapsed={ this.props.collapsed }/>;
}
else {
var SearchBox = sdk.getComponent('structures.SearchBox');
} else {
const SearchBox = sdk.getComponent('structures.SearchBox');
topBox = <SearchBox collapsed={ this.props.collapsed } onSearch={ this.onSearch } />;
}
var classes = "mx_LeftPanel mx_fadable";
let classes = "mx_LeftPanel mx_fadable";
if (this.props.collapsed) {
classes += " collapsed";
}
var callPreview;
if (this.state.showCallElement && !this.props.collapsed) {
var CallView = sdk.getComponent('voip.CallView');
callPreview = (
<CallView
className="mx_LeftPanel_callView" showVoice={true} onClick={this.onCallViewClick}
ConferenceHandler={VectorConferenceHandler} />
);
}
return (
<aside className={classes} style={{ opacity: this.props.opacity }}
onKeyDown={ this._onKeyDown } onFocus={ this._onFocus } onBlur={ this._onBlur }>
{ topBox }
{ callPreview }
<CallPreview ConferenceHandler={VectorConferenceHandler} />
<RoomList
selectedRoom={this.props.selectedRoom}
collapsed={this.props.collapsed}
searchFilter={this.state.searchFilter}
ConferenceHandler={VectorConferenceHandler} />

View file

@ -84,7 +84,7 @@ module.exports = React.createClass({
var self = this;
return (
<div className="mx_SearchBox">
<div className="mx_SearchBox mx_LoginBox">
{ loginButton }
{ toggleCollapse }
</div>

View file

@ -75,8 +75,8 @@ var RoomSubList = React.createClass({
order: React.PropTypes.string.isRequired,
// undefined if no room is selected (eg we are showing settings)
selectedRoom: React.PropTypes.string,
// passed through to RoomTile and used to highlight room with `!` regardless of notifications count
isInvite: React.PropTypes.bool,
startAsHidden: React.PropTypes.bool,
showSpinner: React.PropTypes.bool, // true to show a spinner if 0 elements when expanded
@ -104,6 +104,7 @@ var RoomSubList = React.createClass({
onHeaderClick: function() {}, // NOP
onShowMoreRooms: function() {}, // NOP
extraTiles: [],
isInvite: false,
};
},
@ -248,7 +249,7 @@ var RoomSubList = React.createClass({
return this.props.list.reduce(function(result, room, index) {
if (truncateAt === undefined || index >= truncateAt) {
var roomNotifState = RoomNotifs.getRoomNotifsState(room.roomId);
var highlight = room.getUnreadNotificationCount('highlight') > 0 || self.props.label === 'Invites';
var highlight = room.getUnreadNotificationCount('highlight') > 0 || self.props.isInvite;
var notificationCount = room.getUnreadNotificationCount();
const notifBadges = notificationCount > 0 && self._shouldShowNotifBadge(roomNotifState);
@ -368,7 +369,6 @@ var RoomSubList = React.createClass({
var self = this;
var DNDRoomTile = sdk.getComponent("rooms.DNDRoomTile");
return this.state.sortedList.map(function(room) {
var selected = room.roomId == self.props.selectedRoom;
// XXX: is it evil to pass in self as a prop to RoomTile?
return (
<DNDRoomTile
@ -376,10 +376,9 @@ var RoomSubList = React.createClass({
roomSubList={ self }
key={ room.roomId }
collapsed={ self.props.collapsed || false}
selected={ selected }
unread={ Unread.doesRoomHaveUnreadMessages(room) }
highlight={ room.getUnreadNotificationCount('highlight') > 0 || self.props.label === 'Invites' }
isInvite={ self.props.label === 'Invites' }
highlight={ room.getUnreadNotificationCount('highlight') > 0 || self.props.isInvite }
isInvite={ self.props.isInvite }
refreshSubList={ self._updateSubListCount }
incomingCall={ null }
onClick={ self.onRoomTileClick }
@ -411,6 +410,9 @@ var RoomSubList = React.createClass({
var badge;
if (subListNotifCount > 0) {
badge = <div className={badgeClasses}>{ FormattingUtils.formatCount(subListNotifCount) }</div>;
} else if (this.props.isInvite) {
// no notifications but highlight anyway because this is an invite badge
badge = <div className={badgeClasses}>!</div>;
}
// When collapsed, allow a long hover on the header to show user