Remove presence management

The feature is incredibly buggy and doesn't work as expected due to server behaviour and client interaction. One of the major problems is the constantly confused presence state - this is caused by the mobile apps conflicting on the state of the web app, causing it to consider the user offline or online (and rarely away) depending on how riot-android/ios is behaving at the time.

This reverts two PRs:
* https://github.com/matrix-org/matrix-react-sdk/pull/1620
* https://github.com/matrix-org/matrix-react-sdk/pull/1482

The changes to the context menu positioning were not reverted as they are useful outside of presence management.

Signed-off-by: Travis Ralston <travpc@gmail.com>
This commit is contained in:
Travis Ralston 2017-12-25 14:25:13 -07:00 committed by David Baker
parent 760f21b1d9
commit 91a41392b4
5 changed files with 6 additions and 205 deletions

View file

@ -98,7 +98,6 @@ class MatrixClientPeg {
const opts = utils.deepCopy(this.opts);
// the react sdk doesn't work without this, so don't allow
opts.pendingEventOrdering = "detached";
opts.disablePresence = true; // we do this manually
try {
const promise = this.matrixClient.store.startup();

View file

@ -57,27 +57,13 @@ class Presence {
return this.state;
}
/**
* Get the current status message.
* @returns {String} the status message, may be null
*/
getStatusMessage() {
return this.statusMessage;
}
/**
* Set the presence state.
* If the state has changed, the Home Server will be notified.
* @param {string} newState the new presence state (see PRESENCE enum)
* @param {String} statusMessage an optional status message for the presence
* @param {boolean} maintain true to have this status maintained by this tracker
*/
setState(newState, statusMessage=null, maintain=false) {
if (this.maintain) {
// Don't update presence if we're maintaining a particular status
return;
}
if (newState === this.state && statusMessage === this.statusMessage) {
setState(newState) {
if (newState === this.state) {
return;
}
if (PRESENCE_STATES.indexOf(newState) === -1) {
@ -87,37 +73,21 @@ class Presence {
return;
}
const old_state = this.state;
const old_message = this.statusMessage;
this.state = newState;
this.statusMessage = statusMessage;
this.maintain = maintain;
if (MatrixClientPeg.get().isGuest()) {
return; // don't try to set presence when a guest; it won't work.
}
const updateContent = {
presence: this.state,
status_msg: this.statusMessage ? this.statusMessage : '',
};
const self = this;
MatrixClientPeg.get().setPresence(updateContent).done(function() {
MatrixClientPeg.get().setPresence(this.state).done(function() {
console.log("Presence: %s", newState);
// We have to dispatch because the js-sdk is unreliable at telling us about our own presence
dis.dispatch({action: "self_presence_updated", statusInfo: updateContent});
}, function(err) {
console.error("Failed to set presence: %s", err);
self.state = old_state;
self.statusMessage = old_message;
});
}
stopMaintainingStatus() {
this.maintain = false;
}
/**
* Callback called when the user made no action on the page for UNAVAILABLE_TIME ms.
* @private

View file

@ -1,169 +0,0 @@
/*
Copyright 2017 Travis Ralston
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';
import React from "react";
import PropTypes from 'prop-types';
import * as sdk from "../../../index";
import MatrixClientPeg from "../../../MatrixClientPeg";
import AccessibleButton from '../elements/AccessibleButton';
import Presence from "../../../Presence";
import dispatcher from "../../../dispatcher";
import * as ContextualMenu from "../../structures/ContextualMenu";
import SettingsStore from "../../../settings/SettingsStore";
// This is an avatar with presence information and controls on it.
module.exports = React.createClass({
displayName: 'MemberPresenceAvatar',
propTypes: {
member: PropTypes.object.isRequired,
width: PropTypes.number,
height: PropTypes.number,
resizeMethod: PropTypes.string,
},
getDefaultProps: function() {
return {
width: 40,
height: 40,
resizeMethod: 'crop',
};
},
getInitialState: function() {
let presenceState = null;
let presenceMessage = null;
// RoomMembers do not necessarily have a user.
if (this.props.member.user) {
presenceState = this.props.member.user.presence;
presenceMessage = this.props.member.user.presenceStatusMsg;
}
return {
status: presenceState,
message: presenceMessage,
};
},
componentWillMount: function() {
MatrixClientPeg.get().on("User.presence", this.onUserPresence);
this.dispatcherRef = dispatcher.register(this.onAction);
},
componentWillUnmount: function() {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("User.presence", this.onUserPresence);
}
dispatcher.unregister(this.dispatcherRef);
},
onAction: function(payload) {
if (payload.action !== "self_presence_updated") return;
if (this.props.member.userId !== MatrixClientPeg.get().getUserId()) return;
this.setState({
status: payload.statusInfo.presence,
message: payload.statusInfo.status_msg,
});
},
onUserPresence: function(event, user) {
if (user.userId !== MatrixClientPeg.get().getUserId()) return;
this.setState({
status: user.presence,
message: user.presenceStatusMsg,
});
},
onStatusChange: function(newStatus) {
Presence.stopMaintainingStatus();
if (newStatus === "online") {
Presence.setState(newStatus);
} else Presence.setState(newStatus, null, true);
},
onClick: function(e) {
const PresenceContextMenu = sdk.getComponent('context_menus.PresenceContextMenu');
const elementRect = e.target.getBoundingClientRect();
// The window X and Y offsets are to adjust position when zoomed in to page
const x = (elementRect.left + window.pageXOffset) - (elementRect.width / 2) + 3;
const chevronOffset = 12;
let y = elementRect.top + (elementRect.height / 2) + window.pageYOffset;
y = y - (chevronOffset + 4); // where 4 is 1/4 the height of the chevron
ContextualMenu.createMenu(PresenceContextMenu, {
chevronOffset: chevronOffset,
chevronFace: 'bottom',
left: x,
top: y,
menuWidth: 125,
currentStatus: this.state.status,
onChange: this.onStatusChange,
});
e.stopPropagation();
// XXX NB the following assumes that user is non-null, which is not valid
// const presenceState = this.props.member.user.presence;
// const presenceLastActiveAgo = this.props.member.user.lastActiveAgo;
// const presenceLastTs = this.props.member.user.lastPresenceTs;
// const presenceCurrentlyActive = this.props.member.user.currentlyActive;
// const presenceMessage = this.props.member.user.presenceStatusMsg;
},
render: function() {
const MemberAvatar = sdk.getComponent("avatars.MemberAvatar");
let onClickFn = null;
if (this.props.member.userId === MatrixClientPeg.get().getUserId()) {
onClickFn = this.onClick;
}
const avatarNode = (
<MemberAvatar member={this.props.member} width={this.props.width} height={this.props.height}
resizeMethod={this.props.resizeMethod} />
);
let statusNode = (
<span className={"mx_MemberPresenceAvatar_status mx_MemberPresenceAvatar_status_" + this.state.status} />
);
// LABS: Disable presence management functions for now
// Also disable the presence information if there's no status information
if (!SettingsStore.isFeatureEnabled("feature_presence_management") || !this.state.status) {
statusNode = null;
onClickFn = null;
}
let avatar = (
<div className="mx_MemberPresenceAvatar">
{ avatarNode }
{ statusNode }
</div>
);
if (onClickFn) {
avatar = (
<AccessibleButton onClick={onClickFn} className="mx_MemberPresenceAvatar" element="div">
{ avatarNode }
{ statusNode }
</AccessibleButton>
);
}
return avatar;
},
});

View file

@ -251,7 +251,7 @@ export default class MessageComposer extends React.Component {
render() {
const me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId);
const uploadInputStyle = {display: 'none'};
const MemberPresenceAvatar = sdk.getComponent('avatars.MemberPresenceAvatar');
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
const TintableSvg = sdk.getComponent("elements.TintableSvg");
const MessageComposerInput = sdk.getComponent("rooms.MessageComposerInput");
@ -259,7 +259,7 @@ export default class MessageComposer extends React.Component {
controls.push(
<div key="controls_avatar" className="mx_MessageComposer_avatar">
<MemberPresenceAvatar member={me} width={24} height={24} />
<MemberAvatar member={me} width={24} height={24} />
</div>,
);

View file

@ -170,6 +170,7 @@
"%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s widget modified by %(senderName)s",
"%(widgetName)s widget added by %(senderName)s": "%(widgetName)s widget added by %(senderName)s",
"%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s widget removed by %(senderName)s",
"Message Pinning": "Message Pinning",
"%(displayName)s is typing": "%(displayName)s is typing",
"%(names)s and %(count)s others are typing|other": "%(names)s and %(count)s others are typing",
"%(names)s and %(count)s others are typing|one": "%(names)s and one other is typing",