Add a ToastStore
To store toast. Rather than them being stored in the state of the ToastContainer component, they now have a dedicated store. This mostly fixes problems involving showing toasts when the app loaded because we would otherwise have a race condition where something tries to show a toast before the ToastContainer is mounted.
This commit is contained in:
parent
3ed7beac78
commit
83b1505401
4 changed files with 71 additions and 31 deletions
|
@ -64,6 +64,7 @@ import { ThemeWatcher } from "../../theme";
|
|||
import { storeRoomAliasInCache } from '../../RoomAliasCache';
|
||||
import { defer } from "../../utils/promise";
|
||||
import KeyVerificationStateObserver from '../../utils/KeyVerificationStateObserver';
|
||||
import ToastStore from "../../stores/ToastStore";
|
||||
|
||||
/** constants for MatrixChat.state.view */
|
||||
export const VIEWS = {
|
||||
|
@ -1458,15 +1459,12 @@ export default createReactClass({
|
|||
}
|
||||
|
||||
if (!requestObserver || requestObserver.pending) {
|
||||
dis.dispatch({
|
||||
action: "show_toast",
|
||||
toast: {
|
||||
key: request.event.getId(),
|
||||
title: _t("Verification Request"),
|
||||
icon: "verification",
|
||||
props: {request, requestObserver},
|
||||
component: sdk.getComponent("toasts.VerificationRequestToast"),
|
||||
},
|
||||
ToastStore.sharedInstance().addOrReplaceToast({
|
||||
key: 'verifreq_' + request.event.getId(),
|
||||
title: _t("Verification Request"),
|
||||
icon: "verification",
|
||||
props: {request, requestObserver},
|
||||
component: sdk.getComponent("toasts.VerificationRequestToast"),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -15,8 +15,8 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import dis from "../../dispatcher";
|
||||
import { _t } from '../../languageHandler';
|
||||
import ToastStore from "../../stores/ToastStore";
|
||||
import classNames from "classnames";
|
||||
|
||||
export default class ToastContainer extends React.Component {
|
||||
|
@ -26,26 +26,15 @@ export default class ToastContainer extends React.Component {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._dispatcherRef = dis.register(this.onAction);
|
||||
ToastStore.sharedInstance().on('update', this._onToastStoreUpdate);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
dis.unregister(this._dispatcherRef);
|
||||
ToastStore.sharedInstance().removeListener('update', this._onToastStoreUpdate);
|
||||
}
|
||||
|
||||
onAction = (payload) => {
|
||||
if (payload.action === "show_toast") {
|
||||
this._addToast(payload.toast);
|
||||
}
|
||||
};
|
||||
|
||||
_addToast(toast) {
|
||||
this.setState({toasts: this.state.toasts.concat(toast)});
|
||||
}
|
||||
|
||||
dismissTopToast = () => {
|
||||
const [, ...remaining] = this.state.toasts;
|
||||
this.setState({toasts: remaining});
|
||||
_onToastStoreUpdate = () => {
|
||||
this.setState({toasts: ToastStore.sharedInstance().getToasts()});
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -62,8 +51,8 @@ export default class ToastContainer extends React.Component {
|
|||
const countIndicator = isStacked ? _t(" (1/%(totalCount)s)", {totalCount}) : null;
|
||||
|
||||
const toastProps = Object.assign({}, props, {
|
||||
dismiss: this.dismissTopToast,
|
||||
key,
|
||||
toastKey: key,
|
||||
});
|
||||
toast = (<div className={toastClasses}>
|
||||
<h2>{title}{countIndicator}</h2>
|
||||
|
|
|
@ -23,6 +23,7 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg';
|
|||
import {verificationMethods} from 'matrix-js-sdk/src/crypto';
|
||||
import KeyVerificationStateObserver, {userLabelForEventRoom} from "../../../utils/KeyVerificationStateObserver";
|
||||
import dis from "../../../dispatcher";
|
||||
import ToastStore from "../../../stores/ToastStore";
|
||||
|
||||
export default class VerificationRequestToast extends React.PureComponent {
|
||||
constructor(props) {
|
||||
|
@ -63,12 +64,12 @@ export default class VerificationRequestToast extends React.PureComponent {
|
|||
|
||||
_checkRequestIsPending = () => {
|
||||
if (!this.props.requestObserver.pending) {
|
||||
this.props.dismiss();
|
||||
ToastStore.sharedInstance().dismissToast(this.props.toastKey);
|
||||
}
|
||||
}
|
||||
|
||||
cancel = () => {
|
||||
this.props.dismiss();
|
||||
ToastStore.sharedInstance().dismissToast(this.props.toastKey);
|
||||
try {
|
||||
this.props.request.cancel();
|
||||
} catch (err) {
|
||||
|
@ -77,7 +78,7 @@ export default class VerificationRequestToast extends React.PureComponent {
|
|||
}
|
||||
|
||||
accept = () => {
|
||||
this.props.dismiss();
|
||||
ToastStore.sharedInstance().dismissToast(this.props.toastKey);
|
||||
const {event} = this.props.request;
|
||||
// no room id for to_device requests
|
||||
if (event.getRoomId()) {
|
||||
|
@ -119,7 +120,7 @@ export default class VerificationRequestToast extends React.PureComponent {
|
|||
}
|
||||
|
||||
VerificationRequestToast.propTypes = {
|
||||
dismiss: PropTypes.func.isRequired,
|
||||
request: PropTypes.object.isRequired,
|
||||
requestObserver: PropTypes.instanceOf(KeyVerificationStateObserver),
|
||||
toastKey: PropTypes.string.isRequired,
|
||||
};
|
||||
|
|
52
src/stores/ToastStore.js
Normal file
52
src/stores/ToastStore.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 EventEmitter from 'events';
|
||||
|
||||
/**
|
||||
* Holds the active toasts
|
||||
*/
|
||||
export default class ToastStore extends EventEmitter {
|
||||
static sharedInstance() {
|
||||
if (!global.mx_ToastStore) global.mx_ToastStore = new ToastStore();
|
||||
return global.mx_ToastStore;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._dispatcherRef = null;
|
||||
this._toasts = [];
|
||||
}
|
||||
|
||||
addOrReplaceToast(newToast) {
|
||||
const oldIndex = this._toasts.findIndex(t => t.key === newToast.key);
|
||||
if (oldIndex === -1) {
|
||||
this._toasts.push(newToast);
|
||||
} else {
|
||||
this._toasts[oldIndex] = newToast;
|
||||
}
|
||||
this.emit('update');
|
||||
}
|
||||
|
||||
dismissToast(key) {
|
||||
this._toasts = this._toasts.filter(t => t.key !== key);
|
||||
this.emit('update');
|
||||
}
|
||||
|
||||
getToasts() {
|
||||
return this._toasts;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue