Prefer RoomStateEvent.Update where possible as it fires far less (#7878)

This commit is contained in:
Michael Telatynski 2022-02-24 14:39:25 +00:00 committed by GitHub
parent 36ae0ea49d
commit c257bc3f7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 223 additions and 190 deletions

View file

@ -17,7 +17,7 @@ limitations under the License.
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { CryptoEvent } from "matrix-js-sdk/src/crypto"; 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 { MatrixClientPeg } from './MatrixClientPeg';
import dis from "./dispatcher/dispatcher"; import dis from "./dispatcher/dispatcher";
@ -184,9 +184,7 @@ export default class DeviceListener {
}; };
private onRoomStateEvents = (ev: MatrixEvent) => { private onRoomStateEvents = (ev: MatrixEvent) => {
if (ev.getType() !== "m.room.encryption") { if (ev.getType() !== EventType.RoomEncryption) return;
return;
}
// If a room changes to encrypted, re-check as it may be our first // If a room changes to encrypted, re-check as it may be our first
// encrypted room. This also catches encrypted room creation as well. // encrypted room. This also catches encrypted room creation as well.

View file

@ -61,13 +61,13 @@ export default class UserProvider extends AutocompleteProvider {
}); });
MatrixClientPeg.get().on(RoomEvent.Timeline, this.onRoomTimeline); MatrixClientPeg.get().on(RoomEvent.Timeline, this.onRoomTimeline);
MatrixClientPeg.get().on(RoomStateEvent.Members, this.onRoomStateMember); MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate);
} }
destroy() { destroy() {
if (MatrixClientPeg.get()) { if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener(RoomEvent.Timeline, this.onRoomTimeline); 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); this.onUserSpoke(ev.sender);
}; };
private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember) => { private onRoomStateUpdate = (state: RoomState) => {
// ignore members in other rooms // ignore updates in other rooms
if (member.roomId !== this.room.roomId) { if (state.roomId !== this.room.roomId) return;
return;
}
// blow away the users cache // blow away the users cache
this.users = null; this.users = null;

View file

@ -17,6 +17,7 @@ limitations under the License.
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { ClientEvent } from "matrix-js-sdk/src/client";
import type { EventSubscription } from "fbemitter"; import type { EventSubscription } from "fbemitter";
import GroupFilterOrderStore from '../../stores/GroupFilterOrderStore'; import GroupFilterOrderStore from '../../stores/GroupFilterOrderStore';
@ -51,6 +52,7 @@ interface IGroupFilterPanelState {
@replaceableComponent("structures.GroupFilterPanel") @replaceableComponent("structures.GroupFilterPanel")
class GroupFilterPanel extends React.Component<IGroupFilterPanelProps, IGroupFilterPanelState> { class GroupFilterPanel extends React.Component<IGroupFilterPanelProps, IGroupFilterPanelState> {
public static contextType = MatrixClientContext; public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
public state = { public state = {
orderedTags: [], orderedTags: [],
@ -63,8 +65,8 @@ class GroupFilterPanel extends React.Component<IGroupFilterPanelProps, IGroupFil
public componentDidMount() { public componentDidMount() {
this.unmounted = false; this.unmounted = false;
this.context.on("Group.myMembership", this.onGroupMyMembership); this.context.on(ClientEvent.GroupMyMembership, this.onGroupMyMembership);
this.context.on("sync", this.onClientSync); this.context.on(ClientEvent.Sync, this.onClientSync);
this.groupFilterOrderStoreToken = GroupFilterOrderStore.addListener(() => { this.groupFilterOrderStoreToken = GroupFilterOrderStore.addListener(() => {
if (this.unmounted) { if (this.unmounted) {
@ -82,8 +84,8 @@ class GroupFilterPanel extends React.Component<IGroupFilterPanelProps, IGroupFil
public componentWillUnmount() { public componentWillUnmount() {
this.unmounted = true; this.unmounted = true;
this.context.removeListener("Group.myMembership", this.onGroupMyMembership); this.context.removeListener(ClientEvent.GroupMyMembership, this.onGroupMyMembership);
this.context.removeListener("sync", this.onClientSync); this.context.removeListener(ClientEvent.Sync, this.onClientSync);
if (this.groupFilterOrderStoreToken) { if (this.groupFilterOrderStoreToken) {
this.groupFilterOrderStoreToken.remove(); this.groupFilterOrderStoreToken.remove();
} }

View file

@ -317,7 +317,7 @@ class LoggedInView extends React.Component<IProps, IState> {
private onRoomStateEvents = (ev: MatrixEvent): void => { private onRoomStateEvents = (ev: MatrixEvent): void => {
const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice]; 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(); this.updateServerNoticeEvents();
} }
}; };

View file

@ -23,7 +23,6 @@ import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
import { Relations } from "matrix-js-sdk/src/models/relations"; import { Relations } from "matrix-js-sdk/src/models/relations";
import { logger } from 'matrix-js-sdk/src/logger'; import { logger } from 'matrix-js-sdk/src/logger';
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { throttle } from "lodash";
import shouldHideEvent from '../../shouldHideEvent'; import shouldHideEvent from '../../shouldHideEvent';
import { wantsDateSeparator } from '../../DateUtils'; import { wantsDateSeparator } from '../../DateUtils';
@ -277,13 +276,13 @@ export default class MessagePanel extends React.Component<IProps, IState> {
componentDidMount() { componentDidMount() {
this.calculateRoomMembersCount(); this.calculateRoomMembersCount();
this.props.room?.currentState.on(RoomStateEvent.Members, this.onRoomMembers); this.props.room?.currentState.on(RoomStateEvent.Update, this.calculateRoomMembersCount);
this.isMounted = true; this.isMounted = true;
} }
componentWillUnmount() { componentWillUnmount() {
this.isMounted = false; 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); 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; return this.props.room?.getInvitedAndJoinedMemberCount() <= 2 && this.props.layout === Layout.Bubble;
} }
private onRoomMembers = (event: MatrixEvent): void => { private calculateRoomMembersCount = (): void => {
if (this.props.room && event.getRoomId() !== this.props.room.roomId) return; // different room
this.calculateRoomMembersCount();
};
private calculateRoomMembersCount = throttle((): void => {
this.setState({ this.setState({
hideSender: this.shouldHideSender(), hideSender: this.shouldHideSender(),
}); });
}, 200, { leading: true, trailing: true }); };
private onShowTypingNotificationsChange = (): void => { private onShowTypingNotificationsChange = (): void => {
this.setState({ this.setState({

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react'; import React from 'react';
import { Room } from "matrix-js-sdk/src/models/room"; 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 { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { throttle } from 'lodash'; import { throttle } from 'lodash';
@ -67,6 +67,7 @@ interface IState {
@replaceableComponent("structures.RightPanel") @replaceableComponent("structures.RightPanel")
export default class RightPanel extends React.Component<IProps, IState> { export default class RightPanel extends React.Component<IProps, IState> {
static contextType = MatrixClientContext; static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
constructor(props, context) { constructor(props, context) {
super(props, context); super(props, context);
@ -81,15 +82,12 @@ export default class RightPanel extends React.Component<IProps, IState> {
}, 500, { leading: true, trailing: true }); }, 500, { leading: true, trailing: true });
public componentDidMount(): void { public componentDidMount(): void {
const cli = this.context; this.context.on(RoomStateEvent.Members, this.onRoomStateMember);
cli.on("RoomState.members", this.onRoomStateMember);
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate); RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
} }
public componentWillUnmount(): void { public componentWillUnmount(): void {
if (this.context) { this.context?.removeListener(RoomStateEvent.Members, this.onRoomStateMember);
this.context.removeListener("RoomState.members", this.onRoomStateMember);
}
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate); RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
} }

View file

@ -22,17 +22,19 @@ limitations under the License.
import React, { createRef } from 'react'; import React, { createRef } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { IRecommendedVersion, NotificationCountType, Room } from "matrix-js-sdk/src/models/room"; import { IRecommendedVersion, NotificationCountType, Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
import { EventSubscription } from "fbemitter"; import { EventSubscription } from "fbemitter";
import { ISearchResults } from 'matrix-js-sdk/src/@types/search'; import { ISearchResults } from 'matrix-js-sdk/src/@types/search';
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { EventTimeline } from 'matrix-js-sdk/src/models/event-timeline'; import { EventTimeline } from 'matrix-js-sdk/src/models/event-timeline';
import { EventType } from 'matrix-js-sdk/src/@types/event'; 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 { CallState, CallType, MatrixCall } from "matrix-js-sdk/src/webrtc/call";
import { throttle } from "lodash"; import { throttle } from "lodash";
import { MatrixError } from 'matrix-js-sdk/src/http-api'; 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 shouldHideEvent from '../../shouldHideEvent';
import { _t } from '../../languageHandler'; import { _t } from '../../languageHandler';
@ -230,11 +232,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
private roomViewBody = createRef<HTMLDivElement>(); private roomViewBody = createRef<HTMLDivElement>();
static contextType = MatrixClientContext; static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
constructor(props, context) { constructor(props: IRoomProps, context: React.ContextType<typeof MatrixClientContext>) {
super(props, context); super(props, context);
const llMembers = this.context.hasLazyLoadMembersEnabled(); const llMembers = context.hasLazyLoadMembersEnabled();
this.state = { this.state = {
roomId: null, roomId: null,
roomLoading: true, roomLoading: true,
@ -268,7 +271,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
showJoinLeaves: true, showJoinLeaves: true,
showAvatarChanges: true, showAvatarChanges: true,
showDisplaynameChanges: true, showDisplaynameChanges: true,
matrixClientIsReady: this.context && this.context.isInitialSyncComplete(), matrixClientIsReady: context?.isInitialSyncComplete(),
mainSplitContentType: MainSplitContentType.Timeline, mainSplitContentType: MainSplitContentType.Timeline,
timelineRenderingType: TimelineRenderingType.Room, timelineRenderingType: TimelineRenderingType.Room,
liveTimeline: undefined, liveTimeline: undefined,
@ -276,19 +279,19 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}; };
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
this.context.on("Room", this.onRoom); context.on(ClientEvent.Room, this.onRoom);
this.context.on("Room.timeline", this.onRoomTimeline); context.on(RoomEvent.Timeline, this.onRoomTimeline);
this.context.on("Room.name", this.onRoomName); context.on(RoomEvent.Name, this.onRoomName);
this.context.on("Room.accountData", this.onRoomAccountData); context.on(RoomEvent.AccountData, this.onRoomAccountData);
this.context.on("RoomState.events", this.onRoomStateEvents); context.on(RoomStateEvent.Events, this.onRoomStateEvents);
this.context.on("RoomState.members", this.onRoomStateMember); context.on(RoomStateEvent.Update, this.onRoomStateUpdate);
this.context.on("Room.myMembership", this.onMyMembership); context.on(RoomEvent.MyMembership, this.onMyMembership);
this.context.on("accountData", this.onAccountData); context.on(ClientEvent.AccountData, this.onAccountData);
this.context.on("crypto.keyBackupStatus", this.onKeyBackupStatus); context.on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
this.context.on("deviceVerificationChanged", this.onDeviceVerificationChanged); context.on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
this.context.on("userTrustStatusChanged", this.onUserVerificationChanged); context.on(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
this.context.on("crossSigning.keysChanged", this.onCrossSigningKeysChanged); context.on(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
this.context.on("Event.decrypted", this.onEventDecrypted); context.on(MatrixEventEvent.Decrypted, this.onEventDecrypted);
// Start listening for RoomViewStore updates // Start listening for RoomViewStore updates
this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate); this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate);
@ -704,19 +707,19 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
dis.unregister(this.dispatcherRef); dis.unregister(this.dispatcherRef);
if (this.context) { if (this.context) {
this.context.removeListener("Room", this.onRoom); this.context.removeListener(ClientEvent.Room, this.onRoom);
this.context.removeListener("Room.timeline", this.onRoomTimeline); this.context.removeListener(RoomEvent.Timeline, this.onRoomTimeline);
this.context.removeListener("Room.name", this.onRoomName); this.context.removeListener(RoomEvent.Name, this.onRoomName);
this.context.removeListener("Room.accountData", this.onRoomAccountData); this.context.removeListener(RoomEvent.AccountData, this.onRoomAccountData);
this.context.removeListener("RoomState.events", this.onRoomStateEvents); this.context.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
this.context.removeListener("Room.myMembership", this.onMyMembership); this.context.removeListener(RoomEvent.MyMembership, this.onMyMembership);
this.context.removeListener("RoomState.members", this.onRoomStateMember); this.context.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
this.context.removeListener("accountData", this.onAccountData); this.context.removeListener(ClientEvent.AccountData, this.onAccountData);
this.context.removeListener("crypto.keyBackupStatus", this.onKeyBackupStatus); this.context.removeListener(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
this.context.removeListener("deviceVerificationChanged", this.onDeviceVerificationChanged); this.context.removeListener(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
this.context.removeListener("userTrustStatusChanged", this.onUserVerificationChanged); this.context.removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
this.context.removeListener("crossSigning.keysChanged", this.onCrossSigningKeysChanged); this.context.removeListener(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
this.context.removeListener("Event.decrypted", this.onEventDecrypted); this.context.removeListener(MatrixEventEvent.Decrypted, this.onEventDecrypted);
} }
window.removeEventListener('beforeunload', this.onPageUnload); 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; const room = this.state.room;
if (!room.currentState.getMember(userId)) { if (!room.currentState.getMember(userId)) {
return; return;
@ -1105,7 +1108,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.updateE2EStatus(room); this.updateE2EStatus(room);
}; };
private onUserVerificationChanged = (userId: string, trustStatus: object) => { private onUserVerificationChanged = (userId: string) => {
const room = this.state.room; const room = this.state.room;
if (!room || !room.currentState.getMember(userId)) { if (!room || !room.currentState.getMember(userId)) {
return; return;
@ -1156,9 +1159,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
private onRoomStateEvents = (ev: MatrixEvent, state: RoomState) => { private onRoomStateEvents = (ev: MatrixEvent, state: RoomState) => {
// ignore if we don't have a room yet // ignore if we don't have a room yet
if (!this.state.room || this.state.room.roomId !== state.roomId) { if (!this.state.room || this.state.room.roomId !== state.roomId) return;
return;
}
if (ev.getType() === EventType.RoomCanonicalAlias) { if (ev.getType() === EventType.RoomCanonicalAlias) {
// re-view the room so MatrixChat can manage the alias in the URL properly // 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); this.updatePermissions(this.state.room);
}; };
private onRoomStateMember = (ev: MatrixEvent, state, member) => { private onRoomStateUpdate = (state: RoomState) => {
// ignore if we don't have a room yet
if (!this.state.room) {
return;
}
// ignore members in other rooms // ignore members in other rooms
if (member.roomId !== this.state.room.roomId) { if (state.roomId !== this.state.room?.roomId) {
return; return;
} }
@ -1255,7 +1251,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
private onJoinButtonClicked = () => { private onJoinButtonClicked = () => {
// If the user is a ROU, allow them to transition to a PWLU // 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 // Join this room once the user has registered and logged in
// (If we failed to peek, we may not have a valid room object.) // (If we failed to peek, we may not have a valid room object.)
dis.dispatch<DoAfterSyncPreparedPayload<ViewRoomPayload>>({ dis.dispatch<DoAfterSyncPreparedPayload<ViewRoomPayload>>({
@ -1712,7 +1708,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
getHiddenHighlightCount() { getHiddenHighlightCount() {
const oldRoom = this.getOldRoom(); const oldRoom = this.getOldRoom();
if (!oldRoom) return 0; if (!oldRoom) return 0;
return oldRoom.getUnreadNotificationCount('highlight'); return oldRoom.getUnreadNotificationCount(NotificationCountType.Highlight);
} }
onHiddenHighlightsClick = () => { onHiddenHighlightsClick = () => {

View file

@ -27,7 +27,7 @@ import React, {
useRef, useRef,
useState, useState,
} from "react"; } 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 { RoomHierarchy } from "matrix-js-sdk/src/room-hierarchy";
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event"; import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
import { IHierarchyRelation, IHierarchyRoom } from "matrix-js-sdk/src/@types/spaces"; 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 { IState, RovingTabIndexProvider, useRovingTabIndex } from "../../accessibility/RovingTabIndex";
import { getDisplayAliasForRoom } from "./RoomDirectory"; import { getDisplayAliasForRoom } from "./RoomDirectory";
import MatrixClientContext from "../../contexts/MatrixClientContext"; import MatrixClientContext from "../../contexts/MatrixClientContext";
import { useEventEmitterState } from "../../hooks/useEventEmitter"; import { useTypedEventEmitterState } from "../../hooks/useEventEmitter";
import { IOOBData } from "../../stores/ThreepidInviteStore"; import { IOOBData } from "../../stores/ThreepidInviteStore";
import { awaitRoomDownSync } from "../../utils/RoomUpgrade"; import { awaitRoomDownSync } from "../../utils/RoomUpgrade";
import RoomViewStore from "../../stores/RoomViewStore"; import RoomViewStore from "../../stores/RoomViewStore";
@ -99,7 +99,7 @@ const Tile: React.FC<ITileProps> = ({
const cliRoom = cli.getRoom(room.room_id); const cliRoom = cli.getRoom(room.room_id);
return cliRoom?.getMyMembership() === "join" ? cliRoom : null; 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] const name = joinedRoomName || room.name || room.canonical_alias || room.aliases?.[0]
|| (room.room_type === RoomType.Space ? _t("Unnamed Space") : _t("Unnamed Room")); || (room.room_type === RoomType.Space ? _t("Unnamed Space") : _t("Unnamed Room"));

View file

@ -17,7 +17,7 @@ limitations under the License.
import React, { RefObject, useContext, useRef, useState } from "react"; import React, { RefObject, useContext, useRef, useState } from "react";
import { EventType } from "matrix-js-sdk/src/@types/event"; import { EventType } from "matrix-js-sdk/src/@types/event";
import { JoinRule, Preset } from "matrix-js-sdk/src/@types/partials"; 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 { logger } from "matrix-js-sdk/src/logger";
import MatrixClientContext from "../../contexts/MatrixClientContext"; import MatrixClientContext from "../../contexts/MatrixClientContext";
@ -31,7 +31,7 @@ import { inviteMultipleToRoom, showRoomInviteDialog } from "../../RoomInvite";
import { useRoomMembers } from "../../hooks/useRoomMembers"; import { useRoomMembers } from "../../hooks/useRoomMembers";
import createRoom, { IOpts } from "../../createRoom"; import createRoom, { IOpts } from "../../createRoom";
import Field from "../views/elements/Field"; import Field from "../views/elements/Field";
import { useEventEmitter } from "../../hooks/useEventEmitter"; import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
import withValidation from "../views/elements/Validation"; import withValidation from "../views/elements/Validation";
import * as Email from "../../email"; import * as Email from "../../email";
import defaultDispatcher from "../../dispatcher/dispatcher"; import defaultDispatcher from "../../dispatcher/dispatcher";
@ -121,7 +121,7 @@ const RoomMemberCount = ({ room, children }) => {
const useMyRoomMembership = (room: Room) => { const useMyRoomMembership = (room: Room) => {
const [membership, setMembership] = useState(room.getMyMembership()); const [membership, setMembership] = useState(room.getMyMembership());
useEventEmitter(room, "Room.myMembership", () => { useTypedEventEmitter(room, RoomEvent.MyMembership, () => {
setMembership(room.getMyMembership()); setMembership(room.getMyMembership());
}); });
return membership; return membership;
@ -790,17 +790,18 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
export default class SpaceRoomView extends React.PureComponent<IProps, IState> { export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
static contextType = MatrixClientContext; static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
private readonly creator: string; private readonly creator: string;
private readonly dispatcherRef: string; private readonly dispatcherRef: string;
constructor(props, context) { constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
super(props, context); super(props, context);
let phase = Phase.Landing; let phase = Phase.Landing;
this.creator = this.props.space.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender(); 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) { if (showSetup) {
phase = this.props.justCreatedOpts.createOpts.preset === Preset.PublicChat 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); this.dispatcherRef = defaultDispatcher.register(this.onAction);
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate); RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
this.context.on("Room.myMembership", this.onMyMembership); }
componentDidMount() {
this.context.on(RoomEvent.MyMembership, this.onMyMembership);
} }
componentWillUnmount() { componentWillUnmount() {
defaultDispatcher.unregister(this.dispatcherRef); defaultDispatcher.unregister(this.dispatcherRef);
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate); 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) => { private onMyMembership = (room: Room, myMembership: string) => {

View file

@ -20,13 +20,14 @@ limitations under the License.
import React, { useCallback, useContext, useEffect, useState } from 'react'; import React, { useCallback, useContext, useEffect, useState } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { ResizeMethod } from 'matrix-js-sdk/src/@types/partials'; import { ResizeMethod } from 'matrix-js-sdk/src/@types/partials';
import { ClientEvent } from "matrix-js-sdk/src/client";
import * as AvatarLogic from '../../../Avatar'; import * as AvatarLogic from '../../../Avatar';
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
import RoomContext from "../../../contexts/RoomContext"; import RoomContext from "../../../contexts/RoomContext";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { useEventEmitter } from "../../../hooks/useEventEmitter"; import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import { toPx } from "../../../utils/units"; import { toPx } from "../../../utils/units";
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
@ -92,7 +93,7 @@ const useImageUrl = ({ url, urls }): [string, () => void] => {
setIndex(0); setIndex(0);
} }
}, []); }, []);
useEventEmitter(cli, "sync", onClientSync); useTypedEventEmitter(cli, ClientEvent.Sync, onClientSync);
const imageUrl = imageUrls[urlsIndex]; const imageUrl = imageUrls[urlsIndex];
return [imageUrl, onError]; return [imageUrl, onError];

View file

@ -20,6 +20,7 @@ import { ResizeMethod } from 'matrix-js-sdk/src/@types/partials';
import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import classNames from "classnames"; import classNames from "classnames";
import { EventType } from "matrix-js-sdk/src/@types/event";
import BaseAvatar from './BaseAvatar'; import BaseAvatar from './BaseAvatar';
import ImageView from '../elements/ImageView'; import ImageView from '../elements/ImageView';
@ -86,10 +87,7 @@ export default class RoomAvatar extends React.Component<IProps, IState> {
} }
private onRoomStateEvents = (ev: MatrixEvent) => { private onRoomStateEvents = (ev: MatrixEvent) => {
if (!this.props.room || if (ev.getRoomId() !== this.props.room?.roomId || ev.getType() !== EventType.RoomAvatar) return;
ev.getRoomId() !== this.props.room.roomId ||
ev.getType() !== 'm.room.avatar'
) return;
this.setState({ this.setState({
urls: RoomAvatar.getImageUrls(this.props), urls: RoomAvatar.getImageUrls(this.props),

View file

@ -24,6 +24,7 @@ import {
PHASE_STARTED, PHASE_STARTED,
PHASE_CANCELLED, PHASE_CANCELLED,
VerificationRequest, VerificationRequest,
VerificationRequestEvent,
} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
@ -34,7 +35,7 @@ import SyntaxHighlight from '../elements/SyntaxHighlight';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import Field from "../elements/Field"; import Field from "../elements/Field";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { useEventEmitter } from "../../../hooks/useEventEmitter"; import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import WidgetStore, { IApp } from "../../../stores/WidgetStore"; import WidgetStore, { IApp } from "../../../stores/WidgetStore";
import { UPDATE_EVENT } from "../../../stores/AsyncStore"; import { UPDATE_EVENT } from "../../../stores/AsyncStore";
import { SETTINGS } from "../../../settings/Settings"; import { SETTINGS } from "../../../settings/Settings";
@ -756,7 +757,7 @@ const VerificationRequestExplorer: React.FC<{
const [timeout, setRequestTimeout] = useState(request.timeout); const [timeout, setRequestTimeout] = useState(request.timeout);
/* Re-render if something changes state */ /* Re-render if something changes state */
useEventEmitter(request, "change", updateState); useTypedEventEmitter(request, VerificationRequestEvent.Change, updateState);
/* Keep re-rendering if there's a timeout */ /* Keep re-rendering if there's a timeout */
useEffect(() => { useEffect(() => {

View file

@ -15,9 +15,9 @@ limitations under the License.
*/ */
import React, { useEffect, useState } from "react"; 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 { interface IProps {
room: Room; room: Room;
@ -26,7 +26,7 @@ interface IProps {
const RoomName = ({ room, children }: IProps): JSX.Element => { const RoomName = ({ room, children }: IProps): JSX.Element => {
const [name, setName] = useState(room?.name); const [name, setName] = useState(room?.name);
useEventEmitter(room, "Room.name", () => { useTypedEventEmitter(room, RoomEvent.Name, () => {
setName(room?.name); setName(room?.name);
}); });
useEffect(() => { useEffect(() => {

View file

@ -17,8 +17,10 @@ limitations under the License.
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { EventType } from "matrix-js-sdk/src/@types/event"; import { EventType } from "matrix-js-sdk/src/@types/event";
import { Room } from "matrix-js-sdk/src/models/room"; 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"; import { linkifyElement } from "../../../HtmlUtils";
interface IProps { interface IProps {
@ -30,7 +32,8 @@ export const getTopic = room => room?.currentState?.getStateEvents(EventType.Roo
const RoomTopic = ({ room, children }: IProps): JSX.Element => { const RoomTopic = ({ room, children }: IProps): JSX.Element => {
const [topic, setTopic] = useState(getTopic(room)); 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)); setTopic(getTopic(room));
}); });
useEffect(() => { useEffect(() => {

View file

@ -17,6 +17,7 @@
import React from 'react'; import React from 'react';
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { MsgType } from "matrix-js-sdk/src/@types/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 Flair from '../elements/Flair';
import FlairStore from '../../../stores/FlairStore'; import FlairStore from '../../../stores/FlairStore';
@ -35,13 +36,14 @@ interface IProps {
} }
interface IState { interface IState {
userGroups; userGroups: string[];
relatedGroups; relatedGroups: string[];
} }
@replaceableComponent("views.messages.SenderProfile") @replaceableComponent("views.messages.SenderProfile")
export default class SenderProfile extends React.Component<IProps, IState> { export default class SenderProfile extends React.Component<IProps, IState> {
static contextType = MatrixClientContext; static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
private unmounted = false; private unmounted = false;
constructor(props: IProps) { constructor(props: IProps) {
@ -61,12 +63,12 @@ export default class SenderProfile extends React.Component<IProps, IState> {
this.getPublicisedGroups(); this.getPublicisedGroups();
} }
this.context.on('RoomState.events', this.onRoomStateEvents); this.context.on(RoomStateEvent.Events, this.onRoomStateEvents);
} }
componentWillUnmount() { componentWillUnmount() {
this.unmounted = true; this.unmounted = true;
this.context.removeListener('RoomState.events', this.onRoomStateEvents); this.context.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
} }
private async getPublicisedGroups() { private async getPublicisedGroups() {

View file

@ -16,9 +16,10 @@ limitations under the License.
import React, { useCallback, useEffect, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import { import {
VerificationRequest,
PHASE_REQUESTED, PHASE_REQUESTED,
PHASE_UNSENT, PHASE_UNSENT,
VerificationRequest,
VerificationRequestEvent,
} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { User } from "matrix-js-sdk/src/models/user"; import { User } from "matrix-js-sdk/src/models/user";
@ -27,7 +28,7 @@ import EncryptionInfo from "./EncryptionInfo";
import VerificationPanel from "./VerificationPanel"; import VerificationPanel from "./VerificationPanel";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { ensureDMExists } from "../../../createRoom"; import { ensureDMExists } from "../../../createRoom";
import { useEventEmitter } from "../../../hooks/useEventEmitter"; import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import * as sdk from "../../../index"; import * as sdk from "../../../index";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
@ -107,7 +108,7 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
} }
}, [onClose, request]); }, [onClose, request]);
useEventEmitter(request, "change", changeHandler); useTypedEventEmitter(request, VerificationRequestEvent.Change, changeHandler);
const onStartVerification = useCallback(async () => { const onStartVerification = useCallback(async () => {
setRequesting(true); setRequesting(true);

View file

@ -15,16 +15,17 @@ limitations under the License.
*/ */
import React, { useCallback, useContext, useEffect, useState } from "react"; 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 { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType } from 'matrix-js-sdk/src/@types/event'; import { EventType } from 'matrix-js-sdk/src/@types/event';
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import BaseCard from "./BaseCard"; import BaseCard from "./BaseCard";
import Spinner from "../elements/Spinner"; import Spinner from "../elements/Spinner";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { useEventEmitter } from "../../../hooks/useEventEmitter"; import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import PinningUtils from "../../../utils/PinningUtils"; import PinningUtils from "../../../utils/PinningUtils";
import { useAsyncMemo } from "../../../hooks/useAsyncMemo"; import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
import PinnedEventTile from "../rooms/PinnedEventTile"; import PinnedEventTile from "../rooms/PinnedEventTile";
@ -45,7 +46,7 @@ export const usePinnedEvents = (room: Room): string[] => {
setPinnedEvents(room.currentState.getStateEvents(EventType.RoomPinnedEvents, "")?.getContent()?.pinned || []); setPinnedEvents(room.currentState.getStateEvents(EventType.RoomPinnedEvents, "")?.getContent()?.pinned || []);
}, [room]); }, [room]);
useEventEmitter(room?.currentState, "RoomState.events", update); useTypedEventEmitter(room?.currentState, RoomStateEvent.Events, update);
useEffect(() => { useEffect(() => {
update(); update();
return () => { return () => {
@ -67,7 +68,7 @@ export const useReadPinnedEvents = (room: Room): Set<string> => {
setReadPinnedEvents(new Set(readPins || [])); setReadPinnedEvents(new Set(readPins || []));
}, [room]); }, [room]);
useEventEmitter(room, "Room.accountData", update); useTypedEventEmitter(room, RoomEvent.AccountData, update);
useEffect(() => { useEffect(() => {
update(); update();
return () => { return () => {

View file

@ -19,7 +19,7 @@ limitations under the License.
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import classNames from 'classnames'; 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 { RoomMember } from 'matrix-js-sdk/src/models/room-member';
import { User } from 'matrix-js-sdk/src/models/user'; import { User } from 'matrix-js-sdk/src/models/user';
import { Room } from 'matrix-js-sdk/src/models/room'; 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 { EventType } from "matrix-js-sdk/src/@types/event";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { CryptoEvent } from "matrix-js-sdk/src/crypto"; import { CryptoEvent } from "matrix-js-sdk/src/crypto";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import dis from '../../../dispatcher/dispatcher'; import dis from '../../../dispatcher/dispatcher';
import Modal from '../../../Modal'; import Modal from '../../../Modal';
@ -42,7 +43,7 @@ import MultiInviter from "../../../utils/MultiInviter";
import GroupStore from "../../../stores/GroupStore"; import GroupStore from "../../../stores/GroupStore";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import E2EIcon from "../rooms/E2EIcon"; import E2EIcon from "../rooms/E2EIcon";
import { useEventEmitter } from "../../../hooks/useEventEmitter"; import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import { textualPowerLevel } from '../../../Roles'; import { textualPowerLevel } from '../../../Roles';
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases'; import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
@ -547,7 +548,7 @@ export const useRoomPowerLevels = (cli: MatrixClient, room: Room) => {
setPowerLevels(getPowerLevels(room)); setPowerLevels(getPowerLevels(room));
}, [room]); }, [room]);
useEventEmitter(cli, "RoomState.events", update); useTypedEventEmitter(cli, RoomStateEvent.Events, update);
useEffect(() => { useEffect(() => {
update(); update();
return () => { return () => {
@ -1105,7 +1106,7 @@ function useRoomPermissions(cli: MatrixClient, room: Room, user: RoomMember): IR
}); });
}, [cli, user, room]); }, [cli, user, room]);
useEventEmitter(cli, "RoomState.members", updateRoomPermissions); useTypedEventEmitter(cli, RoomStateEvent.Update, updateRoomPermissions);
useEffect(() => { useEffect(() => {
updateRoomPermissions(); updateRoomPermissions();
return () => { return () => {
@ -1316,7 +1317,7 @@ const BasicUserInfo: React.FC<{
setIsIgnored(cli.isUserIgnored(member.userId)); setIsIgnored(cli.isUserIgnored(member.userId));
} }
}, [cli, 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 // Count of how many operations are currently in progress, if > 0 then show a Spinner
const [pendingUpdateCount, setPendingUpdateCount] = useState(0); const [pendingUpdateCount, setPendingUpdateCount] = useState(0);

View file

@ -19,6 +19,7 @@ import { lexicographicCompare } from 'matrix-js-sdk/src/utils';
import { Room } from 'matrix-js-sdk/src/models/room'; import { Room } from 'matrix-js-sdk/src/models/room';
import { throttle } from 'lodash'; import { throttle } from 'lodash';
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import AppsDrawer from './AppsDrawer'; import AppsDrawer from './AppsDrawer';
@ -67,14 +68,13 @@ export default class AuxPanel extends React.Component<IProps, IState> {
componentDidMount() { componentDidMount() {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
if (SettingsStore.getValue("feature_state_counters")) { if (SettingsStore.getValue("feature_state_counters")) {
cli.on(RoomStateEvent.Events, this.rateLimitedUpdate); cli.on(RoomStateEvent.Events, this.onRoomStateEvents);
} }
} }
componentWillUnmount() { componentWillUnmount() {
const cli = MatrixClientPeg.get(); if (SettingsStore.getValue("feature_state_counters")) {
if (cli && SettingsStore.getValue("feature_state_counters")) { MatrixClientPeg.get()?.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
cli.removeListener(RoomStateEvent.Events, this.rateLimitedUpdate);
} }
} }
@ -82,7 +82,13 @@ export default class AuxPanel extends React.Component<IProps, IState> {
return objectHasDiff(this.props, nextProps) || objectHasDiff(this.state, nextState); 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() }); this.setState({ counters: this.computeCounters() });
}, 500, { leading: true, trailing: true }); }, 500, { leading: true, trailing: true });

View file

@ -26,6 +26,7 @@ import { User, UserEvent } from "matrix-js-sdk/src/models/user";
import { throttle } from 'lodash'; import { throttle } from 'lodash';
import { JoinRule } from "matrix-js-sdk/src/@types/partials"; import { JoinRule } from "matrix-js-sdk/src/@types/partials";
import { ClientEvent } from "matrix-js-sdk/src/client"; import { ClientEvent } from "matrix-js-sdk/src/client";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import SdkConfig from '../../../SdkConfig'; import SdkConfig from '../../../SdkConfig';
@ -113,7 +114,7 @@ export default class MemberList extends React.Component<IProps, IState> {
private listenForMembersChanges(): void { private listenForMembersChanges(): void {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
cli.on(RoomStateEvent.Members, this.onRoomStateMember); cli.on(RoomStateEvent.Update, this.onRoomStateUpdate);
cli.on(RoomMemberEvent.Name, this.onRoomMemberName); cli.on(RoomMemberEvent.Name, this.onRoomMemberName);
cli.on(RoomStateEvent.Events, this.onRoomStateEvent); cli.on(RoomStateEvent.Events, this.onRoomStateEvent);
// We listen for changes to the lastPresenceTs which is essentially // 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; this.mounted = false;
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
if (cli) { if (cli) {
cli.removeListener(RoomStateEvent.Members, this.onRoomStateMember); cli.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
cli.removeListener(RoomMemberEvent.Name, this.onRoomMemberName); cli.removeListener(RoomMemberEvent.Name, this.onRoomMemberName);
cli.removeListener(RoomEvent.MyMembership, this.onMyMembership); cli.removeListener(RoomEvent.MyMembership, this.onMyMembership);
cli.removeListener(RoomStateEvent.Events, this.onRoomStateEvent); 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 => { private onRoomStateUpdate = (state: RoomState): void => {
if (member.roomId !== this.props.roomId) { if (state.roomId !== this.props.roomId) return;
return;
}
this.updateList(); this.updateList();
}; };
@ -238,9 +237,8 @@ export default class MemberList extends React.Component<IProps, IState> {
this.updateList(); this.updateList();
}; };
private onRoomStateEvent = (event: MatrixEvent, state: RoomState): void => { private onRoomStateEvent = (event: MatrixEvent): void => {
if (event.getRoomId() === this.props.roomId && if (event.getRoomId() === this.props.roomId && event.getType() === EventType.RoomThirdPartyInvite) {
event.getType() === "m.room.third_party_invite") {
this.updateList(); this.updateList();
} }

View file

@ -229,19 +229,19 @@ export default class MessageComposer extends React.Component<IProps, IState> {
this.voiceRecording = null; this.voiceRecording = null;
} }
private onRoomStateEvents = (ev, state) => { private onRoomStateEvents = (ev: MatrixEvent) => {
if (ev.getRoomId() !== this.props.room.roomId) return; if (ev.getRoomId() !== this.props.room.roomId) return;
if (ev.getType() === 'm.room.tombstone') { if (ev.getType() === EventType.RoomTombstone) {
this.setState({ tombstone: this.getRoomTombstone() }); this.setState({ tombstone: this.getRoomTombstone() });
} }
if (ev.getType() === 'm.room.power_levels') { if (ev.getType() === EventType.RoomPowerLevels) {
this.setState({ canSendMessages: this.props.room.maySendMessage() }); this.setState({ canSendMessages: this.props.room.maySendMessage() });
} }
}; };
private getRoomTombstone() { private getRoomTombstone() {
return this.props.room.currentState.getStateEvents('m.room.tombstone', ''); return this.props.room.currentState.getStateEvents(EventType.RoomTombstone, '');
} }
private onTombstoneClick = (ev) => { private onTombstoneClick = (ev) => {

View file

@ -18,7 +18,7 @@ limitations under the License.
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { throttle } from 'lodash'; 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 { CallType } from "matrix-js-sdk/src/webrtc/call";
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
@ -94,7 +94,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
notiStore.removeListener(NotificationStateEvents.Update, this.onNotificationUpdate); 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) { if (!this.props.room || event.getRoomId() !== this.props.room.roomId) {
return; return;
} }

View file

@ -128,7 +128,7 @@ const auxButtonContextMenuPosition = (handle: RefObject<HTMLDivElement>) => {
const DmAuxButton = ({ tabIndex, dispatcher = defaultDispatcher }: IAuxButtonProps) => { const DmAuxButton = ({ tabIndex, dispatcher = defaultDispatcher }: IAuxButtonProps) => {
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>(); 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; return SpaceStore.instance.activeSpaceRoom;
}); });

View file

@ -15,11 +15,12 @@ limitations under the License.
*/ */
import React, { ComponentProps, useContext, useEffect, useState } from "react"; 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 { EventType } from "matrix-js-sdk/src/@types/event";
import { ClientEvent } from "matrix-js-sdk/src/client";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { useEventEmitter, useEventEmitterState } from "../../../hooks/useEventEmitter"; import { useEventEmitterState, useTypedEventEmitter, useTypedEventEmitterState } from "../../../hooks/useEventEmitter";
import SpaceStore from "../../../stores/spaces/SpaceStore"; import SpaceStore from "../../../stores/spaces/SpaceStore";
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu"; import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
import SpaceContextMenu from "../context_menus/SpaceContextMenu"; import SpaceContextMenu from "../context_menus/SpaceContextMenu";
@ -150,7 +151,7 @@ const useJoiningRooms = (): Set<string> => {
break; break;
} }
}); });
useEventEmitter(cli, "Room", (room: Room) => { useTypedEventEmitter(cli, ClientEvent.Room, (room: Room) => {
if (joiningRooms.delete(room.roomId)) { if (joiningRooms.delete(room.roomId)) {
setJoiningRooms(new Set(joiningRooms)); 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 // 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); 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(() => { useEffect(() => {
if (onVisibilityChange) { if (onVisibilityChange) {

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react'; import React from 'react';
import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
import { Room } from 'matrix-js-sdk/src/models/room'; 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 Modal from '../../../Modal';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
@ -56,7 +56,7 @@ export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, I
this.context.removeListener(RoomStateEvent.Events, this.onStateEvents); 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) { if (!this.props.room || event.getRoomId() !== this.props.room.roomId) {
return; return;
} }

View file

@ -19,6 +19,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
@ -82,8 +83,8 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
} }
} }
onRoomStateEvents = (ev) => { onRoomStateEvents = (ev: MatrixEvent) => {
if (ev.getType() === "m.room.third_party_invite" && ev.getStateKey() === this.state.stateKey) { if (ev.getType() === EventType.RoomThirdPartyInvite && ev.getStateKey() === this.state.stateKey) {
const newDisplayName = ev.getContent().display_name; const newDisplayName = ev.getContent().display_name;
const isInvited = isValid3pidInvite(ev); const isInvited = isValid3pidInvite(ev);

View file

@ -18,6 +18,7 @@ import React from 'react';
import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
import { Room } from 'matrix-js-sdk/src/models/room'; import { Room } from 'matrix-js-sdk/src/models/room';
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
@ -96,8 +97,10 @@ export default class ChangeAvatar extends React.Component<IProps, IState> {
return; return;
} }
if (ev.getRoomId() !== this.props.room.roomId || ev.getType() !== 'm.room.avatar' if (ev.getRoomId() !== this.props.room.roomId ||
|| ev.getSender() !== MatrixClientPeg.get().getUserId()) { ev.getType() !== EventType.RoomAvatar ||
ev.getSender() !== MatrixClientPeg.get().getUserId()
) {
return; return;
} }

View file

@ -17,7 +17,6 @@ limitations under the License.
import React from 'react'; import React from 'react';
import { EventType } from "matrix-js-sdk/src/@types/event"; import { EventType } from "matrix-js-sdk/src/@types/event";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; 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 { RoomState, RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { throttle } from "lodash"; import { throttle } from "lodash";
@ -123,17 +122,17 @@ interface IProps {
@replaceableComponent("views.settings.tabs.room.RolesRoomSettingsTab") @replaceableComponent("views.settings.tabs.room.RolesRoomSettingsTab")
export default class RolesRoomSettingsTab extends React.Component<IProps> { export default class RolesRoomSettingsTab extends React.Component<IProps> {
componentDidMount() { componentDidMount() {
MatrixClientPeg.get().on(RoomStateEvent.Members, this.onRoomMembership); MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate);
} }
componentWillUnmount() { componentWillUnmount() {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
if (client) { 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; if (state.roomId !== this.props.roomId) return;
this.onThisRoomMembership(); this.onThisRoomMembership();
}; };

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { Room } from "matrix-js-sdk"; import { Room } from "matrix-js-sdk/src/models/room";
import { Action } from "../actions"; import { Action } from "../actions";
import { ActionPayload } from "../payloads"; import { ActionPayload } from "../payloads";

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { MatrixError } from "matrix-js-sdk"; import { MatrixError } from "matrix-js-sdk/src/http-api";
import { ActionPayload } from "../payloads"; import { ActionPayload } from "../payloads";
import { Action } from "../actions"; import { Action } from "../actions";

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. 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 { ActionPayload } from "../payloads";
import { Action } from "../actions"; import { Action } from "../actions";

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { User } from "matrix-js-sdk"; import { User } from "matrix-js-sdk/src/models/user";
import { ActionPayload } from "../payloads"; import { ActionPayload } from "../payloads";
import { Action } from "../actions"; import { Action } from "../actions";

View file

@ -15,11 +15,11 @@ limitations under the License.
*/ */
import { useCallback, useState } from "react"; 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 { 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; 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; if (event.getType() !== eventType) return;
setValue(event.getContent()); setValue(event.getContent());
}, [eventType]); }, [eventType]);
useEventEmitter(cli, "accountData", handler); useTypedEventEmitter(cli, ClientEvent.AccountData, handler);
return value || {} as T; return value || {} as T;
}; };
@ -44,7 +44,7 @@ export const useRoomAccountData = <T extends {}>(room: Room, eventType: string)
if (event.getType() !== eventType) return; if (event.getType() !== eventType) return;
setValue(event.getContent()); setValue(event.getContent());
}, [eventType]); }, [eventType]);
useEventEmitter(room, "Room.accountData", handler); useTypedEventEmitter(room, RoomEvent.AccountData, handler);
return value || {} as T; return value || {} as T;
}; };

View file

@ -15,17 +15,29 @@ limitations under the License.
*/ */
import { useRef, useEffect, useState, useCallback } from "react"; import { useRef, useEffect, useState, useCallback } from "react";
import { ListenerMap, TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter";
import type { EventEmitter } from "events"; import type { EventEmitter } from "events";
type Handler = (...args: any[]) => void; 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 // Hook to wrap event emitter on and removeListener in hook lifecycle
export const useEventEmitter = ( export function useEventEmitter(
emitter: EventEmitter | undefined, emitter: EventEmitter | undefined,
eventName: string | symbol, eventName: string | symbol,
handler: Handler, handler: Handler,
) => { ): void {
// Create a ref that stores handler // Create a ref that stores handler
const savedHandler = useRef(handler); const savedHandler = useRef(handler);
@ -52,15 +64,27 @@ export const useEventEmitter = (
}, },
[eventName, emitter], // Re-run if eventName or emitter changes [eventName, emitter], // Re-run if eventName or emitter changes
); );
}; }
type Mapper<T> = (...args: any[]) => T; 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, emitter: EventEmitter | undefined,
eventName: string | symbol, eventName: string | symbol,
fn: Mapper<T>, fn: Mapper<T>,
): T => { ): T {
const [value, setValue] = useState<T>(fn()); const [value, setValue] = useState<T>(fn());
const handler = useCallback((...args: any[]) => { const handler = useCallback((...args: any[]) => {
setValue(fn(...args)); setValue(fn(...args));
@ -69,4 +93,4 @@ export const useEventEmitterState = <T>(
useEffect(handler, [emitter]); // eslint-disable-line react-hooks/exhaustive-deps useEffect(handler, [emitter]); // eslint-disable-line react-hooks/exhaustive-deps
useEventEmitter(emitter, eventName, handler); useEventEmitter(emitter, eventName, handler);
return value; return value;
}; }

View file

@ -18,19 +18,21 @@ import { useCallback, useState } from "react";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { MatrixClient } from "matrix-js-sdk/src/client";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk/src/models/room"; 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 // 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 { export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | undefined {
const [isEncrypted, setIsEncrypted] = useState(room ? cli.isRoomEncrypted(room.roomId) : undefined); const [isEncrypted, setIsEncrypted] = useState(room ? cli.isRoomEncrypted(room.roomId) : undefined);
const update = useCallback((event: MatrixEvent) => { const update = useCallback((event: MatrixEvent) => {
if (room && event.getType() === "m.room.encryption") { if (room && event.getType() === EventType.RoomEncryption) {
setIsEncrypted(cli.isRoomEncrypted(room.roomId)); setIsEncrypted(cli.isRoomEncrypted(room.roomId));
} }
}, [cli, room]); }, [cli, room]);
useEventEmitter(room ? room.currentState : undefined, "RoomState.events", update); useTypedEventEmitter(room?.currentState, RoomStateEvent.Events, update);
return isEncrypted; return isEncrypted;
} }

View file

@ -17,14 +17,15 @@ limitations under the License.
import { useState } from "react"; import { useState } from "react";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; 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 { throttle } from "lodash";
import { useEventEmitter } from "./useEventEmitter"; import { useTypedEventEmitter } from "./useEventEmitter";
// Hook to simplify watching Matrix Room joined members // Hook to simplify watching Matrix Room joined members
export const useRoomMembers = (room: Room, throttleWait = 250) => { export const useRoomMembers = (room: Room, throttleWait = 250) => {
const [members, setMembers] = useState<RoomMember[]>(room.getJoinedMembers()); const [members, setMembers] = useState<RoomMember[]>(room.getJoinedMembers());
useEventEmitter(room.currentState, "RoomState.members", throttle(() => { useTypedEventEmitter(room.currentState, RoomStateEvent.Update, throttle(() => {
setMembers(room.getJoinedMembers()); setMembers(room.getJoinedMembers());
}, throttleWait, { leading: true, trailing: true })); }, throttleWait, { leading: true, trailing: true }));
return members; return members;
@ -33,7 +34,7 @@ export const useRoomMembers = (room: Room, throttleWait = 250) => {
// Hook to simplify watching Matrix Room joined member count // Hook to simplify watching Matrix Room joined member count
export const useRoomMemberCount = (room: Room, throttleWait = 250) => { export const useRoomMemberCount = (room: Room, throttleWait = 250) => {
const [count, setCount] = useState<number>(room.getJoinedMemberCount()); const [count, setCount] = useState<number>(room.getJoinedMemberCount());
useEventEmitter(room.currentState, "RoomState.members", throttle(() => { useTypedEventEmitter(room.currentState, RoomStateEvent.Update, throttle(() => {
setCount(room.getJoinedMemberCount()); setCount(room.getJoinedMemberCount());
}, throttleWait, { leading: true, trailing: true })); }, throttleWait, { leading: true, trailing: true }));
return count; return count;

View file

@ -16,9 +16,9 @@ limitations under the License.
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { Room } from "matrix-js-sdk/src/models/room"; 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; type Mapper<T> = (roomState: RoomState) => T;
const defaultMapper: Mapper<RoomState> = (roomState: RoomState) => roomState; const defaultMapper: Mapper<RoomState> = (roomState: RoomState) => roomState;
@ -36,7 +36,7 @@ export const useRoomState = <T extends any = RoomState>(
setValue(mapper(room.currentState)); setValue(mapper(room.currentState));
}, [room, mapper]); }, [room, mapper]);
useEventEmitter(room?.currentState, "RoomState.events", update); useTypedEventEmitter(room?.currentState, RoomStateEvent.Update, update);
useEffect(() => { useEffect(() => {
update(); update();
return () => { return () => {

View file

@ -15,11 +15,11 @@ limitations under the License.
*/ */
import { MatrixClient } from "matrix-js-sdk/src/client"; 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 { useContext } from "react";
import MatrixClientContext from "../contexts/MatrixClientContext"; import MatrixClientContext from "../contexts/MatrixClientContext";
import { useEventEmitterState } from "./useEventEmitter"; import { useTypedEventEmitterState } from "./useEventEmitter";
import { Member } from "../components/views/right_panel/UserInfo"; import { Member } from "../components/views/right_panel/UserInfo";
import { useFeatureEnabled } from "./useSettings"; import { useFeatureEnabled } from "./useSettings";
@ -29,10 +29,11 @@ const getStatusMessage = (cli: MatrixClient, user: Member): string => {
}; };
// Hook to simplify handling Matrix User status // Hook to simplify handling Matrix User status
export const useUserStatusMessage = (user?: Member): string => { export const useUserStatusMessage = (member?: Member): string => {
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const enabled = useFeatureEnabled("feature_custom_status"); 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); return getStatusMessage(cli, user);
}); });
}; };

View file

@ -18,6 +18,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { User, UserEvent } from "matrix-js-sdk/src/models/user"; import { User, UserEvent } from "matrix-js-sdk/src/models/user";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { throttle } from "lodash"; import { throttle } from "lodash";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { ActionPayload } from "../dispatcher/payloads"; import { ActionPayload } from "../dispatcher/payloads";
import { AsyncStoreWithClient } from "./AsyncStoreWithClient"; 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.DisplayName, this.onProfileUpdate);
this.monitoredUser.removeListener(UserEvent.AvatarUrl, 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({}); await this.reset({});
} }
@ -127,7 +126,7 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
// we don't actually do anything here // 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 // 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). // could easily be wrong (such as per-room instead of global profile).
const profileInfo = await this.matrixClient.getProfileInfo(this.matrixClient.getUserId()); const profileInfo = await this.matrixClient.getProfileInfo(this.matrixClient.getUserId());
@ -147,12 +146,12 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
avatarUrl: profileInfo.avatar_url, avatarUrl: profileInfo.avatar_url,
fetchedAt: Date.now(), fetchedAt: Date.now(),
}); });
}; }, 200, { trailing: true, leading: true });
private onStateEvents = throttle(async (ev: MatrixEvent) => { private onStateEvents = async (ev: MatrixEvent) => {
const myUserId = MatrixClientPeg.get().getUserId(); 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(); await this.onProfileUpdate();
} }
}, 200, { trailing: true, leading: true }); };
} }

View file

@ -205,8 +205,8 @@ export default class WidgetUtils {
return; return;
} }
function onRoomStateEvents(ev) { function onRoomStateEvents(ev: MatrixEvent) {
if (ev.getRoomId() !== roomId) return; 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) // 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'); const currentWidgetEvents = room.currentState.getStateEvents('im.vector.modular.widgets');