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:
commit
c51dac2f29
8 changed files with 33 additions and 23 deletions
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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())
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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} />
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue