From 27ec81f1a2632e20d907f1220cf5e0521f606f39 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sun, 22 Mar 2020 09:41:14 +0000 Subject: [PATCH] Migrate RoomView to React Contexts in the hope for better temporal stability Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .eslintignore.errorfiles | 5 - src/components/structures/RoomView.js | 149 ++++++++++++-------------- 2 files changed, 71 insertions(+), 83 deletions(-) diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index ffd398cb14..9973cfb120 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -1,6 +1,5 @@ # autogenerated file: run scripts/generate-eslint-error-ignore-file to update. -src/component-index.js src/components/structures/RoomDirectory.js src/components/structures/RoomStatusBar.js src/components/structures/RoomView.js @@ -10,7 +9,6 @@ src/components/structures/UploadBar.js src/components/views/avatars/BaseAvatar.js src/components/views/avatars/MemberAvatar.js src/components/views/create_room/RoomAlias.js -src/components/views/dialogs/DeactivateAccountDialog.js src/components/views/dialogs/SetPasswordDialog.js src/components/views/dialogs/UnknownDeviceDialog.js src/components/views/elements/AddressSelector.js @@ -31,7 +29,6 @@ src/components/views/rooms/MemberInfo.js src/components/views/rooms/MemberList.js src/components/views/rooms/RoomList.js src/components/views/rooms/RoomPreviewBar.js -src/components/views/rooms/SearchBar.js src/components/views/rooms/SearchResultTile.js src/components/views/settings/ChangeAvatar.js src/components/views/settings/ChangePassword.js @@ -44,7 +41,6 @@ src/notifications/ContentRules.js src/notifications/PushRuleVectorState.js src/PlatformPeg.js src/rageshake/rageshake.js -src/rageshake/submit-rageshake.js src/ratelimitedfunc.js src/Rooms.js src/Unread.js @@ -60,7 +56,6 @@ test/components/views/dialogs/InteractiveAuthDialog-test.js test/mock-clock.js test/notifications/ContentRules-test.js test/notifications/PushRuleVectorState-test.js -test/stores/RoomViewStore-test.js src/component-index.js test/end-to-end-tests/node_modules/ test/end-to-end-tests/riot/ diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 0bdbf44bcd..5fd5f42f78 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -30,7 +30,6 @@ import classNames from 'classnames'; import { _t } from '../../languageHandler'; import {RoomPermalinkCreator} from '../../utils/permalinks/Permalinks'; -import {MatrixClientPeg} from '../../MatrixClientPeg'; import ContentMessages from '../../ContentMessages'; import Modal from '../../Modal'; import * as sdk from '../../index'; @@ -55,6 +54,7 @@ import AccessibleButton from "../views/elements/AccessibleButton"; import RightPanelStore from "../../stores/RightPanelStore"; import {haveTileForEvent} from "../views/rooms/EventTile"; import RoomContext from "../../contexts/RoomContext"; +import MatrixClientContext from "../../contexts/MatrixClientContext"; const DEBUG = false; let debuglog = function() {}; @@ -97,8 +97,12 @@ export default createReactClass({ viaServers: PropTypes.arrayOf(PropTypes.string), }, + statics: { + contextType: MatrixClientContext, + }, + getInitialState: function() { - const llMembers = MatrixClientPeg.get().hasLazyLoadMembersEnabled(); + const llMembers = this.context.hasLazyLoadMembersEnabled(); return { room: null, roomId: null, @@ -165,17 +169,17 @@ export default createReactClass({ componentWillMount: function() { this.dispatcherRef = dis.register(this.onAction); - MatrixClientPeg.get().on("Room", this.onRoom); - MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline); - MatrixClientPeg.get().on("Room.name", this.onRoomName); - MatrixClientPeg.get().on("Room.accountData", this.onRoomAccountData); - MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents); - MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember); - MatrixClientPeg.get().on("Room.myMembership", this.onMyMembership); - MatrixClientPeg.get().on("accountData", this.onAccountData); - MatrixClientPeg.get().on("crypto.keyBackupStatus", this.onKeyBackupStatus); - MatrixClientPeg.get().on("deviceVerificationChanged", this.onDeviceVerificationChanged); - MatrixClientPeg.get().on("userTrustStatusChanged", this.onUserVerificationChanged); + this.context.on("Room", this.onRoom); + this.context.on("Room.timeline", this.onRoomTimeline); + this.context.on("Room.name", this.onRoomName); + this.context.on("Room.accountData", this.onRoomAccountData); + this.context.on("RoomState.events", this.onRoomStateEvents); + this.context.on("RoomState.members", this.onRoomStateMember); + this.context.on("Room.myMembership", this.onMyMembership); + this.context.on("accountData", this.onAccountData); + this.context.on("crypto.keyBackupStatus", this.onKeyBackupStatus); + this.context.on("deviceVerificationChanged", this.onDeviceVerificationChanged); + this.context.on("userTrustStatusChanged", this.onUserVerificationChanged); // Start listening for RoomViewStore updates this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate); this._rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this._onRightPanelStoreUpdate); @@ -245,7 +249,7 @@ export default createReactClass({ // NB: This does assume that the roomID will not change for the lifetime of // the RoomView instance if (initial) { - newState.room = MatrixClientPeg.get().getRoom(newState.roomId); + newState.room = this.context.getRoom(newState.roomId); if (newState.room) { newState.showApps = this._shouldShowApps(newState.room); this._onRoomLoaded(newState.room); @@ -347,7 +351,7 @@ export default createReactClass({ peekLoading: true, isPeeking: true, // this will change to false if peeking fails }); - MatrixClientPeg.get().peekInRoom(roomId).then((room) => { + this.context.peekInRoom(roomId).then((room) => { if (this.unmounted) { return; } @@ -380,7 +384,7 @@ export default createReactClass({ }); } else if (room) { // Stop peeking because we have joined this room previously - MatrixClientPeg.get().stopPeeking(); + this.context.stopPeeking(); this.setState({isPeeking: false}); } } @@ -477,18 +481,18 @@ export default createReactClass({ roomView.removeEventListener('dragend', this.onDragLeaveOrEnd); } dis.unregister(this.dispatcherRef); - if (MatrixClientPeg.get()) { - MatrixClientPeg.get().removeListener("Room", this.onRoom); - MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); - MatrixClientPeg.get().removeListener("Room.name", this.onRoomName); - MatrixClientPeg.get().removeListener("Room.accountData", this.onRoomAccountData); - MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents); - MatrixClientPeg.get().removeListener("Room.myMembership", this.onMyMembership); - MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember); - MatrixClientPeg.get().removeListener("accountData", this.onAccountData); - MatrixClientPeg.get().removeListener("crypto.keyBackupStatus", this.onKeyBackupStatus); - MatrixClientPeg.get().removeListener("deviceVerificationChanged", this.onDeviceVerificationChanged); - MatrixClientPeg.get().removeListener("userTrustStatusChanged", this.onUserVerificationChanged); + if (this.context) { + this.context.removeListener("Room", this.onRoom); + this.context.removeListener("Room.timeline", this.onRoomTimeline); + this.context.removeListener("Room.name", this.onRoomName); + this.context.removeListener("Room.accountData", this.onRoomAccountData); + this.context.removeListener("RoomState.events", this.onRoomStateEvents); + this.context.removeListener("Room.myMembership", this.onMyMembership); + this.context.removeListener("RoomState.members", this.onRoomStateMember); + this.context.removeListener("accountData", this.onAccountData); + this.context.removeListener("crypto.keyBackupStatus", this.onKeyBackupStatus); + this.context.removeListener("deviceVerificationChanged", this.onDeviceVerificationChanged); + this.context.removeListener("userTrustStatusChanged", this.onUserVerificationChanged); } window.removeEventListener('beforeunload', this.onPageUnload); @@ -538,7 +542,6 @@ export default createReactClass({ } }, - onKeyDown: function(ev) { let handled = false; const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev); @@ -578,9 +581,7 @@ export default createReactClass({ payload.data.description || payload.data.name); break; case 'picture_snapshot': - ContentMessages.sharedInstance().sendContentListToRoom( - [payload.file], this.state.room.roomId, MatrixClientPeg.get(), - ); + ContentMessages.sharedInstance().sendContentListToRoom([payload.file], this.state.room.roomId, this.context); break; case 'notifier_enabled': case 'upload_started': @@ -669,7 +670,7 @@ export default createReactClass({ // we'll only be showing a spinner. if (this.state.joining) return; - if (ev.getSender() !== MatrixClientPeg.get().credentials.userId) { + if (ev.getSender() !== this.context.credentials.userId) { // update unread count when scrolled up if (!this.state.searchResults && this.state.atEndOfLiveTimeline) { // no change @@ -725,8 +726,7 @@ export default createReactClass({ _loadMembersIfJoined: async function(room) { // lazy load members if enabled - const cli = MatrixClientPeg.get(); - if (cli.hasLazyLoadMembersEnabled()) { + if (this.context.hasLazyLoadMembersEnabled()) { if (room && room.getMyMembership() === 'join') { try { await room.loadMembersIfNeeded(); @@ -761,7 +761,7 @@ export default createReactClass({ _updatePreviewUrlVisibility: function({roomId}) { // URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit - const key = MatrixClientPeg.get().isRoomEncrypted(roomId) ? 'urlPreviewsEnabled_e2ee' : 'urlPreviewsEnabled'; + const key = this.context.isRoomEncrypted(roomId) ? 'urlPreviewsEnabled_e2ee' : 'urlPreviewsEnabled'; this.setState({ showUrlPreview: SettingsStore.getValue(key, roomId), }); @@ -795,11 +795,10 @@ export default createReactClass({ }, _updateE2EStatus: async function(room) { - const cli = MatrixClientPeg.get(); - if (!cli.isRoomEncrypted(room.roomId)) { + if (!this.context.isRoomEncrypted(room.roomId)) { return; } - if (!cli.isCryptoEnabled()) { + if (!this.context.isCryptoEnabled()) { // If crypto is not currently enabled, we aren't tracking devices at all, // so we don't know what the answer is. Let's error on the safe side and show // a warning for this case. @@ -824,21 +823,21 @@ export default createReactClass({ const verified = []; const unverified = []; e2eMembers.map(({userId}) => userId) - .filter((userId) => userId !== cli.getUserId()) + .filter((userId) => userId !== this.context.getUserId()) .forEach((userId) => { - (cli.checkUserTrust(userId).isCrossSigningVerified() ? - verified : unverified).push(userId) + (this.context.checkUserTrust(userId).isCrossSigningVerified() ? + verified : unverified).push(userId); }); debuglog("e2e verified", verified, "unverified", unverified); /* Check all verified user devices. */ /* Don't alarm if no other users are verified */ - const targets = (verified.length > 0) ? [...verified, cli.getUserId()] : verified; + const targets = (verified.length > 0) ? [...verified, this.context.getUserId()] : verified; for (const userId of targets) { - const devices = await cli.getStoredDevicesForUser(userId); + const devices = await this.context.getStoredDevicesForUser(userId); const anyDeviceNotVerified = devices.some(({deviceId}) => { - return !cli.checkDeviceTrust(userId, deviceId).isVerified(); + return !this.context.checkDeviceTrust(userId, deviceId).isVerified(); }); if (anyDeviceNotVerified) { this.setState({ @@ -920,7 +919,7 @@ export default createReactClass({ _updatePermissions: function(room) { if (room) { - const me = MatrixClientPeg.get().getUserId(); + const me = this.context.getUserId(); const canReact = room.getMyMembership() === "join" && room.currentState.maySendEvent("m.reaction", me); const canReply = room.maySendMessage(); @@ -1004,7 +1003,7 @@ export default createReactClass({ if (this.state.searchResults.next_batch) { debuglog("requesting more search results"); - const searchPromise = MatrixClientPeg.get().backPaginateRoomEventsSearch( + const searchPromise = this.context.backPaginateRoomEventsSearch( this.state.searchResults); return this._handleSearchResult(searchPromise); } else { @@ -1030,10 +1029,8 @@ export default createReactClass({ }, onJoinButtonClicked: function(ev) { - const cli = MatrixClientPeg.get(); - // If the user is a ROU, allow them to transition to a PWLU - if (cli && cli.isGuest()) { + if (this.context && this.context.isGuest()) { // Join this room once the user has registered and logged in // (If we failed to peek, we may not have a valid room object.) dis.dispatch({ @@ -1130,7 +1127,7 @@ export default createReactClass({ ev.stopPropagation(); ev.preventDefault(); ContentMessages.sharedInstance().sendContentListToRoom( - ev.dataTransfer.files, this.state.room.roomId, MatrixClientPeg.get(), + ev.dataTransfer.files, this.state.room.roomId, this.context, ); this.setState({ draggingFile: false }); dis.dispatch({action: 'focus_composer'}); @@ -1143,12 +1140,12 @@ export default createReactClass({ }, injectSticker: function(url, info, text) { - if (MatrixClientPeg.get().isGuest()) { + if (this.context.isGuest()) { dis.dispatch({action: 'require_registration'}); return; } - ContentMessages.sharedInstance().sendStickerContentToRoom(url, this.state.room.roomId, info, text, MatrixClientPeg.get()) + ContentMessages.sharedInstance().sendStickerContentToRoom(url, this.state.room.roomId, info, text, this.context) .then(undefined, (error) => { if (error.name === "UnknownDeviceError") { // Let the staus bar handle this @@ -1239,12 +1236,9 @@ export default createReactClass({ }, getSearchResultTiles: function() { - const EventTile = sdk.getComponent('rooms.EventTile'); const SearchResultTile = sdk.getComponent('rooms.SearchResultTile'); const Spinner = sdk.getComponent("elements.Spinner"); - const cli = MatrixClientPeg.get(); - // XXX: todo: merge overlapping results somehow? // XXX: why doesn't searching on name work? @@ -1252,21 +1246,21 @@ export default createReactClass({ if (this.state.searchInProgress) { ret.push(