Merge remote-tracking branch 'origin/develop' into rav/no_preserve_hs_url
This commit is contained in:
@@ -327,17 +327,10 @@ const RoomSubList = React.createClass({
|
||||
|
||||
let incomingCall;
|
||||
if (this.props.incomingCall) {
|
||||
const self = this;
|
||||
// Check if the incoming call is for this section
|
||||
const incomingCallRoom = this.props.list.filter(function(room) {
|
||||
return self.props.incomingCall.roomId === room.roomId;
|
||||
});
|
||||
|
||||
if (incomingCallRoom.length === 1) {
|
||||
const IncomingCallBox = sdk.getComponent("voip.IncomingCallBox");
|
||||
incomingCall =
|
||||
<IncomingCallBox className="mx_RoomSubList_incomingCall" incomingCall={this.props.incomingCall} />;
|
||||
}
|
||||
// We can assume that if we have an incoming call then it is for this list
|
||||
const IncomingCallBox = sdk.getComponent("voip.IncomingCallBox");
|
||||
incomingCall =
|
||||
<IncomingCallBox className="mx_RoomSubList_incomingCall" incomingCall={this.props.incomingCall} />;
|
||||
}
|
||||
|
||||
const tabindex = this.props.searchFilter === "" ? "0" : "-1";
|
||||
|
||||
@@ -607,6 +607,20 @@ module.exports = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
async onRoomRecoveryReminderFinished(backupCreated) {
|
||||
// If the user cancelled the key backup dialog, it suggests they don't
|
||||
// want to be reminded anymore.
|
||||
if (!backupCreated) {
|
||||
await SettingsStore.setValue(
|
||||
"showRoomRecoveryReminder",
|
||||
null,
|
||||
SettingLevel.ACCOUNT,
|
||||
false,
|
||||
);
|
||||
}
|
||||
this.forceUpdate();
|
||||
},
|
||||
|
||||
canResetTimeline: function() {
|
||||
if (!this.refs.messagePanel) {
|
||||
return true;
|
||||
@@ -1521,6 +1535,7 @@ module.exports = React.createClass({
|
||||
const Loader = sdk.getComponent("elements.Spinner");
|
||||
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
|
||||
const RoomUpgradeWarningBar = sdk.getComponent("rooms.RoomUpgradeWarningBar");
|
||||
const RoomRecoveryReminder = sdk.getComponent("rooms.RoomRecoveryReminder");
|
||||
|
||||
if (!this.state.room) {
|
||||
if (this.state.roomLoading || this.state.peekLoading) {
|
||||
@@ -1655,6 +1670,13 @@ module.exports = React.createClass({
|
||||
this.state.room.userMayUpgradeRoom(MatrixClientPeg.get().credentials.userId)
|
||||
);
|
||||
|
||||
const showRoomRecoveryReminder = (
|
||||
SettingsStore.isFeatureEnabled("feature_keybackup") &&
|
||||
SettingsStore.getValue("showRoomRecoveryReminder") &&
|
||||
MatrixClientPeg.get().isRoomEncrypted(this.state.room.roomId) &&
|
||||
!MatrixClientPeg.get().getKeyBackupEnabled()
|
||||
);
|
||||
|
||||
let aux = null;
|
||||
let hideCancel = false;
|
||||
if (this.state.editingRoomSettings) {
|
||||
@@ -1669,6 +1691,9 @@ module.exports = React.createClass({
|
||||
} else if (showRoomUpgradeBar) {
|
||||
aux = <RoomUpgradeWarningBar room={this.state.room} />;
|
||||
hideCancel = true;
|
||||
} else if (showRoomRecoveryReminder) {
|
||||
aux = <RoomRecoveryReminder onFinished={this.onRoomRecoveryReminderFinished} />;
|
||||
hideCancel = true;
|
||||
} else if (this.state.showingPinned) {
|
||||
hideCancel = true; // has own cancel
|
||||
aux = <PinnedEventsPanel room={this.state.room} onCancelClick={this.onPinnedClick} />;
|
||||
|
||||
@@ -64,6 +64,7 @@ const SIMPLE_SETTINGS = [
|
||||
{ id: "urlPreviewsEnabled" },
|
||||
{ id: "autoplayGifsAndVideos" },
|
||||
{ id: "alwaysShowEncryptionIcons" },
|
||||
{ id: "showRoomRecoveryReminder" },
|
||||
{ id: "hideReadReceipts" },
|
||||
{ id: "dontSendTypingNotifications" },
|
||||
{ id: "alwaysShowTimestamps" },
|
||||
|
||||
@@ -35,19 +35,10 @@ export default class DeactivateAccountDialog extends React.Component {
|
||||
this._onPasswordFieldChange = this._onPasswordFieldChange.bind(this);
|
||||
this._onEraseFieldChange = this._onEraseFieldChange.bind(this);
|
||||
|
||||
const deactivationPreferences =
|
||||
MatrixClientPeg.get().getAccountData('im.riot.account_deactivation_preferences');
|
||||
|
||||
const shouldErase = (
|
||||
deactivationPreferences &&
|
||||
deactivationPreferences.getContent() &&
|
||||
deactivationPreferences.getContent().shouldErase
|
||||
) || false;
|
||||
|
||||
this.state = {
|
||||
confirmButtonEnabled: false,
|
||||
busy: false,
|
||||
shouldErase,
|
||||
shouldErase: false,
|
||||
errStr: null,
|
||||
};
|
||||
}
|
||||
@@ -67,36 +58,6 @@ export default class DeactivateAccountDialog extends React.Component {
|
||||
async _onOk() {
|
||||
this.setState({busy: true});
|
||||
|
||||
// Before we deactivate the account insert an event into
|
||||
// the user's account data indicating that they wish to be
|
||||
// erased from the homeserver.
|
||||
//
|
||||
// We do this because the API for erasing after deactivation
|
||||
// might not be supported by the connected homeserver. Leaving
|
||||
// an indication in account data is only best-effort, and
|
||||
// in the worse case, the HS maintainer would have to run a
|
||||
// script to erase deactivated accounts that have shouldErase
|
||||
// set to true in im.riot.account_deactivation_preferences.
|
||||
//
|
||||
// Note: The preferences are scoped to Riot, hence the
|
||||
// "im.riot..." event type.
|
||||
//
|
||||
// Note: This may have already been set on previous attempts
|
||||
// where, for example, the user entered the wrong password.
|
||||
// This is fine because the UI always indicates the preference
|
||||
// prior to us calling `deactivateAccount`.
|
||||
try {
|
||||
await MatrixClientPeg.get().setAccountData('im.riot.account_deactivation_preferences', {
|
||||
shouldErase: this.state.shouldErase,
|
||||
});
|
||||
} catch (err) {
|
||||
this.setState({
|
||||
busy: false,
|
||||
errStr: _t('Failed to indicate account erasure'),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// This assumes that the HS requires password UI auth
|
||||
// for this endpoint. In reality it could be any UI auth.
|
||||
|
||||
@@ -71,6 +71,7 @@ module.exports = React.createClass({
|
||||
isLoadingLeftRooms: false,
|
||||
totalRoomCount: null,
|
||||
lists: {},
|
||||
incomingCallTag: null,
|
||||
incomingCall: null,
|
||||
selectedTags: [],
|
||||
};
|
||||
@@ -155,11 +156,13 @@ module.exports = React.createClass({
|
||||
if (call && call.call_state === 'ringing') {
|
||||
this.setState({
|
||||
incomingCall: call,
|
||||
incomingCallTag: this.getTagNameForRoomId(payload.room_id),
|
||||
});
|
||||
this._repositionIncomingCallBox(undefined, true);
|
||||
} else {
|
||||
this.setState({
|
||||
incomingCall: null,
|
||||
incomingCallTag: null,
|
||||
});
|
||||
}
|
||||
break;
|
||||
@@ -328,6 +331,26 @@ module.exports = React.createClass({
|
||||
// this._lastRefreshRoomListTs = Date.now();
|
||||
},
|
||||
|
||||
getTagNameForRoomId: function(roomId) {
|
||||
const lists = RoomListStore.getRoomLists();
|
||||
for (const tagName of Object.keys(lists)) {
|
||||
for (const room of lists[tagName]) {
|
||||
// Should be impossible, but guard anyways.
|
||||
if (!room) {
|
||||
continue;
|
||||
}
|
||||
const myUserId = MatrixClientPeg.get().getUserId();
|
||||
if (HIDE_CONFERENCE_CHANS && Rooms.isConfCallRoom(room, myUserId, this.props.ConferenceHandler)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (room.roomId === roomId) return tagName;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
getRoomLists: function() {
|
||||
const lists = RoomListStore.getRoomLists();
|
||||
|
||||
@@ -621,6 +644,12 @@ module.exports = React.createClass({
|
||||
// so checking on every render is the sanest thing at this time.
|
||||
const showEmpty = SettingsStore.getValue('RoomSubList.showEmpty');
|
||||
|
||||
const incomingCallIfTaggedAs = (tagName) => {
|
||||
if (!this.state.incomingCall) return null;
|
||||
if (this.state.incomingCallTag !== tagName) return null;
|
||||
return this.state.incomingCall;
|
||||
};
|
||||
|
||||
const self = this;
|
||||
return (
|
||||
<GeminiScrollbarWrapper className="mx_RoomList_scrollbar"
|
||||
@@ -644,7 +673,7 @@ module.exports = React.createClass({
|
||||
editable={false}
|
||||
order="recent"
|
||||
isInvite={true}
|
||||
incomingCall={self.state.incomingCall}
|
||||
incomingCall={incomingCallIfTaggedAs('im.vector.fake.invite')}
|
||||
collapsed={self.props.collapsed}
|
||||
searchFilter={self.props.searchFilter}
|
||||
onHeaderClick={self.onSubListHeaderClick}
|
||||
@@ -658,7 +687,7 @@ module.exports = React.createClass({
|
||||
emptyContent={this._getEmptyContent('m.favourite')}
|
||||
editable={true}
|
||||
order="manual"
|
||||
incomingCall={self.state.incomingCall}
|
||||
incomingCall={incomingCallIfTaggedAs('m.favourite')}
|
||||
collapsed={self.props.collapsed}
|
||||
searchFilter={self.props.searchFilter}
|
||||
onHeaderClick={self.onSubListHeaderClick}
|
||||
@@ -672,7 +701,7 @@ module.exports = React.createClass({
|
||||
headerItems={this._getHeaderItems('im.vector.fake.direct')}
|
||||
editable={true}
|
||||
order="recent"
|
||||
incomingCall={self.state.incomingCall}
|
||||
incomingCall={incomingCallIfTaggedAs('im.vector.fake.direct')}
|
||||
collapsed={self.props.collapsed}
|
||||
alwaysShowHeader={true}
|
||||
searchFilter={self.props.searchFilter}
|
||||
@@ -686,7 +715,7 @@ module.exports = React.createClass({
|
||||
emptyContent={this._getEmptyContent('im.vector.fake.recent')}
|
||||
headerItems={this._getHeaderItems('im.vector.fake.recent')}
|
||||
order="recent"
|
||||
incomingCall={self.state.incomingCall}
|
||||
incomingCall={incomingCallIfTaggedAs('im.vector.fake.recent')}
|
||||
collapsed={self.props.collapsed}
|
||||
searchFilter={self.props.searchFilter}
|
||||
onHeaderClick={self.onSubListHeaderClick}
|
||||
@@ -702,7 +731,7 @@ module.exports = React.createClass({
|
||||
emptyContent={this._getEmptyContent(tagName)}
|
||||
editable={true}
|
||||
order="manual"
|
||||
incomingCall={self.state.incomingCall}
|
||||
incomingCall={incomingCallIfTaggedAs(tagName)}
|
||||
collapsed={self.props.collapsed}
|
||||
searchFilter={self.props.searchFilter}
|
||||
onHeaderClick={self.onSubListHeaderClick}
|
||||
@@ -717,7 +746,7 @@ module.exports = React.createClass({
|
||||
emptyContent={this._getEmptyContent('m.lowpriority')}
|
||||
editable={true}
|
||||
order="recent"
|
||||
incomingCall={self.state.incomingCall}
|
||||
incomingCall={incomingCallIfTaggedAs('m.lowpriority')}
|
||||
collapsed={self.props.collapsed}
|
||||
searchFilter={self.props.searchFilter}
|
||||
onHeaderClick={self.onSubListHeaderClick}
|
||||
@@ -740,7 +769,7 @@ module.exports = React.createClass({
|
||||
startAsHidden={true}
|
||||
showSpinner={self.state.isLoadingLeftRooms}
|
||||
onHeaderClick={self.onArchivedHeaderClick}
|
||||
incomingCall={self.state.incomingCall}
|
||||
incomingCall={incomingCallIfTaggedAs('im.vector.fake.archived')}
|
||||
searchFilter={self.props.searchFilter}
|
||||
onShowMoreRooms={self.onShowMoreRooms}
|
||||
showEmpty={showEmpty} />
|
||||
@@ -750,7 +779,7 @@ module.exports = React.createClass({
|
||||
tagName="m.lowpriority"
|
||||
editable={false}
|
||||
order="recent"
|
||||
incomingCall={self.state.incomingCall}
|
||||
incomingCall={incomingCallIfTaggedAs('m.server_notice')}
|
||||
collapsed={self.props.collapsed}
|
||||
searchFilter={self.props.searchFilter}
|
||||
onHeaderClick={self.onSubListHeaderClick}
|
||||
|
||||
85
src/components/views/rooms/RoomRecoveryReminder.js
Normal file
85
src/components/views/rooms/RoomRecoveryReminder.js
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright 2018 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 sdk from "../../../index";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import Modal from "../../../Modal";
|
||||
|
||||
export default class RoomRecoveryReminder extends React.PureComponent {
|
||||
static propTypes = {
|
||||
onFinished: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
showKeyBackupDialog = () => {
|
||||
Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
|
||||
import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"),
|
||||
{
|
||||
onFinished: this.props.onFinished,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onDontAskAgainClick = () => {
|
||||
// When you choose "Don't ask again" from the room reminder, we show a
|
||||
// dialog to confirm the choice.
|
||||
Modal.createTrackedDialogAsync("Ignore Recovery Reminder", "Ignore Recovery Reminder",
|
||||
import("../../../async-components/views/dialogs/keybackup/IgnoreRecoveryReminderDialog"),
|
||||
{
|
||||
onDontAskAgain: () => {
|
||||
// Report false to the caller, who should prevent the
|
||||
// reminder from appearing in the future.
|
||||
this.props.onFinished(false);
|
||||
},
|
||||
onSetup: () => {
|
||||
this.showKeyBackupDialog();
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onSetupClick = () => {
|
||||
this.showKeyBackupDialog();
|
||||
}
|
||||
|
||||
render() {
|
||||
const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton");
|
||||
|
||||
return (
|
||||
<div className="mx_RoomRecoveryReminder">
|
||||
<div className="mx_RoomRecoveryReminder_header">{_t(
|
||||
"Secure Message Recovery",
|
||||
)}</div>
|
||||
<div className="mx_RoomRecoveryReminder_body">{_t(
|
||||
"If you log out or use another device, you'll lose your " +
|
||||
"secure message history. To prevent this, set up Secure " +
|
||||
"Message Recovery.",
|
||||
)}</div>
|
||||
<div className="mx_RoomRecoveryReminder_buttons">
|
||||
<AccessibleButton className="mx_RoomRecoveryReminder_button mx_RoomRecoveryReminder_secondary"
|
||||
onClick={this.onDontAskAgainClick}>
|
||||
{ _t("Don't ask again") }
|
||||
</AccessibleButton>
|
||||
<AccessibleButton className="mx_RoomRecoveryReminder_button"
|
||||
onClick={this.onSetupClick}>
|
||||
{ _t("Set up") }
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user