diff --git a/reskindex.js b/reskindex.js
index 66dfc39f73..37b3345e36 100755
--- a/reskindex.js
+++ b/reskindex.js
@@ -26,6 +26,9 @@ strm.write(" * THIS FILE IS AUTO-GENERATED\n");
strm.write(" * You can edit it you like, but your changes will be overwritten,\n");
strm.write(" * so you'd just be trying to swim upstream like a salmon.\n");
strm.write(" * You are not a salmon.\n");
+strm.write(" *\n");
+strm.write(" * To update it, run:\n");
+strm.write(" * ./reskindex.js -h header\n");
strm.write(" */\n\n");
if (packageJson['matrix-react-parent']) {
diff --git a/src/component-index.js b/src/component-index.js
index b4452c7902..5a37a98913 100644
--- a/src/component-index.js
+++ b/src/component-index.js
@@ -19,6 +19,9 @@ limitations under the License.
* You can edit it you like, but your changes will be overwritten,
* so you'd just be trying to swim upstream like a salmon.
* You are not a salmon.
+ *
+ * To update it, run:
+ * ./reskindex.js -h header
*/
module.exports.components = {};
@@ -28,6 +31,7 @@ module.exports.components['structures.login.Login'] = require('./components/stru
module.exports.components['structures.login.PostRegistration'] = require('./components/structures/login/PostRegistration');
module.exports.components['structures.login.Registration'] = require('./components/structures/login/Registration');
module.exports.components['structures.MatrixChat'] = require('./components/structures/MatrixChat');
+module.exports.components['structures.RoomStatusBar'] = require('./components/structures/RoomStatusBar');
module.exports.components['structures.RoomView'] = require('./components/structures/RoomView');
module.exports.components['structures.ScrollPanel'] = require('./components/structures/ScrollPanel');
module.exports.components['structures.UploadBar'] = require('./components/structures/UploadBar');
diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js
new file mode 100644
index 0000000000..c15a33d777
--- /dev/null
+++ b/src/components/structures/RoomStatusBar.js
@@ -0,0 +1,180 @@
+/*
+Copyright 2015, 2016 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.
+*/
+
+var React = require('react');
+var sdk = require('../../index');
+var dis = require("../../dispatcher");
+var WhoIsTyping = require("../../WhoIsTyping");
+var MatrixClientPeg = require("../../MatrixClientPeg");
+
+module.exports = React.createClass({
+ displayName: 'RoomStatusBar',
+
+ propTypes: {
+ // the room this statusbar is representing.
+ room: React.PropTypes.object.isRequired,
+
+ // a list of TabCompleteEntries.Entry objects
+ tabCompleteEntries: React.PropTypes.array,
+
+ // the number of messages which have arrived since we've been scrolled up
+ numUnreadMessages: React.PropTypes.number,
+
+ // true if there are messages in the room which had errors on send
+ hasUnsentMessages: React.PropTypes.bool,
+
+ // this is true if we are fully scrolled-down, and are looking at
+ // the end of the live timeline.
+ atEndOfLiveTimeline: React.PropTypes.bool,
+
+ // true if there is an active call in this room (means we show
+ // the 'Active Call' text in the status bar if there is nothing
+ // more interesting)
+ hasActiveCall: React.PropTypes.bool,
+
+ // callback for when the user clicks on the 'resend all' button in the
+ // 'unsent messages' bar
+ onResendAllClick: React.PropTypes.func,
+
+ // callback for when the user clicks on the 'scroll to bottom' button
+ onScrollToBottomClick: React.PropTypes.func,
+ },
+
+ getInitialState: function() {
+ return {
+ syncState: MatrixClientPeg.get().getSyncState(),
+ };
+ },
+
+ componentWillMount: function() {
+ MatrixClientPeg.get().on("sync", this.onSyncStateChange);
+ },
+
+ componentWillUnmount: function() {
+ MatrixClientPeg.get().removeListener("sync", this.onSyncStateChange);
+ },
+
+ onSyncStateChange: function(state, prevState) {
+ if (state === "SYNCING" && prevState === "SYNCING") {
+ return;
+ }
+ this.setState({
+ syncState: state
+ });
+ },
+
+ render: function() {
+ var TabCompleteBar = sdk.getComponent('rooms.TabCompleteBar');
+ var TintableSvg = sdk.getComponent("elements.TintableSvg");
+
+ // no conn bar trumps unread count since you can't get unread messages
+ // without a connection! (technically may already have some but meh)
+ // It also trumps the "some not sent" msg since you can't resend without
+ // a connection!
+ if (this.state.syncState === "ERROR") {
+ return (
+
+
+
+
+ Connectivity to the server has been lost.
+
+
+ Sent messages will be stored until your connection has returned.
+
+
+
+ );
+ }
+
+ if (this.props.tabCompleteEntries) {
+ return (
+
+
...
+
+
+
+
+ Auto-complete
+
+
+
+ );
+ }
+
+ if (this.props.hasUnsentMessages) {
+ return (
+
+
+
+
+ Some of your messages have not been sent.
+
+
+
+
+ );
+ }
+
+ // unread count trumps who is typing since the unread count is only
+ // set when you've scrolled up
+ if (this.props.numUnreadMsgs) {
+ var unreadMsgs = this.props.numUnreadMessages + " new message" +
+ (this.props.numUnreadMessages > 1 ? "s" : "");
+
+ return (
+
+
+ {unreadMsgs}
+
+ );
+ }
+
+ var typingString = WhoIsTyping.whoIsTypingString(this.props.room);
+ if (typingString) {
+ return (
+
+ );
+ }
+
+ if (!this.props.atEndOfLiveTimeline) {
+ return (
+
+
+
+ );
+ }
+
+ if (this.props.hasActiveCall) {
+ return (
+
+
+
Active call
+
+ );
+ }
+
+ return ;
+ },
+});
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index 78c206a28a..820aaf407a 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -30,7 +30,6 @@ var EventTimeline = Matrix.EventTimeline;
var MatrixClientPeg = require("../../MatrixClientPeg");
var ContentMessages = require("../../ContentMessages");
-var WhoIsTyping = require("../../WhoIsTyping");
var Modal = require("../../Modal");
var sdk = require('../../index');
var CallHandler = require('../../CallHandler');
@@ -104,7 +103,6 @@ module.exports = React.createClass({
draggingFile: false,
searching: false,
searchResults: null,
- syncState: MatrixClientPeg.get().getSyncState(),
hasUnsentMessages: this._hasUnsentMessages(room),
callState: null,
timelineLoading: true, // track whether our room timeline is loading
@@ -130,7 +128,6 @@ module.exports = React.createClass({
MatrixClientPeg.get().on("Room.receipt", this.onRoomReceipt);
MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping);
MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember);
- MatrixClientPeg.get().on("sync", this.onSyncStateChange);
// xchat-style tab complete, add a colon if tab
// completing at the start of the text
this.tabComplete = new TabComplete({
@@ -286,7 +283,6 @@ module.exports = React.createClass({
MatrixClientPeg.get().removeListener("Room.receipt", this.onRoomReceipt);
MatrixClientPeg.get().removeListener("RoomMember.typing", this.onRoomMemberTyping);
MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
- MatrixClientPeg.get().removeListener("sync", this.onSyncStateChange);
}
window.removeEventListener('resize', this.onResize);
@@ -352,15 +348,6 @@ module.exports = React.createClass({
}
},
- onSyncStateChange: function(state, prevState) {
- if (state === "SYNCING" && prevState === "SYNCING") {
- return;
- }
- this.setState({
- syncState: state
- });
- },
-
componentWillReceiveProps: function(newProps) {
if (newProps.roomId != this.props.roomId) {
throw new Error("changing room on a RoomView is not supported");
@@ -833,10 +820,6 @@ module.exports = React.createClass({
});
},
- getWhoIsTypingString: function() {
- return WhoIsTyping.whoIsTypingString(this.state.room);
- },
-
onSearch: function(term, scope) {
this.setState({
searchTerm: term,
@@ -1320,13 +1303,6 @@ module.exports = React.createClass({
});
},
- getUnreadMessagesString: function() {
- if (!this.state.numUnreadMessages) {
- return "";
- }
- return this.state.numUnreadMessages + " new message" + (this.state.numUnreadMessages > 1 ? "s" : "");
- },
-
// jump down to the bottom of this room, where new events are arriving
jumpToLiveTimeline: function() {
// if we can't forward-paginate the existing timeline, then there
@@ -1559,6 +1535,12 @@ module.exports = React.createClass({
// We have successfully loaded this room, and are not previewing.
// Display the "normal" room view.
+ var call = CallHandler.getCallForRoom(this.props.roomId);
+ var inCall = false;
+ if (call && (this.state.callState !== 'ended' && this.state.callState !== 'ringing')) {
+ inCall = true;
+ }
+
var scrollheader_classes = classNames({
mx_RoomView_scrollheader: true,
loading: this.state.paginating
@@ -1577,86 +1559,20 @@ module.exports = React.createClass({
var UploadBar = sdk.getComponent('structures.UploadBar');
statusBar =
} else if (!this.state.searchResults) {
- var typingString = this.getWhoIsTypingString();
- // typingString = "S͚͍̭̪̤͙̱͙̖̥͙̥̤̻̙͕͓͂̌ͬ͐̂k̜̝͎̰̥̻̼̂̌͛͗͊̅̒͂̊̍̍͌̈̈́͌̋̊ͬa͉̯͚̺̗̳̩ͪ̋̑͌̓̆̍̂̉̏̅̆ͧ̌̑v̲̲̪̝ͥ̌ͨͮͭ̊͆̾ͮ̍ͮ͑̚e̮̙͈̱̘͕̼̮͒ͩͨͫ̃͗̇ͩ͒ͣͦ͒̄̍͐ͣ̿ͥṘ̗̺͇̺̺͔̄́̊̓͊̍̃ͨ̚ā̼͎̘̟̼͎̜̪̪͚̋ͨͨͧ̓ͦͯͤ̄͆̋͂ͩ͌ͧͅt̙̙̹̗̦͖̞ͫͪ͑̑̅ͪ̃̚ͅ is typing...";
- var unreadMsgs = this.getUnreadMessagesString();
- // no conn bar trumps unread count since you can't get unread messages
- // without a connection! (technically may already have some but meh)
- // It also trumps the "some not sent" msg since you can't resend without
- // a connection!
- if (this.state.syncState === "ERROR") {
- statusBar = (
-
-
-
-
- Connectivity to the server has been lost.
-
-
- Sent messages will be stored until your connection has returned.
-
-
-
- );
- }
- else if (this.tabComplete.isTabCompleting()) {
- var TabCompleteBar = sdk.getComponent('rooms.TabCompleteBar');
- statusBar = (
-
-
...
-
-
-
-
- Auto-complete
-
-
-
- );
- }
- else if (this.state.hasUnsentMessages) {
- statusBar = (
-
-
-
-
- Some of your messages have not been sent.
-
-
-
-
- );
- }
- // unread count trumps who is typing since the unread count is only
- // set when you've scrolled up
- else if (unreadMsgs) {
- statusBar = (
-
-
- {unreadMsgs}
-
- );
- }
- else if (typingString) {
- statusBar = (
-
- );
- }
- else if (!this.state.atEndOfLiveTimeline) {
- statusBar = (
-
-
-
- );
- }
+ var RoomStatusBar = sdk.getComponent('structures.RoomStatusBar');
+ var tabEntries = this.tabComplete.isTabCompleting() ?
+ this.tabComplete.peek(6) : null;
+
+ statusBar =
}
var aux = null;
@@ -1727,11 +1643,7 @@ module.exports = React.createClass({
};
}
- var call = CallHandler.getCallForRoom(this.props.roomId);
- //var call = CallHandler.getAnyActiveCall();
- var inCall = false;
- if (call && (this.state.callState !== 'ended' && this.state.callState !== 'ringing')) {
- inCall = true;
+ if (inCall) {
var zoomButton, voiceMuteButton, videoMuteButton;
if (call.type === "video") {
@@ -1755,14 +1667,7 @@ module.exports = React.createClass({
width="21" height="26"/>
- if (!statusBar) {
- statusBar =
-
-
-
Active call
-
;
- }
-
+ // wrap the existing status bar into a 'callStatusBar' which adds more knobs.
statusBar =
{ voiceMuteButton }