Merge branch 'vector' of github.com:matrix-org/matrix-react-sdk into erikj/room_editing

pull/1/head
Erik Johnston 2015-07-20 18:18:04 +01:00
commit 813cf0481e
11 changed files with 199 additions and 49 deletions

View File

@ -51,3 +51,11 @@ limitations under the License.
overflow: hidden;
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";
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 (
<div className="mx_MemberTile" onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave } >
<div className={mainClassName} onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave }
>
<div className="mx_MemberTile_avatar">
<img className="mx_MemberTile_avatarImg"
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) {
var m = self.state.memberDict[userId];
return (
<MemberTile key={userId} member={m} />
<MemberTile key={userId} member={m} ref={userId} />
);
});
},

View File

@ -116,6 +116,10 @@ function _setCallListeners(call) {
_setCallState(call, call.roomId, "busy");
pause("ringbackAudio");
play("busyAudio");
Modal.createDialog(ErrorDialog, {
title: "Call Timeout",
description: "The remote side failed to pick up."
});
}
else if (oldState === "invite_sent") {
_setCallState(call, call.roomId, "stop_ringback");

View File

@ -22,18 +22,25 @@ var Matrix = require("matrix-js-sdk");
var matrixClient = null;
var localStorage = window.localStorage;
function createClient(hs_url, is_url, user_id, access_token) {
var opts = {
baseUrl: hs_url,
idBaseUrl: is_url,
accessToken: access_token,
userId: user_id
};
matrixClient = Matrix.createClient(opts);
}
if (localStorage) {
var hs_url = localStorage.getItem("mx_hs_url");
var is_url = localStorage.getItem("mx_is_url") || 'https://matrix.org';
var access_token = localStorage.getItem("mx_access_token");
var user_id = localStorage.getItem("mx_user_id");
if (access_token && user_id && hs_url) {
matrixClient = Matrix.createClient({
baseUrl: hs_url,
idBaseUrl: is_url,
accessToken: access_token,
userId: user_id
});
createClient(hs_url, is_url, user_id, access_token);
}
}
@ -42,8 +49,8 @@ module.exports = {
return matrixClient;
},
replace: function(cli) {
matrixClient = cli;
unset: function() {
matrixClient = null;
},
replaceUsingUrls: function(hs_url, is_url) {
@ -51,6 +58,23 @@ module.exports = {
baseUrl: hs_url,
idBaseUrl: is_url
});
},
replaceUsingAccessToken: function(hs_url, is_url, user_id, access_token) {
createClient(hs_url, is_url, user_id, access_token);
if (localStorage) {
try {
localStorage.clear();
localStorage.setItem("mx_hs_url", hs_url);
localStorage.setItem("mx_is_url", is_url);
localStorage.setItem("mx_user_id", user_id);
localStorage.setItem("mx_access_token", access_token);
} catch (e) {
console.warn("Error using local storage: can't persist session!");
}
} else {
console.warn("No local storage available: can't persist session!");
}
}
};

105
src/Presence.js Normal file
View File

@ -0,0 +1,105 @@
/*
Copyright 2015 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 MatrixClientPeg = require("./MatrixClientPeg");
// Time in ms after that a user is considered as unavailable/away
var UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins
var PRESENCE_STATES = ["online", "offline", "unavailable"];
// The current presence state
var state, timer;
module.exports = {
/**
* Start listening the user activity to evaluate his presence state.
* Any state change will be sent to the Home Server.
*/
start: function() {
var self = this;
this.running = true;
if (undefined === state) {
// The user is online if they move the mouse or press a key
document.onmousemove = function() { self._resetTimer(); };
document.onkeypress = function() { self._resetTimer(); };
this._resetTimer();
}
},
/**
* Stop tracking user activity
*/
stop: function() {
this.running = false;
if (timer) {
clearTimeout(timer);
timer = undefined;
}
state = undefined;
},
/**
* Get the current presence state.
* @returns {string} the presence state (see PRESENCE enum)
*/
getState: function() {
return state;
},
/**
* 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)
*/
setState: function(newState) {
if (newState === state) {
return;
}
if (PRESENCE_STATES.indexOf(newState) === -1) {
throw new Error("Bad presence state: " + newState);
}
if (!this.running) {
return;
}
state = newState;
MatrixClientPeg.get().setPresence(state).catch(function(err) {
console.error("Failed to set presence: %s", err);
});
},
/**
* Callback called when the user made no action on the page for UNAVAILABLE_TIME ms.
* @private
*/
_onUnavailableTimerFire: function() {
this.setState("unavailable");
},
/**
* Callback called when the user made an action on the page
* @private
*/
_resetTimer: function() {
var self = this;
this.setState("online");
// Re-arm the timer
clearTimeout(timer);
timer = setTimeout(function() {
self._onUnavailableTimerFire();
}, UNAVAILABLE_TIME_MS);
}
};

View File

@ -106,7 +106,7 @@ module.exports = {
// show the message
this.element.value = this.data[this.position];
}
else if (this.originalText) {
else if (this.originalText !== undefined) {
// restore the original text the user was typing.
this.element.value = this.originalText;
}

View File

@ -18,6 +18,9 @@ limitations under the License.
var React = require("react");
var MatrixClientPeg = require("../../MatrixClientPeg");
var Modal = require("../../Modal");
var ComponentBroker = require('../../ComponentBroker');
var ErrorDialog = ComponentBroker.get("organisms/ErrorDialog");
var INITIAL_LOAD_NUM_MEMBERS = 50;
@ -37,6 +40,7 @@ module.exports = {
componentWillUnmount: function() {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
MatrixClientPeg.get().removeListener("User.presence", this.userPresenceFn);
}
},
@ -48,8 +52,19 @@ module.exports = {
memberDict: self.roomMembers()
});
}, 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
/*componentWillReceiveProps: function(newProps) {
},*/
@ -67,6 +82,10 @@ module.exports = {
inputText = inputText.trim(); // react requires es5-shim so we know trim() exists
if (inputText[0] !== '@' || inputText.indexOf(":") === -1) {
console.error("Bad user ID to invite: %s", inputText);
Modal.createDialog(ErrorDialog, {
title: "Invite Error",
description: "Malformed user ID. Should look like '@localpart:domain'"
});
return;
}
self.setState({
@ -81,6 +100,10 @@ module.exports = {
});
}, function(err) {
console.error("Failed to invite: %s", JSON.stringify(err));
Modal.createDialog(ErrorDialog, {
title: "Invite Server Error",
description: err.message
});
self.setState({
inviting: false
});

View File

@ -21,7 +21,7 @@ var Loader = require("react-loader");
var MatrixClientPeg = require("../../MatrixClientPeg");
var RoomListSorter = require("../../RoomListSorter");
var Presence = require("../../Presence");
var dis = require("../../dispatcher");
var ComponentBroker = require('../../ComponentBroker');
@ -89,8 +89,9 @@ module.exports = {
window.localStorage.clear();
}
Notifier.stop();
Presence.stop();
MatrixClientPeg.get().removeAllListeners();
MatrixClientPeg.replace(null);
MatrixClientPeg.unset();
break;
case 'start_registration':
if (this.state.logged_in) return;
@ -187,6 +188,7 @@ module.exports = {
});
});
Notifier.start();
Presence.start();
cli.startClient();
},

View File

@ -75,27 +75,10 @@ module.exports = {
'user': formVals.username,
'password': formVals.password
}).done(function(data) {
// XXX: we assume this means we're logged in, but there could be a next stage
MatrixClientPeg.replace(Matrix.createClient({
baseUrl: self.state.hs_url,
idBaseUrl: self.state.is_url,
userId: data.user_id,
accessToken: data.access_token
}));
var localStorage = window.localStorage;
if (localStorage) {
try {
localStorage.clear();
localStorage.setItem("mx_hs_url", self.state.hs_url);
localStorage.setItem("mx_is_url", self.state.is_url);
localStorage.setItem("mx_user_id", data.user_id);
localStorage.setItem("mx_access_token", data.access_token);
} catch (e) {
console.warn("Error using local storage: can't persist session!");
}
} else {
console.warn("No local storage available: can't persist session!");
}
MatrixClientPeg.replaceUsingAccessToken(
self.state.hs_url, self.state.is_url,
data.user_id, data.access_token
);
if (self.props.onLoggedIn) {
self.props.onLoggedIn();
}

View File

@ -259,20 +259,9 @@ module.exports = {
},
onRegistered: function(user_id, access_token) {
MatrixClientPeg.replace(Matrix.createClient({
baseUrl: this.state.hs_url,
idBaseUrl: this.state.is_url,
userId: user_id,
accessToken: access_token
}));
var localStorage = window.localStorage;
if (localStorage) {
localStorage.setItem("mx_hs_url", this.state.hs_url);
localStorage.setItem("mx_user_id", user_id);
localStorage.setItem("mx_access_token", access_token);
} else {
console.warn("No local storage available: can't persist session!");
}
MatrixClientPeg.replaceUsingAccessToken(
this.state.hs_url, this.state.is_url, user_id, access_token
);
if (this.props.onLoggedIn) {
this.props.onLoggedIn();
}