Merge branch 'experimental' into bwindels/smarterresizer

This commit is contained in:
Bruno Windels 2019-01-15 10:23:50 +01:00
commit 1bbf1502ec
62 changed files with 1703 additions and 420 deletions

View file

@ -24,6 +24,8 @@ import ObjectUtils from '../../../ObjectUtils';
import AppsDrawer from './AppsDrawer';
import { _t } from '../../../languageHandler';
import classNames from 'classnames';
import RateLimitedFunc from '../../../ratelimitedfunc';
import SettingsStore from "../../../settings/SettingsStore";
module.exports = React.createClass({
@ -60,6 +62,22 @@ module.exports = React.createClass({
hideAppsDrawer: false,
},
getInitialState: function() {
return { counters: this._computeCounters() };
},
componentDidMount: function() {
const cli = MatrixClientPeg.get();
cli.on("RoomState.events", this._rateLimitedUpdate);
},
componentWillUnmount: function() {
const cli = MatrixClientPeg.get();
if (cli) {
cli.removeListener("RoomState.events", this._rateLimitedUpdate);
}
},
shouldComponentUpdate: function(nextProps, nextState) {
return (!ObjectUtils.shallowEqual(this.props, nextProps) ||
!ObjectUtils.shallowEqual(this.state, nextState));
@ -82,6 +100,43 @@ module.exports = React.createClass({
ev.preventDefault();
},
_rateLimitedUpdate: new RateLimitedFunc(function() {
if (SettingsStore.isFeatureEnabled("feature_state_counters")) {
this.setState({counters: this._computeCounters()});
}
}, 500),
_computeCounters: function() {
let counters = [];
if (this.props.room && SettingsStore.isFeatureEnabled("feature_state_counters")) {
const stateEvs = this.props.room.currentState.getStateEvents('re.jki.counter');
stateEvs.sort((a, b) => {
return a.getStateKey() < b.getStateKey();
});
stateEvs.forEach((ev, idx) => {
const title = ev.getContent().title;
const value = ev.getContent().value;
const link = ev.getContent().link;
const severity = ev.getContent().severity || "normal";
const stateKey = ev.getStateKey();
if (title && value && severity) {
counters.push({
"title": title,
"value": value,
"link": link,
"severity": severity,
"stateKey": stateKey
})
}
});
}
return counters;
},
render: function() {
const CallView = sdk.getComponent("voip.CallView");
const TintableSvg = sdk.getComponent("elements.TintableSvg");
@ -145,6 +200,58 @@ module.exports = React.createClass({
hide={this.props.hideAppsDrawer}
/>;
let stateViews = null;
if (this.state.counters && SettingsStore.isFeatureEnabled("feature_state_counters")) {
let counters = [];
this.state.counters.forEach((counter, idx) => {
const title = counter.title;
const value = counter.value;
const link = counter.link;
const severity = counter.severity;
const stateKey = counter.stateKey;
if (title && value && severity) {
let span = <span>{ title }: { value }</span>
if (link) {
span = (
<a href={link} target="_blank" rel="noopener">
{ span }
</a>
);
}
span = (
<span
className="m_RoomView_auxPanel_stateViews_span"
data-severity={severity}
key={ "x-" + stateKey }
>
{span}
</span>
);
counters.push(span);
counters.push(
<span
className="m_RoomView_auxPanel_stateViews_delim"
key={"delim" + idx}
> </span>
);
}
});
if (counters.length > 0) {
counters.pop(); // remove last deliminator
stateViews = (
<div className="m_RoomView_auxPanel_stateViews">
{ counters }
</div>
);
}
}
const classes = classNames({
"mx_RoomView_auxPanel": true,
"mx_RoomView_auxPanel_fullHeight": this.props.fullHeight,
@ -156,6 +263,7 @@ module.exports = React.createClass({
return (
<div className={classes} style={style} >
{ stateViews }
{ appsDrawer }
{ fileDropTarget }
{ callView }

View file

@ -62,6 +62,7 @@ const stateEventTileTypes = {
'm.room.pinned_events': 'messages.TextualEvent',
'm.room.server_acl': 'messages.TextualEvent',
'im.vector.modular.widgets': 'messages.TextualEvent',
'm.room.tombstone': 'messages.TextualEvent',
};
function getHandlerTile(ev) {

View file

@ -39,7 +39,6 @@ import Unread from '../../../Unread';
import { findReadReceiptFromUserId } from '../../../utils/Receipt';
import withMatrixClient from '../../../wrappers/withMatrixClient';
import AccessibleButton from '../elements/AccessibleButton';
import RoomViewStore from '../../../stores/RoomViewStore';
import SdkConfig from '../../../SdkConfig';
import MultiInviter from "../../../utils/MultiInviter";
import SettingsStore from "../../../settings/SettingsStore";
@ -50,6 +49,7 @@ module.exports = withMatrixClient(React.createClass({
propTypes: {
matrixClient: PropTypes.object.isRequired,
member: PropTypes.object.isRequired,
roomId: PropTypes.string,
},
getInitialState: function() {
@ -713,8 +713,8 @@ module.exports = withMatrixClient(React.createClass({
}
if (!member || !member.membership || member.membership === 'leave') {
const roomId = member && member.roomId ? member.roomId : RoomViewStore.getRoomId();
const onInviteUserButton = async() => {
const roomId = member && member.roomId ? member.roomId : this.props.roomId;
const onInviteUserButton = async () => {
try {
// We use a MultiInviter to re-use the invite logic, even though
// we're only inviting one user.

View file

@ -22,7 +22,6 @@ import MatrixClientPeg from '../../../MatrixClientPeg';
import Modal from '../../../Modal';
import sdk from '../../../index';
import dis from '../../../dispatcher';
import RoomViewStore from '../../../stores/RoomViewStore';
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
import Stickerpicker from './Stickerpicker';
import { makeRoomPermalink } from '../../../matrix-to';
@ -63,7 +62,7 @@ export default class MessageComposer extends React.Component {
isRichTextEnabled: SettingsStore.getValue('MessageComposerInput.isRichTextEnabled'),
},
showFormatting: SettingsStore.getValue('MessageComposer.showFormatting'),
isQuoting: Boolean(RoomViewStore.getQuotingEvent()),
isQuoting: Boolean(this.props.roomViewStore.getQuotingEvent()),
tombstone: this._getRoomTombstone(),
};
}
@ -75,7 +74,7 @@ export default class MessageComposer extends React.Component {
// XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something.
MatrixClientPeg.get().on("event", this.onEvent);
MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents);
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate);
this._waitForOwnMember();
}
@ -124,14 +123,14 @@ export default class MessageComposer extends React.Component {
}
_onRoomViewStoreUpdate() {
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
const isQuoting = Boolean(this.props.roomViewStore.getQuotingEvent());
if (this.state.isQuoting === isQuoting) return;
this.setState({ isQuoting });
}
onUploadClick(ev) {
if (MatrixClientPeg.get().isGuest()) {
dis.dispatch({action: 'require_registration'});
this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'});
return;
}
@ -165,7 +164,7 @@ export default class MessageComposer extends React.Component {
}
}
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
const isQuoting = Boolean(this.props.roomViewStore.getQuotingEvent());
let replyToWarning = null;
if (isQuoting) {
replyToWarning = <p>{
@ -229,7 +228,7 @@ export default class MessageComposer extends React.Component {
if (!call) {
return;
}
dis.dispatch({
this.props.roomViewStore.getDispatcher().dispatch({
action: 'hangup',
// hangup the call for this room, which may not be the room in props
// (e.g. conferences which will hangup the 1:1 room instead)
@ -238,7 +237,7 @@ export default class MessageComposer extends React.Component {
}
onCallClick(ev) {
dis.dispatch({
this.props.roomViewStore.getDispatcher().dispatch({
action: 'place_call',
type: ev.shiftKey ? "screensharing" : "video",
room_id: this.props.room.roomId,
@ -246,7 +245,7 @@ export default class MessageComposer extends React.Component {
}
onVoiceCallClick(ev) {
dis.dispatch({
this.props.roomViewStore.getDispatcher().dispatch({
action: 'place_call',
type: "voice",
room_id: this.props.room.roomId,
@ -282,10 +281,22 @@ export default class MessageComposer extends React.Component {
ev.preventDefault();
const replacementRoomId = this.state.tombstone.getContent()['replacement_room'];
dis.dispatch({
const replacementRoom = MatrixClientPeg.get().getRoom(replacementRoomId);
let createEventId = null;
if (replacementRoom) {
const createEvent = replacementRoom.currentState.getStateEvents('m.room.create', '');
if (createEvent && createEvent.getId()) createEventId = createEvent.getId();
}
this.props.roomViewStore.getDispatcher().dispatch({
action: 'view_room',
highlighted: true,
event_id: createEventId,
room_id: replacementRoomId,
// Try to join via the server that sent the event. This converts $something:example.org
// into a server domain by splitting on colons and ignoring the first entry ("$something").
via_servers: [this.state.tombstone.getId().split(':').splice(1).join(':')],
});
}
@ -421,8 +432,10 @@ export default class MessageComposer extends React.Component {
controls.push(
<MessageComposerInput
roomViewStore={this.props.roomViewStore}
ref={(c) => this.messageComposerInput = c}
key="controls_input"
isGrid={this.props.isGrid}
onResize={this.props.onResize}
room={this.props.room}
placeholder={placeholderText}
@ -529,5 +542,6 @@ MessageComposer.propTypes = {
uploadAllowed: PropTypes.func.isRequired,
// string representing the current room app drawer state
showApps: PropTypes.bool
showApps: PropTypes.bool,
roomViewStore: PropTypes.object.isRequired,
};

View file

@ -15,13 +15,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import type SyntheticKeyboardEvent from 'react/lib/SyntheticKeyboardEvent';
import { Editor } from 'slate-react';
import { getEventTransfer } from 'slate-react';
import { Value, Document, Block, Inline, Text, Range, Node } from 'slate';
import { Value, Block, Inline, Range } from 'slate';
import type { Change } from 'slate';
import Html from 'slate-html-serializer';
@ -30,7 +28,6 @@ import Plain from 'slate-plain-serializer';
import PlainWithPillsSerializer from "../../../autocomplete/PlainWithPillsSerializer";
import classNames from 'classnames';
import Promise from 'bluebird';
import MatrixClientPeg from '../../../MatrixClientPeg';
import type {MatrixClient} from 'matrix-js-sdk/lib/matrix';
@ -38,11 +35,9 @@ import {processCommandInput} from '../../../SlashCommands';
import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../../Keyboard';
import Modal from '../../../Modal';
import sdk from '../../../index';
import { _t, _td } from '../../../languageHandler';
import { _t } from '../../../languageHandler';
import Analytics from '../../../Analytics';
import dis from '../../../dispatcher';
import * as RichText from '../../../RichText';
import * as HtmlUtils from '../../../HtmlUtils';
import Autocomplete from './Autocomplete';
@ -51,28 +46,24 @@ import Markdown from '../../../Markdown';
import ComposerHistoryManager from '../../../ComposerHistoryManager';
import MessageComposerStore from '../../../stores/MessageComposerStore';
import {MATRIXTO_MD_LINK_PATTERN, MATRIXTO_URL_PATTERN} from '../../../linkify-matrix';
const REGEX_MATRIXTO_MARKDOWN_GLOBAL = new RegExp(MATRIXTO_MD_LINK_PATTERN, 'g');
import {MATRIXTO_URL_PATTERN} from '../../../linkify-matrix';
import {asciiRegexp, unicodeRegexp, shortnameToUnicode, emojioneList, asciiList, mapUnicodeToShort, toShort} from 'emojione';
import {
asciiRegexp, unicodeRegexp, shortnameToUnicode,
asciiList, mapUnicodeToShort, toShort,
} from 'emojione';
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
import {makeUserPermalink} from "../../../matrix-to";
import ReplyPreview from "./ReplyPreview";
import RoomViewStore from '../../../stores/RoomViewStore';
import ReplyThread from "../elements/ReplyThread";
import {ContentHelpers} from 'matrix-js-sdk';
const EMOJI_SHORTNAMES = Object.keys(emojioneList);
const EMOJI_UNICODE_TO_SHORTNAME = mapUnicodeToShort();
const REGEX_EMOJI_WHITESPACE = new RegExp('(?:^|\\s)(' + asciiRegexp + ')\\s$');
const EMOJI_REGEX = new RegExp(unicodeRegexp, 'g');
const TYPING_USER_TIMEOUT = 10000; const TYPING_SERVER_TIMEOUT = 30000;
const ENTITY_TYPES = {
AT_ROOM_PILL: 'ATROOMPILL',
};
// the Slate node type to default to for unstyled text
const DEFAULT_NODE = 'paragraph';
@ -117,15 +108,6 @@ const SLATE_SCHEMA = {
},
};
function onSendMessageFailed(err, room) {
// XXX: temporary logging to try to diagnose
// https://github.com/vector-im/riot-web/issues/3148
console.log('MessageComposer got send failure: ' + err.name + '('+err+')');
dis.dispatch({
action: 'message_send_failed',
});
}
function rangeEquals(a: Range, b: Range): boolean {
return (a.anchor.key === b.anchor.key
&& a.anchor.offset === b.anchorOffset
@ -135,6 +117,18 @@ function rangeEquals(a: Range, b: Range): boolean {
&& a.isBackward === b.isBackward);
}
class NoopHistoryManager {
getItem() {}
save() {}
get currentIndex() { return 0; }
set currentIndex(_) {}
get history() { return []; }
set history(_) {}
}
/*
* The textInput part of the MessageComposer
*/
@ -150,6 +144,7 @@ export default class MessageComposerInput extends React.Component {
onFilesPasted: PropTypes.func,
onInputStateChanged: PropTypes.func,
roomViewStore: PropTypes.object.isRequired,
};
client: MatrixClient;
@ -344,20 +339,32 @@ export default class MessageComposerInput extends React.Component {
}
componentWillMount() {
this.dispatcherRef = dis.register(this.onAction);
this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_');
this.dispatcherRef = this.props.roomViewStore.getDispatcher().register(this.onAction);
if (this.props.isGrid) {
this.historyManager = new NoopHistoryManager();
} else {
this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_');
}
}
componentWillUnmount() {
dis.unregister(this.dispatcherRef);
this.props.roomViewStore.getDispatcher().unregister(this.dispatcherRef);
}
_collectEditor = (e) => {
this._editor = e;
}
onSendMessageFailed = (err, room) => {
// XXX: temporary logging to try to diagnose
// https://github.com/vector-im/riot-web/issues/3148
console.log('MessageComposer got send failure: ' + err.name + '('+err+')');
this.props.roomViewStore.getDispatcher().dispatch({
action: 'message_send_failed',
});
}
onAction = (payload) => {
const editor = this._editor;
const editorState = this.state.editorState;
switch (payload.action) {
@ -854,7 +861,7 @@ export default class MessageComposerInput extends React.Component {
return true;
}
const newState: ?Value = null;
//const newState: ?Value = null;
// Draft handles rich text mode commands by default but we need to do it ourselves for Markdown.
if (this.state.isRichTextEnabled) {
@ -1105,7 +1112,9 @@ export default class MessageComposerInput extends React.Component {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createTrackedDialog('Server error', '', ErrorDialog, {
title: _t("Server error"),
description: ((err && err.message) ? err.message : _t("Server unavailable, overloaded, or something else went wrong.")),
description: ((err && err.message) ? err.message : _t(
"Server unavailable, overloaded, or something else went wrong.",
)),
});
});
} else if (cmd.error) {
@ -1120,7 +1129,7 @@ export default class MessageComposerInput extends React.Component {
return true;
}
const replyingToEv = RoomViewStore.getQuotingEvent();
const replyingToEv = this.props.roomViewStore.getQuotingEvent();
const mustSendHTML = Boolean(replyingToEv);
if (this.state.isRichTextEnabled) {
@ -1208,18 +1217,18 @@ export default class MessageComposerInput extends React.Component {
// Clear reply_to_event as we put the message into the queue
// if the send fails, retry will handle resending.
dis.dispatch({
this.props.roomViewStore.getDispatcher().dispatch({
action: 'reply_to_event',
event: null,
});
}
this.client.sendMessage(this.props.room.roomId, content).then((res) => {
dis.dispatch({
this.props.roomViewStore.getDispatcher().dispatch({
action: 'message_sent',
});
}).catch((e) => {
onSendMessageFailed(e, this.props.room);
this.onSendMessageFailed(e, this.props.room);
});
this.setState({
@ -1260,7 +1269,7 @@ export default class MessageComposerInput extends React.Component {
}
};
selectHistory = async(up) => {
selectHistory = async (up) => {
const delta = up ? -1 : 1;
// True if we are not currently selecting history, but composing a message
@ -1308,7 +1317,7 @@ export default class MessageComposerInput extends React.Component {
return true;
};
onTab = async(e) => {
onTab = async (e) => {
this.setState({
someCompletions: null,
});
@ -1330,7 +1339,7 @@ export default class MessageComposerInput extends React.Component {
up ? this.autocomplete.onUpArrow() : this.autocomplete.onDownArrow();
};
onEscape = async(e) => {
onEscape = async (e) => {
e.preventDefault();
if (this.autocomplete) {
this.autocomplete.onEscape(e);
@ -1349,7 +1358,7 @@ export default class MessageComposerInput extends React.Component {
/* If passed null, restores the original editor content from state.originalEditorState.
* If passed a non-null displayedCompletion, modifies state.originalEditorState to compute new state.editorState.
*/
setDisplayedCompletion = async(displayedCompletion: ?Completion): boolean => {
setDisplayedCompletion = async (displayedCompletion: ?Completion): boolean => {
const activeEditorState = this.state.originalEditorState || this.state.editorState;
if (displayedCompletion == null) {
@ -1484,7 +1493,9 @@ export default class MessageComposerInput extends React.Component {
});
const style = {};
if (props.selected) style.border = '1px solid blue';
return <img className={ className } src={ uri } title={ shortname } alt={ emojiUnicode } style={style} />;
return <img className={ className } src={ uri }
title={ shortname } alt={ emojiUnicode } style={style}
/>;
}
}
};
@ -1538,7 +1549,6 @@ export default class MessageComposerInput extends React.Component {
getSelectionRange(editorState: Value) {
let beginning = false;
const query = this.getAutocompleteQuery(editorState);
const firstChild = editorState.document.nodes.get(0);
const firstGrandChild = firstChild && firstChild.nodes.get(0);
beginning = (firstChild && firstGrandChild &&
@ -1589,7 +1599,7 @@ export default class MessageComposerInput extends React.Component {
return (
<div className="mx_MessageComposer_input_wrapper" onClick={this.focusComposer}>
<div className="mx_MessageComposer_autocomplete_wrapper">
<ReplyPreview />
<ReplyPreview roomViewStore={this.props.roomViewStore} />
<Autocomplete
ref={(e) => this.autocomplete = e}
room={this.props.room}

View file

@ -18,7 +18,6 @@ import React from 'react';
import dis from '../../../dispatcher';
import sdk from '../../../index';
import { _t } from '../../../languageHandler';
import RoomViewStore from '../../../stores/RoomViewStore';
import SettingsStore from "../../../settings/SettingsStore";
function cancelQuoting() {
@ -38,7 +37,7 @@ export default class ReplyPreview extends React.Component {
this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this);
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate);
this._onRoomViewStoreUpdate();
}
@ -50,7 +49,7 @@ export default class ReplyPreview extends React.Component {
}
_onRoomViewStoreUpdate() {
const event = RoomViewStore.getQuotingEvent();
const event = this.props.roomViewStore.getQuotingEvent();
if (this.state.event !== event) {
this.setState({ event });
}

View file

@ -24,6 +24,7 @@ import { _t } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import Modal from "../../../Modal";
import RateLimitedFunc from '../../../ratelimitedfunc';
import dis from '../../../dispatcher';
import * as linkify from 'linkifyjs';
import linkifyElement from 'linkifyjs/element';
@ -152,6 +153,14 @@ module.exports = React.createClass({
});
},
onToggleRightPanelClick: function(ev) {
if (this.props.collapsedRhs) {
dis.dispatch({action: "show_right_panel"});
} else {
dis.dispatch({action: "hide_right_panel"});
}
},
_hasUnreadPins: function() {
const currentPinEvent = this.props.room.currentState.getStateEvents("m.room.pinned_events", '');
if (!currentPinEvent) return false;
@ -409,6 +418,17 @@ module.exports = React.createClass({
</div>;
}
let toggleRightPanelButton;
if (this.props.isGrid) {
toggleRightPanelButton =
<AccessibleButton
className="mx_RoomHeader_button"
onClick={this.onToggleRightPanelClick}
title={_t('Toggle right panel')}>
<TintableSvg src="img/feather-icons/toggle-right-panel.svg" width="20" height="20" />
</AccessibleButton>;
}
return (
<div className={"mx_RoomHeader light-panel " + (this.props.editing ? "mx_RoomHeader_editing" : "")}>
<div className="mx_RoomHeader_wrapper">
@ -419,7 +439,8 @@ module.exports = React.createClass({
{ saveButton }
{ cancelButton }
{ rightRow }
<RoomHeaderButtons collapsedRhs={this.props.collapsedRhs} />
{ !this.props.isGrid ? <RoomHeaderButtons collapsedRhs={this.props.collapsedRhs} /> : undefined }
{ toggleRightPanelButton }
</div>
</div>
);

View file

@ -102,6 +102,7 @@ module.exports = React.createClass({
cli.on("Event.decrypted", this.onEventDecrypted);
cli.on("accountData", this.onAccountData);
cli.on("Group.myMembership", this._onGroupMyMembership);
cli.on("RoomState.events", this.onRoomStateEvents);
const dmRoomMap = DMRoomMap.shared();
// A map between tags which are group IDs and the room IDs of rooms that should be kept
@ -230,6 +231,7 @@ module.exports = React.createClass({
MatrixClientPeg.get().removeListener("Event.decrypted", this.onEventDecrypted);
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
MatrixClientPeg.get().removeListener("Group.myMembership", this._onGroupMyMembership);
MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents);
}
if (this._tagStoreToken) {
@ -253,6 +255,12 @@ module.exports = React.createClass({
this.updateVisibleRooms();
},
onRoomStateEvents: function(ev, state) {
if (ev.getType() === "m.room.create" || ev.getType() === "m.room.tombstone") {
this.updateVisibleRooms();
}
},
onDeleteRoom: function(roomId) {
this.updateVisibleRooms();
},

View file

@ -1,5 +1,5 @@
/*
Copyright 2018 New Vector Ltd
Copyright 2018, 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.
@ -20,10 +20,16 @@ import sdk from "../../../index";
import { _t } from "../../../languageHandler";
import Modal from "../../../Modal";
import MatrixClientPeg from "../../../MatrixClientPeg";
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
export default class RoomRecoveryReminder extends React.PureComponent {
static propTypes = {
onFinished: PropTypes.func.isRequired,
// called if the user sets the option to suppress this reminder in the future
onDontAskAgainSet: PropTypes.func,
}
static defaultProps = {
onDontAskAgainSet: function() {},
}
constructor(props) {
@ -82,7 +88,6 @@ export default class RoomRecoveryReminder extends React.PureComponent {
Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, {
userId: MatrixClientPeg.get().credentials.userId,
device: this.state.unverifiedDevice,
onFinished: this.props.onFinished,
});
return;
}
@ -91,9 +96,6 @@ export default class RoomRecoveryReminder extends React.PureComponent {
// we'll show the create key backup flow.
Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"),
{
onFinished: this.props.onFinished,
},
);
}
@ -103,10 +105,14 @@ export default class RoomRecoveryReminder extends React.PureComponent {
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);
onDontAskAgain: async () => {
await SettingsStore.setValue(
"showRoomRecoveryReminder",
null,
SettingLevel.ACCOUNT,
false,
);
this.props.onDontAskAgainSet();
},
onSetup: () => {
this.showSetupDialog();

View file

@ -29,7 +29,6 @@ import * as RoomNotifs from '../../../RoomNotifs';
import * as FormattingUtils from '../../../utils/FormattingUtils';
import AccessibleButton from '../elements/AccessibleButton';
import ActiveRoomObserver from '../../../ActiveRoomObserver';
import RoomViewStore from '../../../stores/RoomViewStore';
import SettingsStore from "../../../settings/SettingsStore";
module.exports = React.createClass({
@ -62,7 +61,7 @@ module.exports = React.createClass({
roomName: this.props.room.name,
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
notificationCount: this.props.room.getUnreadNotificationCount(),
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
selected: this.props.room.roomId === ActiveRoomObserver.getActiveRoomId(),
});
},
@ -117,9 +116,9 @@ module.exports = React.createClass({
}
},
_onActiveRoomChange: function() {
_onActiveRoomChange: function(activeRoomId) {
this.setState({
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
selected: this.props.room.roomId === activeRoomId,
});
},