Merge pull request #226 from matrix-org/matthew/fix-last-active

fix last_active_ago timestamps, tab completion ordering, and implement currently_active semantics
This commit is contained in:
Matthew Hodgson 2016-03-17 14:36:52 +00:00
commit c51dac2f29
8 changed files with 33 additions and 23 deletions

View file

@ -24,10 +24,10 @@ const KEY_WINDOWS = 91;
// //
// Capturing group containing the start // Capturing group containing the start
// of line or a whitespace char // of line or a whitespace char
// \_______________ __________Capturing group of 1 or more non-whitespace chars // \_______________ __________Capturing group of 0 or more non-whitespace chars
// _|__ _|_ followed by the end of line // _|__ _|_ followed by the end of line
// / \/ \ // / \/ \
const MATCH_REGEX = /(^|\s)(\S+)$/; const MATCH_REGEX = /(^|\s)(\S*)$/;
class TabComplete { class TabComplete {

View file

@ -127,15 +127,9 @@ MemberEntry.fromMemberList = function(members) {
return 0; // don't care return 0; // don't care
} }
else { // both User objects exist else { // both User objects exist
if (userA.lastActiveAgo < userB.lastActiveAgo) { var lastActiveAgoA = userA.lastActiveAgo || Number.MAX_SAFE_INTEGER;
return -1; // a comes first var lastActiveAgoB = userB.lastActiveAgo || Number.MAX_SAFE_INTEGER;
} return lastActiveAgoA - lastActiveAgoB;
else if (userA.lastActiveAgo > userB.lastActiveAgo) {
return 1; // b comes first
}
else {
return 0; // same last active ago
}
} }
}).map(function(m) { }).map(function(m) {
return new MemberEntry(m); return new MemberEntry(m);

View file

@ -455,11 +455,16 @@ module.exports = React.createClass({
}, },
_updateTabCompleteList: new rate_limited_func(function() { _updateTabCompleteList: new rate_limited_func(function() {
var cli = MatrixClientPeg.get();
if (!this.state.room || !this.tabComplete) { if (!this.state.room || !this.tabComplete) {
return; return;
} }
var members = this.state.room.getJoinedMembers().filter(function(member) {
if (member.userId !== cli.credentials.userId) return true;
});
this.tabComplete.setCompletionList( this.tabComplete.setCompletionList(
MemberEntry.fromMemberList(this.state.room.getJoinedMembers()).concat( MemberEntry.fromMemberList(members).concat(
CommandEntry.fromCommands(SlashCommands.getCommandList()) CommandEntry.fromCommands(SlashCommands.getCommandList())
) )
); );

View file

@ -38,6 +38,7 @@ module.exports = React.createClass({
className: React.PropTypes.string, className: React.PropTypes.string,
presenceState: React.PropTypes.string, presenceState: React.PropTypes.string,
presenceActiveAgo: React.PropTypes.number, presenceActiveAgo: React.PropTypes.number,
presenceCurrentlyActive: React.PropTypes.bool,
showInviteButton: React.PropTypes.bool, showInviteButton: React.PropTypes.bool,
shouldComponentUpdate: React.PropTypes.func, shouldComponentUpdate: React.PropTypes.func,
onClick: React.PropTypes.func, onClick: React.PropTypes.func,
@ -88,6 +89,7 @@ module.exports = React.createClass({
<img className="mx_EntityTile_chevron" src="img/member_chevron.png" width="8" height="12"/> <img className="mx_EntityTile_chevron" src="img/member_chevron.png" width="8" height="12"/>
<div className="mx_EntityTile_name_hover">{ this.props.name }</div> <div className="mx_EntityTile_name_hover">{ this.props.name }</div>
<PresenceLabel activeAgo={this.props.presenceActiveAgo} <PresenceLabel activeAgo={this.props.presenceActiveAgo}
currentlyActive={this.props.presenceCurrentlyActive}
presenceState={this.props.presenceState} /> presenceState={this.props.presenceState} />
</div> </div>
); );

View file

@ -317,10 +317,10 @@ module.exports = React.createClass({
return presenceOrdB - presenceOrdA; return presenceOrdB - presenceOrdA;
} }
var latA = userA ? (userA.lastPresenceTs - (userA.lastActiveAgo || userA.lastPresenceTs)) : 0; var lastActiveTsA = userA && userA.lastActiveAgo ? userA.lastPresenceTs - userA.lastActiveAgo : 0;
var latB = userB ? (userB.lastPresenceTs - (userB.lastActiveAgo || userB.lastPresenceTs)) : 0; var lastActiveTsB = userB && userB.lastActiveAgo ? userB.lastPresenceTs - userB.lastActiveAgo : 0;
return latB - latA; return lastActiveTsB - lastActiveTsA;
}, },
onSearchQueryChanged: function(input) { onSearchQueryChanged: function(input) {

View file

@ -84,14 +84,14 @@ module.exports = React.createClass({
this.user_last_modified_time = member.user.getLastModifiedTime(); this.user_last_modified_time = member.user.getLastModifiedTime();
// FIXME: make presence data update whenever User.presence changes... // FIXME: make presence data update whenever User.presence changes...
active = ( active = member.user.lastActiveAgo ?
(Date.now() - (member.user.lastPresenceTs - member.user.lastActiveAgo)) || -1 (Date.now() - (member.user.lastPresenceTs - member.user.lastActiveAgo)) : -1;
);
} }
this.member_last_modified_time = member.getLastModifiedTime(); this.member_last_modified_time = member.getLastModifiedTime();
return ( return (
<EntityTile {...this.props} presenceActiveAgo={active} presenceState={presenceState} <EntityTile {...this.props} presenceActiveAgo={active} presenceState={presenceState}
presenceCurrentlyActive={ member.user ? member.user.currentlyActive : false }
avatarJsx={av} title={this.getPowerLabel()} onClick={this.onClick} avatarJsx={av} title={this.getPowerLabel()} onClick={this.onClick}
name={name} powerLevel={this.props.member.powerLevel} /> name={name} powerLevel={this.props.member.powerLevel} />
); );

View file

@ -25,7 +25,15 @@ module.exports = React.createClass({
displayName: 'PresenceLabel', displayName: 'PresenceLabel',
propTypes: { propTypes: {
// number of milliseconds ago this user was last active.
// zero = unknown
activeAgo: React.PropTypes.number, activeAgo: React.PropTypes.number,
// if true, activeAgo is an approximation and "Now" should
// be shown instead
currentlyActive: React.PropTypes.bool,
// offline, online, etc
presenceState: React.PropTypes.string presenceState: React.PropTypes.string
}, },
@ -67,9 +75,10 @@ module.exports = React.createClass({
render: function() { render: function() {
if (this.props.activeAgo >= 0) { if (this.props.activeAgo >= 0) {
var ago = this.props.currentlyActive ? "now" : (this.getDuration(this.props.activeAgo) + " ago");
return ( return (
<div className="mx_PresenceLabel"> <div className="mx_PresenceLabel">
{ this.getPrettyPresence(this.props.presenceState) } { this.getDuration(this.props.activeAgo) } ago { this.getPrettyPresence(this.props.presenceState) } { ago }
</div> </div>
); );
} }

View file

@ -38,9 +38,8 @@ module.exports = React.createClass({
var active = -1; var active = -1;
// FIXME: make presence data update whenever User.presence changes... // FIXME: make presence data update whenever User.presence changes...
active = ( active = user.lastActiveAgo ?
(Date.now() - (user.lastPresenceTs - user.lastActiveAgo)) || -1 (Date.now() - (user.lastPresenceTs - user.lastActiveAgo)) : -1;
);
var BaseAvatar = sdk.getComponent('avatars.BaseAvatar'); var BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
var avatarJsx = ( var avatarJsx = (
@ -50,6 +49,7 @@ module.exports = React.createClass({
return ( return (
<EntityTile {...this.props} presenceState={user.presence} presenceActiveAgo={active} <EntityTile {...this.props} presenceState={user.presence} presenceActiveAgo={active}
presenceCurrentlyActive={ user.currentlyActive }
name={name} title={user.userId} avatarJsx={avatarJsx} /> name={name} title={user.userId} avatarJsx={avatarJsx} />
); );
} }