Unified room context menus (#7072)

This commit is contained in:
Michael Telatynski 2021-11-15 11:39:25 +00:00 committed by GitHub
parent 720b092844
commit 27c3153947
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 660 additions and 133 deletions

View file

@ -40,6 +40,7 @@ export const ContextMenuTooltipButton: React.FC<IProps> = ({
onContextMenu={onContextMenu || onClick}
aria-haspopup={true}
aria-expanded={isExpanded}
forceHide={isExpanded}
>
{ children }
</AccessibleTooltipButton>

View file

@ -1486,10 +1486,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
});
};
private onSettingsClick = () => {
dis.dispatch({ action: "open_room_settings" });
};
private onAppsClick = () => {
dis.dispatch({
action: "appsDrawer",
@ -2111,7 +2107,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
oobData={this.props.oobData}
inRoom={myMembership === 'join'}
onSearchClick={this.onSearchClick}
onSettingsClick={this.onSettingsClick}
onForgetClick={(myMembership === "leave") ? this.onForgetClick : null}
e2eStatus={this.state.e2eStatus}
onAppsClick={this.state.hasPinnedWidgets ? this.onAppsClick : null}

View file

@ -0,0 +1,308 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { useContext } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import { logger } from "matrix-js-sdk/src/logger";
import { IProps as IContextMenuProps } from "../../structures/ContextMenu";
import IconizedContextMenu, {
IconizedContextMenuCheckbox,
IconizedContextMenuOption,
IconizedContextMenuOptionList,
} from "./IconizedContextMenu";
import { _t } from "../../../languageHandler";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { ButtonEvent } from "../elements/AccessibleButton";
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
import RoomListStore from "../../../stores/room-list/RoomListStore";
import dis from "../../../dispatcher/dispatcher";
import RoomListActions from "../../../actions/RoomListActions";
import { Key } from "../../../Keyboard";
import { EchoChamber } from "../../../stores/local-echo/EchoChamber";
import { RoomNotifState } from "../../../RoomNotifs";
import Modal from "../../../Modal";
import ExportDialog from "../dialogs/ExportDialog";
import { onRoomFilesClick, onRoomMembersClick } from "../right_panel/RoomSummaryCard";
import RoomViewStore from "../../../stores/RoomViewStore";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
import { Action } from "../../../dispatcher/actions";
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
import { ROOM_NOTIFICATIONS_TAB } from "../dialogs/RoomSettingsDialog";
interface IProps extends IContextMenuProps {
room: Room;
}
const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
const cli = useContext(MatrixClientContext);
const roomTags = RoomListStore.instance.getTagsForRoom(room);
let leaveOption: JSX.Element;
if (roomTags.includes(DefaultTagID.Archived)) {
const onForgetRoomClick = (ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
dis.dispatch({
action: "forget_room",
room_id: room.roomId,
});
onFinished();
};
leaveOption = <IconizedContextMenuOption
iconClassName="mx_RoomTile_iconSignOut"
label={_t("Forget")}
className="mx_IconizedContextMenu_option_red"
onClick={onForgetRoomClick}
/>;
} else {
const onLeaveRoomClick = (ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
dis.dispatch({
action: "leave_room",
room_id: room.roomId,
});
onFinished();
};
leaveOption = <IconizedContextMenuOption
onClick={onLeaveRoomClick}
label={_t("Leave")}
className="mx_IconizedContextMenu_option_red"
iconClassName="mx_RoomTile_iconSignOut"
/>;
}
let inviteOption: JSX.Element;
if (room.canInvite(cli.getUserId())) {
const onInviteClick = (ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
dis.dispatch({
action: "view_invite",
roomId: room.roomId,
});
onFinished();
};
inviteOption = <IconizedContextMenuOption
onClick={onInviteClick}
label={_t("Invite")}
iconClassName="mx_RoomTile_iconInvite"
/>;
}
let favouriteOption: JSX.Element;
let lowPriorityOption: JSX.Element;
let notificationOption: JSX.Element;
if (room.getMyMembership() === "join") {
const isFavorite = roomTags.includes(DefaultTagID.Favourite);
favouriteOption = <IconizedContextMenuCheckbox
onClick={(e) => onTagRoom(e, DefaultTagID.Favourite)}
active={isFavorite}
label={isFavorite ? _t("Favourited") : _t("Favourite")}
iconClassName="mx_RoomTile_iconStar"
/>;
const isLowPriority = roomTags.includes(DefaultTagID.LowPriority);
lowPriorityOption = <IconizedContextMenuCheckbox
onClick={(e) => onTagRoom(e, DefaultTagID.LowPriority)}
active={isLowPriority}
label={_t("Low priority")}
iconClassName="mx_RoomTile_iconArrowDown"
/>;
const echoChamber = EchoChamber.forRoom(room);
let notificationLabel: string;
let iconClassName: string;
switch (echoChamber.notificationVolume) {
case RoomNotifState.AllMessages:
notificationLabel = _t("Default");
iconClassName = "mx_RoomTile_iconNotificationsDefault";
break;
case RoomNotifState.AllMessagesLoud:
notificationLabel = _t("All messages");
iconClassName = "mx_RoomTile_iconNotificationsAllMessages";
break;
case RoomNotifState.MentionsOnly:
notificationLabel = _t("Mentions only");
iconClassName = "mx_RoomTile_iconNotificationsMentionsKeywords";
break;
case RoomNotifState.Mute:
notificationLabel = _t("Mute");
iconClassName = "mx_RoomTile_iconNotificationsNone";
break;
}
notificationOption = <IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
dis.dispatch({
action: "open_room_settings",
room_id: room.roomId,
initial_tab_id: ROOM_NOTIFICATIONS_TAB,
});
onFinished();
}}
label={_t("Notifications")}
iconClassName={iconClassName}
>
<span className="mx_IconizedContextMenu_sublabel">
{ notificationLabel }
</span>
</IconizedContextMenuOption>;
}
const onTagRoom = (ev: ButtonEvent, tagId: TagID) => {
ev.preventDefault();
ev.stopPropagation();
if (tagId === DefaultTagID.Favourite || tagId === DefaultTagID.LowPriority) {
const inverseTag = tagId === DefaultTagID.Favourite ? DefaultTagID.LowPriority : DefaultTagID.Favourite;
const isApplied = RoomListStore.instance.getTagsForRoom(room).includes(tagId);
const removeTag = isApplied ? tagId : inverseTag;
const addTag = isApplied ? null : tagId;
dis.dispatch(RoomListActions.tagRoom(cli, room, removeTag, addTag, undefined, 0));
} else {
logger.warn(`Unexpected tag ${tagId} applied to ${room.roomId}`);
}
if ((ev as React.KeyboardEvent).key === Key.ENTER) {
// Implements https://www.w3.org/TR/wai-aria-practices/#keyboard-interaction-12
onFinished();
}
};
const ensureViewingRoom = () => {
if (RoomViewStore.getRoomId() === room.roomId) return;
dis.dispatch({
action: "view_room",
room_id: room.roomId,
}, true);
};
return <IconizedContextMenu {...props} onFinished={onFinished} className="mx_RoomTile_contextMenu" compact>
<IconizedContextMenuOptionList>
{ inviteOption }
{ notificationOption }
{ favouriteOption }
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
ensureViewingRoom();
onRoomMembersClick(false);
onFinished();
}}
label={_t("People")}
iconClassName="mx_RoomTile_iconPeople"
>
<span className="mx_IconizedContextMenu_sublabel">
{ room.getJoinedMemberCount() }
</span>
</IconizedContextMenuOption>
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
ensureViewingRoom();
onRoomFilesClick(false);
onFinished();
}}
label={_t("Files")}
iconClassName="mx_RoomTile_iconFiles"
/>
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
ensureViewingRoom();
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
action: Action.SetRightPanelPhase,
phase: RightPanelPhases.RoomSummary,
allowClose: false,
});
onFinished();
}}
label={_t("Widgets")}
iconClassName="mx_RoomTile_iconWidgets"
/>
{ lowPriorityOption }
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
dis.dispatch({
action: "copy_room",
room_id: room.roomId,
});
onFinished();
}}
label={_t("Copy link")}
iconClassName="mx_RoomTile_iconCopyLink"
/>
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
dis.dispatch({
action: "open_room_settings",
room_id: room.roomId,
});
onFinished();
}}
label={_t("Settings")}
iconClassName="mx_RoomTile_iconSettings"
/>
<IconizedContextMenuOption
onClick={(ev: ButtonEvent) => {
ev.preventDefault();
ev.stopPropagation();
Modal.createTrackedDialog('Export room dialog', '', ExportDialog, { room });
onFinished();
}}
label={_t("Export chat")}
iconClassName="mx_RoomTile_iconExport"
/>
{ leaveOption }
</IconizedContextMenuOptionList>
</IconizedContextMenu>;
};
export default RoomContextMenu;

