Merge branch 'develop' into bwindels/customtags-featureflag

This commit is contained in:
Bruno Windels 2019-02-08 12:12:43 +00:00
commit 3c5fb61350
12 changed files with 62 additions and 255 deletions

View File

@ -77,7 +77,6 @@
@import "./views/elements/_Dropdown.scss"; @import "./views/elements/_Dropdown.scss";
@import "./views/elements/_EditableItemList.scss"; @import "./views/elements/_EditableItemList.scss";
@import "./views/elements/_Field.scss"; @import "./views/elements/_Field.scss";
@import "./views/elements/_HexVerify.scss";
@import "./views/elements/_ImageView.scss"; @import "./views/elements/_ImageView.scss";
@import "./views/elements/_InlineSpinner.scss"; @import "./views/elements/_InlineSpinner.scss";
@import "./views/elements/_ManageIntegsButton.scss"; @import "./views/elements/_ManageIntegsButton.scss";
@ -156,6 +155,7 @@
@import "./views/settings/tabs/_SecuritySettingsTab.scss"; @import "./views/settings/tabs/_SecuritySettingsTab.scss";
@import "./views/settings/tabs/_SettingsTab.scss"; @import "./views/settings/tabs/_SettingsTab.scss";
@import "./views/settings/tabs/_VoiceSettingsTab.scss"; @import "./views/settings/tabs/_VoiceSettingsTab.scss";
@import "./views/verification/_VerificationShowSas.scss";
@import "./views/voip/_CallView.scss"; @import "./views/voip/_CallView.scss";
@import "./views/voip/_IncomingCallbox.scss"; @import "./views/voip/_IncomingCallbox.scss";
@import "./views/voip/_VideoView.scss"; @import "./views/voip/_VideoView.scss";

View File

