mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1074702 - Part 2: Room views for Loop standalone. r=Standard8
This commit is contained in:
parent
131e1b12f1
commit
7c60277a5e
@ -725,3 +725,59 @@ html, .fx-embedded, #main,
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
/* Standalone rooms */
|
||||
|
||||
.standalone .room-conversation-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.standalone .room-inner-action-area {
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
z-index: 1000;
|
||||
margin: 0 auto;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.standalone .room-inner-action-area button {
|
||||
position: absolute;
|
||||
border-radius: 3px;
|
||||
font-size: 1.2em;
|
||||
padding: .2em 1.2em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.standalone .room-conversation h2.room-name {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
top: 0;
|
||||
right: 0;
|
||||
color: #fff;
|
||||
z-index: 2000000;
|
||||
font-size: 1.2em;
|
||||
padding: .4em;
|
||||
}
|
||||
|
||||
.standalone .room-conversation .media {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.standalone .room-conversation .video_wrapper.remote_wrapper {
|
||||
background-color: #4e4e4e;
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.standalone .room-conversation .local-stream {
|
||||
width: 33%;
|
||||
height: 26.5%;
|
||||
}
|
||||
|
||||
.standalone .room-conversation .conversation-toolbar {
|
||||
background: #000;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.standalone .room-conversation .conversation-toolbar .btn-hangup-entry {
|
||||
display: block;
|
||||
}
|
||||
|
@ -81,7 +81,8 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
video: {enabled: true, visible: true},
|
||||
audio: {enabled: true, visible: true}
|
||||
audio: {enabled: true, visible: true},
|
||||
enableHangup: true
|
||||
};
|
||||
},
|
||||
|
||||
@ -89,7 +90,9 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
video: React.PropTypes.object.isRequired,
|
||||
audio: React.PropTypes.object.isRequired,
|
||||
hangup: React.PropTypes.func.isRequired,
|
||||
publishStream: React.PropTypes.func.isRequired
|
||||
publishStream: React.PropTypes.func.isRequired,
|
||||
hangupButtonLabel: React.PropTypes.string,
|
||||
enableHangup: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
handleClickHangup: function() {
|
||||
@ -104,14 +107,19 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
this.props.publishStream("audio", !this.props.audio.enabled);
|
||||
},
|
||||
|
||||
_getHangupButtonLabel: function() {
|
||||
return this.props.hangupButtonLabel || l10n.get("hangup_button_caption2");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var cx = React.addons.classSet;
|
||||
return (
|
||||
React.DOM.ul({className: "conversation-toolbar"},
|
||||
React.DOM.li({className: "conversation-toolbar-btn-box btn-hangup-entry"},
|
||||
React.DOM.button({className: "btn btn-hangup", onClick: this.handleClickHangup,
|
||||
title: l10n.get("hangup_button_title")},
|
||||
l10n.get("hangup_button_caption2")
|
||||
title: l10n.get("hangup_button_title"),
|
||||
disabled: !this.props.enableHangup},
|
||||
this._getHangupButtonLabel()
|
||||
)
|
||||
),
|
||||
React.DOM.li({className: "conversation-toolbar-btn-box"},
|
||||
|
@ -81,7 +81,8 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
video: {enabled: true, visible: true},
|
||||
audio: {enabled: true, visible: true}
|
||||
audio: {enabled: true, visible: true},
|
||||
enableHangup: true
|
||||
};
|
||||
},
|
||||
|
||||
@ -89,7 +90,9 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
video: React.PropTypes.object.isRequired,
|
||||
audio: React.PropTypes.object.isRequired,
|
||||
hangup: React.PropTypes.func.isRequired,
|
||||
publishStream: React.PropTypes.func.isRequired
|
||||
publishStream: React.PropTypes.func.isRequired,
|
||||
hangupButtonLabel: React.PropTypes.string,
|
||||
enableHangup: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
handleClickHangup: function() {
|
||||
@ -104,14 +107,19 @@ loop.shared.views = (function(_, OT, l10n) {
|
||||
this.props.publishStream("audio", !this.props.audio.enabled);
|
||||
},
|
||||
|
||||
_getHangupButtonLabel: function() {
|
||||
return this.props.hangupButtonLabel || l10n.get("hangup_button_caption2");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var cx = React.addons.classSet;
|
||||
return (
|
||||
<ul className="conversation-toolbar">
|
||||
<li className="conversation-toolbar-btn-box btn-hangup-entry">
|
||||
<button className="btn btn-hangup" onClick={this.handleClickHangup}
|
||||
title={l10n.get("hangup_button_title")}>
|
||||
{l10n.get("hangup_button_caption2")}
|
||||
title={l10n.get("hangup_button_title")}
|
||||
disabled={!this.props.enableHangup}>
|
||||
{this._getHangupButtonLabel()}
|
||||
</button>
|
||||
</li>
|
||||
<li className="conversation-toolbar-btn-box">
|
||||
|
@ -7,11 +7,12 @@
|
||||
/* global loop:true, React */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.standaloneRoomViews = (function() {
|
||||
loop.standaloneRoomViews = (function(mozL10n) {
|
||||
"use strict";
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
var sharedActions = loop.shared.actions;
|
||||
var sharedViews = loop.shared.views;
|
||||
|
||||
var StandaloneRoomView = React.createClass({displayName: 'StandaloneRoomView',
|
||||
mixins: [Backbone.Events],
|
||||
@ -23,7 +24,11 @@ loop.standaloneRoomViews = (function() {
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.activeRoomStore.getStoreState();
|
||||
var storeState = this.props.activeRoomStore.getStoreState();
|
||||
return _.extend({}, storeState, {
|
||||
// Used by the UI showcase.
|
||||
roomState: this.props.roomState || storeState.roomState
|
||||
});
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
@ -41,10 +46,57 @@ loop.standaloneRoomViews = (function() {
|
||||
this.setState(this.props.activeRoomStore.getStoreState());
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns either the required DOMNode
|
||||
*
|
||||
* @param {String} className The name of the class to get the element for.
|
||||
*/
|
||||
_getElement: function(className) {
|
||||
return this.getDOMNode().querySelector(className);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the required configuration for publishing video on the sdk.
|
||||
*/
|
||||
_getPublisherConfig: function() {
|
||||
// height set to 100%" to fix video layout on Google Chrome
|
||||
// @see https://bugzilla.mozilla.org/show_bug.cgi?id=1020445
|
||||
return {
|
||||
insertMode: "append",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
publishVideo: true,
|
||||
style: {
|
||||
audioLevelDisplayMode: "off",
|
||||
bugDisplayMode: "off",
|
||||
buttonDisplayMode: "off",
|
||||
nameDisplayMode: "off",
|
||||
videoDisabledDisplayMode: "off"
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.stopListening(this.props.activeRoomStore);
|
||||
},
|
||||
|
||||
/**
|
||||
* Watches for when we transition from READY to JOINED room state, so we can
|
||||
* request user media access.
|
||||
* @param {Object} nextProps (Unused)
|
||||
* @param {Object} nextState Next state object.
|
||||
*/
|
||||
componentWillUpdate: function(nextProps, nextState) {
|
||||
if (this.state.roomState === ROOM_STATES.READY &&
|
||||
nextState.roomState === ROOM_STATES.JOINED) {
|
||||
this.props.dispatcher.dispatch(new sharedActions.SetupStreamElements({
|
||||
publisherConfig: this._getPublisherConfig(),
|
||||
getLocalElementFunc: this._getElement.bind(this, ".local"),
|
||||
getRemoteElementFunc: this._getElement.bind(this, ".remote")
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
joinRoom: function() {
|
||||
this.props.dispatcher.dispatch(new sharedActions.JoinRoom());
|
||||
},
|
||||
@ -53,30 +105,82 @@ loop.standaloneRoomViews = (function() {
|
||||
this.props.dispatcher.dispatch(new sharedActions.LeaveRoom());
|
||||
},
|
||||
|
||||
// XXX Implement tests for this view when we do the proper views
|
||||
// - bug 1074705 and others
|
||||
render: function() {
|
||||
switch(this.state.roomState) {
|
||||
case ROOM_STATES.READY: {
|
||||
return (
|
||||
React.DOM.div(null, React.DOM.button({onClick: this.joinRoom}, "Join"))
|
||||
);
|
||||
}
|
||||
case ROOM_STATES.JOINED: {
|
||||
return (
|
||||
React.DOM.div(null, React.DOM.button({onClick: this.leaveRoom}, "Leave"))
|
||||
);
|
||||
}
|
||||
default: {
|
||||
return (
|
||||
React.DOM.div(null, this.state.roomState)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Toggles streaming status for a given stream type.
|
||||
*
|
||||
* @param {String} type Stream type ("audio" or "video").
|
||||
* @param {Boolean} enabled Enabled stream flag.
|
||||
*/
|
||||
publishStream: function(type, enabled) {
|
||||
this.props.dispatcher.dispatch(new sharedActions.SetMute({
|
||||
type: type,
|
||||
enabled: enabled
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if current room is active.
|
||||
*
|
||||
* @return {Boolean}
|
||||
*/
|
||||
_roomIsActive: function() {
|
||||
return this.state.roomState === ROOM_STATES.JOINED ||
|
||||
this.state.roomState === ROOM_STATES.SESSION_CONNECTED ||
|
||||
this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS;
|
||||
},
|
||||
|
||||
_renderActionButtons: function() {
|
||||
// XXX Render "Start your own" button when room is over capacity (see
|
||||
// bug 1074709)
|
||||
if (this.state.roomState === ROOM_STATES.INIT ||
|
||||
this.state.roomState === ROOM_STATES.READY) {
|
||||
return (
|
||||
React.DOM.div({className: "room-inner-action-area"},
|
||||
React.DOM.button({className: "btn btn-join btn-info", onClick: this.joinRoom},
|
||||
mozL10n.get("rooms_room_join_label")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var localStreamClasses = React.addons.classSet({
|
||||
hide: !this._roomIsActive(),
|
||||
local: true,
|
||||
"local-stream": true,
|
||||
"local-stream-audio": false
|
||||
});
|
||||
|
||||
return (
|
||||
React.DOM.div({className: "room-conversation-wrapper"},
|
||||
this._renderActionButtons(),
|
||||
React.DOM.div({className: "video-layout-wrapper"},
|
||||
React.DOM.div({className: "conversation room-conversation"},
|
||||
React.DOM.h2({className: "room-name"}, this.state.roomName),
|
||||
React.DOM.div({className: "media nested"},
|
||||
React.DOM.div({className: "video_wrapper remote_wrapper"},
|
||||
React.DOM.div({className: "video_inner remote"})
|
||||
),
|
||||
React.DOM.div({className: localStreamClasses})
|
||||
),
|
||||
sharedViews.ConversationToolbar({
|
||||
video: {enabled: !this.state.videoMuted,
|
||||
visible: this._roomIsActive()},
|
||||
audio: {enabled: !this.state.audioMuted,
|
||||
visible: this._roomIsActive()},
|
||||
publishStream: this.publishStream,
|
||||
hangup: this.leaveRoom,
|
||||
hangupButtonLabel: mozL10n.get("rooms_leave_button_label"),
|
||||
enableHangup: this._roomIsActive()})
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
StandaloneRoomView: StandaloneRoomView
|
||||
};
|
||||
})();
|
||||
})(navigator.mozL10n);
|
||||
|
@ -7,11 +7,12 @@
|
||||
/* global loop:true, React */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.standaloneRoomViews = (function() {
|
||||
loop.standaloneRoomViews = (function(mozL10n) {
|
||||
"use strict";
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
var sharedActions = loop.shared.actions;
|
||||
var sharedViews = loop.shared.views;
|
||||
|
||||
var StandaloneRoomView = React.createClass({
|
||||
mixins: [Backbone.Events],
|
||||
@ -23,7 +24,11 @@ loop.standaloneRoomViews = (function() {
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.activeRoomStore.getStoreState();
|
||||
var storeState = this.props.activeRoomStore.getStoreState();
|
||||
return _.extend({}, storeState, {
|
||||
// Used by the UI showcase.
|
||||
roomState: this.props.roomState || storeState.roomState
|
||||
});
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
@ -41,10 +46,57 @@ loop.standaloneRoomViews = (function() {
|
||||
this.setState(this.props.activeRoomStore.getStoreState());
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns either the required DOMNode
|
||||
*
|
||||
* @param {String} className The name of the class to get the element for.
|
||||
*/
|
||||
_getElement: function(className) {
|
||||
return this.getDOMNode().querySelector(className);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the required configuration for publishing video on the sdk.
|
||||
*/
|
||||
_getPublisherConfig: function() {
|
||||
// height set to 100%" to fix video layout on Google Chrome
|
||||
// @see https://bugzilla.mozilla.org/show_bug.cgi?id=1020445
|
||||
return {
|
||||
insertMode: "append",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
publishVideo: true,
|
||||
style: {
|
||||
audioLevelDisplayMode: "off",
|
||||
bugDisplayMode: "off",
|
||||
buttonDisplayMode: "off",
|
||||
nameDisplayMode: "off",
|
||||
videoDisabledDisplayMode: "off"
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.stopListening(this.props.activeRoomStore);
|
||||
},
|
||||
|
||||
/**
|
||||
* Watches for when we transition from READY to JOINED room state, so we can
|
||||
* request user media access.
|
||||
* @param {Object} nextProps (Unused)
|
||||
* @param {Object} nextState Next state object.
|
||||
*/
|
||||
componentWillUpdate: function(nextProps, nextState) {
|
||||
if (this.state.roomState === ROOM_STATES.READY &&
|
||||
nextState.roomState === ROOM_STATES.JOINED) {
|
||||
this.props.dispatcher.dispatch(new sharedActions.SetupStreamElements({
|
||||
publisherConfig: this._getPublisherConfig(),
|
||||
getLocalElementFunc: this._getElement.bind(this, ".local"),
|
||||
getRemoteElementFunc: this._getElement.bind(this, ".remote")
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
joinRoom: function() {
|
||||
this.props.dispatcher.dispatch(new sharedActions.JoinRoom());
|
||||
},
|
||||
@ -53,30 +105,82 @@ loop.standaloneRoomViews = (function() {
|
||||
this.props.dispatcher.dispatch(new sharedActions.LeaveRoom());
|
||||
},
|
||||
|
||||
// XXX Implement tests for this view when we do the proper views
|
||||
// - bug 1074705 and others
|
||||
render: function() {
|
||||
switch(this.state.roomState) {
|
||||
case ROOM_STATES.READY: {
|
||||
return (
|
||||
<div><button onClick={this.joinRoom}>Join</button></div>
|
||||
);
|
||||
}
|
||||
case ROOM_STATES.JOINED: {
|
||||
return (
|
||||
<div><button onClick={this.leaveRoom}>Leave</button></div>
|
||||
);
|
||||
}
|
||||
default: {
|
||||
return (
|
||||
<div>{this.state.roomState}</div>
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Toggles streaming status for a given stream type.
|
||||
*
|
||||
* @param {String} type Stream type ("audio" or "video").
|
||||
* @param {Boolean} enabled Enabled stream flag.
|
||||
*/
|
||||
publishStream: function(type, enabled) {
|
||||
this.props.dispatcher.dispatch(new sharedActions.SetMute({
|
||||
type: type,
|
||||
enabled: enabled
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if current room is active.
|
||||
*
|
||||
* @return {Boolean}
|
||||
*/
|
||||
_roomIsActive: function() {
|
||||
return this.state.roomState === ROOM_STATES.JOINED ||
|
||||
this.state.roomState === ROOM_STATES.SESSION_CONNECTED ||
|
||||
this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS;
|
||||
},
|
||||
|
||||
_renderActionButtons: function() {
|
||||
// XXX Render "Start your own" button when room is over capacity (see
|
||||
// bug 1074709)
|
||||
if (this.state.roomState === ROOM_STATES.INIT ||
|
||||
this.state.roomState === ROOM_STATES.READY) {
|
||||
return (
|
||||
<div className="room-inner-action-area">
|
||||
<button className="btn btn-join btn-info" onClick={this.joinRoom}>
|
||||
{mozL10n.get("rooms_room_join_label")}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var localStreamClasses = React.addons.classSet({
|
||||
hide: !this._roomIsActive(),
|
||||
local: true,
|
||||
"local-stream": true,
|
||||
"local-stream-audio": false
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="room-conversation-wrapper">
|
||||
{this._renderActionButtons()}
|
||||
<div className="video-layout-wrapper">
|
||||
<div className="conversation room-conversation">
|
||||
<h2 className="room-name">{this.state.roomName}</h2>
|
||||
<div className="media nested">
|
||||
<div className="video_wrapper remote_wrapper">
|
||||
<div className="video_inner remote"></div>
|
||||
</div>
|
||||
<div className={localStreamClasses}></div>
|
||||
</div>
|
||||
<sharedViews.ConversationToolbar
|
||||
video={{enabled: !this.state.videoMuted,
|
||||
visible: this._roomIsActive()}}
|
||||
audio={{enabled: !this.state.audioMuted,
|
||||
visible: this._roomIsActive()}}
|
||||
publishStream={this.publishStream}
|
||||
hangup={this.leaveRoom}
|
||||
hangupButtonLabel={mozL10n.get("rooms_leave_button_label")}
|
||||
enableHangup={this._roomIsActive()} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
StandaloneRoomView: StandaloneRoomView
|
||||
};
|
||||
})();
|
||||
})(navigator.mozL10n);
|
||||
|
@ -101,6 +101,28 @@ describe("loop.shared.views", function() {
|
||||
publishStream = sandbox.stub();
|
||||
});
|
||||
|
||||
it("should accept a hangupButtonLabel optional prop", function() {
|
||||
var comp = mountTestComponent({
|
||||
hangupButtonLabel: "foo",
|
||||
hangup: hangup,
|
||||
publishStream: publishStream
|
||||
});
|
||||
|
||||
expect(comp.getDOMNode().querySelector("button.btn-hangup").textContent)
|
||||
.eql("foo");
|
||||
});
|
||||
|
||||
it("should accept a enableHangup optional prop", function() {
|
||||
var comp = mountTestComponent({
|
||||
enableHangup: false,
|
||||
hangup: hangup,
|
||||
publishStream: publishStream
|
||||
});
|
||||
|
||||
expect(comp.getDOMNode().querySelector("button.btn-hangup").disabled)
|
||||
.eql(true);
|
||||
});
|
||||
|
||||
it("should hangup when hangup button is clicked", function() {
|
||||
var comp = mountTestComponent({
|
||||
hangup: hangup,
|
||||
|
@ -52,6 +52,7 @@
|
||||
<script src="standalone_client_test.js"></script>
|
||||
<script src="standaloneAppStore_test.js"></script>
|
||||
<script src="standaloneMozLoop_test.js"></script>
|
||||
<script src="standaloneRoomViews_test.js"></script>
|
||||
<script src="webapp_test.js"></script>
|
||||
<script src="multiplexGum_test.js"></script>
|
||||
<script>
|
||||
|
@ -0,0 +1,184 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* global loop, sinon */
|
||||
|
||||
var expect = chai.expect;
|
||||
|
||||
describe("loop.standaloneRoomViews", function() {
|
||||
"use strict";
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
var sharedActions = loop.shared.actions;
|
||||
|
||||
var sandbox, dispatcher, activeRoomStore, dispatch;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
dispatcher = new loop.Dispatcher();
|
||||
dispatch = sandbox.stub(dispatcher, "dispatch");
|
||||
activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: {},
|
||||
sdkDriver: {}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe("standaloneRoomView", function() {
|
||||
function mountTestComponent() {
|
||||
return TestUtils.renderIntoDocument(
|
||||
loop.standaloneRoomViews.StandaloneRoomView({
|
||||
dispatcher: dispatcher,
|
||||
activeRoomStore: activeRoomStore
|
||||
}));
|
||||
}
|
||||
|
||||
describe("#componentWillUpdate", function() {
|
||||
it("dispatch an `SetupStreamElements` action on room joined", function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.READY});
|
||||
var view = mountTestComponent();
|
||||
|
||||
sinon.assert.notCalled(dispatch);
|
||||
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.JOINED});
|
||||
|
||||
sinon.assert.calledOnce(dispatch);
|
||||
sinon.assert.calledWithExactly(dispatch,
|
||||
sinon.match.instanceOf(sharedActions.SetupStreamElements));
|
||||
sinon.assert.calledWithExactly(dispatch, sinon.match(function(value) {
|
||||
return value.getLocalElementFunc() ===
|
||||
view.getDOMNode().querySelector(".local");
|
||||
}));
|
||||
sinon.assert.calledWithExactly(dispatch, sinon.match(function(value) {
|
||||
return value.getRemoteElementFunc() ===
|
||||
view.getDOMNode().querySelector(".remote");
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#publishStream", function() {
|
||||
var view;
|
||||
|
||||
beforeEach(function() {
|
||||
view = mountTestComponent();
|
||||
view.setState({
|
||||
audioMuted: true,
|
||||
videoMuted: true
|
||||
});
|
||||
});
|
||||
|
||||
it("should mute local audio stream", function() {
|
||||
TestUtils.Simulate.click(
|
||||
view.getDOMNode().querySelector(".btn-mute-audio"));
|
||||
|
||||
sinon.assert.calledOnce(dispatch);
|
||||
sinon.assert.calledWithExactly(dispatch, new sharedActions.SetMute({
|
||||
type: "audio",
|
||||
enabled: true
|
||||
}));
|
||||
});
|
||||
|
||||
it("should mute local video stream", function() {
|
||||
TestUtils.Simulate.click(
|
||||
view.getDOMNode().querySelector(".btn-mute-video"));
|
||||
|
||||
sinon.assert.calledOnce(dispatch);
|
||||
sinon.assert.calledWithExactly(dispatch, new sharedActions.SetMute({
|
||||
type: "video",
|
||||
enabled: true
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#render", function() {
|
||||
var view;
|
||||
|
||||
beforeEach(function() {
|
||||
view = mountTestComponent();
|
||||
});
|
||||
|
||||
describe("Join button", function() {
|
||||
function getJoinButton(view) {
|
||||
return view.getDOMNode().querySelector(".btn-join");
|
||||
}
|
||||
|
||||
it("should render the Join button when room isn't active", function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.READY});
|
||||
|
||||
expect(getJoinButton(view)).not.eql(null);
|
||||
});
|
||||
|
||||
it("should not render the Join button when room is active",
|
||||
function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.SESSION_CONNECTED});
|
||||
|
||||
expect(getJoinButton(view)).eql(null);
|
||||
});
|
||||
|
||||
it("should join the room when clicking the Join button", function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.READY});
|
||||
|
||||
TestUtils.Simulate.click(getJoinButton(view));
|
||||
|
||||
sinon.assert.calledOnce(dispatch);
|
||||
sinon.assert.calledWithExactly(dispatch, new sharedActions.JoinRoom());
|
||||
});
|
||||
});
|
||||
|
||||
describe("Leave button", function() {
|
||||
function getLeaveButton(view) {
|
||||
return view.getDOMNode().querySelector(".btn-hangup");
|
||||
}
|
||||
|
||||
it("should disable the Leave button when the room state is READY",
|
||||
function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.READY});
|
||||
|
||||
expect(getLeaveButton(view).disabled).eql(true);
|
||||
});
|
||||
|
||||
it("should disable the Leave button when the room state is FAILED",
|
||||
function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.FAILED});
|
||||
|
||||
expect(getLeaveButton(view).disabled).eql(true);
|
||||
});
|
||||
|
||||
it("should enable the Leave button when the room state is SESSION_CONNECTED",
|
||||
function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.SESSION_CONNECTED});
|
||||
|
||||
expect(getLeaveButton(view).disabled).eql(false);
|
||||
});
|
||||
|
||||
it("should enable the Leave button when the room state is JOINED",
|
||||
function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.JOINED});
|
||||
|
||||
expect(getLeaveButton(view).disabled).eql(false);
|
||||
});
|
||||
|
||||
it("should enable the Leave button when the room state is HAS_PARTICIPANTS",
|
||||
function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.HAS_PARTICIPANTS});
|
||||
|
||||
expect(getLeaveButton(view).disabled).eql(false);
|
||||
});
|
||||
|
||||
it("should leave the room when clicking the Leave button", function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.HAS_PARTICIPANTS});
|
||||
|
||||
TestUtils.Simulate.click(getLeaveButton(view));
|
||||
|
||||
sinon.assert.calledOnce(dispatch);
|
||||
sinon.assert.calledWithExactly(dispatch, new sharedActions.LeaveRoom());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -48,6 +48,7 @@
|
||||
<script src="../content/js/conversationViews.js"></script>
|
||||
<script src="../content/js/client.js"></script>
|
||||
<script src="../content/js/webapp.js"></script>
|
||||
<script src="../content/js/standaloneRoomViews.js"></script>
|
||||
<script type="text/javascript;version=1.8" src="../content/js/contacts.js"></script>
|
||||
<script>
|
||||
if (!loop.contacts) {
|
||||
|
@ -163,6 +163,11 @@
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* Rooms edge cases */
|
||||
.standalone .room-conversation .remote_wrapper {
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* SVG icons showcase */
|
||||
|
||||
.svg-icon-entry {
|
||||
|
@ -32,6 +32,7 @@
|
||||
var StartConversationView = loop.webapp.StartConversationView;
|
||||
var FailedConversationView = loop.webapp.FailedConversationView;
|
||||
var EndedConversationView = loop.webapp.EndedConversationView;
|
||||
var StandaloneRoomView = loop.standaloneRoomViews.StandaloneRoomView;
|
||||
|
||||
// 3. Shared components
|
||||
var ConversationToolbar = loop.shared.views.ConversationToolbar;
|
||||
@ -558,6 +559,26 @@
|
||||
)
|
||||
),
|
||||
|
||||
Section({name: "StandaloneRoomView"},
|
||||
Example({summary: "Standalone room conversation (ready)"},
|
||||
React.DOM.div({className: "standalone"},
|
||||
StandaloneRoomView({
|
||||
dispatcher: dispatcher,
|
||||
activeRoomStore: activeRoomStore,
|
||||
roomState: ROOM_STATES.READY})
|
||||
)
|
||||
),
|
||||
|
||||
Example({summary: "Standalone room conversation (has-participants)"},
|
||||
React.DOM.div({className: "standalone"},
|
||||
StandaloneRoomView({
|
||||
dispatcher: dispatcher,
|
||||
activeRoomStore: activeRoomStore,
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
Section({name: "SVG icons preview"},
|
||||
Example({summary: "16x16"},
|
||||
SVGIcons(null)
|
||||
|
@ -32,6 +32,7 @@
|
||||
var StartConversationView = loop.webapp.StartConversationView;
|
||||
var FailedConversationView = loop.webapp.FailedConversationView;
|
||||
var EndedConversationView = loop.webapp.EndedConversationView;
|
||||
var StandaloneRoomView = loop.standaloneRoomViews.StandaloneRoomView;
|
||||
|
||||
// 3. Shared components
|
||||
var ConversationToolbar = loop.shared.views.ConversationToolbar;
|
||||
@ -558,6 +559,26 @@
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
<Section name="StandaloneRoomView">
|
||||
<Example summary="Standalone room conversation (ready)">
|
||||
<div className="standalone">
|
||||
<StandaloneRoomView
|
||||
dispatcher={dispatcher}
|
||||
activeRoomStore={activeRoomStore}
|
||||
roomState={ROOM_STATES.READY} />
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
<Example summary="Standalone room conversation (has-participants)">
|
||||
<div className="standalone">
|
||||
<StandaloneRoomView
|
||||
dispatcher={dispatcher}
|
||||
activeRoomStore={activeRoomStore}
|
||||
roomState={ROOM_STATES.HAS_PARTICIPANTS} />
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
<Section name="SVG icons preview">
|
||||
<Example summary="16x16">
|
||||
<SVGIcons />
|
||||
|
Loading…
Reference in New Issue
Block a user