diff --git a/src/components/structures/EmbeddedPage.js b/src/components/structures/EmbeddedPage.js index ecc01a443d..63767255e2 100644 --- a/src/components/structures/EmbeddedPage.js +++ b/src/components/structures/EmbeddedPage.js @@ -26,8 +26,8 @@ import sanitizeHtml from 'sanitize-html'; import sdk from '../../index'; import dis from '../../dispatcher'; import MatrixClientPeg from '../../MatrixClientPeg'; -import { MatrixClient } from 'matrix-js-sdk'; import classnames from 'classnames'; +import MatrixClientContext from "../../contexts/MatrixClientContext"; export default class EmbeddedPage extends React.PureComponent { static propTypes = { @@ -39,9 +39,7 @@ export default class EmbeddedPage extends React.PureComponent { scrollbar: PropTypes.bool, }; - static contextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient), - }; + static contextType = MatrixClientContext; constructor(props) { super(props); @@ -104,7 +102,7 @@ export default class EmbeddedPage extends React.PureComponent { render() { // HACK: Workaround for the context's MatrixClient not updating. - const client = this.context.matrixClient || MatrixClientPeg.get(); + const client = this.context || MatrixClientPeg.get(); const isGuest = client ? client.isGuest() : true; const className = this.props.className; const classes = classnames({ diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js index a0ad2b5c81..dd842be1ac 100644 --- a/src/components/structures/LeftPanel.js +++ b/src/components/structures/LeftPanel.js @@ -19,7 +19,6 @@ import React from 'react'; import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { MatrixClient } from 'matrix-js-sdk'; import { Key } from '../../Keyboard'; import sdk from '../../index'; import dis from '../../dispatcher'; @@ -39,10 +38,6 @@ const LeftPanel = createReactClass({ collapsed: PropTypes.bool.isRequired, }, - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient), - }, - getInitialState: function() { return { searchFilter: '', diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index df2eebd7c9..7261af3bf0 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -38,6 +38,7 @@ import TagOrderActions from '../../actions/TagOrderActions'; import RoomListActions from '../../actions/RoomListActions'; import ResizeHandle from '../views/elements/ResizeHandle'; import {Resizer, CollapseDistributor} from '../../resizer'; +import MatrixClientContext from "../../contexts/MatrixClientContext"; // We need to fetch each pinned message individually (if we don't already have it) // so each pinned message may trigger a request. Limit the number per room for sanity. // NB. this is just for server notices rather than pinned messages in general. @@ -77,21 +78,6 @@ const LoggedInView = createReactClass({ // and lots and lots of other stuff. }, - childContextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient), - authCache: PropTypes.object, - }, - - getChildContext: function() { - return { - matrixClient: this._matrixClient, - authCache: { - auth: {}, - lastUpdate: 0, - }, - }; - }, - getInitialState: function() { return { // use compact timeline view @@ -631,21 +617,30 @@ const LoggedInView = createReactClass({ } return ( -
- { topBar } - - -
- - - { pageElement } -
-
-
+ +
+ { topBar } + + +
+ + + { pageElement } +
+
+
+
); }, }); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 8cee3e9def..fad57f5d52 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -150,16 +150,6 @@ export default createReactClass({ makeRegistrationUrl: PropTypes.func.isRequired, }, - childContextTypes: { - appConfig: PropTypes.object, - }, - - getChildContext: function() { - return { - appConfig: this.props.config, - }; - }, - getInitialState: function() { const s = { // the master view we are showing. diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index 63ae14ba09..d957e76dfb 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -17,12 +17,11 @@ limitations under the License. import React from 'react'; import createReactClass from 'create-react-class'; -import PropTypes from 'prop-types'; -import { MatrixClient } from 'matrix-js-sdk'; import sdk from '../../index'; import { _t } from '../../languageHandler'; import dis from '../../dispatcher'; import AccessibleButton from '../views/elements/AccessibleButton'; +import MatrixClientContext from "../../contexts/MatrixClientContext"; export default createReactClass({ displayName: 'MyGroups', @@ -34,8 +33,8 @@ export default createReactClass({ }; }, - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, + statics: { + contextType: MatrixClientContext, }, componentWillMount: function() { @@ -47,7 +46,7 @@ export default createReactClass({ }, _fetch: function() { - this.context.matrixClient.getJoinedGroups().then((result) => { + this.context.getJoinedGroups().then((result) => { this.setState({groups: result.groups, error: null}); }, (err) => { if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN') { diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 2f91c5419d..ff987a8f30 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -23,13 +23,13 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import sdk from '../../index'; import dis from '../../dispatcher'; -import { MatrixClient } from 'matrix-js-sdk'; import RateLimitedFunc from '../../ratelimitedfunc'; import { showGroupInviteDialog, showGroupAddRoomDialog } from '../../GroupAddressPicker'; import GroupStore from '../../stores/GroupStore'; import SettingsStore from "../../settings/SettingsStore"; import {RIGHT_PANEL_PHASES, RIGHT_PANEL_PHASES_NO_ARGS} from "../../stores/RightPanelStorePhases"; import RightPanelStore from "../../stores/RightPanelStore"; +import MatrixClientContext from "../../contexts/MatrixClientContext"; export default class RightPanel extends React.Component { static get propTypes() { @@ -40,14 +40,10 @@ export default class RightPanel extends React.Component { }; } - static get contextTypes() { - return { - matrixClient: PropTypes.instanceOf(MatrixClient), - }; - } + static contextType = MatrixClientContext; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.state = { phase: this._getPhaseFromProps(), isUserPrivilegedInGroup: null, @@ -93,15 +89,15 @@ export default class RightPanel extends React.Component { componentWillMount() { this.dispatcherRef = dis.register(this.onAction); - const cli = this.context.matrixClient; + const cli = this.context; cli.on("RoomState.members", this.onRoomStateMember); this._initGroupStore(this.props.groupId); } componentWillUnmount() { dis.unregister(this.dispatcherRef); - if (this.context.matrixClient) { - this.context.matrixClient.removeListener("RoomState.members", this.onRoomStateMember); + if (this.context) { + this.context.removeListener("RoomState.members", this.onRoomStateMember); } this._unregisterGroupStore(this.props.groupId); } diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index 2c885f7eb2..cec016c3cf 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -30,6 +30,7 @@ import PropTypes from 'prop-types'; import { _t } from '../../languageHandler'; import { instanceForInstanceId, protocolNameForInstanceId } from '../../utils/DirectoryUtils'; import Analytics from '../../Analytics'; +import MatrixClientContext from "../../contexts/MatrixClientContext"; const MAX_NAME_LENGTH = 80; const MAX_TOPIC_LENGTH = 160; @@ -65,16 +66,6 @@ module.exports = createReactClass({ }; }, - childContextTypes: { - matrixClient: PropTypes.object, - }, - - getChildContext: function() { - return { - matrixClient: MatrixClientPeg.get(), - }; - }, - componentWillMount: function() { this._unmounted = false; this.nextBatch = null; diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 739519a2b3..8d59e42c3e 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -28,7 +28,6 @@ import createReactClass from 'create-react-class'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import {Room} from "matrix-js-sdk"; import { _t } from '../../languageHandler'; import {RoomPermalinkCreator} from '../../utils/permalinks/Permalinks'; @@ -55,6 +54,7 @@ import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; import WidgetUtils from '../../utils/WidgetUtils'; import AccessibleButton from "../views/elements/AccessibleButton"; import RightPanelStore from "../../stores/RightPanelStore"; +import RoomContext from "../../contexts/RoomContext"; const DEBUG = false; let debuglog = function() {}; @@ -66,12 +66,6 @@ if (DEBUG) { debuglog = console.log.bind(console); } -const RoomContext = PropTypes.shape({ - canReact: PropTypes.bool.isRequired, - canReply: PropTypes.bool.isRequired, - room: PropTypes.instanceOf(Room), -}); - module.exports = createReactClass({ displayName: 'RoomView', propTypes: { @@ -169,21 +163,6 @@ module.exports = createReactClass({ }; }, - childContextTypes: { - room: RoomContext, - }, - - getChildContext: function() { - const {canReact, canReply, room} = this.state; - return { - room: { - canReact, - canReply, - room, - }, - }; - }, - componentWillMount: function() { this.dispatcherRef = dis.register(this.onAction); MatrixClientPeg.get().on("Room", this.onRoom); @@ -1989,45 +1968,47 @@ module.exports = createReactClass({ : null; return ( -
- - - -
- {auxPanel} -
- {topUnreadMessagesBar} - {jumpToBottom} - {messagePanel} - {searchResultsPanel} -
-
-
-
- {statusBar} + +
+ + + +
+ {auxPanel} +
+ {topUnreadMessagesBar} + {jumpToBottom} + {messagePanel} + {searchResultsPanel}
+
+
+
+ {statusBar} +
+
+ {previewBar} + {messageComposer}
- {previewBar} - {messageComposer} -
-
-
-
+ + +
+ ); }, }); diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index a758092dc8..081796cb85 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -16,8 +16,6 @@ limitations under the License. import React from 'react'; import createReactClass from 'create-react-class'; -import PropTypes from 'prop-types'; -import { MatrixClient } from 'matrix-js-sdk'; import TagOrderStore from '../../stores/TagOrderStore'; import GroupActions from '../../actions/GroupActions'; @@ -28,12 +26,13 @@ import { _t } from '../../languageHandler'; import { Droppable } from 'react-beautiful-dnd'; import classNames from 'classnames'; +import MatrixClientContext from "../../contexts/MatrixClientContext"; const TagPanel = createReactClass({ displayName: 'TagPanel', - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient), + statics: { + contextType: MatrixClientContext, }, getInitialState() { @@ -45,8 +44,8 @@ const TagPanel = createReactClass({ componentWillMount: function() { this.unmounted = false; - this.context.matrixClient.on("Group.myMembership", this._onGroupMyMembership); - this.context.matrixClient.on("sync", this._onClientSync); + this.context.on("Group.myMembership", this._onGroupMyMembership); + this.context.on("sync", this._onClientSync); this._tagOrderStoreToken = TagOrderStore.addListener(() => { if (this.unmounted) { @@ -58,13 +57,13 @@ const TagPanel = createReactClass({ }); }); // This could be done by anything with a matrix client - dis.dispatch(GroupActions.fetchJoinedGroups(this.context.matrixClient)); + dis.dispatch(GroupActions.fetchJoinedGroups(this.context)); }, componentWillUnmount() { this.unmounted = true; - this.context.matrixClient.removeListener("Group.myMembership", this._onGroupMyMembership); - this.context.matrixClient.removeListener("sync", this._onClientSync); + this.context.removeListener("Group.myMembership", this._onGroupMyMembership); + this.context.removeListener("sync", this._onClientSync); if (this._filterStoreToken) { this._filterStoreToken.remove(); } @@ -72,7 +71,7 @@ const TagPanel = createReactClass({ _onGroupMyMembership() { if (this.unmounted) return; - dis.dispatch(GroupActions.fetchJoinedGroups(this.context.matrixClient)); + dis.dispatch(GroupActions.fetchJoinedGroups(this.context)); }, _onClientSync(syncState, prevState) { @@ -81,7 +80,7 @@ const TagPanel = createReactClass({ const reconnected = syncState !== "ERROR" && prevState !== syncState; if (reconnected) { // Load joined groups - dis.dispatch(GroupActions.fetchJoinedGroups(this.context.matrixClient)); + dis.dispatch(GroupActions.fetchJoinedGroups(this.context)); } }, diff --git a/src/components/views/avatars/BaseAvatar.js b/src/components/views/avatars/BaseAvatar.js index 82db78615e..51375eb3fa 100644 --- a/src/components/views/avatars/BaseAvatar.js +++ b/src/components/views/avatars/BaseAvatar.js @@ -19,10 +19,10 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; -import { MatrixClient } from 'matrix-js-sdk'; import AvatarLogic from '../../../Avatar'; import SettingsStore from "../../../settings/SettingsStore"; import AccessibleButton from '../elements/AccessibleButton'; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; module.exports = createReactClass({ displayName: 'BaseAvatar', @@ -40,8 +40,8 @@ module.exports = createReactClass({ defaultToInitialLetter: PropTypes.bool, // true to add default url }, - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient), + statics: { + contextType: MatrixClientContext, }, getDefaultProps: function() { @@ -59,12 +59,12 @@ module.exports = createReactClass({ componentDidMount() { this.unmounted = false; - this.context.matrixClient.on('sync', this.onClientSync); + this.context.on('sync', this.onClientSync); }, componentWillUnmount() { this.unmounted = true; - this.context.matrixClient.removeListener('sync', this.onClientSync); + this.context.removeListener('sync', this.onClientSync); }, componentWillReceiveProps: function(nextProps) { diff --git a/src/components/views/avatars/MemberStatusMessageAvatar.js b/src/components/views/avatars/MemberStatusMessageAvatar.js index ed73dd33b9..245d869419 100644 --- a/src/components/views/avatars/MemberStatusMessageAvatar.js +++ b/src/components/views/avatars/MemberStatusMessageAvatar.js @@ -38,8 +38,8 @@ export default class MemberStatusMessageAvatar extends React.Component { resizeMethod: 'crop', }; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.state = { hasStatus: this.hasStatus, diff --git a/src/components/views/context_menus/GroupInviteTileContextMenu.js b/src/components/views/context_menus/GroupInviteTileContextMenu.js index 3feffbc0d9..3c0fd081b4 100644 --- a/src/components/views/context_menus/GroupInviteTileContextMenu.js +++ b/src/components/views/context_menus/GroupInviteTileContextMenu.js @@ -31,8 +31,8 @@ export default class GroupInviteTileContextMenu extends React.Component { onFinished: PropTypes.func, }; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this._onClickReject = this._onClickReject.bind(this); } diff --git a/src/components/views/context_menus/StatusMessageContextMenu.js b/src/components/views/context_menus/StatusMessageContextMenu.js index 441220c95e..31ba788ec7 100644 --- a/src/components/views/context_menus/StatusMessageContextMenu.js +++ b/src/components/views/context_menus/StatusMessageContextMenu.js @@ -27,8 +27,8 @@ export default class StatusMessageContextMenu extends React.Component { user: PropTypes.object, }; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.state = { message: this.comittedStatusMessage, diff --git a/src/components/views/context_menus/TagTileContextMenu.js b/src/components/views/context_menus/TagTileContextMenu.js index 1af0c9ae66..388d8aaf3d 100644 --- a/src/components/views/context_menus/TagTileContextMenu.js +++ b/src/components/views/context_menus/TagTileContextMenu.js @@ -17,12 +17,12 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import { MatrixClient } from 'matrix-js-sdk'; import { _t } from '../../../languageHandler'; import dis from '../../../dispatcher'; import TagOrderActions from '../../../actions/TagOrderActions'; import sdk from '../../../index'; import {MenuItem} from "../../structures/ContextMenu"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; export default class TagTileContextMenu extends React.Component { static propTypes = { @@ -31,9 +31,7 @@ export default class TagTileContextMenu extends React.Component { onFinished: PropTypes.func.isRequired, }; - static contextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient), - }; + static contextType = MatrixClientContext; constructor() { super(); @@ -51,7 +49,7 @@ export default class TagTileContextMenu extends React.Component { } _onRemoveClick() { - dis.dispatch(TagOrderActions.removeTag(this.context.matrixClient, this.props.tag)); + dis.dispatch(TagOrderActions.removeTag(this.context, this.props.tag)); this.props.onFinished(); } diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index 6ba0b322c4..a9f7fbf4b3 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -22,12 +22,11 @@ import FocusLock from 'react-focus-lock'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { MatrixClient } from 'matrix-js-sdk'; - import { Key } from '../../../Keyboard'; import AccessibleButton from '../elements/AccessibleButton'; import MatrixClientPeg from '../../../MatrixClientPeg'; import { _t } from "../../../languageHandler"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; /** * Basic container for modal dialogs. @@ -84,16 +83,6 @@ export default createReactClass({ }; }, - childContextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient), - }, - - getChildContext: function() { - return { - matrixClient: this._matrixClient, - }; - }, - componentWillMount() { this._matrixClient = MatrixClientPeg.get(); }, @@ -122,36 +111,38 @@ export default createReactClass({ } return ( - -
-
- { this.props.title } + + +
+
+ { this.props.title } +
+ { this.props.headerButton } + { cancelButton }
- { this.props.headerButton } - { cancelButton } -
- { this.props.children } - + { this.props.children } + + ); }, }); diff --git a/src/components/views/dialogs/BugReportDialog.js b/src/components/views/dialogs/BugReportDialog.js index a3c4ad96ee..91d2bb5213 100644 --- a/src/components/views/dialogs/BugReportDialog.js +++ b/src/components/views/dialogs/BugReportDialog.js @@ -25,8 +25,8 @@ import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; export default class BugReportDialog extends React.Component { - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.state = { sendLogs: true, busy: false, diff --git a/src/components/views/dialogs/DeactivateAccountDialog.js b/src/components/views/dialogs/DeactivateAccountDialog.js index 703ecaf092..fc7669e1fe 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.js +++ b/src/components/views/dialogs/DeactivateAccountDialog.js @@ -25,8 +25,8 @@ import * as Lifecycle from '../../../Lifecycle'; import { _t } from '../../../languageHandler'; export default class DeactivateAccountDialog extends React.Component { - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this._onOk = this._onOk.bind(this); this._onCancel = this._onCancel.bind(this); diff --git a/src/components/views/dialogs/DevtoolsDialog.js b/src/components/views/dialogs/DevtoolsDialog.js index 9327e1e54e..c9ed71466d 100644 --- a/src/components/views/dialogs/DevtoolsDialog.js +++ b/src/components/views/dialogs/DevtoolsDialog.js @@ -16,23 +16,19 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; +import { Room } from "matrix-js-sdk"; + import sdk from '../../../index'; import SyntaxHighlight from '../elements/SyntaxHighlight'; import { _t } from '../../../languageHandler'; -import MatrixClientPeg from '../../../MatrixClientPeg'; import Field from "../elements/Field"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; -class DevtoolsComponent extends React.Component { - static contextTypes = { - roomId: PropTypes.string.isRequired, - }; -} - -class GenericEditor extends DevtoolsComponent { +class GenericEditor extends React.PureComponent { // static propTypes = {onBack: PropTypes.func.isRequired}; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this._onChange = this._onChange.bind(this); this.onBack = this.onBack.bind(this); } @@ -67,12 +63,15 @@ class SendCustomEvent extends GenericEditor { static propTypes = { onBack: PropTypes.func.isRequired, + room: PropTypes.instanceOf(Room).isRequired, forceStateEvent: PropTypes.bool, inputs: PropTypes.object, }; - constructor(props, context) { - super(props, context); + static contextType = MatrixClientContext; + + constructor(props) { + super(props); this._send = this._send.bind(this); const {eventType, stateKey, evContent} = Object.assign({ @@ -91,11 +90,11 @@ class SendCustomEvent extends GenericEditor { } send(content) { - const cli = MatrixClientPeg.get(); + const cli = this.context; if (this.state.isStateEvent) { - return cli.sendStateEvent(this.context.roomId, this.state.eventType, content, this.state.stateKey); + return cli.sendStateEvent(this.props.room.roomId, this.state.eventType, content, this.state.stateKey); } else { - return cli.sendEvent(this.context.roomId, this.state.eventType, content); + return cli.sendEvent(this.props.room.roomId, this.state.eventType, content); } } @@ -154,13 +153,16 @@ class SendAccountData extends GenericEditor { static getLabel() { return _t('Send Account Data'); } static propTypes = { + room: PropTypes.instanceOf(Room).isRequired, isRoomAccountData: PropTypes.bool, forceMode: PropTypes.bool, inputs: PropTypes.object, }; - constructor(props, context) { - super(props, context); + static contextType = MatrixClientContext; + + constructor(props) { + super(props); this._send = this._send.bind(this); const {eventType, evContent} = Object.assign({ @@ -177,9 +179,9 @@ class SendAccountData extends GenericEditor { } send(content) { - const cli = MatrixClientPeg.get(); + const cli = this.context; if (this.state.isRoomAccountData) { - return cli.setRoomAccountData(this.context.roomId, this.state.eventType, content); + return cli.setRoomAccountData(this.props.room.roomId, this.state.eventType, content); } return cli.setAccountData(this.state.eventType, content); } @@ -234,7 +236,7 @@ class SendAccountData extends GenericEditor { const INITIAL_LOAD_TILES = 20; const LOAD_TILES_STEP_SIZE = 50; -class FilteredList extends React.Component { +class FilteredList extends React.PureComponent { static propTypes = { children: PropTypes.any, query: PropTypes.string, @@ -247,8 +249,8 @@ class FilteredList extends React.Component { return children.filter((child) => child.key.toLowerCase().includes(lcQuery)); } - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.state = { filteredChildren: FilteredList.filterChildren(this.props.children, this.props.query), @@ -305,19 +307,20 @@ class FilteredList extends React.Component { } } -class RoomStateExplorer extends DevtoolsComponent { +class RoomStateExplorer extends React.PureComponent { static getLabel() { return _t('Explore Room State'); } - static propTypes = { onBack: PropTypes.func.isRequired, + room: PropTypes.instanceOf(Room).isRequired, }; - constructor(props, context) { - super(props, context); + static contextType = MatrixClientContext; - const room = MatrixClientPeg.get().getRoom(this.context.roomId); - this.roomStateEvents = room.currentState.events; + constructor(props) { + super(props); + + this.roomStateEvents = this.props.room.currentState.events; this.onBack = this.onBack.bind(this); this.editEv = this.editEv.bind(this); @@ -373,7 +376,7 @@ class RoomStateExplorer extends DevtoolsComponent { render() { if (this.state.event) { if (this.state.editing) { - return ; + return ; } return
@@ -553,17 +562,20 @@ class AccountDataExplorer extends DevtoolsComponent { } } -class ServersInRoomList extends DevtoolsComponent { +class ServersInRoomList extends React.PureComponent { static getLabel() { return _t('View Servers in Room'); } static propTypes = { onBack: PropTypes.func.isRequired, + room: PropTypes.instanceOf(Room).isRequired, }; - constructor(props, context) { - super(props, context); + static contextType = MatrixClientContext; - const room = MatrixClientPeg.get().getRoom(this.context.roomId); + constructor(props) { + super(props); + + const room = this.props.room; const servers = new Set(); room.currentState.getStateEvents("m.room.member").forEach(ev => servers.add(ev.getSender().split(":")[1])); this.servers = Array.from(servers).map(s => @@ -602,19 +614,14 @@ const Entries = [ ServersInRoomList, ]; -export default class DevtoolsDialog extends React.Component { - static childContextTypes = { - roomId: PropTypes.string.isRequired, - // client: PropTypes.instanceOf(MatixClient), - }; - +export default class DevtoolsDialog extends React.PureComponent { static propTypes = { roomId: PropTypes.string.isRequired, onFinished: PropTypes.func.isRequired, }; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.onBack = this.onBack.bind(this); this.onCancel = this.onCancel.bind(this); @@ -627,10 +634,6 @@ export default class DevtoolsDialog extends React.Component { this._unmounted = true; } - getChildContext() { - return { roomId: this.props.roomId }; - } - _setMode(mode) { return () => { this.setState({ mode }); @@ -654,15 +657,17 @@ export default class DevtoolsDialog extends React.Component { let body; if (this.state.mode) { - body =
-
{ this.state.mode.getLabel() }
-
Room ID: { this.props.roomId }
-
- -
; + body = + {(cli) => +
{ this.state.mode.getLabel() }
+
Room ID: { this.props.roomId }
+
+ + } + ; } else { const classes = "mx_DevTools_RoomStateExplorer_button"; - body =
+ body =
{ _t('Toolbox') }
Room ID: { this.props.roomId }
@@ -679,7 +684,7 @@ export default class DevtoolsDialog extends React.Component {
-
; +
; } const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); diff --git a/src/components/views/dialogs/ReportEventDialog.js b/src/components/views/dialogs/ReportEventDialog.js index 394e5ad47d..af140f6e18 100644 --- a/src/components/views/dialogs/ReportEventDialog.js +++ b/src/components/views/dialogs/ReportEventDialog.js @@ -30,8 +30,8 @@ export default class ReportEventDialog extends PureComponent { onFinished: PropTypes.func.isRequired, }; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.state = { reason: "", diff --git a/src/components/views/elements/EditableTextContainer.js b/src/components/views/elements/EditableTextContainer.js index 5cba98470c..3d656e6b79 100644 --- a/src/components/views/elements/EditableTextContainer.js +++ b/src/components/views/elements/EditableTextContainer.js @@ -25,13 +25,13 @@ import sdk from '../../../index'; * Parent components should supply an 'onSubmit' callback which returns a * promise; a spinner is shown until the promise resolves. * - * The parent can also supply a 'getIntialValue' callback, which works in a + * The parent can also supply a 'getInitialValue' callback, which works in a * similarly asynchronous way. If this is not provided, the initial value is * taken from the 'initialValue' property. */ export default class EditableTextContainer extends React.Component { - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this._unmounted = false; this.state = { diff --git a/src/components/views/elements/Flair.js b/src/components/views/elements/Flair.js index 0b9dabeae6..0af772466b 100644 --- a/src/components/views/elements/Flair.js +++ b/src/components/views/elements/Flair.js @@ -18,9 +18,9 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {MatrixClient} from 'matrix-js-sdk'; import FlairStore from '../../../stores/FlairStore'; import dis from '../../../dispatcher'; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; class FlairAvatar extends React.Component { @@ -40,7 +40,7 @@ class FlairAvatar extends React.Component { } render() { - const httpUrl = this.context.matrixClient.mxcUrlToHttp( + const httpUrl = this.context.mxcUrlToHttp( this.props.groupProfile.avatarUrl, 16, 16, 'scale', false); const tooltip = this.props.groupProfile.name ? `${this.props.groupProfile.name} (${this.props.groupProfile.groupId})`: @@ -62,9 +62,7 @@ FlairAvatar.propTypes = { }), }; -FlairAvatar.contextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, -}; +FlairAvatar.contextType = MatrixClientContext; export default class Flair extends React.Component { constructor() { @@ -92,7 +90,7 @@ export default class Flair extends React.Component { for (const groupId of groups) { let groupProfile = null; try { - groupProfile = await FlairStore.getGroupProfileCached(this.context.matrixClient, groupId); + groupProfile = await FlairStore.getGroupProfileCached(this.context, groupId); } catch (err) { console.error('Could not get profile for group', groupId, err); } @@ -134,6 +132,4 @@ Flair.propTypes = { groups: PropTypes.arrayOf(PropTypes.string), }; -Flair.contextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, -}; +Flair.contextType = MatrixClientContext; diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index 12830488b1..99005de03b 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -20,12 +20,13 @@ import createReactClass from 'create-react-class'; import sdk from '../../../index'; import dis from '../../../dispatcher'; import classNames from 'classnames'; -import { Room, RoomMember, MatrixClient } from 'matrix-js-sdk'; +import { Room, RoomMember } from 'matrix-js-sdk'; import PropTypes from 'prop-types'; import MatrixClientPeg from '../../../MatrixClientPeg'; import { getDisplayAliasForRoom } from '../../../Rooms'; import FlairStore from "../../../stores/FlairStore"; import {getPrimaryPermalinkEntity} from "../../../utils/permalinks/Permalinks"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; // For URLs of matrix.to links in the timeline which have been reformatted by // HttpUtils transformTags to relative links. This excludes event URLs (with `[^\/]*`) @@ -66,17 +67,6 @@ const Pill = createReactClass({ isSelected: PropTypes.bool, }, - - childContextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient), - }, - - getChildContext() { - return { - matrixClient: this._matrixClient, - }; - }, - getInitialState() { return { // ID/alias of the room/user @@ -127,7 +117,7 @@ const Pill = createReactClass({ } break; case Pill.TYPE_USER_MENTION: { - const localMember = nextProps.room.getMember(resourceId); + const localMember = nextProps.room ? nextProps.room.getMember(resourceId) : undefined; member = localMember; if (!localMember) { member = new RoomMember(null, resourceId); @@ -276,15 +266,17 @@ const Pill = createReactClass({ }); if (this.state.pillType) { - return this.props.inMessage ? - - { avatar } - { linkText } - : - - { avatar } - { linkText } - ; + return + { this.props.inMessage ? + + { avatar } + { linkText } + : + + { avatar } + { linkText } + } + ; } else { // Deliberately render nothing if the URL isn't recognised return null; diff --git a/src/components/views/elements/ReplyThread.js b/src/components/views/elements/ReplyThread.js index 55fd028980..e7832efca7 100644 --- a/src/components/views/elements/ReplyThread.js +++ b/src/components/views/elements/ReplyThread.js @@ -21,10 +21,11 @@ import {_t} from '../../../languageHandler'; import PropTypes from 'prop-types'; import dis from '../../../dispatcher'; import {wantsDateSeparator} from '../../../DateUtils'; -import {MatrixEvent, MatrixClient} from 'matrix-js-sdk'; +import {MatrixEvent} from 'matrix-js-sdk'; import {makeUserPermalink, RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks"; import SettingsStore from "../../../settings/SettingsStore"; import escapeHtml from "escape-html"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; // This component does no cycle detection, simply because the only way to make such a cycle would be to // craft event_id's, using a homeserver that generates predictable event IDs; even then the impact would @@ -38,12 +39,10 @@ export default class ReplyThread extends React.Component { permalinkCreator: PropTypes.instanceOf(RoomPermalinkCreator).isRequired, }; - static contextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, - }; + static contextType = MatrixClientContext; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.state = { // The loaded events to be rendered as linear-replies @@ -187,7 +186,7 @@ export default class ReplyThread extends React.Component { componentWillMount() { this.unmounted = false; - this.room = this.context.matrixClient.getRoom(this.props.parentEv.getRoomId()); + this.room = this.context.getRoom(this.props.parentEv.getRoomId()); this.room.on("Room.redaction", this.onRoomRedaction); // same event handler as Room.redaction as for both we just do forceUpdate this.room.on("Room.redactionCancelled", this.onRoomRedaction); @@ -259,7 +258,7 @@ export default class ReplyThread extends React.Component { try { // ask the client to fetch the event we want using the context API, only interface to do so is to ask // for a timeline with that event, but once it is loaded we can use findEventById to look up the ev map - await this.context.matrixClient.getEventTimeline(this.room.getUnfilteredTimelineSet(), eventId); + await this.context.getEventTimeline(this.room.getUnfilteredTimelineSet(), eventId); } catch (e) { // if it fails catch the error and return early, there's no point trying to find the event in this case. // Return null as it is falsey and thus should be treated as an error (as the event cannot be resolved). @@ -300,7 +299,7 @@ export default class ReplyThread extends React.Component { } else if (this.state.loadedEv) { const ev = this.state.loadedEv; const Pill = sdk.getComponent('elements.Pill'); - const room = this.context.matrixClient.getRoom(ev.getRoomId()); + const room = this.context.getRoom(ev.getRoomId()); header =
{ _t('In reply to ', {}, { diff --git a/src/components/views/elements/SyntaxHighlight.js b/src/components/views/elements/SyntaxHighlight.js index 82b5ae572c..bce65cf1a9 100644 --- a/src/components/views/elements/SyntaxHighlight.js +++ b/src/components/views/elements/SyntaxHighlight.js @@ -24,8 +24,8 @@ export default class SyntaxHighlight extends React.Component { children: PropTypes.node, }; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this._ref = this._ref.bind(this); } diff --git a/src/components/views/elements/TagTile.js b/src/components/views/elements/TagTile.js index 767980f0a0..c57d973086 100644 --- a/src/components/views/elements/TagTile.js +++ b/src/components/views/elements/TagTile.js @@ -20,7 +20,6 @@ import React, {createRef} from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import classNames from 'classnames'; -import { MatrixClient } from 'matrix-js-sdk'; import sdk from '../../../index'; import dis from '../../../dispatcher'; import {_t} from '../../../languageHandler'; @@ -31,6 +30,7 @@ import FlairStore from '../../../stores/FlairStore'; import GroupStore from '../../../stores/GroupStore'; import TagOrderStore from '../../../stores/TagOrderStore'; import {ContextMenu, ContextMenuButton, toRightOf} from "../../structures/ContextMenu"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; // A class for a child of TagPanel (possibly wrapped in a DNDTagTile) that represents // a thing to click on for the user to filter the visible rooms in the RoomList to: @@ -46,8 +46,8 @@ export default createReactClass({ tag: PropTypes.string, }, - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, + statics: { + contextType: MatrixClientContext, }, getInitialState() { @@ -81,7 +81,7 @@ export default createReactClass({ _onFlairStoreUpdated() { if (this.unmounted) return; FlairStore.getGroupProfileCached( - this.context.matrixClient, + this.context, this.props.tag, ).then((profile) => { if (this.unmounted) return; @@ -145,7 +145,7 @@ export default createReactClass({ const name = profile.name || this.props.tag; const avatarHeight = 40; - const httpUrl = profile.avatarUrl ? this.context.matrixClient.mxcUrlToHttp( + const httpUrl = profile.avatarUrl ? this.context.mxcUrlToHttp( profile.avatarUrl, avatarHeight, avatarHeight, "crop", ) : null; diff --git a/src/components/views/groups/GroupInviteTile.js b/src/components/views/groups/GroupInviteTile.js index a21b091145..c0d0d9eafe 100644 --- a/src/components/views/groups/GroupInviteTile.js +++ b/src/components/views/groups/GroupInviteTile.js @@ -19,13 +19,13 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; -import { MatrixClient } from 'matrix-js-sdk'; import sdk from '../../../index'; import dis from '../../../dispatcher'; import {_t} from '../../../languageHandler'; import classNames from 'classnames'; import MatrixClientPeg from "../../../MatrixClientPeg"; import {ContextMenu, ContextMenuButton, toRightOf} from "../../structures/ContextMenu"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; // XXX this class copies a lot from RoomTile.js export default createReactClass({ @@ -35,8 +35,8 @@ export default createReactClass({ group: PropTypes.object.isRequired, }, - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient), + statics: { + contextType: MatrixClientContext, }, getInitialState: function() { @@ -58,7 +58,7 @@ export default createReactClass({ onMouseEnter: function() { const state = {hover: true}; // Only allow non-guests to access the context menu - if (!this.context.matrixClient.isGuest()) { + if (!this.context.isGuest()) { state.badgeHover = true; } this.setState(state); @@ -118,7 +118,7 @@ export default createReactClass({ const groupName = this.props.group.name || this.props.group.groupId; const httpAvatarUrl = this.props.group.avatarUrl ? - this.context.matrixClient.mxcUrlToHttp(this.props.group.avatarUrl, 24, 24) : null; + this.context.mxcUrlToHttp(this.props.group.avatarUrl, 24, 24) : null; const av = ; diff --git a/src/components/views/groups/GroupMemberInfo.js b/src/components/views/groups/GroupMemberInfo.js index 3dac90fc35..eb90cdc0f8 100644 --- a/src/components/views/groups/GroupMemberInfo.js +++ b/src/components/views/groups/GroupMemberInfo.js @@ -18,7 +18,6 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; -import { MatrixClient } from 'matrix-js-sdk'; import dis from '../../../dispatcher'; import Modal from '../../../Modal'; import sdk from '../../../index'; @@ -26,12 +25,13 @@ import { _t } from '../../../languageHandler'; import { GroupMemberType } from '../../../groups'; import GroupStore from '../../../stores/GroupStore'; import AccessibleButton from '../elements/AccessibleButton'; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; module.exports = createReactClass({ displayName: 'GroupMemberInfo', - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient), + statics: { + contextType: MatrixClientContext, }, propTypes: { @@ -85,7 +85,7 @@ module.exports = createReactClass({ _onKick: function() { const ConfirmUserActionDialog = sdk.getComponent("dialogs.ConfirmUserActionDialog"); Modal.createDialog(ConfirmUserActionDialog, { - matrixClient: this.context.matrixClient, + matrixClient: this.context, groupMember: this.props.groupMember, action: this.state.isUserInvited ? _t('Disinvite') : _t('Remove from community'), title: this.state.isUserInvited ? _t('Disinvite this user from community?') @@ -95,7 +95,7 @@ module.exports = createReactClass({ if (!proceed) return; this.setState({removingUser: true}); - this.context.matrixClient.removeUserFromGroup( + this.context.removeUserFromGroup( this.props.groupId, this.props.groupMember.userId, ).then(() => { // return to the user list @@ -171,7 +171,7 @@ module.exports = createReactClass({ const avatarUrl = this.props.groupMember.avatarUrl; let avatarElement; if (avatarUrl) { - const httpUrl = this.context.matrixClient.mxcUrlToHttp(avatarUrl, 800, 800); + const httpUrl = this.context.mxcUrlToHttp(avatarUrl, 800, 800); avatarElement = (
); diff --git a/src/components/views/groups/GroupMemberTile.js b/src/components/views/groups/GroupMemberTile.js index c4b41d23ce..7a9ba9289b 100644 --- a/src/components/views/groups/GroupMemberTile.js +++ b/src/components/views/groups/GroupMemberTile.js @@ -19,10 +19,10 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; -import { MatrixClient } from 'matrix-js-sdk'; import sdk from '../../../index'; import dis from '../../../dispatcher'; import { GroupMemberType } from '../../../groups'; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; export default createReactClass({ displayName: 'GroupMemberTile', @@ -36,8 +36,8 @@ export default createReactClass({ return {}; }, - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, + statics: { + contextType: MatrixClientContext, }, onClick: function(e) { @@ -53,7 +53,7 @@ export default createReactClass({ const EntityTile = sdk.getComponent('rooms.EntityTile'); const name = this.props.member.displayname || this.props.member.userId; - const avatarUrl = this.context.matrixClient.mxcUrlToHttp( + const avatarUrl = this.context.mxcUrlToHttp( this.props.member.avatarUrl, 36, 36, 'crop', ); diff --git a/src/components/views/groups/GroupRoomInfo.js b/src/components/views/groups/GroupRoomInfo.js index f9f7324e23..d5b8759a67 100644 --- a/src/components/views/groups/GroupRoomInfo.js +++ b/src/components/views/groups/GroupRoomInfo.js @@ -17,18 +17,18 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; -import { MatrixClient } from 'matrix-js-sdk'; import dis from '../../../dispatcher'; import Modal from '../../../Modal'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; import GroupStore from '../../../stores/GroupStore'; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; module.exports = createReactClass({ displayName: 'GroupRoomInfo', - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient), + statics: { + contextType: MatrixClientContext, }, propTypes: { @@ -206,7 +206,7 @@ module.exports = createReactClass({ const avatarUrl = this.state.groupRoom.avatarUrl; let avatarElement; if (avatarUrl) { - const httpUrl = this.context.matrixClient.mxcUrlToHttp(avatarUrl, 800, 800); + const httpUrl = this.context.mxcUrlToHttp(avatarUrl, 800, 800); avatarElement = (
); diff --git a/src/components/views/groups/GroupRoomTile.js b/src/components/views/groups/GroupRoomTile.js index ae325d4796..527e65d30c 100644 --- a/src/components/views/groups/GroupRoomTile.js +++ b/src/components/views/groups/GroupRoomTile.js @@ -17,10 +17,10 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; -import {MatrixClient} from 'matrix-js-sdk'; import sdk from '../../../index'; import dis from '../../../dispatcher'; import { GroupRoomType } from '../../../groups'; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; const GroupRoomTile = createReactClass({ displayName: 'GroupRoomTile', @@ -41,7 +41,7 @@ const GroupRoomTile = createReactClass({ render: function() { const BaseAvatar = sdk.getComponent('avatars.BaseAvatar'); const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); - const avatarUrl = this.context.matrixClient.mxcUrlToHttp( + const avatarUrl = this.context.mxcUrlToHttp( this.props.groupRoom.avatarUrl, 36, 36, 'crop', ); @@ -66,9 +66,7 @@ const GroupRoomTile = createReactClass({ }, }); -GroupRoomTile.contextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, -}; +GroupRoomTile.contextType = MatrixClientContext; export default GroupRoomTile; diff --git a/src/components/views/groups/GroupTile.js b/src/components/views/groups/GroupTile.js index 3b64c10a1e..f3d7418a44 100644 --- a/src/components/views/groups/GroupTile.js +++ b/src/components/views/groups/GroupTile.js @@ -17,11 +17,11 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; -import {MatrixClient} from 'matrix-js-sdk'; import { Draggable, Droppable } from 'react-beautiful-dnd'; import sdk from '../../../index'; import dis from '../../../dispatcher'; import FlairStore from '../../../stores/FlairStore'; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; function nop() {} @@ -37,8 +37,8 @@ const GroupTile = createReactClass({ draggable: PropTypes.bool, }, - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, + statics: { + contextType: MatrixClientContext, }, getInitialState() { @@ -56,7 +56,7 @@ const GroupTile = createReactClass({ }, componentWillMount: function() { - FlairStore.getGroupProfileCached(this.context.matrixClient, this.props.groupId).then((profile) => { + FlairStore.getGroupProfileCached(this.context, this.props.groupId).then((profile) => { this.setState({profile}); }).catch((err) => { console.error('Error whilst getting cached profile for GroupTile', err); @@ -80,7 +80,7 @@ const GroupTile = createReactClass({ const descElement = this.props.showDescription ?
{ profile.shortDescription }
:
; - const httpUrl = profile.avatarUrl ? this.context.matrixClient.mxcUrlToHttp( + const httpUrl = profile.avatarUrl ? this.context.mxcUrlToHttp( profile.avatarUrl, avatarHeight, avatarHeight, "crop") : null; let avatarElement = ( diff --git a/src/components/views/groups/GroupUserSettings.js b/src/components/views/groups/GroupUserSettings.js index 3cd5731b99..297c0fbd30 100644 --- a/src/components/views/groups/GroupUserSettings.js +++ b/src/components/views/groups/GroupUserSettings.js @@ -15,17 +15,16 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import sdk from '../../../index'; -import { MatrixClient } from 'matrix-js-sdk'; import { _t } from '../../../languageHandler'; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; export default createReactClass({ displayName: 'GroupUserSettings', - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient), + statics: { + contextType: MatrixClientContext, }, getInitialState() { @@ -36,7 +35,7 @@ export default createReactClass({ }, componentWillMount: function() { - this.context.matrixClient.getJoinedGroups().then((result) => { + this.context.getJoinedGroups().then((result) => { this.setState({groups: result.groups || [], error: null}); }, (err) => { console.error(err); diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index 552b1108d2..6045ec0571 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -26,6 +26,7 @@ import {decryptFile} from '../../../utils/DecryptFile'; import Tinter from '../../../Tinter'; import request from 'browser-request'; import Modal from '../../../Modal'; +import SdkConfig from "../../../SdkConfig"; // A cached tinted copy of require("../../../../res/img/download.svg") @@ -214,10 +215,6 @@ module.exports = createReactClass({ tileShape: PropTypes.string, }, - contextTypes: { - appConfig: PropTypes.object, - }, - /** * Extracts a human readable label for the file attachment to use as * link text. @@ -360,8 +357,9 @@ module.exports = createReactClass({ // If the attachment is encryped then put the link inside an iframe. let renderer_url = DEFAULT_CROSS_ORIGIN_RENDERER; - if (this.context.appConfig && this.context.appConfig.cross_origin_renderer_url) { - renderer_url = this.context.appConfig.cross_origin_renderer_url; + const appConfig = SdkConfig.get(); + if (appConfig && appConfig.cross_origin_renderer_url) { + renderer_url = appConfig.cross_origin_renderer_url; } renderer_url += "?origin=" + encodeURIComponent(window.location.origin); return ( diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index 427056203d..dbe6636c6b 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -18,7 +18,6 @@ limitations under the License. import React, {createRef} from 'react'; import PropTypes from 'prop-types'; -import { MatrixClient } from 'matrix-js-sdk'; import MFileBody from './MFileBody'; import Modal from '../../../Modal'; @@ -26,6 +25,7 @@ import sdk from '../../../index'; import { decryptFile } from '../../../utils/DecryptFile'; import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; export default class MImageBody extends React.Component { static propTypes = { @@ -39,9 +39,7 @@ export default class MImageBody extends React.Component { maxImageHeight: PropTypes.number, }; - static contextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient), - }; + static contextType = MatrixClientContext; constructor(props) { super(props); @@ -71,7 +69,7 @@ export default class MImageBody extends React.Component { componentWillMount() { this.unmounted = false; - this.context.matrixClient.on('sync', this.onClientSync); + this.context.on('sync', this.onClientSync); } // FIXME: factor this out and aplpy it to MVideoBody and MAudioBody too! @@ -174,7 +172,7 @@ export default class MImageBody extends React.Component { if (content.file !== undefined) { return this.state.decryptedUrl; } else { - return this.context.matrixClient.mxcUrlToHttp(content.url); + return this.context.mxcUrlToHttp(content.url); } } @@ -198,7 +196,7 @@ export default class MImageBody extends React.Component { // special case to return clientside sender-generated thumbnails for SVGs, if any, // given we deliberately don't thumbnail them serverside to prevent // billion lol attacks and similar - return this.context.matrixClient.mxcUrlToHttp( + return this.context.mxcUrlToHttp( content.info.thumbnail_url, thumbWidth, thumbHeight, @@ -221,7 +219,7 @@ export default class MImageBody extends React.Component { pixelRatio === 1.0 || (!info || !info.w || !info.h || !info.size) ) { - return this.context.matrixClient.mxcUrlToHttp(content.url, thumbWidth, thumbHeight); + return this.context.mxcUrlToHttp(content.url, thumbWidth, thumbHeight); } else { // we should only request thumbnails if the image is bigger than 800x600 // (or 1600x1200 on retina) otherwise the image in the timeline will just @@ -242,7 +240,7 @@ export default class MImageBody extends React.Component { // image is too large physically and bytewise to clutter our timeline so // we ask for a thumbnail, despite knowing that it will be max 800x600 // despite us being retina (as synapse doesn't do 1600x1200 thumbs yet). - return this.context.matrixClient.mxcUrlToHttp( + return this.context.mxcUrlToHttp( content.url, thumbWidth, thumbHeight, @@ -251,7 +249,7 @@ export default class MImageBody extends React.Component { // download the original image otherwise, so we can scale it client side // to take pixelRatio into account. // ( no width/height means we want the original image) - return this.context.matrixClient.mxcUrlToHttp( + return this.context.mxcUrlToHttp( content.url, ); } @@ -308,7 +306,7 @@ export default class MImageBody extends React.Component { componentWillUnmount() { this.unmounted = true; - this.context.matrixClient.removeListener('sync', this.onClientSync); + this.context.removeListener('sync', this.onClientSync); this._afterComponentWillUnmount(); if (this.state.decryptedUrl) { diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js index 52d7a74632..5c40c19b49 100644 --- a/src/components/views/messages/MessageActionBar.js +++ b/src/components/views/messages/MessageActionBar.js @@ -25,7 +25,7 @@ import dis from '../../../dispatcher'; import Modal from '../../../Modal'; import {aboveLeftOf, ContextMenu, ContextMenuButton, useContextMenu} from '../../structures/ContextMenu'; import { isContentActionable, canEditContent } from '../../../utils/EventUtils'; -import {RoomContext} from "../../structures/RoomView"; +import RoomContext from "../../../contexts/RoomContext"; const OptionsButton = ({mxEvent, getTile, getReplyThread, permalinkCreator, onFocusChange}) => { const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu(); @@ -117,9 +117,7 @@ export default class MessageActionBar extends React.PureComponent { onFocusChange: PropTypes.func, }; - static contextTypes = { - room: RoomContext, - }; + static contextType = RoomContext; componentDidMount() { this.props.mxEvent.on("Event.decrypted", this.onDecrypted); @@ -164,12 +162,12 @@ export default class MessageActionBar extends React.PureComponent { let editButton; if (isContentActionable(this.props.mxEvent)) { - if (this.context.room.canReact) { + if (this.context.canReact) { reactButton = ( ); } - if (this.context.room.canReply) { + if (this.context.canReply) { replyButton = { if (this.unmounted) return; this.setState({userGroups}); }); - this.context.matrixClient.on('RoomState.events', this.onRoomStateEvents); + this.context.on('RoomState.events', this.onRoomStateEvents); }, componentWillUnmount() { this.unmounted = true; - this.context.matrixClient.removeListener('RoomState.events', this.onRoomStateEvents); + this.context.removeListener('RoomState.events', this.onRoomStateEvents); }, onRoomStateEvents(event) { @@ -71,7 +71,7 @@ export default createReactClass({ _updateRelatedGroups() { if (this.unmounted) return; - const room = this.context.matrixClient.getRoom(this.props.mxEvent.getRoomId()); + const room = this.context.getRoom(this.props.mxEvent.getRoomId()); if (!room) return; const relatedGroupsEvent = room.currentState.getStateEvents('m.room.related_groups', ''); diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js index 65fc0bf66b..da82fb2bdf 100644 --- a/src/components/views/right_panel/UserInfo.js +++ b/src/components/views/right_panel/UserInfo.js @@ -17,7 +17,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useCallback, useMemo, useState, useEffect} from 'react'; +import React, {useCallback, useMemo, useState, useEffect, useContext} from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import {Group, RoomMember, User} from 'matrix-js-sdk'; @@ -37,9 +37,9 @@ import MultiInviter from "../../../utils/MultiInviter"; import GroupStore from "../../../stores/GroupStore"; import MatrixClientPeg from "../../../MatrixClientPeg"; import E2EIcon from "../rooms/E2EIcon"; -import withLegacyMatrixClient from "../../../utils/withLegacyMatrixClient"; import {useEventEmitter} from "../../../hooks/useEventEmitter"; import {textualPowerLevel} from '../../../Roles'; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; const _disambiguateDevices = (devices) => { const names = Object.create(null); @@ -203,7 +203,9 @@ function DevicesSection({devices, userId, loading}) { ); } -const UserOptionsSection = withLegacyMatrixClient(({matrixClient: cli, member, isIgnored, canInvite, devices}) => { +const UserOptionsSection = ({member, isIgnored, canInvite, devices}) => { + const cli = useContext(MatrixClientContext); + let ignoreButton = null; let insertPillButton = null; let inviteUserButton = null; @@ -336,7 +338,7 @@ const UserOptionsSection = withLegacyMatrixClient(({matrixClient: cli, member, i
); -}); +}; const _warnSelfDemote = async () => { const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); @@ -404,7 +406,9 @@ const useRoomPowerLevels = (cli, room) => { return powerLevels; }; -const RoomKickButton = withLegacyMatrixClient(({matrixClient: cli, member, startUpdating, stopUpdating}) => { +const RoomKickButton = ({member, startUpdating, stopUpdating}) => { + const cli = useContext(MatrixClientContext); + const onKick = async () => { const ConfirmUserActionDialog = sdk.getComponent("dialogs.ConfirmUserActionDialog"); const {finished} = Modal.createTrackedDialog( @@ -444,9 +448,11 @@ const RoomKickButton = withLegacyMatrixClient(({matrixClient: cli, member, start return { kickLabel } ; -}); +}; + +const RedactMessagesButton = ({member}) => { + const cli = useContext(MatrixClientContext); -const RedactMessagesButton = withLegacyMatrixClient(({matrixClient: cli, member}) => { const onRedactAllMessages = async () => { const {roomId, userId} = member; const room = cli.getRoom(roomId); @@ -517,9 +523,11 @@ const RedactMessagesButton = withLegacyMatrixClient(({matrixClient: cli, member} return { _t("Remove recent messages") } ; -}); +}; + +const BanToggleButton = ({member, startUpdating, stopUpdating}) => { + const cli = useContext(MatrixClientContext); -const BanToggleButton = withLegacyMatrixClient(({matrixClient: cli, member, startUpdating, stopUpdating}) => { const onBanOrUnban = async () => { const ConfirmUserActionDialog = sdk.getComponent("dialogs.ConfirmUserActionDialog"); const {finished} = Modal.createTrackedDialog( @@ -573,207 +581,206 @@ const BanToggleButton = withLegacyMatrixClient(({matrixClient: cli, member, star return { label } ; -}); +}; -const MuteToggleButton = withLegacyMatrixClient( - ({matrixClient: cli, member, room, powerLevels, startUpdating, stopUpdating}) => { - const isMuted = _isMuted(member, powerLevels); - const onMuteToggle = async () => { - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - const roomId = member.roomId; - const target = member.userId; +const MuteToggleButton = ({member, room, powerLevels, startUpdating, stopUpdating}) => { + const cli = useContext(MatrixClientContext); - // if muting self, warn as it may be irreversible - if (target === cli.getUserId()) { - try { - if (!(await _warnSelfDemote())) return; - } catch (e) { - console.error("Failed to warn about self demotion: ", e); - return; - } + const isMuted = _isMuted(member, powerLevels); + const onMuteToggle = async () => { + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + const roomId = member.roomId; + const target = member.userId; + + // if muting self, warn as it may be irreversible + if (target === cli.getUserId()) { + try { + if (!(await _warnSelfDemote())) return; + } catch (e) { + console.error("Failed to warn about self demotion: ", e); + return; } + } - const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", ""); - if (!powerLevelEvent) return; + const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", ""); + if (!powerLevelEvent) return; - const powerLevels = powerLevelEvent.getContent(); - const levelToSend = ( - (powerLevels.events ? powerLevels.events["m.room.message"] : null) || - powerLevels.events_default - ); - let level; - if (isMuted) { // unmute - level = levelToSend; - } else { // mute - level = levelToSend - 1; - } - level = parseInt(level); + const powerLevels = powerLevelEvent.getContent(); + const levelToSend = ( + (powerLevels.events ? powerLevels.events["m.room.message"] : null) || + powerLevels.events_default + ); + let level; + if (isMuted) { // unmute + level = levelToSend; + } else { // mute + level = levelToSend - 1; + } + level = parseInt(level); - if (!isNaN(level)) { - startUpdating(); - cli.setPowerLevel(roomId, target, level, powerLevelEvent).then(() => { - // NO-OP; rely on the m.room.member event coming down else we could - // get out of sync if we force setState here! - console.log("Mute toggle success"); - }, function(err) { - console.error("Mute error: " + err); - Modal.createTrackedDialog('Failed to mute user', '', ErrorDialog, { - title: _t("Error"), - description: _t("Failed to mute user"), - }); - }).finally(() => { - stopUpdating(); + if (!isNaN(level)) { + startUpdating(); + cli.setPowerLevel(roomId, target, level, powerLevelEvent).then(() => { + // NO-OP; rely on the m.room.member event coming down else we could + // get out of sync if we force setState here! + console.log("Mute toggle success"); + }, function(err) { + console.error("Mute error: " + err); + Modal.createTrackedDialog('Failed to mute user', '', ErrorDialog, { + title: _t("Error"), + description: _t("Failed to mute user"), }); - } + }).finally(() => { + stopUpdating(); + }); + } + }; + + const classes = classNames("mx_UserInfo_field", { + mx_UserInfo_destructive: !isMuted, + }); + + const muteLabel = isMuted ? _t("Unmute") : _t("Mute"); + return + { muteLabel } + ; +}; + +const RoomAdminToolsContainer = ({room, children, member, startUpdating, stopUpdating, powerLevels}) => { + const cli = useContext(MatrixClientContext); + let kickButton; + let banButton; + let muteButton; + let redactButton; + + const editPowerLevel = ( + (powerLevels.events ? powerLevels.events["m.room.power_levels"] : null) || + powerLevels.state_default + ); + + const me = room.getMember(cli.getUserId()); + const isMe = me.userId === member.userId; + const canAffectUser = member.powerLevel < me.powerLevel || isMe; + + if (canAffectUser && me.powerLevel >= powerLevels.kick) { + kickButton = ; + } + if (me.powerLevel >= powerLevels.redact) { + redactButton = ( + + ); + } + if (canAffectUser && me.powerLevel >= powerLevels.ban) { + banButton = ; + } + if (canAffectUser && me.powerLevel >= editPowerLevel) { + muteButton = ( + + ); + } + + if (kickButton || banButton || muteButton || redactButton || children) { + return + { muteButton } + { kickButton } + { banButton } + { redactButton } + { children } + ; + } + + return
; +}; + +const GroupAdminToolsSection = ({children, groupId, groupMember, startUpdating, stopUpdating}) => { + const cli = useContext(MatrixClientContext); + + const [isPrivileged, setIsPrivileged] = useState(false); + const [isInvited, setIsInvited] = useState(false); + + // Listen to group store changes + useEffect(() => { + let unmounted = false; + + const onGroupStoreUpdated = () => { + if (unmounted) return; + setIsPrivileged(GroupStore.isUserPrivileged(groupId)); + setIsInvited(GroupStore.getGroupInvitedMembers(groupId).some( + (m) => m.userId === groupMember.userId, + )); }; - const classes = classNames("mx_UserInfo_field", { - mx_UserInfo_destructive: !isMuted, - }); + GroupStore.registerListener(groupId, onGroupStoreUpdated); + onGroupStoreUpdated(); + // Handle unmount + return () => { + unmounted = true; + GroupStore.unregisterListener(onGroupStoreUpdated); + }; + }, [groupId, groupMember.userId]); - const muteLabel = isMuted ? _t("Unmute") : _t("Mute"); - return - { muteLabel } - ; - }, -); + if (isPrivileged) { + const _onKick = async () => { + const ConfirmUserActionDialog = sdk.getComponent("dialogs.ConfirmUserActionDialog"); + const {finished} = Modal.createDialog(ConfirmUserActionDialog, { + matrixClient: cli, + groupMember, + action: isInvited ? _t('Disinvite') : _t('Remove from community'), + title: isInvited ? _t('Disinvite this user from community?') + : _t('Remove this user from community?'), + danger: true, + }); -const RoomAdminToolsContainer = withLegacyMatrixClient( - ({matrixClient: cli, room, children, member, startUpdating, stopUpdating, powerLevels}) => { - let kickButton; - let banButton; - let muteButton; - let redactButton; + const [proceed] = await finished; + if (!proceed) return; - const editPowerLevel = ( - (powerLevels.events ? powerLevels.events["m.room.power_levels"] : null) || - powerLevels.state_default + startUpdating(); + cli.removeUserFromGroup(groupId, groupMember.userId).then(() => { + // return to the user list + dis.dispatch({ + action: "view_user", + member: null, + }); + }).catch((e) => { + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createTrackedDialog('Failed to remove user from group', '', ErrorDialog, { + title: _t('Error'), + description: isInvited ? + _t('Failed to withdraw invitation') : + _t('Failed to remove user from community'), + }); + console.log(e); + }).finally(() => { + stopUpdating(); + }); + }; + + const kickButton = ( + + { isInvited ? _t('Disinvite') : _t('Remove from community') } + ); - const me = room.getMember(cli.getUserId()); - const isMe = me.userId === member.userId; - const canAffectUser = member.powerLevel < me.powerLevel || isMe; + // No make/revoke admin API yet + /*const opLabel = this.state.isTargetMod ? _t("Revoke Moderator") : _t("Make Moderator"); + giveModButton = + {giveOpLabel} + ;*/ - if (canAffectUser && me.powerLevel >= powerLevels.kick) { - kickButton = ; - } - if (me.powerLevel >= powerLevels.redact) { - redactButton = ( - - ); - } - if (canAffectUser && me.powerLevel >= powerLevels.ban) { - banButton = ; - } - if (canAffectUser && me.powerLevel >= editPowerLevel) { - muteButton = ( - - ); - } + return + { kickButton } + { children } + ; + } - if (kickButton || banButton || muteButton || redactButton || children) { - return - { muteButton } - { kickButton } - { banButton } - { redactButton } - { children } - ; - } - - return
; - }, -); - -const GroupAdminToolsSection = withLegacyMatrixClient( - ({matrixClient: cli, children, groupId, groupMember, startUpdating, stopUpdating}) => { - const [isPrivileged, setIsPrivileged] = useState(false); - const [isInvited, setIsInvited] = useState(false); - - // Listen to group store changes - useEffect(() => { - let unmounted = false; - - const onGroupStoreUpdated = () => { - if (unmounted) return; - setIsPrivileged(GroupStore.isUserPrivileged(groupId)); - setIsInvited(GroupStore.getGroupInvitedMembers(groupId).some( - (m) => m.userId === groupMember.userId, - )); - }; - - GroupStore.registerListener(groupId, onGroupStoreUpdated); - onGroupStoreUpdated(); - // Handle unmount - return () => { - unmounted = true; - GroupStore.unregisterListener(onGroupStoreUpdated); - }; - }, [groupId, groupMember.userId]); - - if (isPrivileged) { - const _onKick = async () => { - const ConfirmUserActionDialog = sdk.getComponent("dialogs.ConfirmUserActionDialog"); - const {finished} = Modal.createDialog(ConfirmUserActionDialog, { - matrixClient: cli, - groupMember, - action: isInvited ? _t('Disinvite') : _t('Remove from community'), - title: isInvited ? _t('Disinvite this user from community?') - : _t('Remove this user from community?'), - danger: true, - }); - - const [proceed] = await finished; - if (!proceed) return; - - startUpdating(); - cli.removeUserFromGroup(groupId, groupMember.userId).then(() => { - // return to the user list - dis.dispatch({ - action: "view_user", - member: null, - }); - }).catch((e) => { - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Failed to remove user from group', '', ErrorDialog, { - title: _t('Error'), - description: isInvited ? - _t('Failed to withdraw invitation') : - _t('Failed to remove user from community'), - }); - console.log(e); - }).finally(() => { - stopUpdating(); - }); - }; - - const kickButton = ( - - { isInvited ? _t('Disinvite') : _t('Remove from community') } - - ); - - // No make/revoke admin API yet - /*const opLabel = this.state.isTargetMod ? _t("Revoke Moderator") : _t("Make Moderator"); - giveModButton = - {giveOpLabel} - ;*/ - - return - { kickButton } - { children } - ; - } - - return
; - }, -); + return
; +}; const GroupMember = PropTypes.shape({ userId: PropTypes.string.isRequired, @@ -849,7 +856,7 @@ function useRoomPermissions(cli, room, user) { return roomPermissions; } -const PowerLevelSection = withLegacyMatrixClient(({matrixClient: cli, user, room, roomPermissions, powerLevels}) => { +const PowerLevelSection = ({user, room, roomPermissions, powerLevels}) => { const [isEditing, setEditing] = useState(false); if (room && user.roomId) { // is in room if (isEditing) { @@ -876,9 +883,11 @@ const PowerLevelSection = withLegacyMatrixClient(({matrixClient: cli, user, room } else { return null; } -}); +}; + +const PowerLevelEditor = ({user, room, roomPermissions, onFinished}) => { + const cli = useContext(MatrixClientContext); -const PowerLevelEditor = withLegacyMatrixClient(({matrixClient: cli, user, room, roomPermissions, onFinished}) => { const [isUpdating, setIsUpdating] = useState(false); const [selectedPowerLevel, setSelectedPowerLevel] = useState(parseInt(user.powerLevel, 10)); const [isDirty, setIsDirty] = useState(false); @@ -982,10 +991,11 @@ const PowerLevelEditor = withLegacyMatrixClient(({matrixClient: cli, user, room, {buttonOrSpinner}
); -}); +}; + +const UserInfo = ({user, groupId, roomId, onClose}) => { + const cli = useContext(MatrixClientContext); -// cli is injected by withLegacyMatrixClient -const UserInfo = withLegacyMatrixClient(({matrixClient: cli, user, groupId, roomId, onClose}) => { // Load room if we are given a room id and memoize it const room = useMemo(() => roomId ? cli.getRoom(roomId) : null, [cli, roomId]); @@ -1316,7 +1326,7 @@ const UserInfo = withLegacyMatrixClient(({matrixClient: cli, user, groupId, room
); -}); +}; UserInfo.propTypes = { user: PropTypes.oneOfType([ diff --git a/src/components/views/room_settings/RelatedGroupSettings.js b/src/components/views/room_settings/RelatedGroupSettings.js index c30f446f41..20118f4f44 100644 --- a/src/components/views/room_settings/RelatedGroupSettings.js +++ b/src/components/views/room_settings/RelatedGroupSettings.js @@ -16,11 +16,12 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {MatrixEvent, MatrixClient} from 'matrix-js-sdk'; +import {MatrixEvent} from 'matrix-js-sdk'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; import ErrorDialog from "../dialogs/ErrorDialog"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; const GROUP_ID_REGEX = /\+\S+:\S+/; @@ -31,9 +32,7 @@ export default class RelatedGroupSettings extends React.Component { relatedGroupsEvent: PropTypes.instanceOf(MatrixEvent), }; - static contextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient), - }; + static contextType = MatrixClientContext; static defaultProps = { canSetRelatedGroups: false, @@ -49,7 +48,7 @@ export default class RelatedGroupSettings extends React.Component { } updateGroups(newGroupsList) { - this.context.matrixClient.sendStateEvent(this.props.roomId, 'm.room.related_groups', { + this.context.sendStateEvent(this.props.roomId, 'm.room.related_groups', { groups: newGroupsList, }, '').catch((err) => { console.error(err); @@ -99,7 +98,7 @@ export default class RelatedGroupSettings extends React.Component { }; render() { - const localDomain = this.context.matrixClient.getDomain(); + const localDomain = this.context.getDomain(); const EditableItemList = sdk.getComponent('elements.EditableItemList'); return
{ @@ -190,7 +188,7 @@ export default class EditMessageComposer extends React.Component { if (this._isContentModified(newContent)) { const roomId = editedEvent.getRoomId(); this._cancelPreviousPendingEdit(); - this.context.matrixClient.sendMessage(roomId, editContent); + this.context.sendMessage(roomId, editContent); } // close the event editing and focus composer @@ -205,7 +203,7 @@ export default class EditMessageComposer extends React.Component { previousEdit.status === EventStatus.QUEUED || previousEdit.status === EventStatus.NOT_SENT )) { - this.context.matrixClient.cancelPendingEvent(previousEdit); + this.context.cancelPendingEvent(previousEdit); } } @@ -232,7 +230,7 @@ export default class EditMessageComposer extends React.Component { _createEditorModel() { const {editState} = this.props; const room = this._getRoom(); - const partCreator = new PartCreator(room, this.context.matrixClient); + const partCreator = new PartCreator(room, this.context); let parts; if (editState.hasEditorState()) { // if restoring state from a previous editor, diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index 988482df7f..784c4071aa 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -31,10 +31,11 @@ const TextForEvent = require('../../../TextForEvent'); import dis from '../../../dispatcher'; import SettingsStore from "../../../settings/SettingsStore"; -import {EventStatus, MatrixClient} from 'matrix-js-sdk'; +import {EventStatus} from 'matrix-js-sdk'; import {formatTime} from "../../../DateUtils"; import MatrixClientPeg from '../../../MatrixClientPeg'; import {ALL_RULE_TYPES} from "../../../mjolnir/BanList"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; const ObjectUtils = require('../../../ObjectUtils'); @@ -222,8 +223,8 @@ module.exports = createReactClass({ }; }, - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, + statics: { + contextType: MatrixClientContext, }, componentWillMount: function() { @@ -237,7 +238,7 @@ module.exports = createReactClass({ componentDidMount: function() { this._suppressReadReceiptAnimation = false; - const client = this.context.matrixClient; + const client = this.context; client.on("deviceVerificationChanged", this.onDeviceVerificationChanged); this.props.mxEvent.on("Event.decrypted", this._onDecrypted); if (this.props.showReactions) { @@ -262,7 +263,7 @@ module.exports = createReactClass({ }, componentWillUnmount: function() { - const client = this.context.matrixClient; + const client = this.context; client.removeListener("deviceVerificationChanged", this.onDeviceVerificationChanged); this.props.mxEvent.removeListener("Event.decrypted", this._onDecrypted); if (this.props.showReactions) { @@ -291,7 +292,7 @@ module.exports = createReactClass({ return; } - const verified = await this.context.matrixClient.isEventSenderVerified(mxEvent); + const verified = await this.context.isEventSenderVerified(mxEvent); this.setState({ verified: verified, }, () => { @@ -349,11 +350,11 @@ module.exports = createReactClass({ }, shouldHighlight: function() { - const actions = this.context.matrixClient.getPushActionsForEvent(this.props.mxEvent); + const actions = this.context.getPushActionsForEvent(this.props.mxEvent); if (!actions || !actions.tweaks) { return false; } // don't show self-highlights from another of our clients - if (this.props.mxEvent.getSender() === this.context.matrixClient.credentials.userId) { + if (this.props.mxEvent.getSender() === this.context.credentials.userId) { return false; } @@ -461,7 +462,7 @@ module.exports = createReactClass({ // Cancel any outgoing key request for this event and resend it. If a response // is received for the request with the required keys, the event could be // decrypted successfully. - this.context.matrixClient.cancelAndResendEventRoomKeyRequest(this.props.mxEvent); + this.context.cancelAndResendEventRoomKeyRequest(this.props.mxEvent); }, onPermalinkClicked: function(e) { @@ -494,7 +495,7 @@ module.exports = createReactClass({ } } - if (this.context.matrixClient.isRoomEncrypted(ev.getRoomId())) { + if (this.context.isRoomEncrypted(ev.getRoomId())) { // else if room is encrypted // and event is being encrypted or is not_sent (Unknown Devices/Network Error) if (ev.status === EventStatus.ENCRYPTING) { @@ -741,7 +742,7 @@ module.exports = createReactClass({ switch (this.props.tileShape) { case 'notif': { - const room = this.context.matrixClient.getRoom(this.props.mxEvent.getRoomId()); + const room = this.context.getRoom(this.props.mxEvent.getRoomId()); return (
diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index 1a2c8e2212..cb8c5b8d49 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -31,7 +31,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import classNames from 'classnames'; -import { MatrixClient } from 'matrix-js-sdk'; import dis from '../../../dispatcher'; import Modal from '../../../Modal'; import sdk from '../../../index'; @@ -48,7 +47,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import E2EIcon from "./E2EIcon"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; import MatrixClientPeg from "../../../MatrixClientPeg"; -import {EventTimeline} from "matrix-js-sdk"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; module.exports = createReactClass({ displayName: 'MemberInfo', @@ -76,13 +75,13 @@ module.exports = createReactClass({ }; }, - contextTypes: { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, + statics: { + contextType: MatrixClientContext, }, componentWillMount: function() { this._cancelDeviceList = null; - const cli = this.context.matrixClient; + const cli = this.context; // only display the devices list if our client supports E2E this._enableDevices = cli.isCryptoEnabled(); @@ -112,7 +111,7 @@ module.exports = createReactClass({ }, componentWillUnmount: function() { - const client = this.context.matrixClient; + const client = this.context; if (client) { client.removeListener("deviceVerificationChanged", this.onDeviceVerificationChanged); client.removeListener("Room", this.onRoom); @@ -131,7 +130,7 @@ module.exports = createReactClass({ }, _checkIgnoreState: function() { - const isIgnoring = this.context.matrixClient.isUserIgnored(this.props.member.userId); + const isIgnoring = this.context.isUserIgnored(this.props.member.userId); this.setState({isIgnoring: isIgnoring}); }, @@ -163,7 +162,7 @@ module.exports = createReactClass({ // Promise.resolve to handle transition from static result to promise; can be removed // in future - Promise.resolve(this.context.matrixClient.getStoredDevicesForUser(userId)).then((devices) => { + Promise.resolve(this.context.getStoredDevicesForUser(userId)).then((devices) => { this.setState({ devices: devices, e2eStatus: this._getE2EStatus(devices), @@ -197,7 +196,7 @@ module.exports = createReactClass({ onRoomReceipt: function(receiptEvent, room) { // because if we read a notification, it will affect notification count // only bother updating if there's a receipt from us - if (findReadReceiptFromUserId(receiptEvent, this.context.matrixClient.credentials.userId)) { + if (findReadReceiptFromUserId(receiptEvent, this.context.credentials.userId)) { this.forceUpdate(); } }, @@ -242,7 +241,7 @@ module.exports = createReactClass({ let cancelled = false; this._cancelDeviceList = function() { cancelled = true; }; - const client = this.context.matrixClient; + const client = this.context; const self = this; client.downloadKeys([member.userId], true).then(() => { return client.getStoredDevicesForUser(member.userId); @@ -267,7 +266,7 @@ module.exports = createReactClass({ }, onIgnoreToggle: function() { - const ignoredUsers = this.context.matrixClient.getIgnoredUsers(); + const ignoredUsers = this.context.getIgnoredUsers(); if (this.state.isIgnoring) { const index = ignoredUsers.indexOf(this.props.member.userId); if (index !== -1) ignoredUsers.splice(index, 1); @@ -275,7 +274,7 @@ module.exports = createReactClass({ ignoredUsers.push(this.props.member.userId); } - this.context.matrixClient.setIgnoredUsers(ignoredUsers).then(() => { + this.context.setIgnoredUsers(ignoredUsers).then(() => { return this.setState({isIgnoring: !this.state.isIgnoring}); }); }, @@ -293,7 +292,7 @@ module.exports = createReactClass({ if (!proceed) return; this.setState({ updating: this.state.updating + 1 }); - this.context.matrixClient.kick( + this.context.kick( this.props.member.roomId, this.props.member.userId, reason || undefined, ).then(function() { @@ -329,11 +328,11 @@ module.exports = createReactClass({ this.setState({ updating: this.state.updating + 1 }); let promise; if (this.props.member.membership === 'ban') { - promise = this.context.matrixClient.unban( + promise = this.context.unban( this.props.member.roomId, this.props.member.userId, ); } else { - promise = this.context.matrixClient.ban( + promise = this.context.ban( this.props.member.roomId, this.props.member.userId, reason || undefined, ); @@ -360,7 +359,7 @@ module.exports = createReactClass({ onRedactAllMessages: async function() { const {roomId, userId} = this.props.member; - const room = this.context.matrixClient.getRoom(roomId); + const room = this.context.getRoom(roomId); if (!room) { return; } @@ -414,7 +413,7 @@ module.exports = createReactClass({ console.info(`Started redacting recent ${count} messages for ${user} in ${roomId}`); await Promise.all(eventsToRedact.map(async event => { try { - await this.context.matrixClient.redactEvent(roomId, event.getId()); + await this.context.redactEvent(roomId, event.getId()); } catch (err) { // log and swallow errors console.error("Could not redact", event.getId()); @@ -446,11 +445,11 @@ module.exports = createReactClass({ const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const roomId = this.props.member.roomId; const target = this.props.member.userId; - const room = this.context.matrixClient.getRoom(roomId); + const room = this.context.getRoom(roomId); if (!room) return; // if muting self, warn as it may be irreversible - if (target === this.context.matrixClient.getUserId()) { + if (target === this.context.getUserId()) { try { if (!(await this._warnSelfDemote())) return; } catch (e) { @@ -478,7 +477,7 @@ module.exports = createReactClass({ if (!isNaN(level)) { this.setState({ updating: this.state.updating + 1 }); - this.context.matrixClient.setPowerLevel(roomId, target, level, powerLevelEvent).then( + this.context.setPowerLevel(roomId, target, level, powerLevelEvent).then( function() { // NO-OP; rely on the m.room.member event coming down else we could // get out of sync if we force setState here! @@ -500,13 +499,13 @@ module.exports = createReactClass({ const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const roomId = this.props.member.roomId; const target = this.props.member.userId; - const room = this.context.matrixClient.getRoom(roomId); + const room = this.context.getRoom(roomId); if (!room) return; const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", ""); if (!powerLevelEvent) return; - const me = room.getMember(this.context.matrixClient.credentials.userId); + const me = room.getMember(this.context.credentials.userId); if (!me) return; const defaultLevel = powerLevelEvent.getContent().users_default; @@ -515,7 +514,7 @@ module.exports = createReactClass({ // toggle the level const newLevel = this.state.isTargetMod ? defaultLevel : modLevel; this.setState({ updating: this.state.updating + 1 }); - this.context.matrixClient.setPowerLevel(roomId, target, parseInt(newLevel), powerLevelEvent).then( + this.context.setPowerLevel(roomId, target, parseInt(newLevel), powerLevelEvent).then( function() { // NO-OP; rely on the m.room.member event coming down else we could // get out of sync if we force setState here! @@ -550,7 +549,7 @@ module.exports = createReactClass({ danger: true, onFinished: (accepted) => { if (!accepted) return; - this.context.matrixClient.deactivateSynapseUser(this.props.member.userId).catch(e => { + this.context.deactivateSynapseUser(this.props.member.userId).catch(e => { console.error("Failed to deactivate user"); console.error(e); @@ -566,7 +565,7 @@ module.exports = createReactClass({ _applyPowerChange: function(roomId, target, powerLevel, powerLevelEvent) { this.setState({ updating: this.state.updating + 1 }); - this.context.matrixClient.setPowerLevel(roomId, target, parseInt(powerLevel), powerLevelEvent).then( + this.context.setPowerLevel(roomId, target, parseInt(powerLevel), powerLevelEvent).then( function() { // NO-OP; rely on the m.room.member event coming down else we could // get out of sync if we force setState here! @@ -587,7 +586,7 @@ module.exports = createReactClass({ onPowerChange: async function(powerLevel) { const roomId = this.props.member.roomId; const target = this.props.member.userId; - const room = this.context.matrixClient.getRoom(roomId); + const room = this.context.getRoom(roomId); if (!room) return; const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", ""); @@ -598,7 +597,7 @@ module.exports = createReactClass({ return; } - const myUserId = this.context.matrixClient.getUserId(); + const myUserId = this.context.getUserId(); const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); // If we are changing our own PL it can only ever be decreasing, which we cannot reverse. @@ -650,9 +649,9 @@ module.exports = createReactClass({ _calculateOpsPermissions: async function(member) { let canDeactivate = false; - if (this.context.matrixClient) { + if (this.context) { try { - canDeactivate = await this.context.matrixClient.isSynapseAdministrator(); + canDeactivate = await this.context.isSynapseAdministrator(); } catch (e) { console.error(e); } @@ -665,13 +664,13 @@ module.exports = createReactClass({ }, muted: false, }; - const room = this.context.matrixClient.getRoom(member.roomId); + const room = this.context.getRoom(member.roomId); if (!room) return defaultPerms; const powerLevels = room.currentState.getStateEvents("m.room.power_levels", ""); if (!powerLevels) return defaultPerms; - const me = room.getMember(this.context.matrixClient.credentials.userId); + const me = room.getMember(this.context.credentials.userId); if (!me) return defaultPerms; const them = member; @@ -738,7 +737,7 @@ module.exports = createReactClass({ const avatarUrl = member.getMxcAvatarUrl(); if (!avatarUrl) return; - const httpUrl = this.context.matrixClient.mxcUrlToHttp(avatarUrl); + const httpUrl = this.context.mxcUrlToHttp(avatarUrl); const ImageView = sdk.getComponent("elements.ImageView"); const params = { src: httpUrl, @@ -797,7 +796,7 @@ module.exports = createReactClass({ }, _renderUserOptions: function() { - const cli = this.context.matrixClient; + const cli = this.context; const member = this.props.member; let ignoreButton = null; @@ -905,9 +904,9 @@ module.exports = createReactClass({ let synapseDeactivateButton; let spinner; - if (this.props.member.userId !== this.context.matrixClient.credentials.userId) { + if (this.props.member.userId !== this.context.credentials.userId) { // TODO: Immutable DMs replaces a lot of this - const dmRoomMap = new DMRoomMap(this.context.matrixClient); + const dmRoomMap = new DMRoomMap(this.context); // dmRooms will not include dmRooms that we have been invited into but did not join. // Because DMRoomMap runs off account_data[m.direct] which is only set on join of dm room. // XXX: we potentially want DMs we have been invited to, to also show up here :L @@ -918,7 +917,7 @@ module.exports = createReactClass({ const tiles = []; for (const roomId of dmRooms) { - const room = this.context.matrixClient.getRoom(roomId); + const room = this.context.getRoom(roomId); if (room) { const myMembership = room.getMyMembership(); // not a DM room if we have are not joined @@ -1064,12 +1063,12 @@ module.exports = createReactClass({ } } - const room = this.context.matrixClient.getRoom(this.props.member.roomId); + const room = this.context.getRoom(this.props.member.roomId); const powerLevelEvent = room ? room.currentState.getStateEvents("m.room.power_levels", "") : null; const powerLevelUsersDefault = powerLevelEvent ? powerLevelEvent.getContent().users_default : 0; const enablePresenceByHsUrl = SdkConfig.get()["enable_presence_by_hs_url"]; - const hsUrl = this.context.matrixClient.baseUrl; + const hsUrl = this.context.baseUrl; let showPresence = true; if (enablePresenceByHsUrl && enablePresenceByHsUrl[hsUrl] !== undefined) { showPresence = enablePresenceByHsUrl[hsUrl]; @@ -1108,7 +1107,7 @@ module.exports = createReactClass({
; - const isEncrypted = this.context.matrixClient.isRoomEncrypted(this.props.member.roomId); + const isEncrypted = this.context.isRoomEncrypted(this.props.member.roomId); if (this.state.e2eStatus && isEncrypted) { e2eIconElement = (); } @@ -1117,7 +1116,7 @@ module.exports = createReactClass({ const avatarUrl = this.props.member.getMxcAvatarUrl(); let avatarElement; if (avatarUrl) { - const httpUrl = this.context.matrixClient.mxcUrlToHttp(avatarUrl, 800, 800); + const httpUrl = this.context.mxcUrlToHttp(avatarUrl, 800, 800); avatarElement =
; diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 580e3b0d81..06e6834bec 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -107,8 +107,8 @@ class UploadButton extends React.Component { roomId: PropTypes.string.isRequired, } - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.onUploadClick = this.onUploadClick.bind(this); this.onUploadFileInputChange = this.onUploadFileInputChange.bind(this); @@ -165,8 +165,8 @@ class UploadButton extends React.Component { } export default class MessageComposer extends React.Component { - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.onInputStateChanged = this.onInputStateChanged.bind(this); this.onEvent = this.onEvent.bind(this); this._onRoomStateEvents = this._onRoomStateEvents.bind(this); diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index dc8e8e439f..595ec0681f 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -141,8 +141,8 @@ export default class MessageComposerInput extends React.Component { autocomplete: Autocomplete; historyManager: SlateComposerHistoryManager; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); const isRichTextEnabled = SettingsStore.getValue('MessageComposerInput.isRichTextEnabled'); diff --git a/src/components/views/rooms/ReplyPreview.js b/src/components/views/rooms/ReplyPreview.js index caf8feeea2..af2ea640f5 100644 --- a/src/components/views/rooms/ReplyPreview.js +++ b/src/components/views/rooms/ReplyPreview.js @@ -35,8 +35,8 @@ export default class ReplyPreview extends React.Component { permalinkCreator: PropTypes.instanceOf(RoomPermalinkCreator).isRequired, }; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.unmounted = false; this.state = { diff --git a/src/components/views/rooms/SendMessageComposer.js b/src/components/views/rooms/SendMessageComposer.js index af25155588..af7177ebc7 100644 --- a/src/components/views/rooms/SendMessageComposer.js +++ b/src/components/views/rooms/SendMessageComposer.js @@ -26,7 +26,6 @@ import { unescapeMessage, } from '../../../editor/serialize'; import {CommandPartCreator} from '../../../editor/parts'; -import {MatrixClient} from 'matrix-js-sdk'; import BasicMessageComposer from "./BasicMessageComposer"; import ReplyPreview from "./ReplyPreview"; import RoomViewStore from '../../../stores/RoomViewStore'; @@ -40,6 +39,7 @@ import Modal from '../../../Modal'; import {_t, _td} from '../../../languageHandler'; import ContentMessages from '../../../ContentMessages'; import {Key} from "../../../Keyboard"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; function addReplyToMessageContent(content, repliedToEvent, permalinkCreator) { const replyContent = ReplyThread.makeReplyMixIn(repliedToEvent); @@ -89,12 +89,10 @@ export default class SendMessageComposer extends React.Component { permalinkCreator: PropTypes.object.isRequired, }; - static contextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, - }; + static contextType = MatrixClientContext; - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.model = null; this._editorRef = null; this.currentlyComposedEditorState = null; @@ -245,7 +243,7 @@ export default class SendMessageComposer extends React.Component { const isReply = !!RoomViewStore.getQuotingEvent(); const {roomId} = this.props.room; const content = createMessageContent(this.model, this.props.permalinkCreator); - this.context.matrixClient.sendMessage(roomId, content); + this.context.sendMessage(roomId, content); if (isReply) { // Clear reply_to_event as we put the message into the queue // if the send fails, retry will handle resending. @@ -273,7 +271,7 @@ export default class SendMessageComposer extends React.Component { } componentWillMount() { - const partCreator = new CommandPartCreator(this.props.room, this.context.matrixClient); + const partCreator = new CommandPartCreator(this.props.room, this.context); const parts = this._restoreStoredEditorState(partCreator) || []; this.model = new EditorModel(parts, partCreator); this.dispatcherRef = dis.register(this.onAction); @@ -361,7 +359,7 @@ export default class SendMessageComposer extends React.Component { // from Finder) but more images copied from a different website // / word processor etc. ContentMessages.sharedInstance().sendContentListToRoom( - Array.from(clipboardData.files), this.props.room.roomId, this.context.matrixClient, + Array.from(clipboardData.files), this.props.room.roomId, this.context, ); } } diff --git a/src/components/views/rooms/SlateMessageComposer.js b/src/components/views/rooms/SlateMessageComposer.js index ebd9017d73..2b68e0d338 100644 --- a/src/components/views/rooms/SlateMessageComposer.js +++ b/src/components/views/rooms/SlateMessageComposer.js @@ -137,8 +137,8 @@ class UploadButton extends React.Component { static propTypes = { roomId: PropTypes.string.isRequired, } - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.onUploadClick = this.onUploadClick.bind(this); this.onUploadFileInputChange = this.onUploadFileInputChange.bind(this); @@ -193,8 +193,8 @@ class UploadButton extends React.Component { } export default class SlateMessageComposer extends React.Component { - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this._onAutocompleteConfirm = this._onAutocompleteConfirm.bind(this); this.onToggleFormattingClicked = this.onToggleFormattingClicked.bind(this); this.onToggleMarkdownClicked = this.onToggleMarkdownClicked.bind(this); diff --git a/src/components/views/settings/DevicesPanel.js b/src/components/views/settings/DevicesPanel.js index cb5db10be4..cdde53b44b 100644 --- a/src/components/views/settings/DevicesPanel.js +++ b/src/components/views/settings/DevicesPanel.js @@ -25,8 +25,8 @@ import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; export default class DevicesPanel extends React.Component { - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this.state = { devices: undefined, diff --git a/src/components/views/settings/DevicesPanelEntry.js b/src/components/views/settings/DevicesPanelEntry.js index 98ba29471d..533c15976b 100644 --- a/src/components/views/settings/DevicesPanelEntry.js +++ b/src/components/views/settings/DevicesPanelEntry.js @@ -23,8 +23,8 @@ import MatrixClientPeg from '../../../MatrixClientPeg'; import {formatDate} from '../../../DateUtils'; export default class DevicesPanelEntry extends React.Component { - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); this._unmounted = false; this.onDeviceToggled = this.onDeviceToggled.bind(this); diff --git a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js index 5d707fcf16..2e718b0b69 100644 --- a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js @@ -18,22 +18,19 @@ import React from 'react'; import PropTypes from 'prop-types'; import {_t} from "../../../../../languageHandler"; import RoomProfileSettings from "../../../room_settings/RoomProfileSettings"; -import MatrixClientPeg from "../../../../../MatrixClientPeg"; import sdk from "../../../../.."; import AccessibleButton from "../../../elements/AccessibleButton"; -import {MatrixClient} from "matrix-js-sdk"; import dis from "../../../../../dispatcher"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; +import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; export default class GeneralRoomSettingsTab extends React.Component { - static childContextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient), - }; - static propTypes = { roomId: PropTypes.string.isRequired, }; + static contextType = MatrixClientContext; + constructor() { super(); @@ -42,14 +39,8 @@ export default class GeneralRoomSettingsTab extends React.Component { }; } - getChildContext() { - return { - matrixClient: MatrixClientPeg.get(), - }; - } - componentWillMount() { - MatrixClientPeg.get().getRoomDirectoryVisibility(this.props.roomId).then((result => { + this.context.getRoomDirectoryVisibility(this.props.roomId).then((result => { this.setState({isRoomPublished: result.visibility === 'public'}); })); } @@ -59,7 +50,7 @@ export default class GeneralRoomSettingsTab extends React.Component { const newValue = !valueBefore; this.setState({isRoomPublished: newValue}); - MatrixClientPeg.get().setRoomDirectoryVisibility( + this.context.setRoomDirectoryVisibility( this.props.roomId, newValue ? 'public' : 'private', ).catch(() => { @@ -80,7 +71,7 @@ export default class GeneralRoomSettingsTab extends React.Component { const RelatedGroupSettings = sdk.getComponent("room_settings.RelatedGroupSettings"); const UrlPreviewSettings = sdk.getComponent("room_settings.UrlPreviewSettings"); - const client = MatrixClientPeg.get(); + const client = this.context; const room = client.getRoom(this.props.roomId); const canSetAliases = true; // Previously, we arbitrarily only allowed admins to do this diff --git a/src/components/views/settings/tabs/user/FlairUserSettingsTab.js b/src/components/views/settings/tabs/user/FlairUserSettingsTab.js index 0063a9a981..26e0033233 100644 --- a/src/components/views/settings/tabs/user/FlairUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/FlairUserSettingsTab.js @@ -17,25 +17,8 @@ limitations under the License. import React from 'react'; import {_t} from "../../../../../languageHandler"; import GroupUserSettings from "../../../groups/GroupUserSettings"; -import MatrixClientPeg from "../../../../../MatrixClientPeg"; -import PropTypes from "prop-types"; -import {MatrixClient} from "matrix-js-sdk"; export default class FlairUserSettingsTab extends React.Component { - static childContextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient), - }; - - constructor() { - super(); - } - - getChildContext() { - return { - matrixClient: MatrixClientPeg.get(), - }; - } - render() { return (
diff --git a/src/utils/withLegacyMatrixClient.js b/src/contexts/MatrixClientContext.js similarity index 51% rename from src/utils/withLegacyMatrixClient.js rename to src/contexts/MatrixClientContext.js index af6a930a88..54a23ca132 100644 --- a/src/utils/withLegacyMatrixClient.js +++ b/src/contexts/MatrixClientContext.js @@ -14,18 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; -import PropTypes from "prop-types"; -import {MatrixClient} from "matrix-js-sdk"; +import { createContext } from "react"; -// Higher Order Component to allow use of legacy MatrixClient React Context -// in Functional Components which do not otherwise support legacy React Contexts -export default (Component) => class extends React.PureComponent { - static contextTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, - }; - - render() { - return ; - } -}; +const MatrixClientContext = createContext(undefined); +MatrixClientContext.displayName = "MatrixClientContext"; +export default MatrixClientContext; diff --git a/src/contexts/RoomContext.js b/src/contexts/RoomContext.js new file mode 100644 index 0000000000..8613be195c --- /dev/null +++ b/src/contexts/RoomContext.js @@ -0,0 +1,25 @@ +/* +Copyright 2019 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 { createContext } from "react"; + +const RoomContext = createContext({ + canReact: undefined, + canReply: undefined, + room: undefined, +}); +RoomContext.displayName = "RoomContext"; +export default RoomContext; diff --git a/test/components/structures/MessagePanel-test.js b/test/components/structures/MessagePanel-test.js index 7c52512bc2..b7c7b4a396 100644 --- a/test/components/structures/MessagePanel-test.js +++ b/test/components/structures/MessagePanel-test.js @@ -36,27 +36,14 @@ const test_utils = require('test-utils'); const mockclock = require('mock-clock'); import Velocity from 'velocity-animate'; +import MatrixClientContext from "../../../src/contexts/MatrixClientContext"; +import RoomContext from "../../../src/contexts/RoomContext"; let client; const room = new Matrix.Room(); // wrap MessagePanel with a component which provides the MatrixClient in the context. const WrappedMessagePanel = createReactClass({ - childContextTypes: { - matrixClient: PropTypes.object, - room: PropTypes.object, - }, - - getChildContext: function() { - return { - matrixClient: client, - room: { - canReact: true, - canReply: true, - }, - }; - }, - getInitialState: function() { return { resizeNotifier: new EventEmitter(), @@ -64,7 +51,11 @@ const WrappedMessagePanel = createReactClass({ }, render: function() { - return ; + return + + + + ; }, }); diff --git a/test/components/views/elements/MemberEventListSummary-test.js b/test/components/views/elements/MemberEventListSummary-test.js index a31cbdebb5..906ba45711 100644 --- a/test/components/views/elements/MemberEventListSummary-test.js +++ b/test/components/views/elements/MemberEventListSummary-test.js @@ -115,7 +115,8 @@ describe('MemberEventListSummary', function() { const renderer = new ShallowRenderer(); renderer.render(); - const result = renderer.getRenderOutput(); + const wrapper = renderer.getRenderOutput(); // matrix cli context wrapper + const result = wrapper.props.children; expect(result.props.children).toEqual([
Expanded membership
, @@ -137,7 +138,8 @@ describe('MemberEventListSummary', function() { const renderer = new ShallowRenderer(); renderer.render(); - const result = renderer.getRenderOutput(); + const wrapper = renderer.getRenderOutput(); // matrix cli context wrapper + const result = wrapper.props.children; expect(result.props.children).toEqual([
Expanded membership
, diff --git a/test/test-utils.js b/test/test-utils.js index 64704fc610..5c8c7f8a10 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -2,13 +2,13 @@ import sinon from 'sinon'; import React from 'react'; -import PropTypes from 'prop-types'; import peg from '../src/MatrixClientPeg'; import dis from '../src/dispatcher'; import jssdk from 'matrix-js-sdk'; import {makeType} from "../src/utils/TypeUtils"; import {ValidatedServerConfig} from "../src/utils/AutoDiscoveryUtils"; import ShallowRenderer from 'react-test-renderer/shallow'; +import MatrixClientContext from "../src/contexts/MatrixClientContext"; const MatrixEvent = jssdk.MatrixEvent; /** @@ -291,22 +291,16 @@ export function getDispatchForStore(store) { export function wrapInMatrixClientContext(WrappedComponent) { class Wrapper extends React.Component { - static childContextTypes = { - matrixClient: PropTypes.object, - } + constructor(props) { + super(props); - getChildContext() { - return { - matrixClient: this._matrixClient, - }; - } - - componentWillMount() { this._matrixClient = peg.get(); } render() { - return ; + return + + ; } } return Wrapper;