@ -21,7 +21,11 @@ limitations under the License.
.mx_CustomRoomTagPanel { .mx_CustomRoomTagPanel {
background-color: $tagpanel-bg-color; background-color: $tagpanel-bg-color;
max-height: 40%; max-height: 40vh;
}
.mx_CustomRoomTagPanel_scroller {
max-height: inherit;
} }
.mx_CustomRoomTagPanel .mx_AccessibleButton { .mx_CustomRoomTagPanel .mx_AccessibleButton {

View File

@ -14,21 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.mx_HexVerify { .mx_VerificationShowSas_sas {
text-align: center; text-align: center;
}
.mx_HexVerify_pair {
display: inline-block;
font-weight: bold; font-weight: bold;
padding-left: 3px; padding-left: 3px;
padding-right: 3px; padding-right: 3px;
} }
.mx_HexVerify_pair_verified {
color: $accent-color;
}
.mx_HexVerify_pair:hover{
color: $accent-color;
}

View File

@ -135,14 +135,7 @@ class MatrixClientPeg {
const opts = utils.deepCopy(this.opts); const opts = utils.deepCopy(this.opts);
// the react sdk doesn't work without this, so don't allow // the react sdk doesn't work without this, so don't allow
opts.pendingEventOrdering = "detached"; opts.pendingEventOrdering = "detached";
opts.lazyLoadMembers = true;
const LAZY_LOADING_FEATURE = "feature_lazyloading";
if (SettingsStore.isFeatureEnabled(LAZY_LOADING_FEATURE)) {
const userId = this.matrixClient.credentials.userId;
if (phasedRollOutExpiredForUser(userId, LAZY_LOADING_FEATURE, Date.now())) {
opts.lazyLoadMembers = true;
}
}
// Connect the matrix client to the dispatcher // Connect the matrix client to the dispatcher
MatrixActionCreators.start(this.matrixClient); MatrixActionCreators.start(this.matrixClient);

View File

@ -19,6 +19,8 @@ import sdk from '../../../../index';
import MatrixClientPeg from '../../../../MatrixClientPeg'; import MatrixClientPeg from '../../../../MatrixClientPeg';
import Modal from '../../../../Modal'; import Modal from '../../../../Modal';
import { MatrixClient } from 'matrix-js-sdk';
import { _t } from '../../../../languageHandler'; import { _t } from '../../../../languageHandler';
const RESTORE_TYPE_PASSPHRASE = 0; const RESTORE_TYPE_PASSPHRASE = 0;
@ -88,7 +90,7 @@ export default React.createClass({
}); });
try { try {
const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithPassword( const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithPassword(
this.state.passPhrase, undefined, undefined, this.state.backupInfo.version, this.state.passPhrase, undefined, undefined, this.state.backupInfo,
); );
this.setState({ this.setState({
loading: false, loading: false,
@ -107,11 +109,11 @@ export default React.createClass({
this.setState({ this.setState({
loading: true, loading: true,
restoreError: null, restoreError: null,
restoreType: RESTORE_TYPE_PASSPHRASE, restoreType: RESTORE_TYPE_RECOVERYKEY,
}); });
try { try {
const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithRecoveryKey( const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithRecoveryKey(
this.state.recoveryKey, undefined, undefined, this.state.backupInfo.version, this.state.recoveryKey, undefined, undefined, this.state.backupInfo,
); );
this.setState({ this.setState({
loading: false, loading: false,
@ -185,32 +187,31 @@ export default React.createClass({
title = _t("Error"); title = _t("Error");
content = _t("Unable to load backup status"); content = _t("Unable to load backup status");
} else if (this.state.restoreError) { } else if (this.state.restoreError) {
title = _t("Error"); if (this.state.restoreError.errcode === MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY) {
content = _t("Unable to restore backup"); if (this.state.restoreType === RESTORE_TYPE_RECOVERYKEY) {
title = _t("Recovery Key Mismatch");
content = <div>
<p>{_t(
"Backup could not be decrypted with this key: " +
"please verify that you entered the correct recovery key.",
)}</p>
</div>;
} else {
title = _t("Incorrect Recovery Passphrase");
content = <div>
<p>{_t(
"Backup could not be decrypted with this passphrase: " +
"please verify that you entered the correct recovery passphrase.",
)}</p>
</div>;
}
} else {
title = _t("Error");
content = _t("Unable to restore backup");
}
} else if (this.state.backupInfo === null) { } else if (this.state.backupInfo === null) {
title = _t("Error"); title = _t("Error");
content = _t("No backup found!"); content = _t("No backup found!");
} else if (
this.state.recoverInfo &&
this.state.recoverInfo.imported === 0 &&
this.state.recoverInfo.total > 0
) {
title = _t("Error Restoring Backup");
if (this.state.restoreType === RESTORE_TYPE_RECOVERYKEY) {
content = <div>
<p>{_t(
"Backup could not be decrypted with this key: " +
"please verify that you entered the correct recovery key.",
)}</p>
</div>;
} else {
content = <div>
<p>{_t(
"Backup could not be decrypted with this passphrase: " +
"please verify that you entered the correct recovery passphrase.",
)}</p>
</div>;
}
} else if (this.state.recoverInfo) { } else if (this.state.recoverInfo) {
title = _t("Backup Restored"); title = _t("Backup Restored");
let failedToDecrypt; let failedToDecrypt;

View File

@ -1,103 +0,0 @@
/*
Copyright 2019 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 React from "react";
import PropTypes from "prop-types";
import classnames from 'classnames';
import sdk from '../../../index';
class HexVerifyPair extends React.Component {
static propTypes = {
text: PropTypes.string.isRequired,
index: PropTypes.number,
verified: PropTypes.bool,
onChange: PropTypes.func.isRequired,
}
_onClick = () => {
this.setState({verified: !this.props.verified});
this.props.onChange(this.props.index, !this.props.verified);
}
render() {
const classNames = {
mx_HexVerify_pair: true,
mx_HexVerify_pair_verified: this.props.verified,
};
const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton');
return <AccessibleButton className={classnames(classNames)}
onClick={this._onClick}
>
{this.props.text}
</AccessibleButton>;
}
}
/*
* Helps a user verify a hexadecimal code matches one displayed
* elsewhere (eg. on a different device)
*/
export default class HexVerify extends React.Component {
static propTypes = {
text: PropTypes.string.isRequired,
onVerifiedStateChange: PropTypes.func,
}
static defaultProps = {
onVerifiedStateChange: function() {},
}
constructor(props) {
super(props);
this.state = {
pairsVerified: [],
};
for (let i = 0; i < props.text.length; i += 2) {
this.state.pairsVerified.push(false);
}
}
_onPairChange = (index, newVal) => {
const oldVerified = this.state.pairsVerified.reduce((acc, val) => {
return acc && val;
}, true);
const newPairsVerified = this.state.pairsVerified.slice(0);
newPairsVerified[index] = newVal;
const newVerified = newPairsVerified.reduce((acc, val) => {
return acc && val;
}, true);
this.setState({pairsVerified: newPairsVerified});
if (oldVerified !== newVerified) {
this.props.onVerifiedStateChange(newVerified);
}
}
render() {
const pairs = [];
for (let i = 0; i < this.props.text.length / 2; ++i) {
pairs.push(<HexVerifyPair key={i} index={i}
text={this.props.text.substr(i * 2, 2)}
verified={this.state.pairsVerified[i]}
onChange={this._onPairChange}
/>);
}
return <div className="mx_HexVerify">
{pairs}
</div>;
}
}

View File

@ -250,19 +250,26 @@ export default class KeyBackupPanel extends React.PureComponent {
backupSigStatuses = _t("Backup is not signed by any of your devices"); backupSigStatuses = _t("Backup is not signed by any of your devices");
} }
let trustedLocally;
if (this.state.backupSigStatus.trusted_locally) {
trustedLocally = _t("This backup is trusted because it has been restored on this device");
}
return <div> return <div>
{_t("Backup version: ")}{this.state.backupInfo.version}<br /> <div>{_t("Backup version: ")}{this.state.backupInfo.version}</div>
{_t("Algorithm: ")}{this.state.backupInfo.algorithm}<br /> <div>{_t("Algorithm: ")}{this.state.backupInfo.algorithm}</div>
{clientBackupStatus}<br /> <div>{clientBackupStatus}</div>
{uploadStatus} {uploadStatus}
<div>{backupSigStatuses}</div><br /> <div>{backupSigStatuses}</div>
<br /> <div>{trustedLocally}</div>
<AccessibleButton kind="primary" onClick={this._restoreBackup}> <p>
{ _t("Restore backup") } <AccessibleButton kind="primary" onClick={this._restoreBackup}>
</AccessibleButton>&nbsp;&nbsp;&nbsp; { _t("Restore backup") }
<AccessibleButton kind="danger" onClick={this._deleteBackup}> </AccessibleButton>&nbsp;&nbsp;&nbsp;
{ _t("Delete backup") } <AccessibleButton kind="danger" onClick={this._deleteBackup}>
</AccessibleButton> { _t("Delete backup") }
</AccessibleButton>
</p>
</div>; </div>;
} else { } else {
return <div> return <div>

View File

@ -18,9 +18,7 @@ import React from 'react';
import {_t} from "../../../../languageHandler"; import {_t} from "../../../../languageHandler";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore";
import MatrixClientPeg from "../../../../MatrixClientPeg";
import LabelledToggleSwitch from "../../elements/LabelledToggleSwitch"; import LabelledToggleSwitch from "../../elements/LabelledToggleSwitch";
const Modal = require("../../../../Modal");
const sdk = require("../../../../index"); const sdk = require("../../../../index");
export class LabsSettingToggle extends React.Component { export class LabsSettingToggle extends React.Component {
@ -28,38 +26,7 @@ export class LabsSettingToggle extends React.Component {
featureId: PropTypes.string.isRequired, featureId: PropTypes.string.isRequired,
}; };
async _onLazyLoadChanging(enabling) {
// don't prevent turning LL off when not supported
if (enabling) {
const supported = await MatrixClientPeg.get().doesServerSupportLazyLoading();
if (!supported) {
await new Promise((resolve) => {
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
Modal.createDialog(QuestionDialog, {
title: _t("Lazy loading members not supported"),
description:
<div>
{ _t("Lazy loading is not supported by your " +
"current homeserver.") }
</div>,
button: _t("OK"),
onFinished: resolve,
});
});
return false;
}
}
return true;
}
_onChange = async (checked) => { _onChange = async (checked) => {
if (this.props.featureId === "feature_lazyloading") {
const confirmed = await this._onLazyLoadChanging(checked);
if (!confirmed) {
return;
}
}
await SettingsStore.setFeatureEnabled(this.props.featureId, checked); await SettingsStore.setFeatureEnabled(this.props.featureId, checked);
this.forceUpdate(); this.forceUpdate();
}; };

View File

@ -28,19 +28,11 @@ export default class VerificationShowSas extends React.Component {
constructor() { constructor() {
super(); super();
this.state = {
sasVerified: false,
};
}
_onVerifiedStateChange = (newVal) => {
this.setState({sasVerified: newVal});
} }
render() { render() {
const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
const HexVerify = sdk.getComponent('views.elements.HexVerify'); return <div className="mx_VerificationShowSas">
return <div>
<p>{_t( <p>{_t(
"Verify this user by confirming the following number appears on their screen.", "Verify this user by confirming the following number appears on their screen.",
)}</p> )}</p>
@ -48,15 +40,11 @@ export default class VerificationShowSas extends React.Component {
"For maximum security, we recommend you do this in person or use another " + "For maximum security, we recommend you do this in person or use another " +
"trusted means of communication.", "trusted means of communication.",
)}</p> )}</p>
<HexVerify text={this.props.sas} <div className="mx_VerificationShowSas_sas">
onVerifiedStateChange={this._onVerifiedStateChange} {this.props.sas}
/> </div>
<p>{_t(
"To continue, click on each pair to confirm it's correct.",
)}</p>
<DialogButtons onPrimaryButtonClick={this.props.onDone} <DialogButtons onPrimaryButtonClick={this.props.onDone}
primaryButton={_t("Continue")} primaryButton={_t("Continue")}
primaryDisabled={!this.state.sasVerified}
hasCancel={true} hasCancel={true}
onCancel={this.props.onCancel} onCancel={this.props.onCancel}
/> />

View File

@ -265,7 +265,6 @@
"Message Pinning": "Message Pinning", "Message Pinning": "Message Pinning",
"Custom user status messages": "Custom user status messages", "Custom user status messages": "Custom user status messages",
"Group & filter rooms by custom tags (refresh to apply changes)": "Group & filter rooms by custom tags (refresh to apply changes)", "Group & filter rooms by custom tags (refresh to apply changes)": "Group & filter rooms by custom tags (refresh to apply changes)",
"Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view",
"Backup of encryption keys to server": "Backup of encryption keys to server", "Backup of encryption keys to server": "Backup of encryption keys to server",
"Render simple counters in room header": "Render simple counters in room header", "Render simple counters in room header": "Render simple counters in room header",
"Two-way device verification using short text": "Two-way device verification using short text", "Two-way device verification using short text": "Two-way device verification using short text",
@ -386,6 +385,7 @@
"Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>", "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>",
"Verify...": "Verify...", "Verify...": "Verify...",
"Backup is not signed by any of your devices": "Backup is not signed by any of your devices", "Backup is not signed by any of your devices": "Backup is not signed by any of your devices",
"This backup is trusted because it has been restored on this device": "This backup is trusted because it has been restored on this device",
"Backup version: ": "Backup version: ", "Backup version: ": "Backup version: ",
"Algorithm: ": "Algorithm: ", "Algorithm: ": "Algorithm: ",
"Restore backup": "Restore backup", "Restore backup": "Restore backup",
@ -477,8 +477,6 @@
"Identity Server is": "Identity Server is", "Identity Server is": "Identity Server is",
"Access Token:": "Access Token:", "Access Token:": "Access Token:",
"click to reveal": "click to reveal", "click to reveal": "click to reveal",
"Lazy loading members not supported": "Lazy loading members not supported",
"Lazy loading is not supported by your current homeserver.": "Lazy loading is not supported by your current homeserver.",
"Labs": "Labs", "Labs": "Labs",
"Notifications": "Notifications", "Notifications": "Notifications",
"Start automatically after system login": "Start automatically after system login", "Start automatically after system login": "Start automatically after system login",
@ -1096,11 +1094,12 @@
"\"%(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",
"Unable to load backup status": "Unable to load backup status", "Unable to load backup status": "Unable to load backup status",
"Recovery Key Mismatch": "Recovery Key Mismatch",
"Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.",
"Incorrect Recovery Passphrase": "Incorrect Recovery Passphrase",
"Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.",
"Unable to restore backup": "Unable to restore backup", "Unable to restore backup": "Unable to restore backup",
"No backup found!": "No backup found!", "No backup found!": "No backup found!",
"Error Restoring Backup": "Error Restoring Backup",
"Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.",
"Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.",
"Backup Restored": "Backup Restored", "Backup Restored": "Backup Restored",
"Failed to decrypt %(failedCount)s sessions!": "Failed to decrypt %(failedCount)s sessions!", "Failed to decrypt %(failedCount)s sessions!": "Failed to decrypt %(failedCount)s sessions!",
"Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys", "Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys",

View File

@ -21,7 +21,6 @@ import {
NotificationBodyEnabledController, NotificationBodyEnabledController,
NotificationsEnabledController, NotificationsEnabledController,
} from "./controllers/NotificationControllers"; } from "./controllers/NotificationControllers";
import LazyLoadingController from "./controllers/LazyLoadingController";
import CustomStatusController from "./controllers/CustomStatusController"; import CustomStatusController from "./controllers/CustomStatusController";
// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times // These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
@ -106,13 +105,6 @@ export const SETTINGS = {
supportedLevels: LEVELS_FEATURE, supportedLevels: LEVELS_FEATURE,
default: false, default: false,
}, },
"feature_lazyloading": {
isFeature: true,
displayName: _td("Increase performance by only loading room members on first view"),
supportedLevels: LEVELS_FEATURE,
controller: new LazyLoadingController(),
default: true,
},
"feature_keybackup": { "feature_keybackup": {
isFeature: true, isFeature: true,
displayName: _td("Backup of encryption keys to server"), displayName: _td("Backup of encryption keys to server"),

View File

@ -1,29 +0,0 @@
/*
Copyright 2018 New Vector
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 SettingController from "./SettingController";
import MatrixClientPeg from "../../MatrixClientPeg";
import PlatformPeg from "../../PlatformPeg";
export default class LazyLoadingController extends SettingController {
async onChange(level, roomId, newValue) {
if (!PlatformPeg.get()) return;
MatrixClientPeg.get().stopClient();
await MatrixClientPeg.get().store.deleteAllData();
PlatformPeg.get().reload();
}
}