Change opacity of member list entries when their presence changes.

This is done by attaching a single room listener at the member list level and
then forceUpdate()ing the individual tiles as presence changes come in from
the JS SDK. This is more efficient than having hundreds of listeners attached
directly to the JS SDK (if we were to add a listener per tile).
This commit is contained in:
Kegan Dougal 2015-07-20 17:42:19 +01:00
parent 9d110d58e5
commit 5d59a5b297
4 changed files with 35 additions and 3 deletions

View File

@ -51,3 +51,11 @@ limitations under the License.
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.mx_MemberTile_unavailable {
opacity: 0.75;
}
.mx_MemberTile_offline {
opacity: 0.5;
}

View File

@ -46,9 +46,21 @@ module.exports = React.createClass({
var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png"; var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png";
power = <img src={ img } className="mx_MemberTile_power" width="48" height="48" alt=""/>; power = <img src={ img } className="mx_MemberTile_power" width="48" height="48" alt=""/>;
} }
var presenceClass = "mx_MemberTile_offline";
var mainClassName = "mx_MemberTile ";
if (this.props.member.user) {
if (this.props.member.user.presence === "online") {
presenceClass = "mx_MemberTile_online";
}
else if (this.props.member.user.presence === "unavailable") {
presenceClass = "mx_MemberTile_unavailable";
}
}
mainClassName += presenceClass;
return ( return (
<div className="mx_MemberTile" onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave } > <div className={mainClassName} onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave }
>
<div className="mx_MemberTile_avatar"> <div className="mx_MemberTile_avatar">
<img className="mx_MemberTile_avatarImg" <img className="mx_MemberTile_avatarImg"
src={ this.props.member ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.member, 40, 40, "crop") : null } src={ this.props.member ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.member, 40, 40, "crop") : null }

View File

@ -47,7 +47,7 @@ module.exports = React.createClass({
return Object.keys(self.state.memberDict).map(function(userId) { return Object.keys(self.state.memberDict).map(function(userId) {
var m = self.state.memberDict[userId]; var m = self.state.memberDict[userId];
return ( return (
<MemberTile key={userId} member={m} /> <MemberTile key={userId} member={m} ref={userId} />
); );
}); });
}, },

View File

@ -40,6 +40,7 @@ module.exports = {
componentWillUnmount: function() { componentWillUnmount: function() {
if (MatrixClientPeg.get()) { if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember); MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
MatrixClientPeg.get().removeListener("User.presence", this.userPresenceFn);
} }
}, },
@ -51,8 +52,19 @@ module.exports = {
memberDict: self.roomMembers() memberDict: self.roomMembers()
}); });
}, 50); }, 50);
},
// Attach a SINGLE listener for global presence changes then locate the
// member tile and re-render it. This is more efficient than every tile
// evar attaching their own listener.
function updateUserState(event, user) {
var tile = self.refs[user.userId];
if (tile) {
tile.forceUpdate();
}
}
MatrixClientPeg.get().on("User.presence", updateUserState);
this.userPresenceFn = updateUserState;
},
// Remember to set 'key' on a MemberList to the ID of the room it's for // Remember to set 'key' on a MemberList to the ID of the room it's for
/*componentWillReceiveProps: function(newProps) { /*componentWillReceiveProps: function(newProps) {
},*/ },*/