зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1209078
- Part 2. If a user attempts to open their own room within Firefox when the room is already open, provide a message to inform the user. r=mikedeboer
This commit is contained in:
Родитель
218567ce2a
Коммит
85a8eff79d
|
@ -623,12 +623,18 @@ loop.store.ActiveRoomStore = (function() {
|
||||||
// previously. We should add better user feedback here.
|
// previously. We should add better user feedback here.
|
||||||
console.error("Firefox didn't handle room it said it could.");
|
console.error("Firefox didn't handle room it said it could.");
|
||||||
} else {
|
} else {
|
||||||
this.dispatcher.dispatch(new sharedActions.JoinedRoom({
|
if (e.detail.message.alreadyOpen) {
|
||||||
apiKey: "",
|
this.dispatcher.dispatch(new sharedActions.ConnectionFailure({
|
||||||
sessionToken: "",
|
reason: FAILURE_DETAILS.ROOM_ALREADY_OPEN
|
||||||
sessionId: "",
|
}));
|
||||||
expires: 0
|
} else {
|
||||||
}));
|
this.dispatcher.dispatch(new sharedActions.JoinedRoom({
|
||||||
|
apiKey: "",
|
||||||
|
sessionToken: "",
|
||||||
|
sessionId: "",
|
||||||
|
expires: 0
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1064,6 +1070,15 @@ loop.store.ActiveRoomStore = (function() {
|
||||||
* will skip the leave message.
|
* will skip the leave message.
|
||||||
*/
|
*/
|
||||||
_leaveRoom: function(nextState, failedJoinRequest) {
|
_leaveRoom: function(nextState, failedJoinRequest) {
|
||||||
|
if (this._storeState.standalone && this._storeState.userAgentHandlesRoom) {
|
||||||
|
// If the user agent is handling the room, all we need to do is advance
|
||||||
|
// to the next state.
|
||||||
|
this.setStoreState({
|
||||||
|
roomState: nextState
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (loop.standaloneMedia) {
|
if (loop.standaloneMedia) {
|
||||||
loop.standaloneMedia.multiplexGum.reset();
|
loop.standaloneMedia.multiplexGum.reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,7 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
|
||||||
var FAILURE_DETAILS = {
|
var FAILURE_DETAILS = {
|
||||||
MEDIA_DENIED: "reason-media-denied",
|
MEDIA_DENIED: "reason-media-denied",
|
||||||
NO_MEDIA: "reason-no-media",
|
NO_MEDIA: "reason-no-media",
|
||||||
|
ROOM_ALREADY_OPEN: "reason-room-already-open",
|
||||||
UNABLE_TO_PUBLISH_MEDIA: "unable-to-publish-media",
|
UNABLE_TO_PUBLISH_MEDIA: "unable-to-publish-media",
|
||||||
USER_UNAVAILABLE: "reason-user-unavailable",
|
USER_UNAVAILABLE: "reason-user-unavailable",
|
||||||
COULD_NOT_CONNECT: "reason-could-not-connect",
|
COULD_NOT_CONNECT: "reason-could-not-connect",
|
||||||
|
|
|
@ -184,6 +184,14 @@ html[dir="rtl"] .rooms-footer .footer-logo {
|
||||||
margin: 2rem auto;
|
margin: 2rem auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.handle-user-agent-view > .info-panel > .failure {
|
||||||
|
color: red;
|
||||||
|
font-weight: bold;
|
||||||
|
/* Add padding to match the height of the button. */
|
||||||
|
padding: 1.15rem 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.handle-user-agent-view > .info-panel > button {
|
.handle-user-agent-view > .info-panel > button {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
height: 4rem;
|
height: 4rem;
|
||||||
|
|
|
@ -125,12 +125,19 @@ loop.store.StandaloneMetricsStore = (function() {
|
||||||
* @param {sharedActions.ConnectionFailure} actionData
|
* @param {sharedActions.ConnectionFailure} actionData
|
||||||
*/
|
*/
|
||||||
connectionFailure: function(actionData) {
|
connectionFailure: function(actionData) {
|
||||||
if (actionData.reason === FAILURE_DETAILS.MEDIA_DENIED) {
|
switch(actionData.reason) {
|
||||||
this._storeEvent(METRICS_GA_CATEGORY.general, METRICS_GA_ACTIONS.failed,
|
case FAILURE_DETAILS.MEDIA_DENIED:
|
||||||
"Media denied");
|
this._storeEvent(METRICS_GA_CATEGORY.general, METRICS_GA_ACTIONS.failed,
|
||||||
} else if (actionData.reason === FAILURE_DETAILS.NO_MEDIA) {
|
"Media denied");
|
||||||
this._storeEvent(METRICS_GA_CATEGORY.general, METRICS_GA_ACTIONS.failed,
|
break;
|
||||||
"No media");
|
case FAILURE_DETAILS.NO_MEDIA:
|
||||||
|
this._storeEvent(METRICS_GA_CATEGORY.general, METRICS_GA_ACTIONS.failed,
|
||||||
|
"No media");
|
||||||
|
break;
|
||||||
|
case FAILURE_DETAILS.ROOM_ALREADY_OPEN:
|
||||||
|
this._storeEvent(METRICS_GA_CATEGORY.general, METRICS_GA_ACTIONS.failed,
|
||||||
|
"Room already open");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
this.props.dispatcher.dispatch(new sharedActions.JoinRoom());
|
this.props.dispatcher.dispatch(new sharedActions.JoinRoom());
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
_renderJoinButton: function() {
|
||||||
var buttonMessage = this.state.roomState === ROOM_STATES.JOINED ?
|
var buttonMessage = this.state.roomState === ROOM_STATES.JOINED ?
|
||||||
mozL10n.get("rooms_room_joined_own_conversation_label") :
|
mozL10n.get("rooms_room_joined_own_conversation_label") :
|
||||||
mozL10n.get("rooms_room_join_label");
|
mozL10n.get("rooms_room_join_label");
|
||||||
|
@ -86,6 +86,22 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
disabled: this.state.roomState === ROOM_STATES.JOINED
|
disabled: this.state.roomState === ROOM_STATES.JOINED
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
React.createElement("button", {
|
||||||
|
className: buttonClasses,
|
||||||
|
onClick: this.handleJoinButton},
|
||||||
|
buttonMessage
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderFailureText: function() {
|
||||||
|
return (
|
||||||
|
React.createElement("p", {className: "failure"}, mozL10n.get("rooms_already_joined") )
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
// The extra scroller div here is for providing a scroll view for shorter
|
// The extra scroller div here is for providing a scroll view for shorter
|
||||||
// screens, as the common.css specifies overflow:hidden for the body which
|
// screens, as the common.css specifies overflow:hidden for the body which
|
||||||
// we need in some places.
|
// we need in some places.
|
||||||
|
@ -96,11 +112,11 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
React.createElement("p", {className: "loop-logo-text", title: mozL10n.get("clientShortname2") }),
|
React.createElement("p", {className: "loop-logo-text", title: mozL10n.get("clientShortname2") }),
|
||||||
React.createElement("p", {className: "roomName"}, this.state.roomName),
|
React.createElement("p", {className: "roomName"}, this.state.roomName),
|
||||||
React.createElement("p", {className: "loop-logo"}),
|
React.createElement("p", {className: "loop-logo"}),
|
||||||
React.createElement("button", {
|
|
||||||
className: buttonClasses,
|
this.state.failureReason ?
|
||||||
onClick: this.handleJoinButton},
|
this._renderFailureText() :
|
||||||
buttonMessage
|
this._renderJoinButton()
|
||||||
)
|
|
||||||
),
|
),
|
||||||
React.createElement(ToSView, {
|
React.createElement(ToSView, {
|
||||||
dispatcher: this.props.dispatcher}),
|
dispatcher: this.props.dispatcher}),
|
||||||
|
|
|
@ -75,7 +75,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
this.props.dispatcher.dispatch(new sharedActions.JoinRoom());
|
this.props.dispatcher.dispatch(new sharedActions.JoinRoom());
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
_renderJoinButton: function() {
|
||||||
var buttonMessage = this.state.roomState === ROOM_STATES.JOINED ?
|
var buttonMessage = this.state.roomState === ROOM_STATES.JOINED ?
|
||||||
mozL10n.get("rooms_room_joined_own_conversation_label") :
|
mozL10n.get("rooms_room_joined_own_conversation_label") :
|
||||||
mozL10n.get("rooms_room_join_label");
|
mozL10n.get("rooms_room_join_label");
|
||||||
|
@ -86,6 +86,22 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
disabled: this.state.roomState === ROOM_STATES.JOINED
|
disabled: this.state.roomState === ROOM_STATES.JOINED
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className={buttonClasses}
|
||||||
|
onClick={this.handleJoinButton}>
|
||||||
|
{buttonMessage}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderFailureText: function() {
|
||||||
|
return (
|
||||||
|
<p className="failure">{ mozL10n.get("rooms_already_joined") }</p>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
// The extra scroller div here is for providing a scroll view for shorter
|
// The extra scroller div here is for providing a scroll view for shorter
|
||||||
// screens, as the common.css specifies overflow:hidden for the body which
|
// screens, as the common.css specifies overflow:hidden for the body which
|
||||||
// we need in some places.
|
// we need in some places.
|
||||||
|
@ -96,11 +112,11 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
<p className="loop-logo-text" title={ mozL10n.get("clientShortname2") }></p>
|
<p className="loop-logo-text" title={ mozL10n.get("clientShortname2") }></p>
|
||||||
<p className="roomName">{ this.state.roomName }</p>
|
<p className="roomName">{ this.state.roomName }</p>
|
||||||
<p className="loop-logo" />
|
<p className="loop-logo" />
|
||||||
<button
|
{
|
||||||
className={buttonClasses}
|
this.state.failureReason ?
|
||||||
onClick={this.handleJoinButton}>
|
this._renderFailureText() :
|
||||||
{buttonMessage}
|
this._renderJoinButton()
|
||||||
</button>
|
}
|
||||||
</div>
|
</div>
|
||||||
<ToSView
|
<ToSView
|
||||||
dispatcher={this.props.dispatcher} />
|
dispatcher={this.props.dispatcher} />
|
||||||
|
|
|
@ -69,6 +69,7 @@ rooms_room_full_call_to_action_label=Learn more about {{clientShortname}} »
|
||||||
rooms_room_joined_label=Someone has joined the conversation!
|
rooms_room_joined_label=Someone has joined the conversation!
|
||||||
rooms_room_join_label=Join the conversation
|
rooms_room_join_label=Join the conversation
|
||||||
rooms_room_joined_own_conversation_label=Enjoy your conversation
|
rooms_room_joined_own_conversation_label=Enjoy your conversation
|
||||||
|
rooms_already_joined=You're already in this conversation.
|
||||||
rooms_display_name_guest=Guest
|
rooms_display_name_guest=Guest
|
||||||
rooms_unavailable_notification_message=Sorry, you cannot join this conversation. The link may be expired or invalid.
|
rooms_unavailable_notification_message=Sorry, you cannot join this conversation. The link may be expired or invalid.
|
||||||
rooms_media_denied_message=We could not get access to your microphone or camera. Please reload the page to try again.
|
rooms_media_denied_message=We could not get access to your microphone or camera. Please reload the page to try again.
|
||||||
|
|
|
@ -873,7 +873,7 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Firefox Handles Room", function() {
|
describe("User Agent Handles Room", function() {
|
||||||
var channelListener;
|
var channelListener;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
@ -951,7 +951,8 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||||
detail: {
|
detail: {
|
||||||
id: "loop-link-clicker",
|
id: "loop-link-clicker",
|
||||||
message: {
|
message: {
|
||||||
response: true
|
response: true,
|
||||||
|
alreadyOpen: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -965,6 +966,28 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||||
expires: 0
|
expires: 0
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should dispatch a ConnectionFailure action if the room was already opened", function() {
|
||||||
|
// Start the join.
|
||||||
|
store.joinRoom();
|
||||||
|
|
||||||
|
// Pretend Firefox calls back.
|
||||||
|
channelListener({
|
||||||
|
detail: {
|
||||||
|
id: "loop-link-clicker",
|
||||||
|
message: {
|
||||||
|
response: true,
|
||||||
|
alreadyOpen: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sinon.assert.called(dispatcher.dispatch);
|
||||||
|
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||||
|
new sharedActions.ConnectionFailure({
|
||||||
|
reason: FAILURE_DETAILS.ROOM_ALREADY_OPEN
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1257,6 +1280,29 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||||
|
|
||||||
expect(store.getStoreState().roomState).eql(ROOM_STATES.FAILED);
|
expect(store.getStoreState().roomState).eql(ROOM_STATES.FAILED);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should set the state to `FAILED` if the user agent is handling the room", function() {
|
||||||
|
store.setStoreState({
|
||||||
|
standalone: true,
|
||||||
|
userAgentHandlesRoom: true
|
||||||
|
});
|
||||||
|
|
||||||
|
store.connectionFailure(connectionFailureAction);
|
||||||
|
|
||||||
|
expect(store.getStoreState().roomState).eql(ROOM_STATES.FAILED);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not do any other cleanup if the user agent is handling the room", function() {
|
||||||
|
store.setStoreState({
|
||||||
|
standalone: true,
|
||||||
|
userAgentHandlesRoom: true
|
||||||
|
});
|
||||||
|
|
||||||
|
store.connectionFailure(connectionFailureAction);
|
||||||
|
|
||||||
|
sinon.assert.notCalled(fakeMultiplexGum.reset);
|
||||||
|
sinon.assert.notCalled(fakeSdkDriver.disconnectSession);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#setMute", function() {
|
describe("#setMute", function() {
|
||||||
|
|
|
@ -77,6 +77,17 @@ describe("loop.store.StandaloneMetricsStore", function() {
|
||||||
"No media");
|
"No media");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should log an event on connection failure if the room was already open", function() {
|
||||||
|
store.connectionFailure(new sharedActions.ConnectionFailure({
|
||||||
|
reason: FAILURE_DETAILS.ROOM_ALREADY_OPEN
|
||||||
|
}));
|
||||||
|
|
||||||
|
sinon.assert.calledOnce(window.ga);
|
||||||
|
sinon.assert.calledWithExactly(window.ga,
|
||||||
|
"send", "event", METRICS_GA_CATEGORY.general, METRICS_GA_ACTIONS.failed,
|
||||||
|
"Room already open");
|
||||||
|
});
|
||||||
|
|
||||||
it("should log an event on GotMediaPermission", function() {
|
it("should log an event on GotMediaPermission", function() {
|
||||||
store.gotMediaPermission();
|
store.gotMediaPermission();
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,28 @@ describe("loop.standaloneRoomViews", function() {
|
||||||
|
|
||||||
expect(button.classList.contains("disabled")).eql(true);
|
expect(button.classList.contains("disabled")).eql(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should not display a join button if there is a failure reason", function() {
|
||||||
|
activeRoomStore.setStoreState({
|
||||||
|
failureReason: FAILURE_DETAILS.ROOM_ALREADY_OPEN
|
||||||
|
});
|
||||||
|
|
||||||
|
view = mountTestComponent();
|
||||||
|
var button = view.getDOMNode().querySelector(".info-panel > button");
|
||||||
|
|
||||||
|
expect(button).eql(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should display a room already joined message if opening failed", function() {
|
||||||
|
activeRoomStore.setStoreState({
|
||||||
|
failureReason: FAILURE_DETAILS.ROOM_ALREADY_OPEN
|
||||||
|
});
|
||||||
|
|
||||||
|
view = mountTestComponent();
|
||||||
|
var text = view.getDOMNode().querySelector(".failure");
|
||||||
|
|
||||||
|
expect(text.textContent).eql("rooms_already_joined");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("StandaloneRoomHeader", function() {
|
describe("StandaloneRoomHeader", function() {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче