зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1088672 - Part 4. Rewrite Loop's incoming call handling in the flux style. Put back alerts and make window unload be handled correctly. r=mikedeboer
This commit is contained in:
Родитель
d5f776b7d0
Коммит
0984661eea
|
@ -35,7 +35,8 @@ loop.conversation = (function(mozL10n) {
|
|||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
roomStore: React.PropTypes.instanceOf(loop.store.RoomStore)
|
||||
roomStore: React.PropTypes.instanceOf(loop.store.RoomStore),
|
||||
mozLoop: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
|
@ -48,7 +49,8 @@ loop.conversation = (function(mozL10n) {
|
|||
case "incoming":
|
||||
case "outgoing": {
|
||||
return (React.createElement(CallControllerView, {
|
||||
dispatcher: this.props.dispatcher}
|
||||
dispatcher: this.props.dispatcher,
|
||||
mozLoop: this.props.mozLoop}
|
||||
));
|
||||
}
|
||||
case "room": {
|
||||
|
@ -152,17 +154,13 @@ loop.conversation = (function(mozL10n) {
|
|||
}
|
||||
|
||||
window.addEventListener("unload", function(event) {
|
||||
// Handle direct close of dialog box via [x] control.
|
||||
// XXX Move to the conversation models, when we transition
|
||||
// incoming calls to flux (bug 1088672).
|
||||
navigator.mozLoop.calls.clearCallInProgress(windowId);
|
||||
|
||||
dispatcher.dispatch(new sharedActions.WindowUnload());
|
||||
});
|
||||
|
||||
React.render(React.createElement(AppControllerView, {
|
||||
roomStore: roomStore,
|
||||
dispatcher: dispatcher}
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop}
|
||||
), document.querySelector('#main'));
|
||||
|
||||
dispatcher.dispatch(new sharedActions.GetWindowData({
|
||||
|
|
|
@ -35,7 +35,8 @@ loop.conversation = (function(mozL10n) {
|
|||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
roomStore: React.PropTypes.instanceOf(loop.store.RoomStore)
|
||||
roomStore: React.PropTypes.instanceOf(loop.store.RoomStore),
|
||||
mozLoop: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
|
@ -49,6 +50,7 @@ loop.conversation = (function(mozL10n) {
|
|||
case "outgoing": {
|
||||
return (<CallControllerView
|
||||
dispatcher={this.props.dispatcher}
|
||||
mozLoop={this.props.mozLoop}
|
||||
/>);
|
||||
}
|
||||
case "room": {
|
||||
|
@ -152,17 +154,13 @@ loop.conversation = (function(mozL10n) {
|
|||
}
|
||||
|
||||
window.addEventListener("unload", function(event) {
|
||||
// Handle direct close of dialog box via [x] control.
|
||||
// XXX Move to the conversation models, when we transition
|
||||
// incoming calls to flux (bug 1088672).
|
||||
navigator.mozLoop.calls.clearCallInProgress(windowId);
|
||||
|
||||
dispatcher.dispatch(new sharedActions.WindowUnload());
|
||||
});
|
||||
|
||||
React.render(<AppControllerView
|
||||
roomStore={roomStore}
|
||||
dispatcher={dispatcher}
|
||||
mozLoop={navigator.mozLoop}
|
||||
/>, document.querySelector('#main'));
|
||||
|
||||
dispatcher.dispatch(new sharedActions.GetWindowData({
|
||||
|
|
|
@ -147,6 +147,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
callType: React.PropTypes.string.isRequired,
|
||||
callerId: React.PropTypes.string.isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
mozLoop: React.PropTypes.object.isRequired,
|
||||
// Only for use by the ui-showcase
|
||||
showMenu: React.PropTypes.bool
|
||||
},
|
||||
|
@ -157,6 +158,14 @@ loop.conversationViews = (function(mozL10n) {
|
|||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.props.mozLoop.startAlerting();
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.props.mozLoop.stopAlerting();
|
||||
},
|
||||
|
||||
clickHandler: function(e) {
|
||||
var target = e.target;
|
||||
if (!target.classList.contains('btn-chevron')) {
|
||||
|
@ -939,7 +948,8 @@ loop.conversationViews = (function(mozL10n) {
|
|||
],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
mozLoop: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
|
@ -989,7 +999,8 @@ loop.conversationViews = (function(mozL10n) {
|
|||
return (React.createElement(AcceptCallView, {
|
||||
callType: this.state.callType,
|
||||
callerId: this.state.callerId,
|
||||
dispatcher: this.props.dispatcher}
|
||||
dispatcher: this.props.dispatcher,
|
||||
mozLoop: this.props.mozLoop}
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -147,6 +147,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
callType: React.PropTypes.string.isRequired,
|
||||
callerId: React.PropTypes.string.isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
mozLoop: React.PropTypes.object.isRequired,
|
||||
// Only for use by the ui-showcase
|
||||
showMenu: React.PropTypes.bool
|
||||
},
|
||||
|
@ -157,6 +158,14 @@ loop.conversationViews = (function(mozL10n) {
|
|||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.props.mozLoop.startAlerting();
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.props.mozLoop.stopAlerting();
|
||||
},
|
||||
|
||||
clickHandler: function(e) {
|
||||
var target = e.target;
|
||||
if (!target.classList.contains('btn-chevron')) {
|
||||
|
@ -939,7 +948,8 @@ loop.conversationViews = (function(mozL10n) {
|
|||
],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
mozLoop: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
|
@ -990,6 +1000,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
callType={this.state.callType}
|
||||
callerId={this.state.callerId}
|
||||
dispatcher={this.props.dispatcher}
|
||||
mozLoop={this.props.mozLoop}
|
||||
/>);
|
||||
}
|
||||
|
||||
|
|
|
@ -425,6 +425,12 @@ loop.store = loop.store || {};
|
|||
* as shutting down the call cleanly and adding any relevant telemetry data.
|
||||
*/
|
||||
windowUnload: function() {
|
||||
if (!this.getStoreState("outgoing") &&
|
||||
this.getStoreState("callState") === CALL_STATES.ALERTING &&
|
||||
this._websocket) {
|
||||
this._websocket.decline();
|
||||
}
|
||||
|
||||
this._endSession();
|
||||
},
|
||||
|
||||
|
|
|
@ -586,6 +586,7 @@ describe("loop.conversationViews", function () {
|
|||
return TestUtils.renderIntoDocument(
|
||||
React.createElement(loop.conversationViews.CallControllerView, {
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: fakeMozLoop
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -1224,7 +1225,8 @@ describe("loop.conversationViews", function () {
|
|||
describe("AcceptCallView", function() {
|
||||
var view;
|
||||
|
||||
function mountTestComponent(props) {
|
||||
function mountTestComponent(extraProps) {
|
||||
var props = _.extend({dispatcher: dispatcher, mozLoop: fakeMozLoop}, extraProps);
|
||||
return TestUtils.renderIntoDocument(
|
||||
React.createElement(loop.conversationViews.AcceptCallView, props));
|
||||
}
|
||||
|
@ -1233,12 +1235,31 @@ describe("loop.conversationViews", function () {
|
|||
view = null;
|
||||
});
|
||||
|
||||
it("should start alerting on display", function() {
|
||||
view = mountTestComponent({
|
||||
callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
callerId: "fake@invalid.com"
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.startAlerting);
|
||||
});
|
||||
|
||||
it("should stop alerting when removed from the display", function() {
|
||||
view = mountTestComponent({
|
||||
callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
callerId: "fake@invalid.com"
|
||||
});
|
||||
|
||||
view.componentWillUnmount();
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.stopAlerting);
|
||||
});
|
||||
|
||||
describe("default answer mode", function() {
|
||||
it("should display video as primary answer mode", function() {
|
||||
view = mountTestComponent({
|
||||
callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
callerId: "fake@invalid.com",
|
||||
dispatcher: dispatcher
|
||||
callerId: "fake@invalid.com"
|
||||
});
|
||||
|
||||
var primaryBtn = view.getDOMNode()
|
||||
|
@ -1250,8 +1271,7 @@ describe("loop.conversationViews", function () {
|
|||
it("should display audio as primary answer mode", function() {
|
||||
view = mountTestComponent({
|
||||
callType: CALL_TYPES.AUDIO_ONLY,
|
||||
callerId: "fake@invalid.com",
|
||||
dispatcher: dispatcher
|
||||
callerId: "fake@invalid.com"
|
||||
});
|
||||
|
||||
var primaryBtn = view.getDOMNode()
|
||||
|
@ -1263,8 +1283,7 @@ describe("loop.conversationViews", function () {
|
|||
it("should accept call with video", function() {
|
||||
view = mountTestComponent({
|
||||
callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
callerId: "fake@invalid.com",
|
||||
dispatcher: dispatcher
|
||||
callerId: "fake@invalid.com"
|
||||
});
|
||||
|
||||
var primaryBtn = view.getDOMNode()
|
||||
|
@ -1282,8 +1301,7 @@ describe("loop.conversationViews", function () {
|
|||
it("should accept call with audio", function() {
|
||||
view = mountTestComponent({
|
||||
callType: CALL_TYPES.AUDIO_ONLY,
|
||||
callerId: "fake@invalid.com",
|
||||
dispatcher: dispatcher
|
||||
callerId: "fake@invalid.com"
|
||||
});
|
||||
|
||||
var primaryBtn = view.getDOMNode()
|
||||
|
@ -1302,8 +1320,7 @@ describe("loop.conversationViews", function () {
|
|||
function() {
|
||||
view = mountTestComponent({
|
||||
callType: CALL_TYPES.AUDIO_ONLY,
|
||||
callerId: "fake@invalid.com",
|
||||
dispatcher: dispatcher
|
||||
callerId: "fake@invalid.com"
|
||||
});
|
||||
|
||||
var secondaryBtn = view.getDOMNode()
|
||||
|
@ -1322,8 +1339,7 @@ describe("loop.conversationViews", function () {
|
|||
function() {
|
||||
view = mountTestComponent({
|
||||
callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
callerId: "fake@invalid.com",
|
||||
dispatcher: dispatcher
|
||||
callerId: "fake@invalid.com"
|
||||
});
|
||||
|
||||
var secondaryBtn = view.getDOMNode()
|
||||
|
@ -1343,8 +1359,7 @@ describe("loop.conversationViews", function () {
|
|||
it("should dispatch a DeclineCall action", function() {
|
||||
view = mountTestComponent({
|
||||
callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
callerId: "fake@invalid.com",
|
||||
dispatcher: dispatcher
|
||||
callerId: "fake@invalid.com"
|
||||
});
|
||||
|
||||
var buttonDecline = view.getDOMNode().querySelector(".btn-decline");
|
||||
|
@ -1361,8 +1376,7 @@ describe("loop.conversationViews", function () {
|
|||
it("should dispatch a DeclineCall action with blockCaller true", function() {
|
||||
view = mountTestComponent({
|
||||
callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
callerId: "fake@invalid.com",
|
||||
dispatcher: dispatcher
|
||||
callerId: "fake@invalid.com"
|
||||
});
|
||||
|
||||
var buttonBlock = view.getDOMNode().querySelector(".btn-block");
|
||||
|
|
|
@ -915,11 +915,46 @@ describe("loop.store.ConversationStore", function () {
|
|||
});
|
||||
|
||||
describe("#windowUnload", function() {
|
||||
it("should disconnect from the servers via the sdk", function() {
|
||||
var fakeWebsocket;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeWebsocket = store._websocket = {
|
||||
close: sinon.stub(),
|
||||
decline: sinon.stub()
|
||||
};
|
||||
|
||||
store.setStoreState({windowId: 42});
|
||||
});
|
||||
|
||||
it("should decline the connection on the websocket for incoming calls if the state is alerting", function() {
|
||||
store.setStoreState({
|
||||
callState: CALL_STATES.ALERTING,
|
||||
outgoing: false
|
||||
});
|
||||
|
||||
store.windowUnload();
|
||||
|
||||
sinon.assert.calledOnce(fakeWebsocket.decline);
|
||||
});
|
||||
|
||||
it("should disconnect the sdk session", function() {
|
||||
store.windowUnload();
|
||||
|
||||
sinon.assert.calledOnce(sdkDriver.disconnectSession);
|
||||
});
|
||||
|
||||
it("should close the websocket", function() {
|
||||
store.windowUnload();
|
||||
|
||||
sinon.assert.calledOnce(fakeWebsocket.close);
|
||||
});
|
||||
|
||||
it("should clear the call in progress for the backend", function() {
|
||||
store.windowUnload();
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.calls.clearCallInProgress);
|
||||
sinon.assert.calledWithExactly(fakeMozLoop.calls.clearCallInProgress, 42);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Events", function() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче