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

@ -266,6 +266,7 @@
@import "./views/settings/_UpdateCheckButton.scss"; @import "./views/settings/_UpdateCheckButton.scss";
@import "./views/settings/tabs/_SettingsTab.scss"; @import "./views/settings/tabs/_SettingsTab.scss";
@import "./views/settings/tabs/room/_GeneralRoomSettingsTab.scss"; @import "./views/settings/tabs/room/_GeneralRoomSettingsTab.scss";
@import "./views/settings/tabs/room/_NotificationSettingsTab.scss";
@import "./views/settings/tabs/room/_RolesRoomSettingsTab.scss"; @import "./views/settings/tabs/room/_RolesRoomSettingsTab.scss";
@import "./views/settings/tabs/room/_SecurityRoomSettingsTab.scss"; @import "./views/settings/tabs/room/_SecurityRoomSettingsTab.scss";
@import "./views/settings/tabs/user/_AppearanceUserSettingsTab.scss"; @import "./views/settings/tabs/user/_AppearanceUserSettingsTab.scss";

View file

@ -17,6 +17,7 @@ limitations under the License.
// A context menu that largely fits the | [icon] [label] | format. // A context menu that largely fits the | [icon] [label] | format.
.mx_IconizedContextMenu { .mx_IconizedContextMenu {
min-width: 146px; min-width: 146px;
width: max-content;
.mx_IconizedContextMenu_optionList { .mx_IconizedContextMenu_optionList {
& > * { & > * {
@ -119,7 +120,7 @@ limitations under the License.
mask-position: center; mask-position: center;
mask-size: contain; mask-size: contain;
mask-repeat: no-repeat; mask-repeat: no-repeat;
background: $primary-content; background-color: $secondary-content;
} }
} }
@ -133,6 +134,14 @@ limitations under the License.
} }
} }
.mx_IconizedContextMenu_option_red {
color: $alert !important;
.mx_IconizedContextMenu_icon::before {
background-color: $alert;
}
}
.mx_IconizedContextMenu_active { .mx_IconizedContextMenu_active {
&.mx_AccessibleButton, .mx_AccessibleButton { &.mx_AccessibleButton, .mx_AccessibleButton {
color: $accent !important; color: $accent !important;
@ -162,4 +171,9 @@ limitations under the License.
.mx_IconizedContextMenu_unchecked::before { .mx_IconizedContextMenu_unchecked::before {
content: unset; content: unset;
} }
.mx_IconizedContextMenu_sublabel {
margin-left: 20px;
color: $tertiary-content;
}
} }

View file

@ -99,7 +99,7 @@ limitations under the License.
} }
.mx_BaseCard_Button { .mx_BaseCard_Button {
padding: 10px 38px 10px 12px; padding: 10px 32px 10px 12px;
margin: 0; margin: 0;
position: relative; position: relative;
font-size: $font-13px; font-size: $font-13px;
@ -109,6 +109,12 @@ limitations under the License.
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
display: flex;
.mx_BaseCard_Button_sublabel {
color: $tertiary-content;
margin-left: auto;
}
&:hover { &:hover {
background-color: rgba(141, 151, 165, 0.1); background-color: rgba(141, 151, 165, 0.1);

View file

@ -33,12 +33,13 @@ limitations under the License.
} }
.mx_RoomHeader_wrapper { .mx_RoomHeader_wrapper {
margin: auto; height: 44px;
height: 50px;
display: flex; display: flex;
align-items: center; align-items: center;
min-width: 0; min-width: 0;
padding: 0 10px 0 18px; margin: 0 20px 0 16px;
padding-top: 8px;
border-bottom: 1px solid $system;
.mx_InviteOnlyIcon_large { .mx_InviteOnlyIcon_large {
margin: 0; margin: 0;
@ -85,40 +86,65 @@ limitations under the License.
.mx_RoomHeader_simpleHeader { .mx_RoomHeader_simpleHeader {
line-height: $font-52px; line-height: $font-52px;
color: $roomheader-color; color: $primary-content;
font-size: $font-18px; font-size: $font-18px;
font-weight: 600; font-weight: $font-semi-bold;
overflow: hidden; overflow: hidden;
margin-left: 63px; margin-left: 63px;
text-overflow: ellipsis; text-overflow: ellipsis;
width: 100%; width: 100%;
}
.mx_RoomHeader_simpleHeader .mx_RoomHeader_cancelButton { .mx_RoomHeader_cancelButton {
float: right; float: right;
} }
.mx_RoomHeader_simpleHeader .mx_RoomHeader_icon { .mx_RoomHeader_icon {
margin-left: 14px; margin-left: 14px;
margin-right: 24px; margin-right: 24px;
vertical-align: -4px; vertical-align: -4px;
}
} }
.mx_RoomHeader_name { .mx_RoomHeader_name {
flex: 0 1 auto; flex: 0 1 auto;
overflow: hidden; overflow: hidden;
color: $roomheader-color; color: $primary-content;
font-weight: 600; font-weight: $font-semi-bold;
font-size: $font-18px; font-size: $font-18px;
border-radius: 6px;
margin: 0 7px; margin: 0 7px;
border-bottom: 1px solid transparent; padding: 1px 4px;
display: flex; display: flex;
} user-select: none;
.mx_RoomHeader_nametext { &:hover {
background-color: $quinary-content;
}
.mx_RoomHeader_nametext {
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
}
.mx_RoomHeader_chevron {
align-self: center;
width: 16px;
height: 16px;
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
background-color: $tertiary-content;
}
&[aria-expanded=true] {
background-color: $quinary-content;
.mx_RoomHeader_chevron {
transform: rotate(180deg);
}
}
} }
.mx_RoomHeader_settingsHint { .mx_RoomHeader_settingsHint {
@ -131,46 +157,17 @@ limitations under the License.
} }
.mx_RoomHeader_name, .mx_RoomHeader_name,
.mx_RoomHeader_avatar, .mx_RoomHeader_avatar {
.mx_RoomHeader_avatarPicker,
.mx_RoomHeader_avatarPicker_edit,
.mx_RoomHeader_avatarPicker_remove {
cursor: pointer; cursor: pointer;
} }
.mx_RoomHeader_avatarPicker_remove {
position: absolute;
top: -11px;
right: -9px;
}
.mx_RoomHeader_name:hover div:not(.mx_RoomHeader_editable) {
color: $accent;
}
.mx_RoomHeader_placeholder {
color: $settings-grey-fg-color !important;
}
.mx_RoomHeader_editable {
border-bottom: 1px solid $strong-input-border-color !important;
min-width: 150px;
cursor: text;
}
.mx_RoomHeader_editable:focus {
border-bottom: 1px solid $accent !important;
outline: none;
box-shadow: none;
}
.mx_RoomHeader_topic { .mx_RoomHeader_topic {
flex: 1; flex: 1;
color: $roomtopic-color; color: $roomtopic-color;
font-weight: 400; font-weight: 400;
font-size: $font-13px; font-size: $font-13px;
margin: 0 7px; // to align baseline of topic with room name
margin-top: 4px; // to align baseline of topic with room name margin: 4px 7px 0;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
border-bottom: 1px solid transparent; border-bottom: 1px solid transparent;
@ -188,24 +185,6 @@ limitations under the License.
object-fit: cover; object-fit: cover;
} }
.mx_RoomHeader_avatarPicker {
position: relative;
}
.mx_RoomHeader_avatarPicker_edit {
position: absolute;
left: 16px;
top: 18px;
}
.mx_RoomHeader_avatarPicker_edit > label {
cursor: pointer;
}
.mx_RoomHeader_avatarPicker_edit > input {
display: none;
}
.mx_RoomHeader_button { .mx_RoomHeader_button {
position: relative; position: relative;
margin-left: 1px; margin-left: 1px;
@ -265,21 +244,10 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/call/video-call.svg'); mask-image: url('$(res)/img/element-icons/call/video-call.svg');
} }
.mx_RoomHeader_showPanel {
height: 16px;
}
.mx_RoomHeader_voipButton {
display: table-cell;
}
.mx_RoomHeader_voipButtons {
margin-top: 18px;
}
@media only screen and (max-width: 480px) { @media only screen and (max-width: 480px) {
.mx_RoomHeader_wrapper { .mx_RoomHeader_wrapper {
padding: 0; padding: 0;
margin: 0;
} }
.mx_RoomHeader { .mx_RoomHeader {
overflow: hidden; overflow: hidden;

View file

@ -189,10 +189,42 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/roomlist/low-priority.svg'); mask-image: url('$(res)/img/element-icons/roomlist/low-priority.svg');
} }
.mx_RoomTile_iconNotificationsDefault::before {
mask-image: url('$(res)/img/element-icons/notifications.svg');
}
.mx_RoomTile_iconNotificationsAllMessages::before {
mask-image: url('$(res)/img/element-icons/roomlist/notifications-default.svg');
}
.mx_RoomTile_iconNotificationsMentionsKeywords::before {
mask-image: url('$(res)/img/element-icons/roomlist/notifications-dm.svg');
}
.mx_RoomTile_iconNotificationsNone::before {
mask-image: url('$(res)/img/element-icons/roomlist/notifications-off.svg');
}
.mx_RoomTile_iconPeople::before {
mask-image: url('$(res)/img/element-icons/room/members.svg');
}
.mx_RoomTile_iconFiles::before {
mask-image: url('$(res)/img/element-icons/room/files.svg');
}
.mx_RoomTile_iconWidgets::before {
mask-image: url('$(res)/img/element-icons/room/apps.svg');
}
.mx_RoomTile_iconSettings::before { .mx_RoomTile_iconSettings::before {
mask-image: url('$(res)/img/element-icons/settings.svg'); mask-image: url('$(res)/img/element-icons/settings.svg');
} }
.mx_RoomTile_iconExport::before {
mask-image: url('$(res)/img/element-icons/export.svg');
}
.mx_RoomTile_iconCopyLink::before { .mx_RoomTile_iconCopyLink::before {
mask-image: url('$(res)/img/element-icons/link.svg'); mask-image: url('$(res)/img/element-icons/link.svg');
} }

View file

@ -0,0 +1,76 @@
/*
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.
*/
.mx_NotificationSettingsTab_notificationsSection {
width: 360px;
.mx_StyledRadioButton {
flex-direction: row-reverse;
color: $primary-content;
font-size: $font-15px;
line-height: $font-18px;
font-weight: $font-semi-bold;
margin-top: 16px;
position: relative;
padding-left: 8px;
align-items: center;
&::before {
content: "";
position: absolute;
height: 24px;
width: 24px;
left: 0;
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
background-color: $secondary-content;
}
input + div {
margin-top: 8px;
}
.mx_NotificationSettingsTab_microCopy {
color: $secondary-content;
font-weight: normal;
font-size: $font-12px;
line-height: $font-15px;
margin-right: 32px;
.mx_AccessibleButton_kind_link {
padding: 0;
font-size: inherit;
}
}
}
.mx_NotificationSettingsTab_defaultEntry::before {
mask-image: url('$(res)/img/element-icons/notifications.svg');
}
.mx_NotificationSettingsTab_allMessagesEntry::before {
mask-image: url('$(res)/img/element-icons/roomlist/notifications-default.svg');
}
.mx_NotificationSettingsTab_mentionsKeywordsEntry::before {
mask-image: url('$(res)/img/element-icons/roomlist/notifications-dm.svg');
}
.mx_NotificationSettingsTab_noneEntry::before {
mask-image: url('$(res)/img/element-icons/roomlist/notifications-off.svg');
}
}

View file

@ -1,14 +1,8 @@
<svg <svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
width="24" <mask id="hole">
height="24" <rect width="100%" height="100%" fill="white"/>
viewBox="0 0 24 24" <circle cx="13" cy="11" r="5" fill="black"/>
fill="none" </mask>
xmlns="http://www.w3.org/2000/svg" <path fill-rule="evenodd" clip-rule="evenodd" d="M8.20757 14.9221C12.1427 14.9221 15.3327 11.7309 15.3327 7.79434C15.3327 3.85781 12.1427 0.666626 8.20757 0.666626C4.27246 0.666626 1.08243 3.85781 1.08243 7.79434C1.08243 8.89706 1.33275 9.9413 1.77965 10.8733L0.90483 13.7175C0.644577 14.5636 1.43951 15.3549 2.28444 15.0908L5.10044 14.2104C6.03948 14.6664 7.09367 14.9221 8.20757 14.9221Z" fill="#737D8C" mask="url(#hole)"/>
> <path fill-rule="evenodd" clip-rule="evenodd" d="M13.6 8.19998C13.6 7.8686 13.3314 7.59998 13 7.59998C12.6686 7.59998 12.4 7.8686 12.4 8.19998L12.4 12.3514L10.8243 10.7757C10.59 10.5414 10.2101 10.5414 9.97574 10.7757C9.74142 11.01 9.74142 11.3899 9.97574 11.6242L12.5757 14.2242C12.8101 14.4585 13.19 14.4585 13.4243 14.2242L16.0243 11.6242C16.2586 11.3899 16.2586 11.01 16.0243 10.7757C15.79 10.5414 15.4101 10.5414 15.1757 10.7757L13.6 12.3514L13.6 8.19998Z" fill="#7C7C7C"/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47716 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM12.7071 17.7071C12.6112 17.803 12.5007 17.8753 12.3828 17.9241L11.2929 17.7071L11.2925 17.7067L7.2929 13.7071C6.90237 13.3166 6.90237 12.6834 7.2929 12.2929C7.68342 11.9024 8.31658 11.9024 8.70711 12.2929L11 14.5858L11 7C11 6.44771 11.4477 6 12 6C12.5523 6 13 6.44771 13 7L13 14.5858L15.2929 12.2929C15.6834 11.9024 16.3166 11.9024 16.7071 12.2929C17.0976 12.6834 17.0976 13.3166 16.7071 13.7071L12.7071 17.7071ZM12.3828 17.9241L11.295 17.7092C11.4758 17.8889 11.7249 18 12 18C12.1356 18 12.2649 17.973 12.3828 17.9241Z"
fill="#C1C6CD"
/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 821 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -43,7 +43,6 @@ $panel-gradient: rgba(34, 38, 46, 0), rgba(34, 38, 46, 1);
$event-selected-color: $system; $event-selected-color: $system;
$progressbar-bg-color: $system; $progressbar-bg-color: $system;
$topleftmenu-color: $primary-content; $topleftmenu-color: $primary-content;
$roomheader-color: $primary-content;
$roomheader-addroom-fg-color: $primary-content; $roomheader-addroom-fg-color: $primary-content;
$h3-color: $primary-content; $h3-color: $primary-content;
$focus-bg-color: $room-highlight-color; $focus-bg-color: $room-highlight-color;

View file

@ -84,7 +84,6 @@ $settings-profile-button-bg-color: #e7e7e7;
$settings-subsection-fg-color: $text-secondary-color; $settings-subsection-fg-color: $text-secondary-color;
$topleftmenu-color: $text-primary-color; $topleftmenu-color: $text-primary-color;
$roomheader-color: $text-primary-color;
$roomheader-addroom-bg-color: #3c4556; $roomheader-addroom-bg-color: #3c4556;
$roomheader-addroom-fg-color: $text-primary-color; $roomheader-addroom-fg-color: $text-primary-color;
$groupFilterPanel-button-color: $header-panel-text-primary-color; $groupFilterPanel-button-color: $header-panel-text-primary-color;

View file

@ -125,7 +125,6 @@ $rte-room-pill-color: #aaa;
$rte-group-pill-color: #aaa; $rte-group-pill-color: #aaa;
$topleftmenu-color: #212121; $topleftmenu-color: #212121;
$roomheader-color: #45474a;
$roomheader-bg-color: $primary-bg-color; $roomheader-bg-color: $primary-bg-color;
$roomheader-addroom-bg-color: #91a1c0; $roomheader-addroom-bg-color: #91a1c0;
$roomheader-addroom-fg-color: $accent-fg-color; $roomheader-addroom-fg-color: $accent-fg-color;

View file

@ -83,7 +83,6 @@ $dialog-title-fg-color: var(--timeline-text-color);
$tab-label-fg-color: var(--timeline-text-color); $tab-label-fg-color: var(--timeline-text-color);
// was #4e5054 // was #4e5054
$authpage-lang-color: var(--timeline-text-color); $authpage-lang-color: var(--timeline-text-color);
$roomheader-color: var(--timeline-text-color);
// was #232f32 // was #232f32
$authpage-primary-color: var(--timeline-text-color); $authpage-primary-color: var(--timeline-text-color);
// --roomlist-text-secondary-color // --roomlist-text-secondary-color

View file

@ -124,7 +124,6 @@ $settings-subsection-fg-color: #61708b;
// RoomHeader // RoomHeader
// ******************** // ********************
$roomheader-color: #45474a;
$roomheader-addroom-bg-color: rgba(92, 100, 112, 0.2); $roomheader-addroom-bg-color: rgba(92, 100, 112, 0.2);
$roomheader-addroom-fg-color: #5c6470; $roomheader-addroom-fg-color: #5c6470;
// ******************** // ********************

View file

@ -40,6 +40,7 @@ export const ContextMenuTooltipButton: React.FC<IProps> = ({
onContextMenu={onContextMenu || onClick} onContextMenu={onContextMenu || onClick}
aria-haspopup={true} aria-haspopup={true}
aria-expanded={isExpanded} aria-expanded={isExpanded}
forceHide={isExpanded}
> >
{ children } { children }
</AccessibleTooltipButton> </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 = () => { private onAppsClick = () => {
dis.dispatch({ dis.dispatch({
action: "appsDrawer", action: "appsDrawer",
@ -2111,7 +2107,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
oobData={this.props.oobData} oobData={this.props.oobData}
inRoom={myMembership === 'join'} inRoom={myMembership === 'join'}
onSearchClick={this.onSearchClick} onSearchClick={this.onSearchClick}
onSettingsClick={this.onSettingsClick}
onForgetClick={(myMembership === "leave") ? this.onForgetClick : null} onForgetClick={(myMembership === "leave") ? this.onForgetClick : null}
e2eStatus={this.state.e2eStatus} e2eStatus={this.state.e2eStatus}
onAppsClick={this.state.hasPinnedWidgets ? this.onAppsClick : null} 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, ROOM_NOTIFICATIONS_TAB,
_td("Notifications"), _td("Notifications"),
"mx_RoomSettingsDialog_notificationsIcon", "mx_RoomSettingsDialog_notificationsIcon",
<NotificationSettingsTab roomId={this.props.roomId} />, <NotificationSettingsTab roomId={this.props.roomId} closeSettingsFn={() => this.props.onFinished(true)} />,
)); ));
if (SettingsStore.getValue("feature_bridge_state")) { if (SettingsStore.getValue("feature_bridge_state")) {

View file

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

View file

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

View file

@ -70,7 +70,7 @@ interface IState {
const messagePreviewId = (roomId: string) => `mx_RoomTile_messagePreview_${roomId}`; 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 // align the context menu's icons with the icon which opened the context menu
const left = elementRect.left + window.pageXOffset - 9; const left = elementRect.left + window.pageXOffset - 9;
const top = elementRect.bottom + window.pageYOffset + 17; const top = elementRect.bottom + window.pageYOffset + 17;
@ -189,7 +189,6 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
defaultDispatcher.unregister(this.dispatcherRef); defaultDispatcher.unregister(this.dispatcherRef);
this.notificationState.off(NOTIFICATION_STATE_UPDATE, this.onNotificationUpdate); this.notificationState.off(NOTIFICATION_STATE_UPDATE, this.onNotificationUpdate);
this.roomProps.off(PROPERTY_UPDATED, this.onRoomPropertyUpdate); this.roomProps.off(PROPERTY_UPDATED, this.onRoomPropertyUpdate);
this.roomProps.off("Room.name", this.onRoomNameUpdate);
CommunityPrototypeStore.instance.off( CommunityPrototypeStore.instance.off(
CommunityPrototypeStore.getUpdateEventName(this.props.room.roomId), CommunityPrototypeStore.getUpdateEventName(this.props.room.roomId),
this.onCommunityUpdate, 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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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 { replaceableComponent } from "../../../../../utils/replaceableComponent";
import { logger } from "matrix-js-sdk/src/logger"; 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 { interface IProps {
roomId: string; roomId: string;
closeSettingsFn(): void;
} }
interface IState { interface IState {
@ -36,10 +45,16 @@ interface IState {
@replaceableComponent("views.settings.tabs.room.NotificationsSettingsTab") @replaceableComponent("views.settings.tabs.room.NotificationsSettingsTab")
export default class NotificationsSettingsTab extends React.Component<IProps, IState> { export default class NotificationsSettingsTab extends React.Component<IProps, IState> {
private readonly roomProps: RoomEchoChamber;
private soundUpload = createRef<HTMLInputElement>(); private soundUpload = createRef<HTMLInputElement>();
constructor(props: IProps) { static contextType = MatrixClientContext;
super(props); 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 = { this.state = {
currentSound: "default", 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 { public render(): JSX.Element {
let currentUploadedFile = null; let currentUploadedFile = null;
if (this.state.uploadedFile) { if (this.state.uploadedFile) {
@ -157,6 +185,63 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
return ( return (
<div className="mx_SettingsTab"> <div className="mx_SettingsTab">
<div className="mx_SettingsTab_heading">{ _t("Notifications") }</div> <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'> <div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
<span className='mx_SettingsTab_subheading'>{ _t("Sounds") }</span> <span className='mx_SettingsTab_subheading'>{ _t("Sounds") }</span>
<div> <div>

View file

@ -1470,6 +1470,12 @@
"URL Previews": "URL Previews", "URL Previews": "URL Previews",
"Room Addresses": "Room Addresses", "Room Addresses": "Room Addresses",
"Uploaded sound": "Uploaded sound", "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", "Sounds": "Sounds",
"Notification sound": "Notification sound", "Notification sound": "Notification sound",
"Set a new custom sound": "Set a new custom 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)|other": "(~%(count)s results)",
"(~%(count)s results)|one": "(~%(count)s result)", "(~%(count)s results)|one": "(~%(count)s result)",
"Join Room": "Join Room", "Join Room": "Join Room",
"Room options": "Room options",
"Forget room": "Forget room", "Forget room": "Forget room",
"Hide Widgets": "Hide Widgets", "Hide Widgets": "Hide Widgets",
"Show Widgets": "Show Widgets", "Show Widgets": "Show Widgets",
@ -1761,7 +1768,6 @@
"Show %(count)s more|one": "Show %(count)s more", "Show %(count)s more|one": "Show %(count)s more",
"Show less": "Show less", "Show less": "Show less",
"Use default": "Use default", "Use default": "Use default",
"All messages": "All messages",
"Mentions & Keywords": "Mentions & Keywords", "Mentions & Keywords": "Mentions & Keywords",
"Notification options": "Notification options", "Notification options": "Notification options",
"Forget Room": "Forget Room", "Forget Room": "Forget Room",
@ -1772,7 +1778,6 @@
"Copy Room Link": "Copy Room Link", "Copy Room Link": "Copy Room Link",
"Settings": "Settings", "Settings": "Settings",
"Leave Room": "Leave Room", "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.|other": "%(count)s unread messages including mentions.",
"%(count)s unread messages including mentions.|one": "1 unread mention.", "%(count)s unread messages including mentions.|one": "1 unread mention.",
"%(count)s unread messages.|other": "%(count)s unread messages.", "%(count)s unread messages.|other": "%(count)s unread messages.",
@ -1873,9 +1878,7 @@
"Add widgets, bridges & bots": "Add widgets, bridges & bots", "Add widgets, bridges & bots": "Add widgets, bridges & bots",
"Not encrypted": "Not encrypted", "Not encrypted": "Not encrypted",
"About": "About", "About": "About",
"%(count)s people|other": "%(count)s people", "Files": "Files",
"%(count)s people|one": "%(count)s person",
"Show files": "Show files",
"Export chat": "Export chat", "Export chat": "Export chat",
"Share room": "Share room", "Share room": "Share room",
"Room settings": "Room settings", "Room settings": "Room settings",
@ -2738,6 +2741,10 @@
"Collapse reply thread": "Collapse reply thread", "Collapse reply thread": "Collapse reply thread",
"Report": "Report", "Report": "Report",
"View in room": "View in room", "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)", "See room timeline (devtools)": "See room timeline (devtools)",
"Add space": "Add space", "Add space": "Add space",
"Manage & explore rooms": "Manage & explore rooms", "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.", "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 Community": "Leave Community",
"Leave %(groupName)s?": "Leave %(groupName)s?", "Leave %(groupName)s?": "Leave %(groupName)s?",
"Leave": "Leave",
"Unable to leave community": "Unable to leave community", "Unable to leave community": "Unable to leave community",
"Community Settings": "Community Settings", "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>", "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 { RoomEchoContext } from "./RoomEchoContext";
import { _t } from "../../languageHandler"; import { _t } from "../../languageHandler";
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";
export enum CachedRoomKey { export enum CachedRoomKey {
NotificationVolume, NotificationVolume,
@ -46,7 +47,7 @@ export class RoomEchoChamber extends GenericEchoChamber<RoomEchoContext, CachedR
} }
private onAccountData = (event: MatrixEvent) => { 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 currentVolume = this.properties.get(CachedRoomKey.NotificationVolume) as RoomNotifState;
const newVolume = getRoomNotifsState(this.context.room.roomId) as RoomNotifState; const newVolume = getRoomNotifsState(this.context.room.roomId) as RoomNotifState;
if (currentVolume !== newVolume) { if (currentVolume !== newVolume) {

View file

@ -159,7 +159,6 @@ function render(room: Room): HTMLDivElement {
<RoomHeader <RoomHeader
room={room} room={room}
inRoom={true} inRoom={true}
onSettingsClick={() => {}}
onSearchClick={() => {}} onSearchClick={() => {}}
onForgetClick={() => {}} onForgetClick={() => {}}
onCallPlaced={(_type: PlaceCallType) => {}} onCallPlaced={(_type: PlaceCallType) => {}}