diff --git a/src/CallHandler.js b/src/CallHandler.js
index 187449924f..189e99b307 100644
--- a/src/CallHandler.js
+++ b/src/CallHandler.js
@@ -138,9 +138,17 @@ function _setCallListeners(call) {
function _setCallState(call, roomId, status) {
console.log(
- "Call state in %s changed to %s (%s)", roomId, status, (call ? call.state : "-")
+ "Call state in %s changed to %s (%s)", roomId, status, (call ? call.call_state : "-")
);
calls[roomId] = call;
+
+ if (status === "ringing") {
+ play("ringAudio")
+ }
+ else if (call && call.call_state === "ringing") {
+ pause("ringAudio")
+ }
+
if (call) {
call.call_state = status;
}
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index 6db2659986..01b877e6cf 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -1207,8 +1207,9 @@ module.exports = React.createClass({
}
var call = CallHandler.getCallForRoom(this.props.roomId);
+ //var call = CallHandler.getAnyActiveCall();
var inCall = false;
- if (call && this.state.callState != 'ended') {
+ if (call && (this.state.callState !== 'ended' && this.state.callState !== 'ringing')) {
inCall = true;
var zoomButton, voiceMuteButton, videoMuteButton;
diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js
index 73f553af6e..7c228b5c9d 100644
--- a/src/components/views/rooms/MessageComposer.js
+++ b/src/components/views/rooms/MessageComposer.js
@@ -529,6 +529,7 @@ module.exports = React.createClass({
onHangupClick: function() {
var call = CallHandler.getCallForRoom(this.props.room.roomId);
+ //var call = CallHandler.getAnyActiveCall();
if (!call) {
return;
}
@@ -563,6 +564,7 @@ module.exports = React.createClass({
var callButton, videoCallButton, hangupButton;
var call = CallHandler.getCallForRoom(this.props.room.roomId);
+ //var call = CallHandler.getAnyActiveCall();
if (this.props.callState && this.props.callState !== 'ended') {
hangupButton =
diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js
index a89dd55f1a..9ec2bf0d45 100644
--- a/src/components/views/rooms/RoomList.js
+++ b/src/components/views/rooms/RoomList.js
@@ -19,6 +19,7 @@ var React = require("react");
var ReactDOM = require("react-dom");
var GeminiScrollbar = require('react-gemini-scrollbar');
var MatrixClientPeg = require("../../../MatrixClientPeg");
+var CallHandler = require('../../../CallHandler');
var RoomListSorter = require("../../../RoomListSorter");
var UnreadStatus = require('../../../UnreadStatus');
var dis = require("../../../dispatcher");
@@ -39,6 +40,7 @@ module.exports = React.createClass({
return {
activityMap: null,
lists: {},
+ incomingCall: null,
}
},
@@ -66,7 +68,21 @@ module.exports = React.createClass({
this.tooltip = payload.tooltip;
this._repositionTooltip();
if (this.tooltip) this.tooltip.style.display = 'block';
- break
+ break;
+ case 'call_state':
+ var call = CallHandler.getCall(payload.room_id);
+ if (call && call.call_state === 'ringing') {
+ this.setState({
+ incomingCall: call
+ });
+ this._repositionIncomingCallBox(undefined, true);
+ }
+ else {
+ this.setState({
+ incomingCall: null
+ });
+ }
+ break;
}
},
@@ -212,10 +228,49 @@ module.exports = React.createClass({
return s;
},
+ _getScrollNode: function() {
+ var panel = ReactDOM.findDOMNode(this);
+ if (!panel) return null;
+
+ if (panel.classList.contains('gm-prevented')) {
+ return panel;
+ } else {
+ return panel.children[2]; // XXX: Fragile!
+ }
+ },
+
+ _repositionTooltips: function(e) {
+ this._repositionTooltip(e);
+ this._repositionIncomingCallBox(e, false);
+ },
+
_repositionTooltip: function(e) {
if (this.tooltip && this.tooltip.parentElement) {
var scroll = ReactDOM.findDOMNode(this);
- this.tooltip.style.top = (scroll.parentElement.offsetTop + this.tooltip.parentElement.offsetTop - scroll.children[2].scrollTop) + "px";
+ this.tooltip.style.top = (scroll.parentElement.offsetTop + this.tooltip.parentElement.offsetTop - this._getScrollNode().scrollTop) + "px";
+ }
+ },
+
+ _repositionIncomingCallBox: function(e, firstTime) {
+ var incomingCallBox = document.getElementById("incomingCallBox");
+ if (incomingCallBox && incomingCallBox.parentElement) {
+ var scroll = this._getScrollNode();
+ var top = (scroll.offsetTop + incomingCallBox.parentElement.offsetTop - scroll.scrollTop);
+
+ if (firstTime) {
+ // scroll to make sure the callbox is on the screen...
+ if (top < 10) {
+ scroll.scrollTop = incomingCallBox.parentElement.offsetTop - 10;
+ }
+ else if (top > scroll.clientHeight - incomingCallBox.offsetHeight) {
+ scroll.scrollTop = incomingCallBox.parentElement.offsetTop - scroll.offsetHeight + incomingCallBox.offsetHeight;
+ }
+ // recalculate top in case we clipped it.
+ top = (scroll.offsetTop + incomingCallBox.parentElement.offsetTop - scroll.scrollTop);
+ }
+
+ incomingCallBox.style.top = top + "px";
+ incomingCallBox.style.left = scroll.offsetLeft + scroll.offsetWidth + "px";
}
},
@@ -234,7 +289,7 @@ module.exports = React.createClass({
var self = this;
return (
-
+
{ expandButton }
@@ -244,6 +299,7 @@ module.exports = React.createClass({
order="recent"
activityMap={ self.state.activityMap }
selectedRoom={ self.props.selectedRoom }
+ incomingCall={ self.state.incomingCall }
collapsed={ self.props.collapsed } />
{ Object.keys(self.state.lists).map(function(tagName) {
@@ -276,6 +334,7 @@ module.exports = React.createClass({
order="manual"
activityMap={ self.state.activityMap }
selectedRoom={ self.props.selectedRoom }
+ incomingCall={ self.state.incomingCall }
collapsed={ self.props.collapsed } />
}
@@ -290,6 +349,7 @@ module.exports = React.createClass({
bottommost={ self.state.lists['im.vector.fake.archived'].length === 0 }
activityMap={ self.state.activityMap }
selectedRoom={ self.props.selectedRoom }
+ incomingCall={ self.state.incomingCall }
collapsed={ self.props.collapsed } />
diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js
index 0a03ebe89d..37a77f9561 100644
--- a/src/components/views/rooms/RoomTile.js
+++ b/src/components/views/rooms/RoomTile.js
@@ -38,6 +38,7 @@ module.exports = React.createClass({
highlight: React.PropTypes.bool.isRequired,
isInvite: React.PropTypes.bool.isRequired,
roomSubList: React.PropTypes.object.isRequired,
+ incomingCall: React.PropTypes.object,
},
getInitialState: function() {
@@ -105,6 +106,12 @@ module.exports = React.createClass({
label = ;
}
+ var incomingCallBox;
+ if (this.props.incomingCall) {
+ var IncomingCallBox = sdk.getComponent("voip.IncomingCallBox");
+ incomingCallBox = ;
+ }
+
var RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
// These props are injected by React DnD,
@@ -120,6 +127,7 @@ module.exports = React.createClass({
{ badge }
{ label }
+ { incomingCallBox }
));
}
diff --git a/src/components/views/voip/CallView.js b/src/components/views/voip/CallView.js
index fbaed1dcd7..d67147dd1e 100644
--- a/src/components/views/voip/CallView.js
+++ b/src/components/views/voip/CallView.js
@@ -35,19 +35,13 @@ module.exports = React.createClass({
componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction);
- this._trackedRoom = null;
if (this.props.room) {
- this._trackedRoom = this.props.room;
- this.showCall(this._trackedRoom.roomId);
+ this.showCall(this.props.room.roomId);
}
else {
+ // XXX: why would we ever not have a this.props.room?
var call = CallHandler.getAnyActiveCall();
if (call) {
- console.log(
- "Global CallView is now tracking active call in room %s",
- call.roomId
- );
- this._trackedRoom = MatrixClientPeg.get().getRoom(call.roomId);
this.showCall(call.roomId);
}
}
@@ -81,7 +75,7 @@ module.exports = React.createClass({
// and for the voice stream of screen captures
call.setRemoteAudioElement(this.getVideoView().getRemoteAudioElement());
}
- if (call && call.type === "video" && call.state !== 'ended') {
+ if (call && call.type === "video" && call.call_state !== "ended" && call.call_state !== "ringing") {
// if this call is a conf call, don't display local video as the
// conference will have us in it
this.getVideoView().getLocalVideoElement().style.display = (
diff --git a/src/components/views/voip/IncomingCallBox.js b/src/components/views/voip/IncomingCallBox.js
index 263bbf543c..b110d45043 100644
--- a/src/components/views/voip/IncomingCallBox.js
+++ b/src/components/views/voip/IncomingCallBox.js
@@ -21,87 +21,29 @@ var CallHandler = require("../../../CallHandler");
module.exports = React.createClass({
displayName: 'IncomingCallBox',
- componentDidMount: function() {
- this.dispatcherRef = dis.register(this.onAction);
- },
-
- componentWillUnmount: function() {
- dis.unregister(this.dispatcherRef);
- },
-
- getInitialState: function() {
- return {
- incomingCall: null
- }
- },
-
- onAction: function(payload) {
- if (payload.action !== 'call_state') {
- return;
- }
- var call = CallHandler.getCall(payload.room_id);
- if (!call || call.call_state !== 'ringing') {
- this.setState({
- incomingCall: null,
- });
- this.getRingAudio().pause();
- return;
- }
- if (call.call_state === "ringing") {
- this.getRingAudio().load();
- this.getRingAudio().play();
- }
- else {
- this.getRingAudio().pause();
- }
-
- this.setState({
- incomingCall: call
- });
- },
-
onAnswerClick: function() {
dis.dispatch({
action: 'answer',
- room_id: this.state.incomingCall.roomId
+ room_id: this.props.incomingCall.roomId
});
},
onRejectClick: function() {
dis.dispatch({
action: 'hangup',
- room_id: this.state.incomingCall.roomId
+ room_id: this.props.incomingCall.roomId
});
},
- getRingAudio: function() {
- return this.refs.ringAudio;
- },
-
render: function() {
- // NB: This block MUST have a "key" so React doesn't clobber the elements
- // between in-call / not-in-call.
- var audioBlock = (
-
- );
- if (!this.state.incomingCall || !this.state.incomingCall.roomId) {
- return (
-
- {audioBlock}
-
- );
- }
- var caller = MatrixClientPeg.get().getRoom(this.state.incomingCall.roomId).name;
+ var room = MatrixClientPeg.get().getRoom(this.props.incomingCall.roomId);
+ var caller = room ? room.name : "unknown";
return (
-
- {audioBlock}
+
- Incoming { this.state.incomingCall ? this.state.incomingCall.type : '' } call from { caller }
+ Incoming { this.props.incomingCall ? this.props.incomingCall.type : '' } call from { caller }