diff --git a/src/Entities.js b/src/Entities.js index ee0d3e9d1b..712f7b4dde 100644 --- a/src/Entities.js +++ b/src/Entities.js @@ -63,7 +63,8 @@ class UserEntity extends Entity { } matches(queryString) { - return this.model.displayName.toLowerCase().indexOf(queryString.toLowerCase()) === 0; + var name = this.model.displayName || this.model.userId; + return name.toLowerCase().indexOf(queryString.toLowerCase()) === 0; } } diff --git a/src/component-index.js b/src/component-index.js index cbecbf7d2e..94f313a83c 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -73,6 +73,7 @@ module.exports.components['views.rooms.RoomTile'] = require('./components/views/ module.exports.components['views.rooms.SearchableEntityList'] = require('./components/views/rooms/SearchableEntityList'); module.exports.components['views.rooms.SearchResultTile'] = require('./components/views/rooms/SearchResultTile'); module.exports.components['views.rooms.TabCompleteBar'] = require('./components/views/rooms/TabCompleteBar'); +module.exports.components['views.rooms.UserTile'] = require('./components/views/rooms/UserTile'); module.exports.components['views.settings.ChangeAvatar'] = require('./components/views/settings/ChangeAvatar'); module.exports.components['views.settings.ChangeDisplayName'] = require('./components/views/settings/ChangeDisplayName'); module.exports.components['views.settings.ChangePassword'] = require('./components/views/settings/ChangePassword'); diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index f5fc5b9f82..625a35e2fa 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -275,14 +275,24 @@ module.exports = React.createClass({ ); } else { - var SearchableEntityList = sdk.getComponent("rooms.SearchableEntityList"); + // TODO: Cache this calculation var room = MatrixClientPeg.get().getRoom(this.props.roomId); + var allUsers = MatrixClientPeg.get().getUsers(); + // only add Users if they don't exist in the member list + allUsers = allUsers.filter(function(u) { + return room.getMember(u.userId) === null; + }); + + var SearchableEntityList = sdk.getComponent("rooms.SearchableEntityList"); + return ( ); diff --git a/src/components/views/rooms/UserTile.js b/src/components/views/rooms/UserTile.js new file mode 100644 index 0000000000..4a06dc9bc3 --- /dev/null +++ b/src/components/views/rooms/UserTile.js @@ -0,0 +1,127 @@ +/* +Copyright 2015, 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. +*/ + +'use strict'; + +var React = require('react'); + +var MatrixClientPeg = require('../../../MatrixClientPeg'); +var sdk = require('../../../index'); +var dis = require('../../../dispatcher'); +var Modal = require("../../../Modal"); + +module.exports = React.createClass({ + displayName: 'UserTile', + + propTypes: { + user: React.PropTypes.any.isRequired, // User + onInviteClick: React.PropTypes.func, //onInviteClick(User) + showInvite: React.PropTypes.bool, + onClick: React.PropTypes.func + }, + + getInitialState: function() { + return {}; + }, + + getDefaultProps: function() { + return { + onClick: function() {}, + onInviteClick: function() {}, + showInvite: false + }; + }, + + shouldComponentUpdate: function(nextProps, nextState) { + if (this.state.hover !== nextState.hover) return true; + return false; + }, + + mouseEnter: function(e) { + this.setState({ 'hover': true }); + }, + + mouseLeave: function(e) { + this.setState({ 'hover': false }); + }, + + render: function() { + var user = this.props.user; + var name = user.displayName || user.userId; + var isMyUser = MatrixClientPeg.get().credentials.userId == user.userId; + var active = -1; + var presenceClass = "mx_MemberTile_offline"; + + this.user_last_modified_time = user.getLastModifiedTime(); + + // FIXME: make presence data update whenever User.presence changes... + active = ( + (Date.now() - (user.lastPresenceTs - user.lastActiveAgo)) || -1 + ); + + if (user.presence === "online") { + presenceClass = "mx_MemberTile_online"; + } + else if (user.presence === "unavailable") { + presenceClass = "mx_MemberTile_unavailable"; + } + + + var mainClassName = "mx_MemberTile "; + mainClassName += presenceClass; + if (this.state.hover) { + mainClassName += " mx_MemberTile_hover"; + } + + var nameEl; + if (this.state.hover) { + var PresenceLabel = sdk.getComponent("rooms.PresenceLabel"); + nameEl = ( +
+ +
{ name }
+ +
+ ); + } + else { + nameEl = ( +
+ { name } +
+ ); + } + + var MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); + + if (this.props.showInvite) { + // TODO + } + + return ( +
+
+ +
+ { nameEl } +
+ ); + } +});