Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
07cd3d8b2e
10 changed files with 347 additions and 214 deletions
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
|
Copyright 2017 New Vector Ltd
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -58,6 +59,7 @@ import sdk from './index';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import Matrix from 'matrix-js-sdk';
|
import Matrix from 'matrix-js-sdk';
|
||||||
import dis from './dispatcher';
|
import dis from './dispatcher';
|
||||||
|
import { showUnknownDeviceDialogForCalls } from './cryptodevices';
|
||||||
|
|
||||||
global.mxCalls = {
|
global.mxCalls = {
|
||||||
//room_id: MatrixCall
|
//room_id: MatrixCall
|
||||||
|
@ -97,19 +99,54 @@ function pause(audioId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _reAttemptCall(call) {
|
||||||
|
if (call.direction === 'outbound') {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'place_call',
|
||||||
|
room_id: call.roomId,
|
||||||
|
type: call.type,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
call.answer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function _setCallListeners(call) {
|
function _setCallListeners(call) {
|
||||||
call.on("error", function(err) {
|
call.on("error", function(err) {
|
||||||
console.error("Call error: %s", err);
|
console.error("Call error: %s", err);
|
||||||
console.error(err.stack);
|
console.error(err.stack);
|
||||||
call.hangup();
|
if (err.code === 'unknown_devices') {
|
||||||
_setCallState(undefined, call.roomId, "ended");
|
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||||
});
|
|
||||||
call.on('send_event_error', function(err) {
|
Modal.createTrackedDialog('Call Failed', '', QuestionDialog, {
|
||||||
if (err.name === "UnknownDeviceError") {
|
title: _t('Call Failed'),
|
||||||
dis.dispatch({
|
description: _t(
|
||||||
action: 'unknown_device_error',
|
"There are unknown devices in this room: "+
|
||||||
err: err,
|
"if you proceed without verifying them, it will be "+
|
||||||
room: MatrixClientPeg.get().getRoom(call.roomId),
|
"possible for someone to eavesdrop on your call."
|
||||||
|
),
|
||||||
|
button: _t('Review Devices'),
|
||||||
|
onFinished: function(confirmed) {
|
||||||
|
if (confirmed) {
|
||||||
|
const room = MatrixClientPeg.get().getRoom(call.roomId);
|
||||||
|
showUnknownDeviceDialogForCalls(
|
||||||
|
MatrixClientPeg.get(),
|
||||||
|
room,
|
||||||
|
() => {
|
||||||
|
_reAttemptCall(call);
|
||||||
|
},
|
||||||
|
call.direction === 'outbound' ? _t("Call Anyway") : _t("Answer Anyway"),
|
||||||
|
call.direction === 'outbound' ? _t("Call") : _t("Answer"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
|
||||||
|
Modal.createTrackedDialog('Call Failed', '', ErrorDialog, {
|
||||||
|
title: _t('Call Failed'),
|
||||||
|
description: err.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -179,7 +216,6 @@ function _setCallState(call, roomId, status) {
|
||||||
function _onAction(payload) {
|
function _onAction(payload) {
|
||||||
function placeCall(newCall) {
|
function placeCall(newCall) {
|
||||||
_setCallListeners(newCall);
|
_setCallListeners(newCall);
|
||||||
_setCallState(newCall, newCall.roomId, "ringback");
|
|
||||||
if (payload.type === 'voice') {
|
if (payload.type === 'voice') {
|
||||||
newCall.placeVoiceCall();
|
newCall.placeVoiceCall();
|
||||||
} else if (payload.type === 'video') {
|
} else if (payload.type === 'video') {
|
||||||
|
|
|
@ -44,13 +44,6 @@ module.exports = {
|
||||||
// XXX: temporary logging to try to diagnose
|
// XXX: temporary logging to try to diagnose
|
||||||
// https://github.com/vector-im/riot-web/issues/3148
|
// https://github.com/vector-im/riot-web/issues/3148
|
||||||
console.log('Resend got send failure: ' + err.name + '('+err+')');
|
console.log('Resend got send failure: ' + err.name + '('+err+')');
|
||||||
if (err.name === "UnknownDeviceError") {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'unknown_device_error',
|
|
||||||
err: err,
|
|
||||||
room: room,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'message_send_failed',
|
action: 'message_send_failed',
|
||||||
|
@ -60,9 +53,5 @@ module.exports = {
|
||||||
},
|
},
|
||||||
removeFromQueue: function(event) {
|
removeFromQueue: function(event) {
|
||||||
MatrixClientPeg.get().cancelPendingEvent(event);
|
MatrixClientPeg.get().cancelPendingEvent(event);
|
||||||
dis.dispatch({
|
|
||||||
action: 'message_send_cancelled',
|
|
||||||
event: event,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 Vector Creations 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import dis from './dispatcher';
|
|
||||||
import sdk from './index';
|
|
||||||
import Modal from './Modal';
|
|
||||||
|
|
||||||
let isDialogOpen = false;
|
|
||||||
|
|
||||||
const onAction = function(payload) {
|
|
||||||
if (payload.action === 'unknown_device_error' && !isDialogOpen) {
|
|
||||||
const UnknownDeviceDialog = sdk.getComponent('dialogs.UnknownDeviceDialog');
|
|
||||||
isDialogOpen = true;
|
|
||||||
Modal.createTrackedDialog('Unknown Device Error', '', UnknownDeviceDialog, {
|
|
||||||
devices: payload.err.devices,
|
|
||||||
room: payload.room,
|
|
||||||
onFinished: (r) => {
|
|
||||||
isDialogOpen = false;
|
|
||||||
// XXX: temporary logging to try to diagnose
|
|
||||||
// https://github.com/vector-im/riot-web/issues/3148
|
|
||||||
console.log('UnknownDeviceDialog closed with '+r);
|
|
||||||
},
|
|
||||||
}, 'mx_Dialog_unknownDevice');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let ref = null;
|
|
||||||
|
|
||||||
export function startListening() {
|
|
||||||
ref = dis.register(onAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function stopListening() {
|
|
||||||
if (ref) {
|
|
||||||
dis.unregister(ref);
|
|
||||||
ref = null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -40,7 +40,6 @@ require('../../stores/LifecycleStore');
|
||||||
import PageTypes from '../../PageTypes';
|
import PageTypes from '../../PageTypes';
|
||||||
|
|
||||||
import createRoom from "../../createRoom";
|
import createRoom from "../../createRoom";
|
||||||
import * as UDEHandler from '../../UnknownDeviceErrorHandler';
|
|
||||||
import KeyRequestHandler from '../../KeyRequestHandler';
|
import KeyRequestHandler from '../../KeyRequestHandler';
|
||||||
import { _t, getCurrentLanguage } from '../../languageHandler';
|
import { _t, getCurrentLanguage } from '../../languageHandler';
|
||||||
import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
|
import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
|
||||||
|
@ -295,7 +294,6 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
UDEHandler.startListening();
|
|
||||||
|
|
||||||
this.focusComposer = false;
|
this.focusComposer = false;
|
||||||
|
|
||||||
|
@ -361,7 +359,6 @@ module.exports = React.createClass({
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
Lifecycle.stopMatrixClient();
|
Lifecycle.stopMatrixClient();
|
||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
UDEHandler.stopListening();
|
|
||||||
window.removeEventListener("focus", this.onFocus);
|
window.removeEventListener("focus", this.onFocus);
|
||||||
window.removeEventListener('resize', this.handleResize);
|
window.removeEventListener('resize', this.handleResize);
|
||||||
},
|
},
|
||||||
|
@ -1398,13 +1395,6 @@ module.exports = React.createClass({
|
||||||
cli.sendEvent(roomId, event.getType(), event.getContent()).done(() => {
|
cli.sendEvent(roomId, event.getType(), event.getContent()).done(() => {
|
||||||
dis.dispatch({action: 'message_sent'});
|
dis.dispatch({action: 'message_sent'});
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
if (err.name === 'UnknownDeviceError') {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'unknown_device_error',
|
|
||||||
err: err,
|
|
||||||
room: cli.getRoom(roomId),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
dis.dispatch({action: 'message_send_failed'});
|
dis.dispatch({action: 'message_send_failed'});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
|
Copyright 2017 New Vector Ltd
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -15,16 +16,26 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Matrix from 'matrix-js-sdk';
|
||||||
import { _t } from '../../languageHandler';
|
import { _t } from '../../languageHandler';
|
||||||
import sdk from '../../index';
|
import sdk from '../../index';
|
||||||
import WhoIsTyping from '../../WhoIsTyping';
|
import WhoIsTyping from '../../WhoIsTyping';
|
||||||
import MatrixClientPeg from '../../MatrixClientPeg';
|
import MatrixClientPeg from '../../MatrixClientPeg';
|
||||||
import MemberAvatar from '../views/avatars/MemberAvatar';
|
import MemberAvatar from '../views/avatars/MemberAvatar';
|
||||||
|
import Resend from '../../Resend';
|
||||||
|
import { showUnknownDeviceDialogForMessages } from '../../cryptodevices';
|
||||||
|
|
||||||
const STATUS_BAR_HIDDEN = 0;
|
const STATUS_BAR_HIDDEN = 0;
|
||||||
const STATUS_BAR_EXPANDED = 1;
|
const STATUS_BAR_EXPANDED = 1;
|
||||||
const STATUS_BAR_EXPANDED_LARGE = 2;
|
const STATUS_BAR_EXPANDED_LARGE = 2;
|
||||||
|
|
||||||
|
function getUnsentMessages(room) {
|
||||||
|
if (!room) { return []; }
|
||||||
|
return room.getPendingEvents().filter(function(ev) {
|
||||||
|
return ev.status === Matrix.EventStatus.NOT_SENT;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'RoomStatusBar',
|
displayName: 'RoomStatusBar',
|
||||||
|
|
||||||
|
@ -35,9 +46,6 @@ module.exports = React.createClass({
|
||||||
// the number of messages which have arrived since we've been scrolled up
|
// the number of messages which have arrived since we've been scrolled up
|
||||||
numUnreadMessages: React.PropTypes.number,
|
numUnreadMessages: React.PropTypes.number,
|
||||||
|
|
||||||
// string to display when there are messages in the room which had errors on send
|
|
||||||
unsentMessageError: React.PropTypes.string,
|
|
||||||
|
|
||||||
// this is true if we are fully scrolled-down, and are looking at
|
// this is true if we are fully scrolled-down, and are looking at
|
||||||
// the end of the live timeline.
|
// the end of the live timeline.
|
||||||
atEndOfLiveTimeline: React.PropTypes.bool,
|
atEndOfLiveTimeline: React.PropTypes.bool,
|
||||||
|
@ -98,12 +106,14 @@ module.exports = React.createClass({
|
||||||
return {
|
return {
|
||||||
syncState: MatrixClientPeg.get().getSyncState(),
|
syncState: MatrixClientPeg.get().getSyncState(),
|
||||||
usersTyping: WhoIsTyping.usersTypingApartFromMe(this.props.room),
|
usersTyping: WhoIsTyping.usersTypingApartFromMe(this.props.room),
|
||||||
|
unsentMessages: getUnsentMessages(this.props.room),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
MatrixClientPeg.get().on("sync", this.onSyncStateChange);
|
MatrixClientPeg.get().on("sync", this.onSyncStateChange);
|
||||||
MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping);
|
MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping);
|
||||||
|
MatrixClientPeg.get().on("Room.localEchoUpdated", this._onRoomLocalEchoUpdated);
|
||||||
|
|
||||||
this._checkSize();
|
this._checkSize();
|
||||||
},
|
},
|
||||||
|
@ -118,6 +128,7 @@ module.exports = React.createClass({
|
||||||
if (client) {
|
if (client) {
|
||||||
client.removeListener("sync", this.onSyncStateChange);
|
client.removeListener("sync", this.onSyncStateChange);
|
||||||
client.removeListener("RoomMember.typing", this.onRoomMemberTyping);
|
client.removeListener("RoomMember.typing", this.onRoomMemberTyping);
|
||||||
|
client.removeListener("Room.localEchoUpdated", this._onRoomLocalEchoUpdated);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -136,6 +147,26 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onResendAllClick: function() {
|
||||||
|
Resend.resendUnsentEvents(this.props.room);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onCancelAllClick: function() {
|
||||||
|
Resend.cancelUnsentEvents(this.props.room);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onShowDevicesClick: function() {
|
||||||
|
showUnknownDeviceDialogForMessages(MatrixClientPeg.get(), this.props.room);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onRoomLocalEchoUpdated: function(event, room, oldEventId, oldStatus) {
|
||||||
|
if (room.roomId !== this.props.room.roomId) return;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
unsentMessages: getUnsentMessages(this.props.room),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// Check whether current size is greater than 0, if yes call props.onVisible
|
// Check whether current size is greater than 0, if yes call props.onVisible
|
||||||
_checkSize: function() {
|
_checkSize: function() {
|
||||||
if (this.props.onVisible && this._getSize()) {
|
if (this.props.onVisible && this._getSize()) {
|
||||||
|
@ -155,7 +186,7 @@ module.exports = React.createClass({
|
||||||
this.props.sentMessageAndIsAlone
|
this.props.sentMessageAndIsAlone
|
||||||
) {
|
) {
|
||||||
return STATUS_BAR_EXPANDED;
|
return STATUS_BAR_EXPANDED;
|
||||||
} else if (this.props.unsentMessageError) {
|
} else if (this.state.unsentMessages.length > 0) {
|
||||||
return STATUS_BAR_EXPANDED_LARGE;
|
return STATUS_BAR_EXPANDED_LARGE;
|
||||||
}
|
}
|
||||||
return STATUS_BAR_HIDDEN;
|
return STATUS_BAR_HIDDEN;
|
||||||
|
@ -241,6 +272,61 @@ module.exports = React.createClass({
|
||||||
return avatars;
|
return avatars;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getUnsentMessageContent: function() {
|
||||||
|
const unsentMessages = this.state.unsentMessages;
|
||||||
|
if (!unsentMessages.length) return null;
|
||||||
|
|
||||||
|
let title;
|
||||||
|
let content;
|
||||||
|
|
||||||
|
const hasUDE = unsentMessages.some((m) => {
|
||||||
|
return m.error && m.error.name === "UnknownDeviceError";
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasUDE) {
|
||||||
|
title = _t("Message not sent due to unknown devices being present");
|
||||||
|
content = _t(
|
||||||
|
"<showDevicesText>Show devices</showDevicesText> or <cancelText>cancel all</cancelText>.",
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
'showDevicesText': (sub) => <a className="mx_RoomStatusBar_resend_link" key="resend" onClick={this._onShowDevicesClick}>{ sub }</a>,
|
||||||
|
'cancelText': (sub) => <a className="mx_RoomStatusBar_resend_link" key="cancel" onClick={this._onCancelAllClick}>{ sub }</a>,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
unsentMessages.length === 1 &&
|
||||||
|
unsentMessages[0].error &&
|
||||||
|
unsentMessages[0].error.data &&
|
||||||
|
unsentMessages[0].error.data.error
|
||||||
|
) {
|
||||||
|
title = unsentMessages[0].error.data.error;
|
||||||
|
} else {
|
||||||
|
title = _t("Some of your messages have not been sent.");
|
||||||
|
}
|
||||||
|
content = _t("<resendText>Resend all</resendText> or <cancelText>cancel all</cancelText> now. " +
|
||||||
|
"You can also select individual messages to resend or cancel.",
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
'resendText': (sub) =>
|
||||||
|
<a className="mx_RoomStatusBar_resend_link" key="resend" onClick={this._onResendAllClick}>{ sub }</a>,
|
||||||
|
'cancelText': (sub) =>
|
||||||
|
<a className="mx_RoomStatusBar_resend_link" key="cancel" onClick={this._onCancelAllClick}>{ sub }</a>,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className="mx_RoomStatusBar_connectionLostBar">
|
||||||
|
<img src="img/warning.svg" width="24" height="23" title={_t("Warning")} alt={_t("Warning")} />
|
||||||
|
<div className="mx_RoomStatusBar_connectionLostBar_title">
|
||||||
|
{ title }
|
||||||
|
</div>
|
||||||
|
<div className="mx_RoomStatusBar_connectionLostBar_desc">
|
||||||
|
{ content }
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
},
|
||||||
|
|
||||||
// return suitable content for the main (text) part of the status bar.
|
// return suitable content for the main (text) part of the status bar.
|
||||||
_getContent: function() {
|
_getContent: function() {
|
||||||
const EmojiText = sdk.getComponent('elements.EmojiText');
|
const EmojiText = sdk.getComponent('elements.EmojiText');
|
||||||
|
@ -263,28 +349,8 @@ module.exports = React.createClass({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.unsentMessageError) {
|
if (this.state.unsentMessages.length > 0) {
|
||||||
return (
|
return this._getUnsentMessageContent();
|
||||||
<div className="mx_RoomStatusBar_connectionLostBar">
|
|
||||||
<img src="img/warning.svg" width="24" height="23" title="/!\ " alt="/!\ " />
|
|
||||||
<div className="mx_RoomStatusBar_connectionLostBar_title">
|
|
||||||
{ this.props.unsentMessageError }
|
|
||||||
</div>
|
|
||||||
<div className="mx_RoomStatusBar_connectionLostBar_desc">
|
|
||||||
{
|
|
||||||
_t("<resendText>Resend all</resendText> or <cancelText>cancel all</cancelText> now. " +
|
|
||||||
"You can also select individual messages to resend or cancel.",
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
'resendText': (sub) =>
|
|
||||||
<a className="mx_RoomStatusBar_resend_link" key="resend" onClick={this.props.onResendAllClick}>{ sub }</a>,
|
|
||||||
'cancelText': (sub) =>
|
|
||||||
<a className="mx_RoomStatusBar_resend_link" key="cancel" onClick={this.props.onCancelAllClick}>{ sub }</a>,
|
|
||||||
},
|
|
||||||
) }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unread count trumps who is typing since the unread count is only
|
// unread count trumps who is typing since the unread count is only
|
||||||
|
@ -342,7 +408,6 @@ module.exports = React.createClass({
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
const content = this._getContent();
|
const content = this._getContent();
|
||||||
const indicator = this._getIndicator(this.state.usersTyping.length > 0);
|
const indicator = this._getIndicator(this.state.usersTyping.length > 0);
|
||||||
|
|
|
@ -26,7 +26,6 @@ const React = require("react");
|
||||||
const ReactDOM = require("react-dom");
|
const ReactDOM = require("react-dom");
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
const classNames = require("classnames");
|
const classNames = require("classnames");
|
||||||
const Matrix = require("matrix-js-sdk");
|
|
||||||
import { _t } from '../../languageHandler';
|
import { _t } from '../../languageHandler';
|
||||||
|
|
||||||
const MatrixClientPeg = require("../../MatrixClientPeg");
|
const MatrixClientPeg = require("../../MatrixClientPeg");
|
||||||
|
@ -34,7 +33,6 @@ const ContentMessages = require("../../ContentMessages");
|
||||||
const Modal = require("../../Modal");
|
const Modal = require("../../Modal");
|
||||||
const sdk = require('../../index');
|
const sdk = require('../../index');
|
||||||
const CallHandler = require('../../CallHandler');
|
const CallHandler = require('../../CallHandler');
|
||||||
const Resend = require("../../Resend");
|
|
||||||
const dis = require("../../dispatcher");
|
const dis = require("../../dispatcher");
|
||||||
const Tinter = require("../../Tinter");
|
const Tinter = require("../../Tinter");
|
||||||
const rate_limited_func = require('../../ratelimitedfunc');
|
const rate_limited_func = require('../../ratelimitedfunc');
|
||||||
|
@ -110,7 +108,6 @@ module.exports = React.createClass({
|
||||||
draggingFile: false,
|
draggingFile: false,
|
||||||
searching: false,
|
searching: false,
|
||||||
searchResults: null,
|
searchResults: null,
|
||||||
unsentMessageError: '',
|
|
||||||
callState: null,
|
callState: null,
|
||||||
guestsCanJoin: false,
|
guestsCanJoin: false,
|
||||||
canPeek: false,
|
canPeek: false,
|
||||||
|
@ -202,7 +199,6 @@ module.exports = React.createClass({
|
||||||
if (initial) {
|
if (initial) {
|
||||||
newState.room = MatrixClientPeg.get().getRoom(newState.roomId);
|
newState.room = MatrixClientPeg.get().getRoom(newState.roomId);
|
||||||
if (newState.room) {
|
if (newState.room) {
|
||||||
newState.unsentMessageError = this._getUnsentMessageError(newState.room);
|
|
||||||
newState.showApps = this._shouldShowApps(newState.room);
|
newState.showApps = this._shouldShowApps(newState.room);
|
||||||
this._onRoomLoaded(newState.room);
|
this._onRoomLoaded(newState.room);
|
||||||
}
|
}
|
||||||
|
@ -462,11 +458,6 @@ module.exports = React.createClass({
|
||||||
case 'message_send_failed':
|
case 'message_send_failed':
|
||||||
case 'message_sent':
|
case 'message_sent':
|
||||||
this._checkIfAlone(this.state.room);
|
this._checkIfAlone(this.state.room);
|
||||||
// no break; to intentionally fall through
|
|
||||||
case 'message_send_cancelled':
|
|
||||||
this.setState({
|
|
||||||
unsentMessageError: this._getUnsentMessageError(this.state.room),
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case 'notifier_enabled':
|
case 'notifier_enabled':
|
||||||
case 'upload_failed':
|
case 'upload_failed':
|
||||||
|
@ -711,35 +702,6 @@ module.exports = React.createClass({
|
||||||
this.setState({isAlone: joinedMembers.length === 1});
|
this.setState({isAlone: joinedMembers.length === 1});
|
||||||
},
|
},
|
||||||
|
|
||||||
_getUnsentMessageError: function(room) {
|
|
||||||
const unsentMessages = this._getUnsentMessages(room);
|
|
||||||
if (!unsentMessages.length) return "";
|
|
||||||
|
|
||||||
if (
|
|
||||||
unsentMessages.length === 1 &&
|
|
||||||
unsentMessages[0].error &&
|
|
||||||
unsentMessages[0].error.data &&
|
|
||||||
unsentMessages[0].error.data.error &&
|
|
||||||
unsentMessages[0].error.name !== "UnknownDeviceError"
|
|
||||||
) {
|
|
||||||
return unsentMessages[0].error.data.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const event of unsentMessages) {
|
|
||||||
if (!event.error || event.error.name !== "UnknownDeviceError") {
|
|
||||||
return _t("Some of your messages have not been sent.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _t("Message not sent due to unknown devices being present");
|
|
||||||
},
|
|
||||||
|
|
||||||
_getUnsentMessages: function(room) {
|
|
||||||
if (!room) { return []; }
|
|
||||||
return room.getPendingEvents().filter(function(ev) {
|
|
||||||
return ev.status === Matrix.EventStatus.NOT_SENT;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateConfCallNotification: function() {
|
_updateConfCallNotification: function() {
|
||||||
const room = this.state.room;
|
const room = this.state.room;
|
||||||
if (!room || !this.props.ConferenceHandler) {
|
if (!room || !this.props.ConferenceHandler) {
|
||||||
|
@ -784,14 +746,6 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onResendAllClick: function() {
|
|
||||||
Resend.resendUnsentEvents(this.state.room);
|
|
||||||
},
|
|
||||||
|
|
||||||
onCancelAllClick: function() {
|
|
||||||
Resend.cancelUnsentEvents(this.state.room);
|
|
||||||
},
|
|
||||||
|
|
||||||
onInviteButtonClick: function() {
|
onInviteButtonClick: function() {
|
||||||
// call AddressPickerDialog
|
// call AddressPickerDialog
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
|
@ -935,11 +889,7 @@ module.exports = React.createClass({
|
||||||
file, this.state.room.roomId, MatrixClientPeg.get(),
|
file, this.state.room.roomId, MatrixClientPeg.get(),
|
||||||
).done(undefined, (error) => {
|
).done(undefined, (error) => {
|
||||||
if (error.name === "UnknownDeviceError") {
|
if (error.name === "UnknownDeviceError") {
|
||||||
dis.dispatch({
|
// Let the staus bar handle this
|
||||||
action: 'unknown_device_error',
|
|
||||||
err: error,
|
|
||||||
room: this.state.room,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
@ -1571,12 +1521,9 @@ module.exports = React.createClass({
|
||||||
statusBar = <RoomStatusBar
|
statusBar = <RoomStatusBar
|
||||||
room={this.state.room}
|
room={this.state.room}
|
||||||
numUnreadMessages={this.state.numUnreadMessages}
|
numUnreadMessages={this.state.numUnreadMessages}
|
||||||
unsentMessageError={this.state.unsentMessageError}
|
|
||||||
atEndOfLiveTimeline={this.state.atEndOfLiveTimeline}
|
atEndOfLiveTimeline={this.state.atEndOfLiveTimeline}
|
||||||
sentMessageAndIsAlone={this.state.isAlone}
|
sentMessageAndIsAlone={this.state.isAlone}
|
||||||
hasActiveCall={inCall}
|
hasActiveCall={inCall}
|
||||||
onResendAllClick={this.onResendAllClick}
|
|
||||||
onCancelAllClick={this.onCancelAllClick}
|
|
||||||
onInviteClick={this.onInviteButtonClick}
|
onInviteClick={this.onInviteButtonClick}
|
||||||
onStopWarningClick={this.onStopAloneWarningClick}
|
onStopWarningClick={this.onStopAloneWarningClick}
|
||||||
onScrollToBottomClick={this.jumpToLiveTimeline}
|
onScrollToBottomClick={this.jumpToLiveTimeline}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2017 Vector Creations Ltd
|
Copyright 2017 Vector Creations Ltd
|
||||||
|
Copyright 2017 New Vector Ltd
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -15,6 +16,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
import GeminiScrollbar from 'react-gemini-scrollbar';
|
import GeminiScrollbar from 'react-gemini-scrollbar';
|
||||||
|
@ -22,6 +24,14 @@ import Resend from '../../../Resend';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
|
|
||||||
|
function markAllDevicesKnown(devices) {
|
||||||
|
Object.keys(devices).forEach((userId) => {
|
||||||
|
Object.keys(devices[userId]).map((deviceId) => {
|
||||||
|
MatrixClientPeg.get().setDeviceKnown(userId, deviceId, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function DeviceListEntry(props) {
|
function DeviceListEntry(props) {
|
||||||
const {userId, device} = props;
|
const {userId, device} = props;
|
||||||
|
|
||||||
|
@ -38,10 +48,10 @@ function DeviceListEntry(props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceListEntry.propTypes = {
|
DeviceListEntry.propTypes = {
|
||||||
userId: React.PropTypes.string.isRequired,
|
userId: PropTypes.string.isRequired,
|
||||||
|
|
||||||
// deviceinfo
|
// deviceinfo
|
||||||
device: React.PropTypes.object.isRequired,
|
device: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,10 +71,10 @@ function UserUnknownDeviceList(props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
UserUnknownDeviceList.propTypes = {
|
UserUnknownDeviceList.propTypes = {
|
||||||
userId: React.PropTypes.string.isRequired,
|
userId: PropTypes.string.isRequired,
|
||||||
|
|
||||||
// map from deviceid -> deviceinfo
|
// map from deviceid -> deviceinfo
|
||||||
userDevices: React.PropTypes.object.isRequired,
|
userDevices: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,7 +93,7 @@ function UnknownDeviceList(props) {
|
||||||
|
|
||||||
UnknownDeviceList.propTypes = {
|
UnknownDeviceList.propTypes = {
|
||||||
// map from userid -> deviceid -> deviceinfo
|
// map from userid -> deviceid -> deviceinfo
|
||||||
devices: React.PropTypes.object.isRequired,
|
devices: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,28 +101,63 @@ export default React.createClass({
|
||||||
displayName: 'UnknownDeviceDialog',
|
displayName: 'UnknownDeviceDialog',
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
room: React.PropTypes.object.isRequired,
|
room: PropTypes.object.isRequired,
|
||||||
|
|
||||||
// map from userid -> deviceid -> deviceinfo
|
// map from userid -> deviceid -> deviceinfo or null if devices are not yet loaded
|
||||||
devices: React.PropTypes.object.isRequired,
|
devices: PropTypes.object,
|
||||||
onFinished: React.PropTypes.func.isRequired,
|
|
||||||
|
onFinished: PropTypes.func.isRequired,
|
||||||
|
|
||||||
|
// Label for the button that marks all devices known and tries the send again
|
||||||
|
sendAnywayLabel: PropTypes.string.isRequired,
|
||||||
|
|
||||||
|
// Label for the button that to send the event if you've verified all devices
|
||||||
|
sendLabel: PropTypes.string.isRequired,
|
||||||
|
|
||||||
|
// function to retry the request once all devices are verified / known
|
||||||
|
onSend: PropTypes.func.isRequired,
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentWillMount: function() {
|
||||||
// Given we've now shown the user the unknown device, it is no longer
|
MatrixClientPeg.get().on("deviceVerificationChanged", this._onDeviceVerificationChanged);
|
||||||
// unknown to them. Therefore mark it as 'known'.
|
},
|
||||||
Object.keys(this.props.devices).forEach((userId) => {
|
|
||||||
Object.keys(this.props.devices[userId]).map((deviceId) => {
|
|
||||||
MatrixClientPeg.get().setDeviceKnown(userId, deviceId, true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// XXX: temporary logging to try to diagnose
|
componentWillUnmount: function() {
|
||||||
// https://github.com/vector-im/riot-web/issues/3148
|
if (MatrixClientPeg.get()) {
|
||||||
console.log('Opening UnknownDeviceDialog');
|
MatrixClientPeg.get().removeListener("deviceVerificationChanged", this._onDeviceVerificationChanged);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onDeviceVerificationChanged: function(userId, deviceId, deviceInfo) {
|
||||||
|
if (this.props.devices[userId] && this.props.devices[userId][deviceId]) {
|
||||||
|
// XXX: Mutating props :/
|
||||||
|
this.props.devices[userId][deviceId] = deviceInfo;
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onDismissClicked: function() {
|
||||||
|
this.props.onFinished();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onSendAnywayClicked: function() {
|
||||||
|
markAllDevicesKnown(this.props.devices);
|
||||||
|
|
||||||
|
this.props.onFinished();
|
||||||
|
this.props.onSend();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onSendClicked: function() {
|
||||||
|
this.props.onFinished();
|
||||||
|
this.props.onSend();
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
if (this.props.devices === null) {
|
||||||
|
const Spinner = sdk.getComponent("elements.Spinner");
|
||||||
|
return <Spinner />;
|
||||||
|
}
|
||||||
|
|
||||||
let warning;
|
let warning;
|
||||||
if (SettingsStore.getValue("blacklistUnverifiedDevices", this.props.room.roomId)) {
|
if (SettingsStore.getValue("blacklistUnverifiedDevices", this.props.room.roomId)) {
|
||||||
warning = (
|
warning = (
|
||||||
|
@ -133,15 +178,30 @@ export default React.createClass({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let haveUnknownDevices = false;
|
||||||
|
Object.keys(this.props.devices).forEach((userId) => {
|
||||||
|
Object.keys(this.props.devices[userId]).map((deviceId) => {
|
||||||
|
const device = this.props.devices[userId][deviceId];
|
||||||
|
if (device.isUnverified() && !device.isKnown()) {
|
||||||
|
haveUnknownDevices = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let sendButton;
|
||||||
|
if (haveUnknownDevices) {
|
||||||
|
sendButton = <button onClick={this._onSendAnywayClicked}>
|
||||||
|
{ this.props.sendAnywayLabel }
|
||||||
|
</button>;
|
||||||
|
} else {
|
||||||
|
sendButton = <button onClick={this._onSendClicked}>
|
||||||
|
{ this.props.sendLabel }
|
||||||
|
</button>;
|
||||||
|
}
|
||||||
|
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
return (
|
return (
|
||||||
<BaseDialog className='mx_UnknownDeviceDialog'
|
<BaseDialog className='mx_UnknownDeviceDialog'
|
||||||
onFinished={() => {
|
onFinished={this.props.onFinished}
|
||||||
// XXX: temporary logging to try to diagnose
|
|
||||||
// https://github.com/vector-im/riot-web/issues/3148
|
|
||||||
console.log("UnknownDeviceDialog closed by escape");
|
|
||||||
this.props.onFinished();
|
|
||||||
}}
|
|
||||||
title={_t('Room contains unknown devices')}
|
title={_t('Room contains unknown devices')}
|
||||||
>
|
>
|
||||||
<GeminiScrollbar autoshow={false} className="mx_Dialog_content">
|
<GeminiScrollbar autoshow={false} className="mx_Dialog_content">
|
||||||
|
@ -154,21 +214,11 @@ export default React.createClass({
|
||||||
<UnknownDeviceList devices={this.props.devices} />
|
<UnknownDeviceList devices={this.props.devices} />
|
||||||
</GeminiScrollbar>
|
</GeminiScrollbar>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
|
{sendButton}
|
||||||
<button className="mx_Dialog_primary" autoFocus={true}
|
<button className="mx_Dialog_primary" autoFocus={true}
|
||||||
onClick={() => {
|
onClick={this._onDismissClicked}
|
||||||
this.props.onFinished();
|
>
|
||||||
Resend.resendUnsentEvents(this.props.room);
|
{_t("Dismiss")}
|
||||||
}}>
|
|
||||||
{ _t("Send anyway") }
|
|
||||||
</button>
|
|
||||||
<button className="mx_Dialog_primary" autoFocus={true}
|
|
||||||
onClick={() => {
|
|
||||||
// XXX: temporary logging to try to diagnose
|
|
||||||
// https://github.com/vector-im/riot-web/issues/3148
|
|
||||||
console.log("UnknownDeviceDialog closed by OK");
|
|
||||||
this.props.onFinished();
|
|
||||||
}}>
|
|
||||||
OK
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
|
|
|
@ -74,13 +74,6 @@ function onSendMessageFailed(err, room) {
|
||||||
// XXX: temporary logging to try to diagnose
|
// XXX: temporary logging to try to diagnose
|
||||||
// https://github.com/vector-im/riot-web/issues/3148
|
// https://github.com/vector-im/riot-web/issues/3148
|
||||||
console.log('MessageComposer got send failure: ' + err.name + '('+err+')');
|
console.log('MessageComposer got send failure: ' + err.name + '('+err+')');
|
||||||
if (err.name === "UnknownDeviceError") {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'unknown_device_error',
|
|
||||||
err: err,
|
|
||||||
room: room,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'message_send_failed',
|
action: 'message_send_failed',
|
||||||
});
|
});
|
||||||
|
|
104
src/cryptodevices.js
Normal file
104
src/cryptodevices.js
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 New Vector 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Resend from './Resend';
|
||||||
|
import sdk from './index';
|
||||||
|
import Modal from './Modal';
|
||||||
|
import { _t } from './languageHandler';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all crypto devices in a room that are marked neither known
|
||||||
|
* nor verified.
|
||||||
|
*
|
||||||
|
* @param {MatrixClient} matrixClient A MatrixClient
|
||||||
|
* @param {Room} room js-sdk room object representing the room
|
||||||
|
* @return {Promise} A promise which resolves to a map userId->deviceId->{@link
|
||||||
|
* module:crypto~DeviceInfo|DeviceInfo}.
|
||||||
|
*/
|
||||||
|
export function getUnknownDevicesForRoom(matrixClient, room) {
|
||||||
|
const roomMembers = room.getJoinedMembers().map((m) => {
|
||||||
|
return m.userId;
|
||||||
|
});
|
||||||
|
return matrixClient.downloadKeys(roomMembers, false).then((devices) => {
|
||||||
|
const unknownDevices = {};
|
||||||
|
// This is all devices in this room, so find the unknown ones.
|
||||||
|
Object.keys(devices).forEach((userId) => {
|
||||||
|
Object.keys(devices[userId]).map((deviceId) => {
|
||||||
|
const device = devices[userId][deviceId];
|
||||||
|
|
||||||
|
if (device.isUnverified() && !device.isKnown()) {
|
||||||
|
if (unknownDevices[userId] === undefined) {
|
||||||
|
unknownDevices[userId] = {};
|
||||||
|
}
|
||||||
|
unknownDevices[userId][deviceId] = device;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return unknownDevices;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the UnknownDeviceDialog for a given room. The dialog will inform the user
|
||||||
|
* that messages they sent to this room have not been sent due to unknown devices
|
||||||
|
* being present.
|
||||||
|
*
|
||||||
|
* @param {MatrixClient} matrixClient A MatrixClient
|
||||||
|
* @param {Room} room js-sdk room object representing the room
|
||||||
|
*/
|
||||||
|
export function showUnknownDeviceDialogForMessages(matrixClient, room) {
|
||||||
|
getUnknownDevicesForRoom(matrixClient, room).then((unknownDevices) => {
|
||||||
|
const onSendClicked = () => {
|
||||||
|
Resend.resendUnsentEvents(room);
|
||||||
|
};
|
||||||
|
|
||||||
|
const UnknownDeviceDialog = sdk.getComponent('dialogs.UnknownDeviceDialog');
|
||||||
|
Modal.createTrackedDialog('Unknown Device Dialog', '', UnknownDeviceDialog, {
|
||||||
|
room: room,
|
||||||
|
devices: unknownDevices,
|
||||||
|
sendAnywayLabel: _t("Send anyway"),
|
||||||
|
sendLabel: _t("Send"),
|
||||||
|
onSend: onSendClicked,
|
||||||
|
}, 'mx_Dialog_unknownDevice');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the UnknownDeviceDialog for a given room. The dialog will inform the user
|
||||||
|
* that a call they tried to place or answer in the room couldn't be placed or
|
||||||
|
* answered due to unknown devices being present.
|
||||||
|
*
|
||||||
|
* @param {MatrixClient} matrixClient A MatrixClient
|
||||||
|
* @param {Room} room js-sdk room object representing the room
|
||||||
|
* @param {func} sendAnyway Function called when the 'call anyway' or 'call'
|
||||||
|
* button is pressed. This should attempt to place or answer the call again.
|
||||||
|
* @param {string} sendAnywayLabel Label for the button displayed to retry the call
|
||||||
|
* when unknown devices are still present (eg. "Call Anyway")
|
||||||
|
* @param {string} sendLabel Label for the button displayed to retry the call
|
||||||
|
* after all devices have been verified (eg. "Call")
|
||||||
|
*/
|
||||||
|
export function showUnknownDeviceDialogForCalls(matrixClient, room, sendAnyway, sendAnywayLabel, sendLabel) {
|
||||||
|
getUnknownDevicesForRoom(matrixClient, room).then((unknownDevices) => {
|
||||||
|
const UnknownDeviceDialog = sdk.getComponent('dialogs.UnknownDeviceDialog');
|
||||||
|
Modal.createTrackedDialog('Unknown Device Dialog', '', UnknownDeviceDialog, {
|
||||||
|
room: room,
|
||||||
|
devices: unknownDevices,
|
||||||
|
sendAnywayLabel: sendAnywayLabel,
|
||||||
|
sendLabel: sendLabel,
|
||||||
|
onSend: sendAnyway,
|
||||||
|
}, 'mx_Dialog_unknownDevice');
|
||||||
|
});
|
||||||
|
}
|
|
@ -2,6 +2,13 @@
|
||||||
"This email address is already in use": "This email address is already in use",
|
"This email address is already in use": "This email address is already in use",
|
||||||
"This phone number is already in use": "This phone number is already in use",
|
"This phone number is already in use": "This phone number is already in use",
|
||||||
"Failed to verify email address: make sure you clicked the link in the email": "Failed to verify email address: make sure you clicked the link in the email",
|
"Failed to verify email address: make sure you clicked the link in the email": "Failed to verify email address: make sure you clicked the link in the email",
|
||||||
|
"Call Failed": "Call Failed",
|
||||||
|
"There are unknown devices in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "There are unknown devices in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.",
|
||||||
|
"Review Devices": "Review Devices",
|
||||||
|
"Call Anyway": "Call Anyway",
|
||||||
|
"Answer Anyway": "Answer Anyway",
|
||||||
|
"Call": "Call",
|
||||||
|
"Answer": "Answer",
|
||||||
"Call Timeout": "Call Timeout",
|
"Call Timeout": "Call Timeout",
|
||||||
"The remote side failed to pick up": "The remote side failed to pick up",
|
"The remote side failed to pick up": "The remote side failed to pick up",
|
||||||
"Unable to capture screen": "Unable to capture screen",
|
"Unable to capture screen": "Unable to capture screen",
|
||||||
|
@ -156,6 +163,8 @@
|
||||||
"%(names)s and %(lastPerson)s are typing": "%(names)s and %(lastPerson)s are typing",
|
"%(names)s and %(lastPerson)s are typing": "%(names)s and %(lastPerson)s are typing",
|
||||||
"Failure to create room": "Failure to create room",
|
"Failure to create room": "Failure to create room",
|
||||||
"Server may be unavailable, overloaded, or you hit a bug.": "Server may be unavailable, overloaded, or you hit a bug.",
|
"Server may be unavailable, overloaded, or you hit a bug.": "Server may be unavailable, overloaded, or you hit a bug.",
|
||||||
|
"Send anyway": "Send anyway",
|
||||||
|
"Send": "Send",
|
||||||
"Unnamed Room": "Unnamed Room",
|
"Unnamed Room": "Unnamed Room",
|
||||||
"Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions",
|
"Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions",
|
||||||
"Not a valid Riot keyfile": "Not a valid Riot keyfile",
|
"Not a valid Riot keyfile": "Not a valid Riot keyfile",
|
||||||
|
@ -695,7 +704,6 @@
|
||||||
"Room contains unknown devices": "Room contains unknown devices",
|
"Room contains unknown devices": "Room contains unknown devices",
|
||||||
"\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.",
|
"\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.",
|
||||||
"Unknown devices": "Unknown devices",
|
"Unknown devices": "Unknown devices",
|
||||||
"Send anyway": "Send anyway",
|
|
||||||
"Private Chat": "Private Chat",
|
"Private Chat": "Private Chat",
|
||||||
"Public Chat": "Public Chat",
|
"Public Chat": "Public Chat",
|
||||||
"Custom": "Custom",
|
"Custom": "Custom",
|
||||||
|
@ -760,17 +768,19 @@
|
||||||
"To join an existing community you'll have to know its community identifier; this will look something like <i>+example:matrix.org</i>.": "To join an existing community you'll have to know its community identifier; this will look something like <i>+example:matrix.org</i>.",
|
"To join an existing community you'll have to know its community identifier; this will look something like <i>+example:matrix.org</i>.": "To join an existing community you'll have to know its community identifier; this will look something like <i>+example:matrix.org</i>.",
|
||||||
"You have no visible notifications": "You have no visible notifications",
|
"You have no visible notifications": "You have no visible notifications",
|
||||||
"Scroll to bottom of page": "Scroll to bottom of page",
|
"Scroll to bottom of page": "Scroll to bottom of page",
|
||||||
|
"Message not sent due to unknown devices being present": "Message not sent due to unknown devices being present",
|
||||||
|
"<showDevicesText>Show devices</showDevicesText> or <cancelText>cancel all</cancelText>.": "<showDevicesText>Show devices</showDevicesText> or <cancelText>cancel all</cancelText>.",
|
||||||
|
"Some of your messages have not been sent.": "Some of your messages have not been sent.",
|
||||||
|
"<resendText>Resend all</resendText> or <cancelText>cancel all</cancelText> now. You can also select individual messages to resend or cancel.": "<resendText>Resend all</resendText> or <cancelText>cancel all</cancelText> now. You can also select individual messages to resend or cancel.",
|
||||||
|
"Warning": "Warning",
|
||||||
"Connectivity to the server has been lost.": "Connectivity to the server has been lost.",
|
"Connectivity to the server has been lost.": "Connectivity to the server has been lost.",
|
||||||
"Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.",
|
"Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.",
|
||||||
"<resendText>Resend all</resendText> or <cancelText>cancel all</cancelText> now. You can also select individual messages to resend or cancel.": "<resendText>Resend all</resendText> or <cancelText>cancel all</cancelText> now. You can also select individual messages to resend or cancel.",
|
|
||||||
"%(count)s new messages|other": "%(count)s new messages",
|
"%(count)s new messages|other": "%(count)s new messages",
|
||||||
"%(count)s new messages|one": "%(count)s new message",
|
"%(count)s new messages|one": "%(count)s new message",
|
||||||
"Active call": "Active call",
|
"Active call": "Active call",
|
||||||
"There's no one else here! Would you like to <inviteText>invite others</inviteText> or <nowarnText>stop warning about the empty room</nowarnText>?": "There's no one else here! Would you like to <inviteText>invite others</inviteText> or <nowarnText>stop warning about the empty room</nowarnText>?",
|
"There's no one else here! Would you like to <inviteText>invite others</inviteText> or <nowarnText>stop warning about the empty room</nowarnText>?": "There's no one else here! Would you like to <inviteText>invite others</inviteText> or <nowarnText>stop warning about the empty room</nowarnText>?",
|
||||||
"You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?",
|
"You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?",
|
||||||
"You seem to be in a call, are you sure you want to quit?": "You seem to be in a call, are you sure you want to quit?",
|
"You seem to be in a call, are you sure you want to quit?": "You seem to be in a call, are you sure you want to quit?",
|
||||||
"Some of your messages have not been sent.": "Some of your messages have not been sent.",
|
|
||||||
"Message not sent due to unknown devices being present": "Message not sent due to unknown devices being present",
|
|
||||||
"Failed to upload file": "Failed to upload file",
|
"Failed to upload file": "Failed to upload file",
|
||||||
"Server may be unavailable, overloaded, or the file too big": "Server may be unavailable, overloaded, or the file too big",
|
"Server may be unavailable, overloaded, or the file too big": "Server may be unavailable, overloaded, or the file too big",
|
||||||
"Search failed": "Search failed",
|
"Search failed": "Search failed",
|
||||||
|
|
Loading…
Reference in a new issue