You've already forked matrix-react-sdk
							
							
				mirror of
				https://github.com/matrix-org/matrix-react-sdk.git
				synced 2025-11-03 00:33:22 +03:00 
			
		
		
		
	Prefer RoomStateEvent.Update where possible as it fires far less (#7878)
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							36ae0ea49d
						
					
				
				
					commit
					c257bc3f7a
				
			@@ -17,7 +17,7 @@ limitations under the License.
 | 
			
		||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import { logger } from "matrix-js-sdk/src/logger";
 | 
			
		||||
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
 | 
			
		||||
import { ClientEvent, RoomStateEvent } from "matrix-js-sdk/src/matrix";
 | 
			
		||||
import { ClientEvent, EventType, RoomStateEvent } from "matrix-js-sdk/src/matrix";
 | 
			
		||||
 | 
			
		||||
import { MatrixClientPeg } from './MatrixClientPeg';
 | 
			
		||||
import dis from "./dispatcher/dispatcher";
 | 
			
		||||
@@ -184,9 +184,7 @@ export default class DeviceListener {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onRoomStateEvents = (ev: MatrixEvent) => {
 | 
			
		||||
        if (ev.getType() !== "m.room.encryption") {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (ev.getType() !== EventType.RoomEncryption) return;
 | 
			
		||||
 | 
			
		||||
        // If a room changes to encrypted, re-check as it may be our first
 | 
			
		||||
        // encrypted room. This also catches encrypted room creation as well.
 | 
			
		||||
 
 | 
			
		||||
@@ -61,13 +61,13 @@ export default class UserProvider extends AutocompleteProvider {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        MatrixClientPeg.get().on(RoomEvent.Timeline, this.onRoomTimeline);
 | 
			
		||||
        MatrixClientPeg.get().on(RoomStateEvent.Members, this.onRoomStateMember);
 | 
			
		||||
        MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    destroy() {
 | 
			
		||||
        if (MatrixClientPeg.get()) {
 | 
			
		||||
            MatrixClientPeg.get().removeListener(RoomEvent.Timeline, this.onRoomTimeline);
 | 
			
		||||
            MatrixClientPeg.get().removeListener(RoomStateEvent.Members, this.onRoomStateMember);
 | 
			
		||||
            MatrixClientPeg.get().removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -93,11 +93,9 @@ export default class UserProvider extends AutocompleteProvider {
 | 
			
		||||
        this.onUserSpoke(ev.sender);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember) => {
 | 
			
		||||
        // ignore members in other rooms
 | 
			
		||||
        if (member.roomId !== this.room.roomId) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    private onRoomStateUpdate = (state: RoomState) => {
 | 
			
		||||
        // ignore updates in other rooms
 | 
			
		||||
        if (state.roomId !== this.room.roomId) return;
 | 
			
		||||
 | 
			
		||||
        // blow away the users cache
 | 
			
		||||
        this.users = null;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { ClientEvent } from "matrix-js-sdk/src/client";
 | 
			
		||||
 | 
			
		||||
import type { EventSubscription } from "fbemitter";
 | 
			
		||||
import GroupFilterOrderStore from '../../stores/GroupFilterOrderStore';
 | 
			
		||||
@@ -51,6 +52,7 @@ interface IGroupFilterPanelState {
 | 
			
		||||
@replaceableComponent("structures.GroupFilterPanel")
 | 
			
		||||
class GroupFilterPanel extends React.Component<IGroupFilterPanelProps, IGroupFilterPanelState> {
 | 
			
		||||
    public static contextType = MatrixClientContext;
 | 
			
		||||
    public context!: React.ContextType<typeof MatrixClientContext>;
 | 
			
		||||
 | 
			
		||||
    public state = {
 | 
			
		||||
        orderedTags: [],
 | 
			
		||||
@@ -63,8 +65,8 @@ class GroupFilterPanel extends React.Component<IGroupFilterPanelProps, IGroupFil
 | 
			
		||||
 | 
			
		||||
    public componentDidMount() {
 | 
			
		||||
        this.unmounted = false;
 | 
			
		||||
        this.context.on("Group.myMembership", this.onGroupMyMembership);
 | 
			
		||||
        this.context.on("sync", this.onClientSync);
 | 
			
		||||
        this.context.on(ClientEvent.GroupMyMembership, this.onGroupMyMembership);
 | 
			
		||||
        this.context.on(ClientEvent.Sync, this.onClientSync);
 | 
			
		||||
 | 
			
		||||
        this.groupFilterOrderStoreToken = GroupFilterOrderStore.addListener(() => {
 | 
			
		||||
            if (this.unmounted) {
 | 
			
		||||
@@ -82,8 +84,8 @@ class GroupFilterPanel extends React.Component<IGroupFilterPanelProps, IGroupFil
 | 
			
		||||
 | 
			
		||||
    public componentWillUnmount() {
 | 
			
		||||
        this.unmounted = true;
 | 
			
		||||
        this.context.removeListener("Group.myMembership", this.onGroupMyMembership);
 | 
			
		||||
        this.context.removeListener("sync", this.onClientSync);
 | 
			
		||||
        this.context.removeListener(ClientEvent.GroupMyMembership, this.onGroupMyMembership);
 | 
			
		||||
        this.context.removeListener(ClientEvent.Sync, this.onClientSync);
 | 
			
		||||
        if (this.groupFilterOrderStoreToken) {
 | 
			
		||||
            this.groupFilterOrderStoreToken.remove();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -317,7 +317,7 @@ class LoggedInView extends React.Component<IProps, IState> {
 | 
			
		||||
 | 
			
		||||
    private onRoomStateEvents = (ev: MatrixEvent): void => {
 | 
			
		||||
        const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice];
 | 
			
		||||
        if (serverNoticeList && serverNoticeList.some(r => r.roomId === ev.getRoomId())) {
 | 
			
		||||
        if (serverNoticeList?.some(r => r.roomId === ev.getRoomId())) {
 | 
			
		||||
            this.updateServerNoticeEvents();
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@ import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
 | 
			
		||||
import { Relations } from "matrix-js-sdk/src/models/relations";
 | 
			
		||||
import { logger } from 'matrix-js-sdk/src/logger';
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { throttle } from "lodash";
 | 
			
		||||
 | 
			
		||||
import shouldHideEvent from '../../shouldHideEvent';
 | 
			
		||||
import { wantsDateSeparator } from '../../DateUtils';
 | 
			
		||||
@@ -277,13 +276,13 @@ export default class MessagePanel extends React.Component<IProps, IState> {
 | 
			
		||||
 | 
			
		||||
    componentDidMount() {
 | 
			
		||||
        this.calculateRoomMembersCount();
 | 
			
		||||
        this.props.room?.currentState.on(RoomStateEvent.Members, this.onRoomMembers);
 | 
			
		||||
        this.props.room?.currentState.on(RoomStateEvent.Update, this.calculateRoomMembersCount);
 | 
			
		||||
        this.isMounted = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentWillUnmount() {
 | 
			
		||||
        this.isMounted = false;
 | 
			
		||||
        this.props.room?.currentState.off(RoomStateEvent.Members, this.onRoomMembers);
 | 
			
		||||
        this.props.room?.currentState.off(RoomStateEvent.Update, this.calculateRoomMembersCount);
 | 
			
		||||
        SettingsStore.unwatchSetting(this.showTypingNotificationsWatcherRef);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -314,16 +313,11 @@ export default class MessagePanel extends React.Component<IProps, IState> {
 | 
			
		||||
        return this.props.room?.getInvitedAndJoinedMemberCount() <= 2 && this.props.layout === Layout.Bubble;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onRoomMembers = (event: MatrixEvent): void => {
 | 
			
		||||
        if (this.props.room && event.getRoomId() !== this.props.room.roomId) return; // different room
 | 
			
		||||
        this.calculateRoomMembersCount();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private calculateRoomMembersCount = throttle((): void => {
 | 
			
		||||
    private calculateRoomMembersCount = (): void => {
 | 
			
		||||
        this.setState({
 | 
			
		||||
            hideSender: this.shouldHideSender(),
 | 
			
		||||
        });
 | 
			
		||||
    }, 200, { leading: true, trailing: true });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onShowTypingNotificationsChange = (): void => {
 | 
			
		||||
        this.setState({
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { RoomState } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { RoomState, RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
 | 
			
		||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import { throttle } from 'lodash';
 | 
			
		||||
@@ -67,6 +67,7 @@ interface IState {
 | 
			
		||||
@replaceableComponent("structures.RightPanel")
 | 
			
		||||
export default class RightPanel extends React.Component<IProps, IState> {
 | 
			
		||||
    static contextType = MatrixClientContext;
 | 
			
		||||
    public context!: React.ContextType<typeof MatrixClientContext>;
 | 
			
		||||
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
@@ -81,15 +82,12 @@ export default class RightPanel extends React.Component<IProps, IState> {
 | 
			
		||||
    }, 500, { leading: true, trailing: true });
 | 
			
		||||
 | 
			
		||||
    public componentDidMount(): void {
 | 
			
		||||
        const cli = this.context;
 | 
			
		||||
        cli.on("RoomState.members", this.onRoomStateMember);
 | 
			
		||||
        this.context.on(RoomStateEvent.Members, this.onRoomStateMember);
 | 
			
		||||
        RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public componentWillUnmount(): void {
 | 
			
		||||
        if (this.context) {
 | 
			
		||||
            this.context.removeListener("RoomState.members", this.onRoomStateMember);
 | 
			
		||||
        }
 | 
			
		||||
        this.context?.removeListener(RoomStateEvent.Members, this.onRoomStateMember);
 | 
			
		||||
        RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,17 +22,19 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
import React, { createRef } from 'react';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { IRecommendedVersion, NotificationCountType, Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import { IRecommendedVersion, NotificationCountType, Room, RoomEvent } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import { EventSubscription } from "fbemitter";
 | 
			
		||||
import { ISearchResults } from 'matrix-js-sdk/src/@types/search';
 | 
			
		||||
import { logger } from "matrix-js-sdk/src/logger";
 | 
			
		||||
import { EventTimeline } from 'matrix-js-sdk/src/models/event-timeline';
 | 
			
		||||
import { EventType } from 'matrix-js-sdk/src/@types/event';
 | 
			
		||||
import { RoomState } from 'matrix-js-sdk/src/models/room-state';
 | 
			
		||||
import { RoomState, RoomStateEvent } from 'matrix-js-sdk/src/models/room-state';
 | 
			
		||||
import { CallState, CallType, MatrixCall } from "matrix-js-sdk/src/webrtc/call";
 | 
			
		||||
import { throttle } from "lodash";
 | 
			
		||||
import { MatrixError } from 'matrix-js-sdk/src/http-api';
 | 
			
		||||
import { ClientEvent } from "matrix-js-sdk/src/client";
 | 
			
		||||
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
 | 
			
		||||
 | 
			
		||||
import shouldHideEvent from '../../shouldHideEvent';
 | 
			
		||||
import { _t } from '../../languageHandler';
 | 
			
		||||
@@ -230,11 +232,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
 | 
			
		||||
    private roomViewBody = createRef<HTMLDivElement>();
 | 
			
		||||
 | 
			
		||||
    static contextType = MatrixClientContext;
 | 
			
		||||
    public context!: React.ContextType<typeof MatrixClientContext>;
 | 
			
		||||
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
    constructor(props: IRoomProps, context: React.ContextType<typeof MatrixClientContext>) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
 | 
			
		||||
        const llMembers = this.context.hasLazyLoadMembersEnabled();
 | 
			
		||||
        const llMembers = context.hasLazyLoadMembersEnabled();
 | 
			
		||||
        this.state = {
 | 
			
		||||
            roomId: null,
 | 
			
		||||
            roomLoading: true,
 | 
			
		||||
@@ -268,7 +271,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
 | 
			
		||||
            showJoinLeaves: true,
 | 
			
		||||
            showAvatarChanges: true,
 | 
			
		||||
            showDisplaynameChanges: true,
 | 
			
		||||
            matrixClientIsReady: this.context && this.context.isInitialSyncComplete(),
 | 
			
		||||
            matrixClientIsReady: context?.isInitialSyncComplete(),
 | 
			
		||||
            mainSplitContentType: MainSplitContentType.Timeline,
 | 
			
		||||
            timelineRenderingType: TimelineRenderingType.Room,
 | 
			
		||||
            liveTimeline: undefined,
 | 
			
		||||
@@ -276,19 +279,19 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        this.dispatcherRef = dis.register(this.onAction);
 | 
			
		||||
        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);
 | 
			
		||||
        this.context.on("crossSigning.keysChanged", this.onCrossSigningKeysChanged);
 | 
			
		||||
        this.context.on("Event.decrypted", this.onEventDecrypted);
 | 
			
		||||
        context.on(ClientEvent.Room, this.onRoom);
 | 
			
		||||
        context.on(RoomEvent.Timeline, this.onRoomTimeline);
 | 
			
		||||
        context.on(RoomEvent.Name, this.onRoomName);
 | 
			
		||||
        context.on(RoomEvent.AccountData, this.onRoomAccountData);
 | 
			
		||||
        context.on(RoomStateEvent.Events, this.onRoomStateEvents);
 | 
			
		||||
        context.on(RoomStateEvent.Update, this.onRoomStateUpdate);
 | 
			
		||||
        context.on(RoomEvent.MyMembership, this.onMyMembership);
 | 
			
		||||
        context.on(ClientEvent.AccountData, this.onAccountData);
 | 
			
		||||
        context.on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
 | 
			
		||||
        context.on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
 | 
			
		||||
        context.on(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
 | 
			
		||||
        context.on(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
 | 
			
		||||
        context.on(MatrixEventEvent.Decrypted, this.onEventDecrypted);
 | 
			
		||||
        // Start listening for RoomViewStore updates
 | 
			
		||||
        this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate);
 | 
			
		||||
 | 
			
		||||
@@ -704,19 +707,19 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
 | 
			
		||||
 | 
			
		||||
        dis.unregister(this.dispatcherRef);
 | 
			
		||||
        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);
 | 
			
		||||
            this.context.removeListener("crossSigning.keysChanged", this.onCrossSigningKeysChanged);
 | 
			
		||||
            this.context.removeListener("Event.decrypted", this.onEventDecrypted);
 | 
			
		||||
            this.context.removeListener(ClientEvent.Room, this.onRoom);
 | 
			
		||||
            this.context.removeListener(RoomEvent.Timeline, this.onRoomTimeline);
 | 
			
		||||
            this.context.removeListener(RoomEvent.Name, this.onRoomName);
 | 
			
		||||
            this.context.removeListener(RoomEvent.AccountData, this.onRoomAccountData);
 | 
			
		||||
            this.context.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
 | 
			
		||||
            this.context.removeListener(RoomEvent.MyMembership, this.onMyMembership);
 | 
			
		||||
            this.context.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
 | 
			
		||||
            this.context.removeListener(ClientEvent.AccountData, this.onAccountData);
 | 
			
		||||
            this.context.removeListener(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
 | 
			
		||||
            this.context.removeListener(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
 | 
			
		||||
            this.context.removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
 | 
			
		||||
            this.context.removeListener(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
 | 
			
		||||
            this.context.removeListener(MatrixEventEvent.Decrypted, this.onEventDecrypted);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        window.removeEventListener('beforeunload', this.onPageUnload);
 | 
			
		||||
@@ -1097,7 +1100,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onDeviceVerificationChanged = (userId: string, device: object) => {
 | 
			
		||||
    private onDeviceVerificationChanged = (userId: string) => {
 | 
			
		||||
        const room = this.state.room;
 | 
			
		||||
        if (!room.currentState.getMember(userId)) {
 | 
			
		||||
            return;
 | 
			
		||||
@@ -1105,7 +1108,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
 | 
			
		||||
        this.updateE2EStatus(room);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onUserVerificationChanged = (userId: string, trustStatus: object) => {
 | 
			
		||||
    private onUserVerificationChanged = (userId: string) => {
 | 
			
		||||
        const room = this.state.room;
 | 
			
		||||
        if (!room || !room.currentState.getMember(userId)) {
 | 
			
		||||
            return;
 | 
			
		||||
@@ -1156,9 +1159,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
 | 
			
		||||
 | 
			
		||||
    private onRoomStateEvents = (ev: MatrixEvent, state: RoomState) => {
 | 
			
		||||
        // ignore if we don't have a room yet
 | 
			
		||||
        if (!this.state.room || this.state.room.roomId !== state.roomId) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (!this.state.room || this.state.room.roomId !== state.roomId) return;
 | 
			
		||||
 | 
			
		||||
        if (ev.getType() === EventType.RoomCanonicalAlias) {
 | 
			
		||||
            // re-view the room so MatrixChat can manage the alias in the URL properly
 | 
			
		||||
@@ -1173,14 +1174,9 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
 | 
			
		||||
        this.updatePermissions(this.state.room);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onRoomStateMember = (ev: MatrixEvent, state, member) => {
 | 
			
		||||
        // ignore if we don't have a room yet
 | 
			
		||||
        if (!this.state.room) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private onRoomStateUpdate = (state: RoomState) => {
 | 
			
		||||
        // ignore members in other rooms
 | 
			
		||||
        if (member.roomId !== this.state.room.roomId) {
 | 
			
		||||
        if (state.roomId !== this.state.room?.roomId) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1255,7 +1251,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
 | 
			
		||||
 | 
			
		||||
    private onJoinButtonClicked = () => {
 | 
			
		||||
        // If the user is a ROU, allow them to transition to a PWLU
 | 
			
		||||
        if (this.context && this.context.isGuest()) {
 | 
			
		||||
        if (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<DoAfterSyncPreparedPayload<ViewRoomPayload>>({
 | 
			
		||||
@@ -1712,7 +1708,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
 | 
			
		||||
    getHiddenHighlightCount() {
 | 
			
		||||
        const oldRoom = this.getOldRoom();
 | 
			
		||||
        if (!oldRoom) return 0;
 | 
			
		||||
        return oldRoom.getUnreadNotificationCount('highlight');
 | 
			
		||||
        return oldRoom.getUnreadNotificationCount(NotificationCountType.Highlight);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onHiddenHighlightsClick = () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ import React, {
 | 
			
		||||
    useRef,
 | 
			
		||||
    useState,
 | 
			
		||||
} from "react";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { RoomHierarchy } from "matrix-js-sdk/src/room-hierarchy";
 | 
			
		||||
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
import { IHierarchyRelation, IHierarchyRoom } from "matrix-js-sdk/src/@types/spaces";
 | 
			
		||||
@@ -58,7 +58,7 @@ import { Key } from "../../Keyboard";
 | 
			
		||||
import { IState, RovingTabIndexProvider, useRovingTabIndex } from "../../accessibility/RovingTabIndex";
 | 
			
		||||
import { getDisplayAliasForRoom } from "./RoomDirectory";
 | 
			
		||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
 | 
			
		||||
import { useEventEmitterState } from "../../hooks/useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitterState } from "../../hooks/useEventEmitter";
 | 
			
		||||
import { IOOBData } from "../../stores/ThreepidInviteStore";
 | 
			
		||||
import { awaitRoomDownSync } from "../../utils/RoomUpgrade";
 | 
			
		||||
import RoomViewStore from "../../stores/RoomViewStore";
 | 
			
		||||
@@ -99,7 +99,7 @@ const Tile: React.FC<ITileProps> = ({
 | 
			
		||||
        const cliRoom = cli.getRoom(room.room_id);
 | 
			
		||||
        return cliRoom?.getMyMembership() === "join" ? cliRoom : null;
 | 
			
		||||
    });
 | 
			
		||||
    const joinedRoomName = useEventEmitterState(joinedRoom, "Room.name", room => room?.name);
 | 
			
		||||
    const joinedRoomName = useTypedEventEmitterState(joinedRoom, RoomEvent.Name, room => room?.name);
 | 
			
		||||
    const name = joinedRoomName || room.name || room.canonical_alias || room.aliases?.[0]
 | 
			
		||||
        || (room.room_type === RoomType.Space ? _t("Unnamed Space") : _t("Unnamed Room"));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ limitations under the License.
 | 
			
		||||
import React, { RefObject, useContext, useRef, useState } from "react";
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
import { JoinRule, Preset } from "matrix-js-sdk/src/@types/partials";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { logger } from "matrix-js-sdk/src/logger";
 | 
			
		||||
 | 
			
		||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
 | 
			
		||||
@@ -31,7 +31,7 @@ import { inviteMultipleToRoom, showRoomInviteDialog } from "../../RoomInvite";
 | 
			
		||||
import { useRoomMembers } from "../../hooks/useRoomMembers";
 | 
			
		||||
import createRoom, { IOpts } from "../../createRoom";
 | 
			
		||||
import Field from "../views/elements/Field";
 | 
			
		||||
import { useEventEmitter } from "../../hooks/useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
 | 
			
		||||
import withValidation from "../views/elements/Validation";
 | 
			
		||||
import * as Email from "../../email";
 | 
			
		||||
import defaultDispatcher from "../../dispatcher/dispatcher";
 | 
			
		||||
@@ -121,7 +121,7 @@ const RoomMemberCount = ({ room, children }) => {
 | 
			
		||||
 | 
			
		||||
const useMyRoomMembership = (room: Room) => {
 | 
			
		||||
    const [membership, setMembership] = useState(room.getMyMembership());
 | 
			
		||||
    useEventEmitter(room, "Room.myMembership", () => {
 | 
			
		||||
    useTypedEventEmitter(room, RoomEvent.MyMembership, () => {
 | 
			
		||||
        setMembership(room.getMyMembership());
 | 
			
		||||
    });
 | 
			
		||||
    return membership;
 | 
			
		||||
@@ -790,17 +790,18 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
 | 
			
		||||
 | 
			
		||||
export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
 | 
			
		||||
    static contextType = MatrixClientContext;
 | 
			
		||||
    public context!: React.ContextType<typeof MatrixClientContext>;
 | 
			
		||||
 | 
			
		||||
    private readonly creator: string;
 | 
			
		||||
    private readonly dispatcherRef: string;
 | 
			
		||||
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
    constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
 | 
			
		||||
        let phase = Phase.Landing;
 | 
			
		||||
 | 
			
		||||
        this.creator = this.props.space.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender();
 | 
			
		||||
        const showSetup = this.props.justCreatedOpts && this.context.getUserId() === this.creator;
 | 
			
		||||
        const showSetup = this.props.justCreatedOpts && context.getUserId() === this.creator;
 | 
			
		||||
 | 
			
		||||
        if (showSetup) {
 | 
			
		||||
            phase = this.props.justCreatedOpts.createOpts.preset === Preset.PublicChat
 | 
			
		||||
@@ -815,13 +816,16 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
 | 
			
		||||
 | 
			
		||||
        this.dispatcherRef = defaultDispatcher.register(this.onAction);
 | 
			
		||||
        RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
 | 
			
		||||
        this.context.on("Room.myMembership", this.onMyMembership);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentDidMount() {
 | 
			
		||||
        this.context.on(RoomEvent.MyMembership, this.onMyMembership);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentWillUnmount() {
 | 
			
		||||
        defaultDispatcher.unregister(this.dispatcherRef);
 | 
			
		||||
        RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
 | 
			
		||||
        this.context.off("Room.myMembership", this.onMyMembership);
 | 
			
		||||
        this.context.off(RoomEvent.MyMembership, this.onMyMembership);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onMyMembership = (room: Room, myMembership: string) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,13 +20,14 @@ limitations under the License.
 | 
			
		||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { ResizeMethod } from 'matrix-js-sdk/src/@types/partials';
 | 
			
		||||
import { ClientEvent } from "matrix-js-sdk/src/client";
 | 
			
		||||
 | 
			
		||||
import * as AvatarLogic from '../../../Avatar';
 | 
			
		||||
import SettingsStore from "../../../settings/SettingsStore";
 | 
			
		||||
import AccessibleButton from '../elements/AccessibleButton';
 | 
			
		||||
import RoomContext from "../../../contexts/RoomContext";
 | 
			
		||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
 | 
			
		||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import { toPx } from "../../../utils/units";
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
 | 
			
		||||
@@ -92,7 +93,7 @@ const useImageUrl = ({ url, urls }): [string, () => void] => {
 | 
			
		||||
            setIndex(0);
 | 
			
		||||
        }
 | 
			
		||||
    }, []);
 | 
			
		||||
    useEventEmitter(cli, "sync", onClientSync);
 | 
			
		||||
    useTypedEventEmitter(cli, ClientEvent.Sync, onClientSync);
 | 
			
		||||
 | 
			
		||||
    const imageUrl = imageUrls[urlsIndex];
 | 
			
		||||
    return [imageUrl, onError];
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ import { ResizeMethod } from 'matrix-js-sdk/src/@types/partials';
 | 
			
		||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import classNames from "classnames";
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
 | 
			
		||||
import BaseAvatar from './BaseAvatar';
 | 
			
		||||
import ImageView from '../elements/ImageView';
 | 
			
		||||
@@ -86,10 +87,7 @@ export default class RoomAvatar extends React.Component<IProps, IState> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onRoomStateEvents = (ev: MatrixEvent) => {
 | 
			
		||||
        if (!this.props.room ||
 | 
			
		||||
            ev.getRoomId() !== this.props.room.roomId ||
 | 
			
		||||
            ev.getType() !== 'm.room.avatar'
 | 
			
		||||
        ) return;
 | 
			
		||||
        if (ev.getRoomId() !== this.props.room?.roomId || ev.getType() !== EventType.RoomAvatar) return;
 | 
			
		||||
 | 
			
		||||
        this.setState({
 | 
			
		||||
            urls: RoomAvatar.getImageUrls(this.props),
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ import {
 | 
			
		||||
    PHASE_STARTED,
 | 
			
		||||
    PHASE_CANCELLED,
 | 
			
		||||
    VerificationRequest,
 | 
			
		||||
    VerificationRequestEvent,
 | 
			
		||||
} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
@@ -34,7 +35,7 @@ import SyntaxHighlight from '../elements/SyntaxHighlight';
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
import Field from "../elements/Field";
 | 
			
		||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
 | 
			
		||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import WidgetStore, { IApp } from "../../../stores/WidgetStore";
 | 
			
		||||
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
 | 
			
		||||
import { SETTINGS } from "../../../settings/Settings";
 | 
			
		||||
@@ -756,7 +757,7 @@ const VerificationRequestExplorer: React.FC<{
 | 
			
		||||
    const [timeout, setRequestTimeout] = useState(request.timeout);
 | 
			
		||||
 | 
			
		||||
    /* Re-render if something changes state */
 | 
			
		||||
    useEventEmitter(request, "change", updateState);
 | 
			
		||||
    useTypedEventEmitter(request, VerificationRequestEvent.Change, updateState);
 | 
			
		||||
 | 
			
		||||
    /* Keep re-rendering if there's a timeout */
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,9 @@ limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import React, { useEffect, useState } from "react";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
 | 
			
		||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
 | 
			
		||||
interface IProps {
 | 
			
		||||
    room: Room;
 | 
			
		||||
@@ -26,7 +26,7 @@ interface IProps {
 | 
			
		||||
 | 
			
		||||
const RoomName = ({ room, children }: IProps): JSX.Element => {
 | 
			
		||||
    const [name, setName] = useState(room?.name);
 | 
			
		||||
    useEventEmitter(room, "Room.name", () => {
 | 
			
		||||
    useTypedEventEmitter(room, RoomEvent.Name, () => {
 | 
			
		||||
        setName(room?.name);
 | 
			
		||||
    });
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,10 @@ limitations under the License.
 | 
			
		||||
import React, { useEffect, useState } from "react";
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
 | 
			
		||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import { linkifyElement } from "../../../HtmlUtils";
 | 
			
		||||
 | 
			
		||||
interface IProps {
 | 
			
		||||
@@ -30,7 +32,8 @@ export const getTopic = room => room?.currentState?.getStateEvents(EventType.Roo
 | 
			
		||||
 | 
			
		||||
const RoomTopic = ({ room, children }: IProps): JSX.Element => {
 | 
			
		||||
    const [topic, setTopic] = useState(getTopic(room));
 | 
			
		||||
    useEventEmitter(room.currentState, "RoomState.events", () => {
 | 
			
		||||
    useTypedEventEmitter(room.currentState, RoomStateEvent.Events, (ev: MatrixEvent) => {
 | 
			
		||||
        if (ev.getType() !== EventType.RoomTopic) return;
 | 
			
		||||
        setTopic(getTopic(room));
 | 
			
		||||
    });
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import { MsgType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
 | 
			
		||||
import Flair from '../elements/Flair';
 | 
			
		||||
import FlairStore from '../../../stores/FlairStore';
 | 
			
		||||
@@ -35,13 +36,14 @@ interface IProps {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IState {
 | 
			
		||||
    userGroups;
 | 
			
		||||
    relatedGroups;
 | 
			
		||||
    userGroups: string[];
 | 
			
		||||
    relatedGroups: string[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@replaceableComponent("views.messages.SenderProfile")
 | 
			
		||||
export default class SenderProfile extends React.Component<IProps, IState> {
 | 
			
		||||
    static contextType = MatrixClientContext;
 | 
			
		||||
    public context!: React.ContextType<typeof MatrixClientContext>;
 | 
			
		||||
    private unmounted = false;
 | 
			
		||||
 | 
			
		||||
    constructor(props: IProps) {
 | 
			
		||||
@@ -61,12 +63,12 @@ export default class SenderProfile extends React.Component<IProps, IState> {
 | 
			
		||||
            this.getPublicisedGroups();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.context.on('RoomState.events', this.onRoomStateEvents);
 | 
			
		||||
        this.context.on(RoomStateEvent.Events, this.onRoomStateEvents);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentWillUnmount() {
 | 
			
		||||
        this.unmounted = true;
 | 
			
		||||
        this.context.removeListener('RoomState.events', this.onRoomStateEvents);
 | 
			
		||||
        this.context.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async getPublicisedGroups() {
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,10 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
import React, { useCallback, useEffect, useState } from "react";
 | 
			
		||||
import {
 | 
			
		||||
    VerificationRequest,
 | 
			
		||||
    PHASE_REQUESTED,
 | 
			
		||||
    PHASE_UNSENT,
 | 
			
		||||
    VerificationRequest,
 | 
			
		||||
    VerificationRequestEvent,
 | 
			
		||||
} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
 | 
			
		||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
 | 
			
		||||
import { User } from "matrix-js-sdk/src/models/user";
 | 
			
		||||
@@ -27,7 +28,7 @@ import EncryptionInfo from "./EncryptionInfo";
 | 
			
		||||
import VerificationPanel from "./VerificationPanel";
 | 
			
		||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
 | 
			
		||||
import { ensureDMExists } from "../../../createRoom";
 | 
			
		||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import Modal from "../../../Modal";
 | 
			
		||||
import * as sdk from "../../../index";
 | 
			
		||||
import { _t } from "../../../languageHandler";
 | 
			
		||||
@@ -107,7 +108,7 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
 | 
			
		||||
        }
 | 
			
		||||
    }, [onClose, request]);
 | 
			
		||||
 | 
			
		||||
    useEventEmitter(request, "change", changeHandler);
 | 
			
		||||
    useTypedEventEmitter(request, VerificationRequestEvent.Change, changeHandler);
 | 
			
		||||
 | 
			
		||||
    const onStartVerification = useCallback(async () => {
 | 
			
		||||
        setRequesting(true);
 | 
			
		||||
 
 | 
			
		||||
@@ -15,16 +15,17 @@ limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import React, { useCallback, useContext, useEffect, useState } from "react";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import { EventType } from 'matrix-js-sdk/src/@types/event';
 | 
			
		||||
import { logger } from "matrix-js-sdk/src/logger";
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
 | 
			
		||||
import { _t } from "../../../languageHandler";
 | 
			
		||||
import BaseCard from "./BaseCard";
 | 
			
		||||
import Spinner from "../elements/Spinner";
 | 
			
		||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
 | 
			
		||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import PinningUtils from "../../../utils/PinningUtils";
 | 
			
		||||
import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
 | 
			
		||||
import PinnedEventTile from "../rooms/PinnedEventTile";
 | 
			
		||||
@@ -45,7 +46,7 @@ export const usePinnedEvents = (room: Room): string[] => {
 | 
			
		||||
        setPinnedEvents(room.currentState.getStateEvents(EventType.RoomPinnedEvents, "")?.getContent()?.pinned || []);
 | 
			
		||||
    }, [room]);
 | 
			
		||||
 | 
			
		||||
    useEventEmitter(room?.currentState, "RoomState.events", update);
 | 
			
		||||
    useTypedEventEmitter(room?.currentState, RoomStateEvent.Events, update);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        update();
 | 
			
		||||
        return () => {
 | 
			
		||||
@@ -67,7 +68,7 @@ export const useReadPinnedEvents = (room: Room): Set<string> => {
 | 
			
		||||
        setReadPinnedEvents(new Set(readPins || []));
 | 
			
		||||
    }, [room]);
 | 
			
		||||
 | 
			
		||||
    useEventEmitter(room, "Room.accountData", update);
 | 
			
		||||
    useTypedEventEmitter(room, RoomEvent.AccountData, update);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        update();
 | 
			
		||||
        return () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
 | 
			
		||||
import { ClientEvent, MatrixClient } from 'matrix-js-sdk/src/client';
 | 
			
		||||
import { RoomMember } from 'matrix-js-sdk/src/models/room-member';
 | 
			
		||||
import { User } from 'matrix-js-sdk/src/models/user';
 | 
			
		||||
import { Room } from 'matrix-js-sdk/src/models/room';
 | 
			
		||||
@@ -29,6 +29,7 @@ import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/reque
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
import { logger } from "matrix-js-sdk/src/logger";
 | 
			
		||||
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
 | 
			
		||||
import dis from '../../../dispatcher/dispatcher';
 | 
			
		||||
import Modal from '../../../Modal';
 | 
			
		||||
@@ -42,7 +43,7 @@ import MultiInviter from "../../../utils/MultiInviter";
 | 
			
		||||
import GroupStore from "../../../stores/GroupStore";
 | 
			
		||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
 | 
			
		||||
import E2EIcon from "../rooms/E2EIcon";
 | 
			
		||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import { textualPowerLevel } from '../../../Roles';
 | 
			
		||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
 | 
			
		||||
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
 | 
			
		||||
@@ -547,7 +548,7 @@ export const useRoomPowerLevels = (cli: MatrixClient, room: Room) => {
 | 
			
		||||
        setPowerLevels(getPowerLevels(room));
 | 
			
		||||
    }, [room]);
 | 
			
		||||
 | 
			
		||||
    useEventEmitter(cli, "RoomState.events", update);
 | 
			
		||||
    useTypedEventEmitter(cli, RoomStateEvent.Events, update);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        update();
 | 
			
		||||
        return () => {
 | 
			
		||||
@@ -1105,7 +1106,7 @@ function useRoomPermissions(cli: MatrixClient, room: Room, user: RoomMember): IR
 | 
			
		||||
        });
 | 
			
		||||
    }, [cli, user, room]);
 | 
			
		||||
 | 
			
		||||
    useEventEmitter(cli, "RoomState.members", updateRoomPermissions);
 | 
			
		||||
    useTypedEventEmitter(cli, RoomStateEvent.Update, updateRoomPermissions);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        updateRoomPermissions();
 | 
			
		||||
        return () => {
 | 
			
		||||
@@ -1316,7 +1317,7 @@ const BasicUserInfo: React.FC<{
 | 
			
		||||
            setIsIgnored(cli.isUserIgnored(member.userId));
 | 
			
		||||
        }
 | 
			
		||||
    }, [cli, member.userId]);
 | 
			
		||||
    useEventEmitter(cli, "accountData", accountDataHandler);
 | 
			
		||||
    useTypedEventEmitter(cli, ClientEvent.AccountData, accountDataHandler);
 | 
			
		||||
 | 
			
		||||
    // Count of how many operations are currently in progress, if > 0 then show a Spinner
 | 
			
		||||
    const [pendingUpdateCount, setPendingUpdateCount] = useState(0);
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ import { lexicographicCompare } from 'matrix-js-sdk/src/utils';
 | 
			
		||||
import { Room } from 'matrix-js-sdk/src/models/room';
 | 
			
		||||
import { throttle } from 'lodash';
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
 | 
			
		||||
 | 
			
		||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
 | 
			
		||||
import AppsDrawer from './AppsDrawer';
 | 
			
		||||
@@ -67,14 +68,13 @@ export default class AuxPanel extends React.Component<IProps, IState> {
 | 
			
		||||
    componentDidMount() {
 | 
			
		||||
        const cli = MatrixClientPeg.get();
 | 
			
		||||
        if (SettingsStore.getValue("feature_state_counters")) {
 | 
			
		||||
            cli.on(RoomStateEvent.Events, this.rateLimitedUpdate);
 | 
			
		||||
            cli.on(RoomStateEvent.Events, this.onRoomStateEvents);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentWillUnmount() {
 | 
			
		||||
        const cli = MatrixClientPeg.get();
 | 
			
		||||
        if (cli && SettingsStore.getValue("feature_state_counters")) {
 | 
			
		||||
            cli.removeListener(RoomStateEvent.Events, this.rateLimitedUpdate);
 | 
			
		||||
        if (SettingsStore.getValue("feature_state_counters")) {
 | 
			
		||||
            MatrixClientPeg.get()?.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -82,7 +82,13 @@ export default class AuxPanel extends React.Component<IProps, IState> {
 | 
			
		||||
        return objectHasDiff(this.props, nextProps) || objectHasDiff(this.state, nextState);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private rateLimitedUpdate = throttle(() => {
 | 
			
		||||
    private onRoomStateEvents = (ev: MatrixEvent) => {
 | 
			
		||||
        if (ev.getType() === "re.jki.counter") {
 | 
			
		||||
            this.updateCounters();
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private updateCounters = throttle(() => {
 | 
			
		||||
        this.setState({ counters: this.computeCounters() });
 | 
			
		||||
    }, 500, { leading: true, trailing: true });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ import { User, UserEvent } from "matrix-js-sdk/src/models/user";
 | 
			
		||||
import { throttle } from 'lodash';
 | 
			
		||||
import { JoinRule } from "matrix-js-sdk/src/@types/partials";
 | 
			
		||||
import { ClientEvent } from "matrix-js-sdk/src/client";
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
import SdkConfig from '../../../SdkConfig';
 | 
			
		||||
@@ -113,7 +114,7 @@ export default class MemberList extends React.Component<IProps, IState> {
 | 
			
		||||
 | 
			
		||||
    private listenForMembersChanges(): void {
 | 
			
		||||
        const cli = MatrixClientPeg.get();
 | 
			
		||||
        cli.on(RoomStateEvent.Members, this.onRoomStateMember);
 | 
			
		||||
        cli.on(RoomStateEvent.Update, this.onRoomStateUpdate);
 | 
			
		||||
        cli.on(RoomMemberEvent.Name, this.onRoomMemberName);
 | 
			
		||||
        cli.on(RoomStateEvent.Events, this.onRoomStateEvent);
 | 
			
		||||
        // We listen for changes to the lastPresenceTs which is essentially
 | 
			
		||||
@@ -129,7 +130,7 @@ export default class MemberList extends React.Component<IProps, IState> {
 | 
			
		||||
        this.mounted = false;
 | 
			
		||||
        const cli = MatrixClientPeg.get();
 | 
			
		||||
        if (cli) {
 | 
			
		||||
            cli.removeListener(RoomStateEvent.Members, this.onRoomStateMember);
 | 
			
		||||
            cli.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
 | 
			
		||||
            cli.removeListener(RoomMemberEvent.Name, this.onRoomMemberName);
 | 
			
		||||
            cli.removeListener(RoomEvent.MyMembership, this.onMyMembership);
 | 
			
		||||
            cli.removeListener(RoomStateEvent.Events, this.onRoomStateEvent);
 | 
			
		||||
@@ -224,10 +225,8 @@ export default class MemberList extends React.Component<IProps, IState> {
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember): void => {
 | 
			
		||||
        if (member.roomId !== this.props.roomId) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    private onRoomStateUpdate = (state: RoomState): void => {
 | 
			
		||||
        if (state.roomId !== this.props.roomId) return;
 | 
			
		||||
        this.updateList();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -238,9 +237,8 @@ export default class MemberList extends React.Component<IProps, IState> {
 | 
			
		||||
        this.updateList();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onRoomStateEvent = (event: MatrixEvent, state: RoomState): void => {
 | 
			
		||||
        if (event.getRoomId() === this.props.roomId &&
 | 
			
		||||
            event.getType() === "m.room.third_party_invite") {
 | 
			
		||||
    private onRoomStateEvent = (event: MatrixEvent): void => {
 | 
			
		||||
        if (event.getRoomId() === this.props.roomId && event.getType() === EventType.RoomThirdPartyInvite) {
 | 
			
		||||
            this.updateList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -229,19 +229,19 @@ export default class MessageComposer extends React.Component<IProps, IState> {
 | 
			
		||||
        this.voiceRecording = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onRoomStateEvents = (ev, state) => {
 | 
			
		||||
    private onRoomStateEvents = (ev: MatrixEvent) => {
 | 
			
		||||
        if (ev.getRoomId() !== this.props.room.roomId) return;
 | 
			
		||||
 | 
			
		||||
        if (ev.getType() === 'm.room.tombstone') {
 | 
			
		||||
        if (ev.getType() === EventType.RoomTombstone) {
 | 
			
		||||
            this.setState({ tombstone: this.getRoomTombstone() });
 | 
			
		||||
        }
 | 
			
		||||
        if (ev.getType() === 'm.room.power_levels') {
 | 
			
		||||
        if (ev.getType() === EventType.RoomPowerLevels) {
 | 
			
		||||
            this.setState({ canSendMessages: this.props.room.maySendMessage() });
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private getRoomTombstone() {
 | 
			
		||||
        return this.props.room.currentState.getStateEvents('m.room.tombstone', '');
 | 
			
		||||
        return this.props.room.currentState.getStateEvents(EventType.RoomTombstone, '');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onTombstoneClick = (ev) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ limitations under the License.
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { throttle } from 'lodash';
 | 
			
		||||
import { MatrixEvent, Room, RoomState, RoomStateEvent } from 'matrix-js-sdk/src';
 | 
			
		||||
import { MatrixEvent, Room, RoomStateEvent } from 'matrix-js-sdk/src';
 | 
			
		||||
import { CallType } from "matrix-js-sdk/src/webrtc/call";
 | 
			
		||||
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
@@ -94,7 +94,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
 | 
			
		||||
        notiStore.removeListener(NotificationStateEvents.Update, this.onNotificationUpdate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onRoomStateEvents = (event: MatrixEvent, state: RoomState) => {
 | 
			
		||||
    private onRoomStateEvents = (event: MatrixEvent) => {
 | 
			
		||||
        if (!this.props.room || event.getRoomId() !== this.props.room.roomId) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -128,7 +128,7 @@ const auxButtonContextMenuPosition = (handle: RefObject<HTMLDivElement>) => {
 | 
			
		||||
 | 
			
		||||
const DmAuxButton = ({ tabIndex, dispatcher = defaultDispatcher }: IAuxButtonProps) => {
 | 
			
		||||
    const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
 | 
			
		||||
    const activeSpace = useEventEmitterState<Room>(SpaceStore.instance, UPDATE_SELECTED_SPACE, () => {
 | 
			
		||||
    const activeSpace: Room = useEventEmitterState(SpaceStore.instance, UPDATE_SELECTED_SPACE, () => {
 | 
			
		||||
        return SpaceStore.instance.activeSpaceRoom;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,11 +15,12 @@ limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import React, { ComponentProps, useContext, useEffect, useState } from "react";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
import { ClientEvent } from "matrix-js-sdk/src/client";
 | 
			
		||||
 | 
			
		||||
import { _t } from "../../../languageHandler";
 | 
			
		||||
import { useEventEmitter, useEventEmitterState } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import { useEventEmitterState, useTypedEventEmitter, useTypedEventEmitterState } from "../../../hooks/useEventEmitter";
 | 
			
		||||
import SpaceStore from "../../../stores/spaces/SpaceStore";
 | 
			
		||||
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
 | 
			
		||||
import SpaceContextMenu from "../context_menus/SpaceContextMenu";
 | 
			
		||||
@@ -150,7 +151,7 @@ const useJoiningRooms = (): Set<string> => {
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    useEventEmitter(cli, "Room", (room: Room) => {
 | 
			
		||||
    useTypedEventEmitter(cli, ClientEvent.Room, (room: Room) => {
 | 
			
		||||
        if (joiningRooms.delete(room.roomId)) {
 | 
			
		||||
            setJoiningRooms(new Set(joiningRooms));
 | 
			
		||||
        }
 | 
			
		||||
@@ -190,7 +191,7 @@ const RoomListHeader = ({ spacePanelDisabled, onVisibilityChange }: IProps) => {
 | 
			
		||||
    // we pass null for the queryLength to inhibit the metrics hook for when there is no filterCondition
 | 
			
		||||
    useWebSearchMetrics(count, filterCondition ? filterCondition.search.length : null, false);
 | 
			
		||||
 | 
			
		||||
    const spaceName = useEventEmitterState(activeSpace, "Room.name", () => activeSpace?.name);
 | 
			
		||||
    const spaceName = useTypedEventEmitterState(activeSpace, RoomEvent.Name, () => activeSpace?.name);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (onVisibilityChange) {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ limitations under the License.
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
 | 
			
		||||
import { Room } from 'matrix-js-sdk/src/models/room';
 | 
			
		||||
import { RoomState, RoomStateEvent } from 'matrix-js-sdk/src/models/room-state';
 | 
			
		||||
import { RoomStateEvent } from 'matrix-js-sdk/src/models/room-state';
 | 
			
		||||
 | 
			
		||||
import Modal from '../../../Modal';
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
@@ -56,7 +56,7 @@ export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, I
 | 
			
		||||
        this.context.removeListener(RoomStateEvent.Events, this.onStateEvents);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onStateEvents = (event: MatrixEvent, state: RoomState): void => {
 | 
			
		||||
    private onStateEvents = (event: MatrixEvent): void => {
 | 
			
		||||
        if (!this.props.room || event.getRoomId() !== this.props.room.roomId) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { logger } from "matrix-js-sdk/src/logger";
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
 | 
			
		||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
 | 
			
		||||
import { _t } from "../../../languageHandler";
 | 
			
		||||
@@ -82,8 +83,8 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onRoomStateEvents = (ev) => {
 | 
			
		||||
        if (ev.getType() === "m.room.third_party_invite" && ev.getStateKey() === this.state.stateKey) {
 | 
			
		||||
    onRoomStateEvents = (ev: MatrixEvent) => {
 | 
			
		||||
        if (ev.getType() === EventType.RoomThirdPartyInvite && ev.getStateKey() === this.state.stateKey) {
 | 
			
		||||
            const newDisplayName = ev.getContent().display_name;
 | 
			
		||||
            const isInvited = isValid3pidInvite(ev);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ import React from 'react';
 | 
			
		||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
 | 
			
		||||
import { Room } from 'matrix-js-sdk/src/models/room';
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
 | 
			
		||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
@@ -96,8 +97,10 @@ export default class ChangeAvatar extends React.Component<IProps, IState> {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (ev.getRoomId() !== this.props.room.roomId || ev.getType() !== 'm.room.avatar'
 | 
			
		||||
            || ev.getSender() !== MatrixClientPeg.get().getUserId()) {
 | 
			
		||||
        if (ev.getRoomId() !== this.props.room.roomId ||
 | 
			
		||||
            ev.getType() !== EventType.RoomAvatar ||
 | 
			
		||||
            ev.getSender() !== MatrixClientPeg.get().getUserId()
 | 
			
		||||
        ) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,6 @@ limitations under the License.
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
 | 
			
		||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import { RoomState, RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { logger } from "matrix-js-sdk/src/logger";
 | 
			
		||||
import { throttle } from "lodash";
 | 
			
		||||
@@ -123,17 +122,17 @@ interface IProps {
 | 
			
		||||
@replaceableComponent("views.settings.tabs.room.RolesRoomSettingsTab")
 | 
			
		||||
export default class RolesRoomSettingsTab extends React.Component<IProps> {
 | 
			
		||||
    componentDidMount() {
 | 
			
		||||
        MatrixClientPeg.get().on(RoomStateEvent.Members, this.onRoomMembership);
 | 
			
		||||
        MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentWillUnmount() {
 | 
			
		||||
        const client = MatrixClientPeg.get();
 | 
			
		||||
        if (client) {
 | 
			
		||||
            client.removeListener(RoomStateEvent.Members, this.onRoomMembership);
 | 
			
		||||
            client.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onRoomMembership = (event: MatrixEvent, state: RoomState, member: RoomMember) => {
 | 
			
		||||
    private onRoomStateUpdate = (state: RoomState) => {
 | 
			
		||||
        if (state.roomId !== this.props.roomId) return;
 | 
			
		||||
        this.onThisRoomMembership();
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import { Room } from "matrix-js-sdk";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
 | 
			
		||||
import { Action } from "../actions";
 | 
			
		||||
import { ActionPayload } from "../payloads";
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import { MatrixError } from "matrix-js-sdk";
 | 
			
		||||
import { MatrixError } from "matrix-js-sdk/src/http-api";
 | 
			
		||||
 | 
			
		||||
import { ActionPayload } from "../payloads";
 | 
			
		||||
import { Action } from "../actions";
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import { MatrixError, Room } from "matrix-js-sdk";
 | 
			
		||||
import { MatrixError, Room } from "matrix-js-sdk/src/matrix";
 | 
			
		||||
 | 
			
		||||
import { ActionPayload } from "../payloads";
 | 
			
		||||
import { Action } from "../actions";
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import { User } from "matrix-js-sdk";
 | 
			
		||||
import { User } from "matrix-js-sdk/src/models/user";
 | 
			
		||||
 | 
			
		||||
import { ActionPayload } from "../payloads";
 | 
			
		||||
import { Action } from "../actions";
 | 
			
		||||
 
 | 
			
		||||
@@ -15,11 +15,11 @@ limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import { useCallback, useState } from "react";
 | 
			
		||||
import { MatrixClient } from "matrix-js-sdk/src/client";
 | 
			
		||||
import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client";
 | 
			
		||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
 | 
			
		||||
import { useEventEmitter } from "./useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "./useEventEmitter";
 | 
			
		||||
 | 
			
		||||
const tryGetContent = <T extends {}>(ev?: MatrixEvent) => ev ? ev.getContent<T>() : undefined;
 | 
			
		||||
 | 
			
		||||
@@ -31,7 +31,7 @@ export const useAccountData = <T extends {}>(cli: MatrixClient, eventType: strin
 | 
			
		||||
        if (event.getType() !== eventType) return;
 | 
			
		||||
        setValue(event.getContent());
 | 
			
		||||
    }, [eventType]);
 | 
			
		||||
    useEventEmitter(cli, "accountData", handler);
 | 
			
		||||
    useTypedEventEmitter(cli, ClientEvent.AccountData, handler);
 | 
			
		||||
 | 
			
		||||
    return value || {} as T;
 | 
			
		||||
};
 | 
			
		||||
@@ -44,7 +44,7 @@ export const useRoomAccountData = <T extends {}>(room: Room, eventType: string)
 | 
			
		||||
        if (event.getType() !== eventType) return;
 | 
			
		||||
        setValue(event.getContent());
 | 
			
		||||
    }, [eventType]);
 | 
			
		||||
    useEventEmitter(room, "Room.accountData", handler);
 | 
			
		||||
    useTypedEventEmitter(room, RoomEvent.AccountData, handler);
 | 
			
		||||
 | 
			
		||||
    return value || {} as T;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -15,17 +15,29 @@ limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import { useRef, useEffect, useState, useCallback } from "react";
 | 
			
		||||
import { ListenerMap, TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter";
 | 
			
		||||
 | 
			
		||||
import type { EventEmitter } from "events";
 | 
			
		||||
 | 
			
		||||
type Handler = (...args: any[]) => void;
 | 
			
		||||
 | 
			
		||||
export function useTypedEventEmitter<
 | 
			
		||||
    Events extends string,
 | 
			
		||||
    Arguments extends ListenerMap<Events>,
 | 
			
		||||
>(
 | 
			
		||||
    emitter: TypedEventEmitter<Events, Arguments>,
 | 
			
		||||
    eventName: Events,
 | 
			
		||||
    handler: Handler,
 | 
			
		||||
): void {
 | 
			
		||||
    useEventEmitter(emitter, eventName, handler);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Hook to wrap event emitter on and removeListener in hook lifecycle
 | 
			
		||||
export const useEventEmitter = (
 | 
			
		||||
export function useEventEmitter(
 | 
			
		||||
    emitter: EventEmitter | undefined,
 | 
			
		||||
    eventName: string | symbol,
 | 
			
		||||
    handler: Handler,
 | 
			
		||||
) => {
 | 
			
		||||
): void {
 | 
			
		||||
    // Create a ref that stores handler
 | 
			
		||||
    const savedHandler = useRef(handler);
 | 
			
		||||
 | 
			
		||||
@@ -52,15 +64,27 @@ export const useEventEmitter = (
 | 
			
		||||
        },
 | 
			
		||||
        [eventName, emitter], // Re-run if eventName or emitter changes
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Mapper<T> = (...args: any[]) => T;
 | 
			
		||||
 | 
			
		||||
export const useEventEmitterState = <T>(
 | 
			
		||||
export function useTypedEventEmitterState<
 | 
			
		||||
    T,
 | 
			
		||||
    Events extends string,
 | 
			
		||||
    Arguments extends ListenerMap<Events>,
 | 
			
		||||
>(
 | 
			
		||||
    emitter: TypedEventEmitter<Events, Arguments>,
 | 
			
		||||
    eventName: Events,
 | 
			
		||||
    fn: Mapper<T>,
 | 
			
		||||
): T {
 | 
			
		||||
    return useEventEmitterState<T>(emitter, eventName, fn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useEventEmitterState<T>(
 | 
			
		||||
    emitter: EventEmitter | undefined,
 | 
			
		||||
    eventName: string | symbol,
 | 
			
		||||
    fn: Mapper<T>,
 | 
			
		||||
): T => {
 | 
			
		||||
): T {
 | 
			
		||||
    const [value, setValue] = useState<T>(fn());
 | 
			
		||||
    const handler = useCallback((...args: any[]) => {
 | 
			
		||||
        setValue(fn(...args));
 | 
			
		||||
@@ -69,4 +93,4 @@ export const useEventEmitterState = <T>(
 | 
			
		||||
    useEffect(handler, [emitter]); // eslint-disable-line react-hooks/exhaustive-deps
 | 
			
		||||
    useEventEmitter(emitter, eventName, handler);
 | 
			
		||||
    return value;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,19 +18,21 @@ import { useCallback, useState } from "react";
 | 
			
		||||
import { MatrixClient } from "matrix-js-sdk/src/client";
 | 
			
		||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
 | 
			
		||||
import { useEventEmitter } from "./useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "./useEventEmitter";
 | 
			
		||||
 | 
			
		||||
// Hook to simplify watching whether a Matrix room is encrypted, returns undefined if room is undefined
 | 
			
		||||
export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | undefined {
 | 
			
		||||
    const [isEncrypted, setIsEncrypted] = useState(room ? cli.isRoomEncrypted(room.roomId) : undefined);
 | 
			
		||||
 | 
			
		||||
    const update = useCallback((event: MatrixEvent) => {
 | 
			
		||||
        if (room && event.getType() === "m.room.encryption") {
 | 
			
		||||
        if (room && event.getType() === EventType.RoomEncryption) {
 | 
			
		||||
            setIsEncrypted(cli.isRoomEncrypted(room.roomId));
 | 
			
		||||
        }
 | 
			
		||||
    }, [cli, room]);
 | 
			
		||||
    useEventEmitter(room ? room.currentState : undefined, "RoomState.events", update);
 | 
			
		||||
    useTypedEventEmitter(room?.currentState, RoomStateEvent.Events, update);
 | 
			
		||||
 | 
			
		||||
    return isEncrypted;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,14 +17,15 @@ limitations under the License.
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { throttle } from "lodash";
 | 
			
		||||
 | 
			
		||||
import { useEventEmitter } from "./useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "./useEventEmitter";
 | 
			
		||||
 | 
			
		||||
// Hook to simplify watching Matrix Room joined members
 | 
			
		||||
export const useRoomMembers = (room: Room, throttleWait = 250) => {
 | 
			
		||||
    const [members, setMembers] = useState<RoomMember[]>(room.getJoinedMembers());
 | 
			
		||||
    useEventEmitter(room.currentState, "RoomState.members", throttle(() => {
 | 
			
		||||
    useTypedEventEmitter(room.currentState, RoomStateEvent.Update, throttle(() => {
 | 
			
		||||
        setMembers(room.getJoinedMembers());
 | 
			
		||||
    }, throttleWait, { leading: true, trailing: true }));
 | 
			
		||||
    return members;
 | 
			
		||||
@@ -33,7 +34,7 @@ export const useRoomMembers = (room: Room, throttleWait = 250) => {
 | 
			
		||||
// Hook to simplify watching Matrix Room joined member count
 | 
			
		||||
export const useRoomMemberCount = (room: Room, throttleWait = 250) => {
 | 
			
		||||
    const [count, setCount] = useState<number>(room.getJoinedMemberCount());
 | 
			
		||||
    useEventEmitter(room.currentState, "RoomState.members", throttle(() => {
 | 
			
		||||
    useTypedEventEmitter(room.currentState, RoomStateEvent.Update, throttle(() => {
 | 
			
		||||
        setCount(room.getJoinedMemberCount());
 | 
			
		||||
    }, throttleWait, { leading: true, trailing: true }));
 | 
			
		||||
    return count;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,9 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { useCallback, useEffect, useState } from "react";
 | 
			
		||||
import { Room } from "matrix-js-sdk/src/models/room";
 | 
			
		||||
import { RoomState } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { RoomState, RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
 | 
			
		||||
import { useEventEmitter } from "./useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitter } from "./useEventEmitter";
 | 
			
		||||
 | 
			
		||||
type Mapper<T> = (roomState: RoomState) => T;
 | 
			
		||||
const defaultMapper: Mapper<RoomState> = (roomState: RoomState) => roomState;
 | 
			
		||||
@@ -36,7 +36,7 @@ export const useRoomState = <T extends any = RoomState>(
 | 
			
		||||
        setValue(mapper(room.currentState));
 | 
			
		||||
    }, [room, mapper]);
 | 
			
		||||
 | 
			
		||||
    useEventEmitter(room?.currentState, "RoomState.events", update);
 | 
			
		||||
    useTypedEventEmitter(room?.currentState, RoomStateEvent.Update, update);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        update();
 | 
			
		||||
        return () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,11 +15,11 @@ limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import { MatrixClient } from "matrix-js-sdk/src/client";
 | 
			
		||||
import { User } from "matrix-js-sdk/src/models/user";
 | 
			
		||||
import { User, UserEvent } from "matrix-js-sdk/src/models/user";
 | 
			
		||||
import { useContext } from "react";
 | 
			
		||||
 | 
			
		||||
import MatrixClientContext from "../contexts/MatrixClientContext";
 | 
			
		||||
import { useEventEmitterState } from "./useEventEmitter";
 | 
			
		||||
import { useTypedEventEmitterState } from "./useEventEmitter";
 | 
			
		||||
import { Member } from "../components/views/right_panel/UserInfo";
 | 
			
		||||
import { useFeatureEnabled } from "./useSettings";
 | 
			
		||||
 | 
			
		||||
@@ -29,10 +29,11 @@ const getStatusMessage = (cli: MatrixClient, user: Member): string => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Hook to simplify handling Matrix User status
 | 
			
		||||
export const useUserStatusMessage = (user?: Member): string => {
 | 
			
		||||
export const useUserStatusMessage = (member?: Member): string => {
 | 
			
		||||
    const cli = useContext(MatrixClientContext);
 | 
			
		||||
    const enabled = useFeatureEnabled("feature_custom_status");
 | 
			
		||||
    return useEventEmitterState(enabled && getUser(cli, user), "User.unstable_statusMessage", () => {
 | 
			
		||||
    const user = enabled ? getUser(cli, member) : undefined;
 | 
			
		||||
    return useTypedEventEmitterState(user, UserEvent._UnstableStatusMessage, () => {
 | 
			
		||||
        return getStatusMessage(cli, user);
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 | 
			
		||||
import { User, UserEvent } from "matrix-js-sdk/src/models/user";
 | 
			
		||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
 | 
			
		||||
import { throttle } from "lodash";
 | 
			
		||||
import { EventType } from "matrix-js-sdk/src/@types/event";
 | 
			
		||||
 | 
			
		||||
import { ActionPayload } from "../dispatcher/payloads";
 | 
			
		||||
import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
 | 
			
		||||
@@ -102,9 +103,7 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
 | 
			
		||||
            this.monitoredUser.removeListener(UserEvent.DisplayName, this.onProfileUpdate);
 | 
			
		||||
            this.monitoredUser.removeListener(UserEvent.AvatarUrl, this.onProfileUpdate);
 | 
			
		||||
        }
 | 
			
		||||
        if (this.matrixClient) {
 | 
			
		||||
            this.matrixClient.removeListener(RoomStateEvent.Events, this.onStateEvents);
 | 
			
		||||
        }
 | 
			
		||||
        this.matrixClient?.removeListener(RoomStateEvent.Events, this.onStateEvents);
 | 
			
		||||
        await this.reset({});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -127,7 +126,7 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
 | 
			
		||||
        // we don't actually do anything here
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onProfileUpdate = async () => {
 | 
			
		||||
    private onProfileUpdate = throttle(async () => {
 | 
			
		||||
        // We specifically do not use the User object we stored for profile info as it
 | 
			
		||||
        // could easily be wrong (such as per-room instead of global profile).
 | 
			
		||||
        const profileInfo = await this.matrixClient.getProfileInfo(this.matrixClient.getUserId());
 | 
			
		||||
@@ -147,12 +146,12 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
 | 
			
		||||
            avatarUrl: profileInfo.avatar_url,
 | 
			
		||||
            fetchedAt: Date.now(),
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
    }, 200, { trailing: true, leading: true });
 | 
			
		||||
 | 
			
		||||
    private onStateEvents = throttle(async (ev: MatrixEvent) => {
 | 
			
		||||
    private onStateEvents = async (ev: MatrixEvent) => {
 | 
			
		||||
        const myUserId = MatrixClientPeg.get().getUserId();
 | 
			
		||||
        if (ev.getType() === 'm.room.member' && ev.getSender() === myUserId && ev.getStateKey() === myUserId) {
 | 
			
		||||
        if (ev.getType() === EventType.RoomMember && ev.getSender() === myUserId && ev.getStateKey() === myUserId) {
 | 
			
		||||
            await this.onProfileUpdate();
 | 
			
		||||
        }
 | 
			
		||||
    }, 200, { trailing: true, leading: true });
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -205,8 +205,8 @@ export default class WidgetUtils {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function onRoomStateEvents(ev) {
 | 
			
		||||
                if (ev.getRoomId() !== roomId) return;
 | 
			
		||||
            function onRoomStateEvents(ev: MatrixEvent) {
 | 
			
		||||
                if (ev.getRoomId() !== roomId || ev.getType() !== "im.vector.modular.widgets") return;
 | 
			
		||||
 | 
			
		||||
                // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
 | 
			
		||||
                const currentWidgetEvents = room.currentState.getStateEvents('im.vector.modular.widgets');
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user