View file

@ -113,7 +113,7 @@ export default class RoomSettingsDialog extends React.Component<IProps, IState>
ROOM_NOTIFICATIONS_TAB,
_td("Notifications"),
"mx_RoomSettingsDialog_notificationsIcon",
<NotificationSettingsTab roomId={this.props.roomId} />,
<NotificationSettingsTab roomId={this.props.roomId} closeSettingsFn={() => this.props.onFinished(true)} />,
));
if (SettingsStore.getValue("feature_bridge_state")) {

View file

@ -207,17 +207,19 @@ const AppsSection: React.FC<IAppsSectionProps> = ({ room }) => {
</Group>;
};
const onRoomMembersClick = () => {
export const onRoomMembersClick = (allowClose = true) => {
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
action: Action.SetRightPanelPhase,
phase: RightPanelPhases.RoomMemberList,
allowClose,
});
};
const onRoomFilesClick = () => {
export const onRoomFilesClick = (allowClose = true) => {
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
action: Action.SetRightPanelPhase,
phase: RightPanelPhases.FilePanel,
allowClose,
});
};
@ -275,10 +277,13 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, onClose }) => {
return <BaseCard header={header} className="mx_RoomSummaryCard" onClose={onClose}>
<Group title={_t("About")} className="mx_RoomSummaryCard_aboutGroup">
<Button className="mx_RoomSummaryCard_icon_people" onClick={onRoomMembersClick}>
{ _t("%(count)s people", { count: memberCount }) }
{ _t("People") }
<span className="mx_BaseCard_Button_sublabel">
{ memberCount }
</span>
</Button>
<Button className="mx_RoomSummaryCard_icon_files" onClick={onRoomFilesClick}>
{ _t("Show files") }
{ _t("Files") }
</Button>
<Button className="mx_RoomSummaryCard_icon_export" onClick={onRoomExportClick}>
{ _t("Export chat") }

View file

@ -36,6 +36,9 @@ import { MatrixEvent, Room, RoomState } from 'matrix-js-sdk/src';
import { E2EStatus } from '../../../utils/ShieldUtils';
import { IOOBData } from '../../../stores/ThreepidInviteStore';
import { SearchScope } from './SearchBar';
import { ContextMenuTooltipButton } from '../../structures/ContextMenu';
import RoomContextMenu from "../context_menus/RoomContextMenu";
import { contextMenuBelow } from './RoomTile';
export interface ISearchInfo {
searchTerm: string;
@ -47,7 +50,6 @@ interface IProps {
room: Room;
oobData?: IOOBData;
inRoom: boolean;
onSettingsClick: () => void;
onSearchClick: () => void;
onForgetClick: () => void;
onCallPlaced: (type: PlaceCallType) => void;
@ -57,13 +59,23 @@ interface IProps {
searchInfo: ISearchInfo;
}
interface IState {
contextMenuPosition?: DOMRect;
}
@replaceableComponent("views.rooms.RoomHeader")
export default class RoomHeader extends React.Component<IProps> {
export default class RoomHeader extends React.Component<IProps, IState> {
static defaultProps = {
editing: false,
inRoom: false,
};
constructor(props, context) {
super(props, context);
this.state = {};
}
public componentDidMount() {
const cli = MatrixClientPeg.get();
cli.on("RoomState.events", this.onRoomStateEvents);
@ -97,6 +109,17 @@ export default class RoomHeader extends React.Component<IProps> {
});
}
private onContextMenuOpenClick = (ev: React.MouseEvent) => {
ev.preventDefault();
ev.stopPropagation();
const target = ev.target as HTMLButtonElement;
this.setState({ contextMenuPosition: target.getBoundingClientRect() });
};
private onContextMenuCloseClick = () => {
this.setState({ contextMenuPosition: null });
};
public render() {
let searchStatus = null;
@ -127,17 +150,35 @@ export default class RoomHeader extends React.Component<IProps> {
oobName = this.props.oobData.name;
}
let contextMenu: JSX.Element;
if (this.state.contextMenuPosition && this.props.room) {
contextMenu = (
<RoomContextMenu
{...contextMenuBelow(this.state.contextMenuPosition)}
room={this.props.room}
onFinished={this.onContextMenuCloseClick}
/>
);
}
const textClasses = classNames('mx_RoomHeader_nametext', { mx_RoomHeader_settingsHint: settingsHint });
const name =
<div className="mx_RoomHeader_name" onClick={this.props.onSettingsClick}>
const name = (
<ContextMenuTooltipButton
className="mx_RoomHeader_name"
onClick={this.onContextMenuOpenClick}
isExpanded={!!this.state.contextMenuPosition}
title={_t("Room options")}
>
<RoomName room={this.props.room}>
{ (name) => {
const roomName = name || oobName;
return <div dir="auto" className={textClasses} title={roomName}>{ roomName }</div>;
} }
</RoomName>
{ searchStatus }
</div>;
{ this.props.room && <div className="mx_RoomHeader_chevron" /> }
{ contextMenu }
</ContextMenuTooltipButton>
);
const topicElement = <RoomTopic room={this.props.room}>
{ (topic, ref) => <div className="mx_RoomHeader_topic" ref={ref} title={topic} dir="auto">
@ -149,7 +190,7 @@ export default class RoomHeader extends React.Component<IProps> {
if (this.props.room) {
roomAvatar = <DecoratedRoomAvatar
room={this.props.room}
avatarSize={32}
avatarSize={24}
oobData={this.props.oobData}
viewAvatarOnClick={true}
/>;
@ -219,6 +260,7 @@ export default class RoomHeader extends React.Component<IProps> {
<div className="mx_RoomHeader_avatar">{ roomAvatar }</div>
<div className="mx_RoomHeader_e2eIcon">{ e2eIcon }</div>
{ name }
{ searchStatus }
{ topicElement }
{ rightRow }
<RoomHeaderButtons room={this.props.room} />

View file

@ -70,7 +70,7 @@ interface IState {
const messagePreviewId = (roomId: string) => `mx_RoomTile_messagePreview_${roomId}`;
const contextMenuBelow = (elementRect: PartialDOMRect) => {
export const contextMenuBelow = (elementRect: PartialDOMRect) => {
// align the context menu's icons with the icon which opened the context menu
const left = elementRect.left + window.pageXOffset - 9;
const top = elementRect.bottom + window.pageYOffset + 17;
@ -189,7 +189,6 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
defaultDispatcher.unregister(this.dispatcherRef);
this.notificationState.off(NOTIFICATION_STATE_UPDATE, this.onNotificationUpdate);
this.roomProps.off(PROPERTY_UPDATED, this.onRoomPropertyUpdate);
this.roomProps.off("Room.name", this.onRoomNameUpdate);
CommunityPrototypeStore.instance.off(
CommunityPrototypeStore.getUpdateEventName(this.props.room.roomId),
this.onCommunityUpdate,

View file

@ -1,5 +1,5 @@
/*
Copyright 2019 New Vector Ltd
Copyright 2019 - 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -24,9 +24,18 @@ import { SettingLevel } from "../../../../../settings/SettingLevel";
import { replaceableComponent } from "../../../../../utils/replaceableComponent";
import { logger } from "matrix-js-sdk/src/logger";
import { RoomEchoChamber } from "../../../../../stores/local-echo/RoomEchoChamber";
import { EchoChamber } from '../../../../../stores/local-echo/EchoChamber';
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
import StyledRadioGroup from "../../../elements/StyledRadioGroup";
import { RoomNotifState } from '../../../../../RoomNotifs';
import defaultDispatcher from "../../../../../dispatcher/dispatcher";
import { Action } from "../../../../../dispatcher/actions";
import { UserTab } from "../../../dialogs/UserSettingsDialog";
interface IProps {
roomId: string;
closeSettingsFn(): void;
}
interface IState {
@ -36,10 +45,16 @@ interface IState {
@replaceableComponent("views.settings.tabs.room.NotificationsSettingsTab")
export default class NotificationsSettingsTab extends React.Component<IProps, IState> {
private readonly roomProps: RoomEchoChamber;
private soundUpload = createRef<HTMLInputElement>();
constructor(props: IProps) {
super(props);
static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
super(props, context);
this.roomProps = EchoChamber.forRoom(context.getRoom(this.props.roomId));
this.state = {
currentSound: "default",
@ -144,6 +159,19 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
});
};
private onRoomNotificationChange = (value: RoomNotifState) => {
this.roomProps.notificationVolume = value;
this.forceUpdate();
};
private onOpenSettingsClick = () => {
this.props.closeSettingsFn();
defaultDispatcher.dispatch({
action: Action.ViewUserSettings,
initialTabId: UserTab.Notifications,
});
};
public render(): JSX.Element {
let currentUploadedFile = null;
if (this.state.uploadedFile) {
@ -157,6 +185,63 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
return (
<div className="mx_SettingsTab">
<div className="mx_SettingsTab_heading">{ _t("Notifications") }</div>
<div className="mx_SettingsTab_section mx_NotificationSettingsTab_notificationsSection">
<StyledRadioGroup
name="roomNotificationSetting"
definitions={[
{
value: RoomNotifState.AllMessages,
className: "mx_NotificationSettingsTab_defaultEntry",
label: <>
{ _t("Default") }
<div className="mx_NotificationSettingsTab_microCopy">
{ _t("Get notifications as set up in your <a>settings</a>", {}, {
a: sub => <AccessibleButton kind="link" onClick={this.onOpenSettingsClick}>
{ sub }
</AccessibleButton>,
}) }
</div>
</>,
}, {
value: RoomNotifState.AllMessagesLoud,
className: "mx_NotificationSettingsTab_allMessagesEntry",
label: <>
{ _t("All messages") }
<div className="mx_NotificationSettingsTab_microCopy">
{ _t("Get notified for every message") }
</div>
</>,
}, {
value: RoomNotifState.MentionsOnly,
className: "mx_NotificationSettingsTab_mentionsKeywordsEntry",
label: <>
{ _t("@mentions & keywords") }
<div className="mx_NotificationSettingsTab_microCopy">
{ _t("Get notified only with mentions and keywords " +
"as set up in your <a>settings</a>", {}, {
a: sub => <AccessibleButton kind="link" onClick={this.onOpenSettingsClick}>
{ sub }
</AccessibleButton>,
}) }
</div>
</>,
}, {
value: RoomNotifState.Mute,
className: "mx_NotificationSettingsTab_noneEntry",
label: <>
{ _t("Off") }
<div className="mx_NotificationSettingsTab_microCopy">
{ _t("You won't get any notifications") }
</div>
</>,
},
]}
onChange={this.onRoomNotificationChange}
value={this.roomProps.notificationVolume}
/>
</div>
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
<span className='mx_SettingsTab_subheading'>{ _t("Sounds") }</span>
<div>

View file

@ -1470,6 +1470,12 @@
"URL Previews": "URL Previews",
"Room Addresses": "Room Addresses",
"Uploaded sound": "Uploaded sound",
"Get notifications as set up in your <a>settings</a>": "Get notifications as set up in your <a>settings</a>",
"All messages": "All messages",
"Get notified for every message": "Get notified for every message",
"@mentions & keywords": "@mentions & keywords",
"Get notified only with mentions and keywords as set up in your <a>settings</a>": "Get notified only with mentions and keywords as set up in your <a>settings</a>",
"You won't get any notifications": "You won't get any notifications",
"Sounds": "Sounds",
"Notification sound": "Notification sound",
"Set a new custom sound": "Set a new custom sound",
@ -1680,6 +1686,7 @@
"(~%(count)s results)|other": "(~%(count)s results)",
"(~%(count)s results)|one": "(~%(count)s result)",
"Join Room": "Join Room",
"Room options": "Room options",
"Forget room": "Forget room",
"Hide Widgets": "Hide Widgets",
"Show Widgets": "Show Widgets",
@ -1761,7 +1768,6 @@
"Show %(count)s more|one": "Show %(count)s more",
"Show less": "Show less",
"Use default": "Use default",
"All messages": "All messages",
"Mentions & Keywords": "Mentions & Keywords",
"Notification options": "Notification options",
"Forget Room": "Forget Room",
@ -1772,7 +1778,6 @@
"Copy Room Link": "Copy Room Link",
"Settings": "Settings",
"Leave Room": "Leave Room",
"Room options": "Room options",
"%(count)s unread messages including mentions.|other": "%(count)s unread messages including mentions.",
"%(count)s unread messages including mentions.|one": "1 unread mention.",
"%(count)s unread messages.|other": "%(count)s unread messages.",
@ -1873,9 +1878,7 @@
"Add widgets, bridges & bots": "Add widgets, bridges & bots",
"Not encrypted": "Not encrypted",
"About": "About",
"%(count)s people|other": "%(count)s people",
"%(count)s people|one": "%(count)s person",
"Show files": "Show files",
"Files": "Files",
"Export chat": "Export chat",
"Share room": "Share room",
"Room settings": "Room settings",
@ -2738,6 +2741,10 @@
"Collapse reply thread": "Collapse reply thread",
"Report": "Report",
"View in room": "View in room",
"Forget": "Forget",
"Leave": "Leave",
"Mentions only": "Mentions only",
"Copy link": "Copy link",
"See room timeline (devtools)": "See room timeline (devtools)",
"Add space": "Add space",
"Manage & explore rooms": "Manage & explore rooms",
@ -2845,7 +2852,6 @@
"You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.",
"Leave Community": "Leave Community",
"Leave %(groupName)s?": "Leave %(groupName)s?",
"Leave": "Leave",
"Unable to leave community": "Unable to leave community",
"Community Settings": "Community Settings",
"Want more than a community? <a>Get your own server</a>": "Want more than a community? <a>Get your own server</a>",

View file

@ -19,6 +19,7 @@ import { getRoomNotifsState, RoomNotifState, setRoomNotifsState } from "../../Ro
import { RoomEchoContext } from "./RoomEchoContext";
import { _t } from "../../languageHandler";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType } from "matrix-js-sdk/src/@types/event";
export enum CachedRoomKey {
NotificationVolume,
@ -46,7 +47,7 @@ export class RoomEchoChamber extends GenericEchoChamber<RoomEchoContext, CachedR
}
private onAccountData = (event: MatrixEvent) => {
if (event.getType() === "m.push_rules") {
if (event.getType() === EventType.PushRules) {
const currentVolume = this.properties.get(CachedRoomKey.NotificationVolume) as RoomNotifState;
const newVolume = getRoomNotifsState(this.context.room.roomId) as RoomNotifState;
if (currentVolume !== newVolume) {