2020-05-08 20:53:05 +02:00
|
|
|
/*
|
|
|
|
Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
|
2021-04-22 00:36:06 +02:00
|
|
|
Copyright 2015-2017, 2019-2021 The Matrix.org Foundation C.I.C.
|
2020-05-08 20:53:05 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2020-07-30 00:54:04 +02:00
|
|
|
import React, { createRef } from "react";
|
2022-02-22 13:18:08 +01:00
|
|
|
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
|
2020-05-08 20:53:05 +02:00
|
|
|
import classNames from "classnames";
|
2021-10-23 00:23:32 +02:00
|
|
|
import { logger } from "matrix-js-sdk/src/logger";
|
2022-03-28 15:12:09 +02:00
|
|
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
|
|
|
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
2021-10-23 00:23:32 +02:00
|
|
|
|
2020-05-08 20:53:05 +02:00
|
|
|
import { RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex";
|
2020-06-16 22:43:48 +02:00
|
|
|
import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton";
|
2020-05-14 21:45:17 +02:00
|
|
|
import dis from '../../../dispatcher/dispatcher';
|
2020-07-30 00:54:04 +02:00
|
|
|
import defaultDispatcher from '../../../dispatcher/dispatcher';
|
2021-11-25 21:49:43 +01:00
|
|
|
import { Action } from "../../../dispatcher/actions";
|
2022-03-22 23:14:11 +01:00
|
|
|
import SettingsStore from "../../../settings/SettingsStore";
|
2020-06-10 07:09:15 +02:00
|
|
|
import { _t } from "../../../languageHandler";
|
2020-08-25 03:19:28 +02:00
|
|
|
import { ChevronFace, ContextMenuTooltipButton } from "../../structures/ContextMenu";
|
2020-06-10 07:09:15 +02:00
|
|
|
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
|
2021-01-15 14:54:38 +01:00
|
|
|
import { MessagePreviewStore } from "../../../stores/room-list/MessagePreviewStore";
|
2020-07-01 00:24:46 +02:00
|
|
|
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
|
2021-09-27 14:32:04 +02:00
|
|
|
import { RoomNotifState } from "../../../RoomNotifs";
|
2020-06-30 23:53:30 +02:00
|
|
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
2020-06-30 21:34:44 +02:00
|
|
|
import NotificationBadge from "./NotificationBadge";
|
2020-07-17 23:11:34 +02:00
|
|
|
import RoomListStore from "../../../stores/room-list/RoomListStore";
|
2020-07-08 00:14:04 +02:00
|
|
|
import RoomListActions from "../../../actions/RoomListActions";
|
2020-07-30 00:54:04 +02:00
|
|
|
import { ActionPayload } from "../../../dispatcher/payloads";
|
2020-07-09 03:26:25 +02:00
|
|
|
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
|
2021-12-07 13:51:34 +01:00
|
|
|
import { NotificationState, NotificationStateEvents } from "../../../stores/notifications/NotificationState";
|
2020-07-17 19:16:00 +02:00
|
|
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
2020-07-30 00:54:04 +02:00
|
|
|
import { EchoChamber } from "../../../stores/local-echo/EchoChamber";
|
2020-07-30 17:15:19 +02:00
|
|
|
import { CachedRoomKey, RoomEchoChamber } from "../../../stores/local-echo/RoomEchoChamber";
|
|
|
|
import { PROPERTY_UPDATED } from "../../../stores/local-echo/GenericEchoChamber";
|
2020-08-04 22:42:39 +02:00
|
|
|
import IconizedContextMenu, {
|
|
|
|
IconizedContextMenuCheckbox,
|
|
|
|
IconizedContextMenuOption,
|
2020-08-25 03:19:28 +02:00
|
|
|
IconizedContextMenuOptionList,
|
2020-08-29 02:11:08 +02:00
|
|
|
IconizedContextMenuRadio,
|
2020-08-04 22:42:39 +02:00
|
|
|
} from "../context_menus/IconizedContextMenu";
|
2022-04-01 16:36:10 +02:00
|
|
|
import VideoChannelStore, { VideoChannelEvent, IJitsiParticipant } from "../../../stores/VideoChannelStore";
|
|
|
|
import { getConnectedMembers } from "../../../utils/VideoChannelUtils";
|
2022-02-09 15:42:08 +01:00
|
|
|
import PosthogTrackers from "../../../PosthogTrackers";
|
2022-02-10 15:29:55 +01:00
|
|
|
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
2022-02-28 17:05:52 +01:00
|
|
|
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
|
|
|
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
2022-03-23 06:29:02 +01:00
|
|
|
import { RoomViewStore } from "../../../stores/RoomViewStore";
|
2020-05-08 20:53:05 +02:00
|
|
|
|
2022-04-01 16:36:10 +02:00
|
|
|
enum VideoStatus {
|
2022-03-22 23:14:11 +01:00
|
|
|
Disconnected,
|
|
|
|
Connected,
|
|
|
|
}
|
|
|
|
|
2020-05-08 20:53:05 +02:00
|
|
|
interface IProps {
|
|
|
|
room: Room;
|
2020-06-05 05:21:04 +02:00
|
|
|
showMessagePreview: boolean;
|
2020-06-11 22:39:28 +02:00
|
|
|
isMinimized: boolean;
|
2020-06-16 20:13:12 +02:00
|
|
|
tag: TagID;
|
2020-05-08 20:53:05 +02:00
|
|
|
}
|
|
|
|
|
2020-07-02 00:06:26 +02:00
|
|
|
type PartialDOMRect = Pick<DOMRect, "left" | "bottom">;
|
|
|
|
|
2020-05-23 02:05:09 +02:00
|
|
|
interface IState {
|
2020-06-05 22:08:20 +02:00
|
|
|
selected: boolean;
|
2020-07-02 00:06:26 +02:00
|
|
|
notificationsMenuPosition: PartialDOMRect;
|
|
|
|
generalMenuPosition: PartialDOMRect;
|
2020-07-24 21:09:26 +02:00
|
|
|
messagePreview?: string;
|
2022-04-01 16:36:10 +02:00
|
|
|
videoStatus: VideoStatus;
|
|
|
|
// Active video channel members, according to room state
|
|
|
|
videoMembers: RoomMember[];
|
|
|
|
// Active video channel members, according to Jitsi
|
2022-03-28 15:12:09 +02:00
|
|
|
jitsiParticipants: IJitsiParticipant[];
|
2020-05-08 20:53:05 +02:00
|
|
|
}
|
|
|
|
|
2020-07-17 23:43:29 +02:00
|
|
|
const messagePreviewId = (roomId: string) => `mx_RoomTile_messagePreview_${roomId}`;
|
2020-07-05 20:38:45 +02:00
|
|
|
|
2021-11-15 12:39:25 +01:00
|
|
|
export const contextMenuBelow = (elementRect: PartialDOMRect) => {
|
2020-07-01 15:05:33 +02:00
|
|
|
// align the context menu's icons with the icon which opened the context menu
|
|
|
|
const left = elementRect.left + window.pageXOffset - 9;
|
2020-07-02 00:09:02 +02:00
|
|
|
const top = elementRect.bottom + window.pageYOffset + 17;
|
2020-07-02 00:56:57 +02:00
|
|
|
const chevronFace = ChevronFace.None;
|
2021-06-29 14:11:58 +02:00
|
|
|
return { left, top, chevronFace };
|
2020-06-30 00:02:10 +02:00
|
|
|
};
|
|
|
|
|
2020-07-24 21:58:21 +02:00
|
|
|
export default class RoomTile extends React.PureComponent<IProps, IState> {
|
2020-07-07 11:34:42 +02:00
|
|
|
private dispatcherRef: string;
|
|
|
|
private roomTileRef = createRef<HTMLDivElement>();
|
2020-07-27 15:39:30 +02:00
|
|
|
private notificationState: NotificationState;
|
2020-07-30 17:15:19 +02:00
|
|
|
private roomProps: RoomEchoChamber;
|
2022-04-01 16:36:10 +02:00
|
|
|
private isVideoRoom: boolean;
|
2020-05-08 20:53:05 +02:00
|
|
|
|
2020-05-12 00:20:26 +02:00
|
|
|
constructor(props: IProps) {
|
|
|
|
super(props);
|
|
|
|
|
2022-04-01 16:36:10 +02:00
|
|
|
const videoConnected = VideoChannelStore.instance.roomId === this.props.room.roomId;
|
|
|
|
|
2020-05-12 00:20:26 +02:00
|
|
|
this.state = {
|
2022-03-23 06:29:02 +01:00
|
|
|
selected: RoomViewStore.instance.getRoomId() === this.props.room.roomId,
|
2020-07-02 00:06:26 +02:00
|
|
|
notificationsMenuPosition: null,
|
|
|
|
generalMenuPosition: null,
|
2020-07-24 21:09:26 +02:00
|
|
|
// generatePreview() will return nothing if the user has previews disabled
|
2021-05-19 14:25:52 +02:00
|
|
|
messagePreview: "",
|
2022-04-01 16:36:10 +02:00
|
|
|
videoStatus: videoConnected ? VideoStatus.Connected : VideoStatus.Disconnected,
|
|
|
|
videoMembers: getConnectedMembers(this.props.room.currentState),
|
|
|
|
jitsiParticipants: videoConnected ? VideoChannelStore.instance.participants : [],
|
2020-05-12 05:09:32 +02:00
|
|
|
};
|
2021-05-19 14:25:52 +02:00
|
|
|
this.generatePreview();
|
|
|
|
|
2021-04-15 17:33:49 +02:00
|
|
|
this.notificationState = RoomNotificationStateStore.instance.getRoomState(this.props.room);
|
|
|
|
this.roomProps = EchoChamber.forRoom(this.props.room);
|
2022-04-04 16:29:40 +02:00
|
|
|
this.isVideoRoom = SettingsStore.getValue("feature_video_rooms") && this.props.room.isElementVideoRoom();
|
2021-01-28 21:36:33 +01:00
|
|
|
}
|
|
|
|
|
2021-09-14 15:36:11 +02:00
|
|
|
private onRoomNameUpdate = (room: Room) => {
|
2021-01-28 21:36:33 +01:00
|
|
|
this.forceUpdate();
|
2021-06-29 14:11:58 +02:00
|
|
|
};
|
2020-05-12 05:09:32 +02:00
|
|
|
|
2020-07-27 15:39:30 +02:00
|
|
|
private onNotificationUpdate = () => {
|
|
|
|
this.forceUpdate(); // notification state changed - update
|
|
|
|
};
|
|
|
|
|
2020-07-30 00:54:04 +02:00
|
|
|
private onRoomPropertyUpdate = (property: CachedRoomKey) => {
|
|
|
|
if (property === CachedRoomKey.NotificationVolume) this.onNotificationUpdate();
|
|
|
|
// else ignore - not important for this tile
|
|
|
|
};
|
|
|
|
|
2020-07-02 21:59:28 +02:00
|
|
|
private get showContextMenu(): boolean {
|
2020-08-14 13:01:16 +02:00
|
|
|
return this.props.tag !== DefaultTagID.Invite;
|
2020-07-02 21:59:28 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 20:38:45 +02:00
|
|
|
private get showMessagePreview(): boolean {
|
2021-05-03 18:32:33 +02:00
|
|
|
return !this.props.isMinimized && this.props.showMessagePreview;
|
2020-07-05 20:38:45 +02:00
|
|
|
}
|
|
|
|
|
2020-08-11 04:52:05 +02:00
|
|
|
public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>) {
|
2021-05-24 17:08:48 +02:00
|
|
|
const showMessageChanged = prevProps.showMessagePreview !== this.props.showMessagePreview;
|
|
|
|
const minimizedChanged = prevProps.isMinimized !== this.props.isMinimized;
|
|
|
|
if (showMessageChanged || minimizedChanged) {
|
2021-05-19 14:25:52 +02:00
|
|
|
this.generatePreview();
|
2020-08-11 04:52:05 +02:00
|
|
|
}
|
2021-01-15 14:54:38 +01:00
|
|
|
if (prevProps.room?.roomId !== this.props.room?.roomId) {
|
|
|
|
MessagePreviewStore.instance.off(
|
|
|
|
MessagePreviewStore.getPreviewChangedEventName(prevProps.room),
|
|
|
|
this.onRoomPreviewChanged,
|
|
|
|
);
|
|
|
|
MessagePreviewStore.instance.on(
|
|
|
|
MessagePreviewStore.getPreviewChangedEventName(this.props.room),
|
|
|
|
this.onRoomPreviewChanged,
|
|
|
|
);
|
2022-04-01 16:36:10 +02:00
|
|
|
prevProps.room?.currentState?.off(RoomStateEvent.Events, this.updateVideoMembers);
|
|
|
|
this.props.room?.currentState?.on(RoomStateEvent.Events, this.updateVideoMembers);
|
|
|
|
this.updateVideoStatus();
|
2022-02-22 13:18:08 +01:00
|
|
|
prevProps.room?.off(RoomEvent.Name, this.onRoomNameUpdate);
|
|
|
|
this.props.room?.on(RoomEvent.Name, this.onRoomNameUpdate);
|
2021-01-15 14:54:38 +01:00
|
|
|
}
|
2020-08-11 04:52:05 +02:00
|
|
|
}
|
|
|
|
|
2020-07-07 11:34:42 +02:00
|
|
|
public componentDidMount() {
|
|
|
|
// when we're first rendered (or our sublist is expanded) make sure we are visible if we're active
|
|
|
|
if (this.state.selected) {
|
|
|
|
this.scrollIntoView();
|
|
|
|
}
|
2021-04-15 16:51:00 +02:00
|
|
|
|
2022-03-23 06:29:02 +01:00
|
|
|
RoomViewStore.instance.addRoomListener(this.props.room.roomId, this.onActiveRoomUpdate);
|
2021-04-15 16:51:00 +02:00
|
|
|
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
|
|
|
MessagePreviewStore.instance.on(
|
|
|
|
MessagePreviewStore.getPreviewChangedEventName(this.props.room),
|
|
|
|
this.onRoomPreviewChanged,
|
|
|
|
);
|
2021-12-07 13:51:34 +01:00
|
|
|
this.notificationState.on(NotificationStateEvents.Update, this.onNotificationUpdate);
|
2021-04-15 16:51:00 +02:00
|
|
|
this.roomProps.on(PROPERTY_UPDATED, this.onRoomPropertyUpdate);
|
2022-03-23 06:29:02 +01:00
|
|
|
this.props.room.on(RoomEvent.Name, this.onRoomNameUpdate);
|
2022-04-05 18:50:37 +02:00
|
|
|
this.props.room.currentState.on(RoomStateEvent.Events, this.updateVideoMembers);
|
2022-04-01 16:36:10 +02:00
|
|
|
|
|
|
|
VideoChannelStore.instance.on(VideoChannelEvent.Connect, this.updateVideoStatus);
|
|
|
|
VideoChannelStore.instance.on(VideoChannelEvent.Disconnect, this.updateVideoStatus);
|
|
|
|
if (VideoChannelStore.instance.roomId === this.props.room.roomId) {
|
|
|
|
VideoChannelStore.instance.on(VideoChannelEvent.Participants, this.updateJitsiParticipants);
|
|
|
|
}
|
2020-07-07 11:34:42 +02:00
|
|
|
}
|
|
|
|
|
2020-05-12 05:09:32 +02:00
|
|
|
public componentWillUnmount() {
|
2022-03-23 06:29:02 +01:00
|
|
|
RoomViewStore.instance.removeRoomListener(this.props.room.roomId, this.onActiveRoomUpdate);
|
|
|
|
MessagePreviewStore.instance.off(
|
|
|
|
MessagePreviewStore.getPreviewChangedEventName(this.props.room),
|
|
|
|
this.onRoomPreviewChanged,
|
|
|
|
);
|
|
|
|
this.props.room.off(RoomEvent.Name, this.onRoomNameUpdate);
|
2022-04-05 18:57:16 +02:00
|
|
|
this.props.room.currentState.off(RoomStateEvent.Events, this.updateVideoMembers);
|
2020-07-07 11:34:42 +02:00
|
|
|
defaultDispatcher.unregister(this.dispatcherRef);
|
2021-12-07 13:51:34 +01:00
|
|
|
this.notificationState.off(NotificationStateEvents.Update, this.onNotificationUpdate);
|
2021-04-15 16:51:00 +02:00
|
|
|
this.roomProps.off(PROPERTY_UPDATED, this.onRoomPropertyUpdate);
|
2022-04-01 16:36:10 +02:00
|
|
|
|
|
|
|
VideoChannelStore.instance.off(VideoChannelEvent.Connect, this.updateVideoStatus);
|
|
|
|
VideoChannelStore.instance.off(VideoChannelEvent.Disconnect, this.updateVideoStatus);
|
2020-05-12 00:20:26 +02:00
|
|
|
}
|
|
|
|
|
2020-07-07 11:34:42 +02:00
|
|
|
private onAction = (payload: ActionPayload) => {
|
2022-01-12 21:12:28 +01:00
|
|
|
if (payload.action === Action.ViewRoom &&
|
|
|
|
payload.room_id === this.props.room.roomId &&
|
|
|
|
payload.show_room_tile
|
|
|
|
) {
|
2020-07-07 11:34:42 +02:00
|
|
|
setImmediate(() => {
|
|
|
|
this.scrollIntoView();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-07-24 06:24:07 +02:00
|
|
|
private onRoomPreviewChanged = (room: Room) => {
|
|
|
|
if (this.props.room && room.roomId === this.props.room.roomId) {
|
2021-05-19 14:25:52 +02:00
|
|
|
this.generatePreview();
|
2020-07-24 06:24:07 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-05-19 14:25:52 +02:00
|
|
|
private async generatePreview() {
|
2020-07-24 21:09:26 +02:00
|
|
|
if (!this.showMessagePreview) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2021-05-19 14:25:52 +02:00
|
|
|
const messagePreview = await MessagePreviewStore.instance.getPreviewForRoom(this.props.room, this.props.tag);
|
|
|
|
this.setState({ messagePreview });
|
2020-07-24 21:09:26 +02:00
|
|
|
}
|
|
|
|
|
2020-07-07 11:34:42 +02:00
|
|
|
private scrollIntoView = () => {
|
|
|
|
if (!this.roomTileRef.current) return;
|
|
|
|
this.roomTileRef.current.scrollIntoView({
|
|
|
|
block: "nearest",
|
|
|
|
behavior: "auto",
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2022-03-22 23:14:11 +01:00
|
|
|
private onTileClick = async (ev: React.KeyboardEvent) => {
|
2020-07-02 00:06:26 +02:00
|
|
|
ev.preventDefault();
|
|
|
|
ev.stopPropagation();
|
2022-02-28 17:05:52 +01:00
|
|
|
|
|
|
|
const action = getKeyBindingsManager().getAccessibilityAction(ev);
|
|
|
|
|
2022-02-10 15:29:55 +01:00
|
|
|
dis.dispatch<ViewRoomPayload>({
|
2021-11-25 21:49:43 +01:00
|
|
|
action: Action.ViewRoom,
|
2020-05-12 00:29:32 +02:00
|
|
|
show_room_tile: true, // make sure the room is visible in the list
|
|
|
|
room_id: this.props.room.roomId,
|
2022-02-28 17:05:52 +01:00
|
|
|
clear_search: [KeyBindingAction.Enter, KeyBindingAction.Space].includes(action),
|
2022-02-17 19:03:27 +01:00
|
|
|
metricsTrigger: "RoomList",
|
|
|
|
metricsViaKeyboard: ev.type !== "click",
|
2020-05-12 00:29:32 +02:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2020-06-05 22:08:20 +02:00
|
|
|
private onActiveRoomUpdate = (isActive: boolean) => {
|
2021-06-29 14:11:58 +02:00
|
|
|
this.setState({ selected: isActive });
|
2020-06-05 22:08:20 +02:00
|
|
|
};
|
|
|
|
|
2020-07-02 00:56:57 +02:00
|
|
|
private onNotificationsMenuOpenClick = (ev: React.MouseEvent) => {
|
2020-06-30 01:16:51 +02:00
|
|
|
ev.preventDefault();
|
|
|
|
ev.stopPropagation();
|
2020-07-02 00:06:26 +02:00
|
|
|
const target = ev.target as HTMLButtonElement;
|
2021-06-29 14:11:58 +02:00
|
|
|
this.setState({ notificationsMenuPosition: target.getBoundingClientRect() });
|
2022-02-09 15:42:08 +01:00
|
|
|
|
|
|
|
PosthogTrackers.trackInteraction("WebRoomListRoomTileNotificationsMenu", ev);
|
2020-06-30 01:16:51 +02:00
|
|
|
};
|
|
|
|
|
2020-07-02 00:06:26 +02:00
|
|
|
private onCloseNotificationsMenu = () => {
|
2021-06-29 14:11:58 +02:00
|
|
|
this.setState({ notificationsMenuPosition: null });
|
2020-06-30 01:16:51 +02:00
|
|
|
};
|
|
|
|
|
2020-07-02 00:56:57 +02:00
|
|
|
private onGeneralMenuOpenClick = (ev: React.MouseEvent) => {
|
2020-06-10 07:09:15 +02:00
|
|
|
ev.preventDefault();
|
|
|
|
ev.stopPropagation();
|
2020-07-02 00:06:26 +02:00
|
|
|
const target = ev.target as HTMLButtonElement;
|
2021-06-29 14:11:58 +02:00
|
|
|
this.setState({ generalMenuPosition: target.getBoundingClientRect() });
|
2020-06-10 07:09:15 +02:00
|
|
|
};
|
|
|
|
|
2020-07-02 00:06:26 +02:00
|
|
|
private onContextMenu = (ev: React.MouseEvent) => {
|
2020-07-02 21:59:28 +02:00
|
|
|
// If we don't have a context menu to show, ignore the action.
|
|
|
|
if (!this.showContextMenu) return;
|
|
|
|
|
2020-06-10 07:09:15 +02:00
|
|
|
ev.preventDefault();
|
|
|
|
ev.stopPropagation();
|
2020-07-02 00:06:26 +02:00
|
|
|
this.setState({
|
|
|
|
generalMenuPosition: {
|
|
|
|
left: ev.clientX,
|
|
|
|
bottom: ev.clientY,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
private onCloseGeneralMenu = () => {
|
2021-06-29 14:11:58 +02:00
|
|
|
this.setState({ generalMenuPosition: null });
|
2020-06-10 07:09:15 +02:00
|
|
|
};
|
|
|
|
|
2020-06-10 23:05:29 +02:00
|
|
|
private onTagRoom = (ev: ButtonEvent, tagId: TagID) => {
|
2020-06-10 07:09:15 +02:00
|
|
|
ev.preventDefault();
|
|
|
|
ev.stopPropagation();
|
|
|
|
|
2020-07-21 10:50:20 +02:00
|
|
|
if (tagId === DefaultTagID.Favourite || tagId === DefaultTagID.LowPriority) {
|
|
|
|
const inverseTag = tagId === DefaultTagID.Favourite ? DefaultTagID.LowPriority : DefaultTagID.Favourite;
|
2020-07-21 14:43:42 +02:00
|
|
|
const isApplied = RoomListStore.instance.getTagsForRoom(this.props.room).includes(tagId);
|
|
|
|
const removeTag = isApplied ? tagId : inverseTag;
|
|
|
|
const addTag = isApplied ? null : tagId;
|
2020-07-08 00:14:04 +02:00
|
|
|
dis.dispatch(RoomListActions.tagRoom(
|
|
|
|
MatrixClientPeg.get(),
|
|
|
|
this.props.room,
|
|
|
|
removeTag,
|
|
|
|
addTag,
|
|
|
|
undefined,
|
2020-08-29 02:11:08 +02:00
|
|
|
0,
|
2020-07-08 00:14:04 +02:00
|
|
|
));
|
|
|
|
} else {
|
2021-10-15 16:31:29 +02:00
|
|
|
logger.warn(`Unexpected tag ${tagId} applied to ${this.props.room.roomId}`);
|
2020-07-08 00:14:04 +02:00
|
|
|
}
|
2020-07-06 11:18:49 +02:00
|
|
|
|
2022-02-28 17:05:52 +01:00
|
|
|
const action = getKeyBindingsManager().getAccessibilityAction(ev as React.KeyboardEvent);
|
|
|
|
switch (action) {
|
|
|
|
case KeyBindingAction.Enter:
|
|
|
|
// Implements https://www.w3.org/TR/wai-aria-practices/#keyboard-interaction-12
|
|
|
|
this.setState({ generalMenuPosition: null }); // hide the menu
|
|
|
|
break;
|
2020-07-06 11:18:49 +02:00
|
|
|
}
|
2020-06-10 07:09:15 +02:00
|
|
|
};
|
|
|
|
|
2020-06-10 23:05:29 +02:00
|
|
|
private onLeaveRoomClick = (ev: ButtonEvent) => {
|
2020-06-10 07:09:15 +02:00
|
|
|
ev.preventDefault();
|
|
|
|
ev.stopPropagation();
|
|
|
|
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'leave_room',
|
|
|
|
room_id: this.props.room.roomId,
|
|
|
|
});
|
2021-06-29 14:11:58 +02:00
|
|
|
this.setState({ generalMenuPosition: null }); // hide the menu
|
2022-02-09 15:42:08 +01:00
|
|
|
|
|
|
|
PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuLeaveItem", ev);
|
2020-06-10 07:09:15 +02:00
|
|
|
};
|
|
|
|
|
2020-07-13 17:35:03 +02:00
|
|
|
private onForgetRoomClick = (ev: ButtonEvent) => {
|
|
|
|
ev.preventDefault();
|
|
|
|
ev.stopPropagation();
|
|
|
|
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'forget_room',
|
|
|
|
room_id: this.props.room.roomId,
|
|
|
|
});
|
2021-06-29 14:11:58 +02:00
|
|
|
this.setState({ generalMenuPosition: null }); // hide the menu
|
2020-07-13 17:35:03 +02:00
|
|
|
};
|
|
|
|
|
2020-06-10 23:05:29 +02:00
|
|
|
private onOpenRoomSettings = (ev: ButtonEvent) => {
|
2020-06-10 07:09:15 +02:00
|
|
|
ev.preventDefault();
|
|
|
|
ev.stopPropagation();
|
|
|
|
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'open_room_settings',
|
|
|
|
room_id: this.props.room.roomId,
|
|
|
|
});
|
2021-06-29 14:11:58 +02:00
|
|
|
this.setState({ generalMenuPosition: null }); // hide the menu
|
2022-02-09 15:42:08 +01:00
|
|
|
|
|
|
|
PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuSettingsItem", ev);
|
2020-06-10 07:09:15 +02:00
|
|
|
};
|
|
|
|
|
2021-07-14 15:58:18 +02:00
|
|
|
private onCopyRoomClick = (ev: ButtonEvent) => {
|
|
|
|
ev.preventDefault();
|
|
|
|
ev.stopPropagation();
|
|
|
|
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'copy_room',
|
|
|
|
room_id: this.props.room.roomId,
|
|
|
|
});
|
|
|
|
this.setState({ generalMenuPosition: null }); // hide the menu
|
|
|
|
};
|
|
|
|
|
2021-02-15 14:43:09 +01:00
|
|
|
private onInviteClick = (ev: ButtonEvent) => {
|
|
|
|
ev.preventDefault();
|
|
|
|
ev.stopPropagation();
|
|
|
|
|
|
|
|
dis.dispatch({
|
|
|
|
action: 'view_invite',
|
|
|
|
roomId: this.props.room.roomId,
|
|
|
|
});
|
2021-06-29 14:11:58 +02:00
|
|
|
this.setState({ generalMenuPosition: null }); // hide the menu
|
2022-02-09 15:42:08 +01:00
|
|
|
|
|
|
|
PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuInviteItem", ev);
|
2021-02-15 14:43:09 +01:00
|
|
|
};
|
|
|
|
|
2021-09-27 14:32:04 +02:00
|
|
|
private async saveNotifState(ev: ButtonEvent, newState: RoomNotifState) {
|
2020-06-30 23:53:30 +02:00
|
|
|
ev.preventDefault();
|
|
|
|
ev.stopPropagation();
|
|
|
|
if (MatrixClientPeg.get().isGuest()) return;
|
|
|
|
|
2020-07-30 00:54:04 +02:00
|
|
|
this.roomProps.notificationVolume = newState;
|
2020-06-30 23:53:30 +02:00
|
|
|
|
2022-02-28 17:05:52 +01:00
|
|
|
const action = getKeyBindingsManager().getAccessibilityAction(ev as React.KeyboardEvent);
|
|
|
|
switch (action) {
|
|
|
|
case KeyBindingAction.Enter:
|
|
|
|
// Implements https://www.w3.org/TR/wai-aria-practices/#keyboard-interaction-12
|
|
|
|
this.setState({ notificationsMenuPosition: null }); // hide the menu
|
|
|
|
break;
|
2020-07-06 11:18:49 +02:00
|
|
|
}
|
2020-06-30 23:53:30 +02:00
|
|
|
}
|
|
|
|
|
2021-09-27 14:32:04 +02:00
|
|
|
private onClickAllNotifs = ev => this.saveNotifState(ev, RoomNotifState.AllMessages);
|
|
|
|
private onClickAlertMe = ev => this.saveNotifState(ev, RoomNotifState.AllMessagesLoud);
|
|
|
|
private onClickMentions = ev => this.saveNotifState(ev, RoomNotifState.MentionsOnly);
|
|
|
|
private onClickMute = ev => this.saveNotifState(ev, RoomNotifState.Mute);
|
2020-06-30 23:53:30 +02:00
|
|
|
|
2020-07-02 23:21:10 +02:00
|
|
|
private renderNotificationsMenu(isActive: boolean): React.ReactElement {
|
2020-08-14 13:01:16 +02:00
|
|
|
if (MatrixClientPeg.get().isGuest() || this.props.tag === DefaultTagID.Archived ||
|
|
|
|
!this.showContextMenu || this.props.isMinimized
|
|
|
|
) {
|
2020-07-01 15:28:00 +02:00
|
|
|
// the menu makes no sense in these cases so do not show one
|
|
|
|
return null;
|
|
|
|
}
|
2020-06-30 01:16:51 +02:00
|
|
|
|
2021-04-15 17:33:49 +02:00
|
|
|
const state = this.roomProps.notificationVolume;
|
2020-06-30 23:32:59 +02:00
|
|
|
|
2020-06-30 01:16:51 +02:00
|
|
|
let contextMenu = null;
|
2020-07-02 00:06:26 +02:00
|
|
|
if (this.state.notificationsMenuPosition) {
|
2020-08-04 22:42:39 +02:00
|
|
|
contextMenu = <IconizedContextMenu
|
|
|
|
{...contextMenuBelow(this.state.notificationsMenuPosition)}
|
|
|
|
onFinished={this.onCloseNotificationsMenu}
|
|
|
|
className="mx_RoomTile_contextMenu"
|
|
|
|
compact
|
|
|
|
>
|
|
|
|
<IconizedContextMenuOptionList first>
|
2020-08-04 18:20:17 +02:00
|
|
|
<IconizedContextMenuRadio
|
2021-07-21 21:01:19 +02:00
|
|
|
label={_t("Use default")}
|
2021-09-27 14:32:04 +02:00
|
|
|
active={state === RoomNotifState.AllMessages}
|
2020-08-04 22:42:39 +02:00
|
|
|
iconClassName="mx_RoomTile_iconBell"
|
|
|
|
onClick={this.onClickAllNotifs}
|
|
|
|
/>
|
2020-08-04 18:20:17 +02:00
|
|
|
<IconizedContextMenuRadio
|
2020-08-04 22:42:39 +02:00
|
|
|
label={_t("All messages")}
|
2021-09-27 14:32:04 +02:00
|
|
|
active={state === RoomNotifState.AllMessagesLoud}
|
2020-08-04 22:42:39 +02:00
|
|
|
iconClassName="mx_RoomTile_iconBellDot"
|
|
|
|
onClick={this.onClickAlertMe}
|
|
|
|
/>
|
2020-08-04 18:20:17 +02:00
|
|
|
<IconizedContextMenuRadio
|
2020-08-04 22:42:39 +02:00
|
|
|
label={_t("Mentions & Keywords")}
|
2021-09-27 14:32:04 +02:00
|
|
|
active={state === RoomNotifState.MentionsOnly}
|
2020-08-04 22:42:39 +02:00
|
|
|
iconClassName="mx_RoomTile_iconBellMentions"
|
|
|
|
onClick={this.onClickMentions}
|
|
|
|
/>
|
2020-08-04 18:20:17 +02:00
|
|
|
<IconizedContextMenuRadio
|
2020-08-04 22:42:39 +02:00
|
|
|
label={_t("None")}
|
2021-09-27 14:32:04 +02:00
|
|
|
active={state === RoomNotifState.Mute}
|
2020-08-04 22:42:39 +02:00
|
|
|
iconClassName="mx_RoomTile_iconBellCrossed"
|
|
|
|
onClick={this.onClickMute}
|
|
|
|
/>
|
|
|
|
</IconizedContextMenuOptionList>
|
|
|
|
</IconizedContextMenu>;
|
2020-06-30 01:16:51 +02:00
|
|
|
}
|
|
|
|
|
2020-07-17 23:43:29 +02:00
|
|
|
const classes = classNames("mx_RoomTile_notificationsButton", {
|
2020-06-30 01:16:51 +02:00
|
|
|
// Show bell icon for the default case too.
|
2021-09-27 14:32:04 +02:00
|
|
|
mx_RoomTile_iconBell: state === RoomNotifState.AllMessages,
|
|
|
|
mx_RoomTile_iconBellDot: state === RoomNotifState.AllMessagesLoud,
|
|
|
|
mx_RoomTile_iconBellMentions: state === RoomNotifState.MentionsOnly,
|
|
|
|
mx_RoomTile_iconBellCrossed: state === RoomNotifState.Mute,
|
2020-07-02 21:33:06 +02:00
|
|
|
|
|
|
|
// Only show the icon by default if the room is overridden to muted.
|
|
|
|
// TODO: [FTUE Notifications] Probably need to detect global mute state
|
2021-09-27 14:32:04 +02:00
|
|
|
mx_RoomTile_notificationsButton_show: state === RoomNotifState.Mute,
|
2020-06-30 01:16:51 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
return (
|
|
|
|
<React.Fragment>
|
2020-07-17 19:16:00 +02:00
|
|
|
<ContextMenuTooltipButton
|
2020-06-30 01:16:51 +02:00
|
|
|
className={classes}
|
|
|
|
onClick={this.onNotificationsMenuOpenClick}
|
2020-07-17 19:16:00 +02:00
|
|
|
title={_t("Notification options")}
|
2020-07-02 00:06:26 +02:00
|
|
|
isExpanded={!!this.state.notificationsMenuPosition}
|
2020-07-02 23:21:10 +02:00
|
|
|
tabIndex={isActive ? 0 : -1}
|
2020-06-30 01:16:51 +02:00
|
|
|
/>
|
2021-07-19 23:43:11 +02:00
|
|
|
{ contextMenu }
|
2020-06-30 01:16:51 +02:00
|
|
|
</React.Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-06-10 07:09:15 +02:00
|
|
|
private renderGeneralMenu(): React.ReactElement {
|
2020-07-02 21:59:28 +02:00
|
|
|
if (!this.showContextMenu) return null; // no menu to show
|
2020-06-11 22:39:28 +02:00
|
|
|
|
2020-06-10 07:09:15 +02:00
|
|
|
let contextMenu = null;
|
2020-07-13 17:35:03 +02:00
|
|
|
if (this.state.generalMenuPosition && this.props.tag === DefaultTagID.Archived) {
|
2020-08-04 22:42:39 +02:00
|
|
|
contextMenu = <IconizedContextMenu
|
|
|
|
{...contextMenuBelow(this.state.generalMenuPosition)}
|
|
|
|
onFinished={this.onCloseGeneralMenu}
|
|
|
|
className="mx_RoomTile_contextMenu"
|
|
|
|
compact
|
|
|
|
>
|
|
|
|
<IconizedContextMenuOptionList red>
|
|
|
|
<IconizedContextMenuOption
|
|
|
|
iconClassName="mx_RoomTile_iconSignOut"
|
|
|
|
label={_t("Forget Room")}
|
|
|
|
onClick={this.onForgetRoomClick}
|
|
|
|
/>
|
|
|
|
</IconizedContextMenuOptionList>
|
|
|
|
</IconizedContextMenu>;
|
2020-07-13 17:35:03 +02:00
|
|
|
} else if (this.state.generalMenuPosition) {
|
2020-07-21 10:50:20 +02:00
|
|
|
const roomTags = RoomListStore.instance.getTagsForRoom(this.props.room);
|
|
|
|
|
|
|
|
const isFavorite = roomTags.includes(DefaultTagID.Favourite);
|
|
|
|
const favouriteLabel = isFavorite ? _t("Favourited") : _t("Favourite");
|
|
|
|
|
|
|
|
const isLowPriority = roomTags.includes(DefaultTagID.LowPriority);
|
|
|
|
const lowPriorityLabel = _t("Low Priority");
|
|
|
|
|
2021-12-09 10:28:12 +01:00
|
|
|
const isDm = roomTags.includes(DefaultTagID.DM);
|
|
|
|
|
2021-02-15 16:22:19 +01:00
|
|
|
const userId = MatrixClientPeg.get().getUserId();
|
2021-12-09 10:28:12 +01:00
|
|
|
const canInvite = this.props.room.canInvite(userId) && !isDm; // hide invite in DMs from this quick menu
|
2020-08-04 22:42:39 +02:00
|
|
|
contextMenu = <IconizedContextMenu
|
|
|
|
{...contextMenuBelow(this.state.generalMenuPosition)}
|
|
|
|
onFinished={this.onCloseGeneralMenu}
|
|
|
|
className="mx_RoomTile_contextMenu"
|
|
|
|
compact
|
|
|
|
>
|
|
|
|
<IconizedContextMenuOptionList>
|
|
|
|
<IconizedContextMenuCheckbox
|
2022-02-09 15:42:08 +01:00
|
|
|
onClick={(e) => {
|
|
|
|
this.onTagRoom(e, DefaultTagID.Favourite);
|
|
|
|
PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuFavouriteToggle", e);
|
|
|
|
}}
|
2020-08-04 22:42:39 +02:00
|
|
|
active={isFavorite}
|
|
|
|
label={favouriteLabel}
|
|
|
|
iconClassName="mx_RoomTile_iconStar"
|
|
|
|
/>
|
|
|
|
<IconizedContextMenuCheckbox
|
|
|
|
onClick={(e) => this.onTagRoom(e, DefaultTagID.LowPriority)}
|
|
|
|
active={isLowPriority}
|
|
|
|
label={lowPriorityLabel}
|
|
|
|
iconClassName="mx_RoomTile_iconArrowDown"
|
|
|
|
/>
|
2021-07-19 23:43:11 +02:00
|
|
|
{ canInvite ? (
|
2021-02-15 16:22:19 +01:00
|
|
|
<IconizedContextMenuOption
|
|
|
|
onClick={this.onInviteClick}
|
2021-12-15 10:56:15 +01:00
|
|
|
label={_t("Invite")}
|
2021-02-15 16:22:19 +01:00
|
|
|
iconClassName="mx_RoomTile_iconInvite"
|
|
|
|
/>
|
2021-07-19 23:43:11 +02:00
|
|
|
) : null }
|
2021-12-09 10:28:12 +01:00
|
|
|
{ !isDm ? <IconizedContextMenuOption
|
2021-07-14 15:58:18 +02:00
|
|
|
onClick={this.onCopyRoomClick}
|
2021-12-15 10:56:15 +01:00
|
|
|
label={_t("Copy room link")}
|
2021-07-16 10:07:52 +02:00
|
|
|
iconClassName="mx_RoomTile_iconCopyLink"
|
2021-12-09 10:28:12 +01:00
|
|
|
/> : null }
|
2020-08-04 22:42:39 +02:00
|
|
|
<IconizedContextMenuOption
|
|
|
|
onClick={this.onOpenRoomSettings}
|
|
|
|
label={_t("Settings")}
|
|
|
|
iconClassName="mx_RoomTile_iconSettings"
|
|
|
|
/>
|
|
|
|
</IconizedContextMenuOptionList>
|
|
|
|
<IconizedContextMenuOptionList red>
|
|
|
|
<IconizedContextMenuOption
|
|
|
|
onClick={this.onLeaveRoomClick}
|
2021-12-15 10:56:15 +01:00
|
|
|
label={_t("Leave")}
|
2020-08-04 22:42:39 +02:00
|
|
|
iconClassName="mx_RoomTile_iconSignOut"
|
|
|
|
/>
|
|
|
|
</IconizedContextMenuOptionList>
|
|
|
|
</IconizedContextMenu>;
|
2020-06-10 07:09:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<React.Fragment>
|
2020-07-17 19:16:00 +02:00
|
|
|
<ContextMenuTooltipButton
|
2020-07-17 23:43:29 +02:00
|
|
|
className="mx_RoomTile_menuButton"
|
2020-06-10 07:09:15 +02:00
|
|
|
onClick={this.onGeneralMenuOpenClick}
|
2020-07-17 19:16:00 +02:00
|
|
|
title={_t("Room options")}
|
2020-07-02 00:06:26 +02:00
|
|
|
isExpanded={!!this.state.generalMenuPosition}
|
2020-06-10 07:09:15 +02:00
|
|
|
/>
|
2021-07-19 23:43:11 +02:00
|
|
|
{ contextMenu }
|
2020-06-10 07:09:15 +02:00
|
|
|
</React.Fragment>
|
2020-06-18 15:32:43 +02:00
|
|
|
);
|
2020-06-10 07:09:15 +02:00
|
|
|
}
|
|
|
|
|
2022-04-01 16:36:10 +02:00
|
|
|
private updateVideoMembers = () => {
|
|
|
|
this.setState({ videoMembers: getConnectedMembers(this.props.room.currentState) });
|
2022-03-22 23:14:11 +01:00
|
|
|
};
|
|
|
|
|
2022-04-01 16:36:10 +02:00
|
|
|
private updateVideoStatus = () => {
|
|
|
|
if (VideoChannelStore.instance.roomId === this.props.room?.roomId) {
|
|
|
|
this.setState({ videoStatus: VideoStatus.Connected });
|
|
|
|
VideoChannelStore.instance.on(VideoChannelEvent.Participants, this.updateJitsiParticipants);
|
2022-03-28 15:12:09 +02:00
|
|
|
} else {
|
2022-04-01 16:36:10 +02:00
|
|
|
this.setState({ videoStatus: VideoStatus.Disconnected });
|
|
|
|
VideoChannelStore.instance.off(VideoChannelEvent.Participants, this.updateJitsiParticipants);
|
2022-03-28 15:12:09 +02:00
|
|
|
}
|
2022-04-01 16:36:10 +02:00
|
|
|
};
|
2022-03-22 23:14:11 +01:00
|
|
|
|
2022-04-01 16:36:10 +02:00
|
|
|
private updateJitsiParticipants = (participants: IJitsiParticipant[]) => {
|
|
|
|
this.setState({ jitsiParticipants: participants });
|
|
|
|
};
|
2022-03-22 23:14:11 +01:00
|
|
|
|
2020-05-08 20:53:05 +02:00
|
|
|
public render(): React.ReactElement {
|
|
|
|
const classes = classNames({
|
2020-07-17 23:43:29 +02:00
|
|
|
'mx_RoomTile': true,
|
|
|
|
'mx_RoomTile_selected': this.state.selected,
|
|
|
|
'mx_RoomTile_hasMenuOpen': !!(this.state.generalMenuPosition || this.state.notificationsMenuPosition),
|
|
|
|
'mx_RoomTile_minimized': this.props.isMinimized,
|
2020-05-08 20:53:05 +02:00
|
|
|
});
|
|
|
|
|
2022-03-23 00:07:37 +01:00
|
|
|
let name = this.props.room.name;
|
2020-08-25 03:19:28 +02:00
|
|
|
if (typeof name !== 'string') name = '';
|
|
|
|
name = name.replace(":", ":\u200b"); // add a zero-width space to allow linewrapping after the colon
|
|
|
|
|
2020-07-01 00:39:25 +02:00
|
|
|
let badge: React.ReactNode;
|
2021-09-09 14:14:05 +02:00
|
|
|
if (!this.props.isMinimized && this.notificationState) {
|
2020-07-05 20:59:29 +02:00
|
|
|
// aria-hidden because we summarise the unread count/highlight status in a manual aria-label below
|
2021-09-09 14:14:05 +02:00
|
|
|
badge = (
|
|
|
|
<div className="mx_RoomTile_badgeContainer" aria-hidden="true">
|
|
|
|
<NotificationBadge
|
|
|
|
notification={this.notificationState}
|
|
|
|
forceCount={false}
|
|
|
|
roomId={this.props.room.roomId}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
);
|
2020-07-01 00:24:46 +02:00
|
|
|
}
|
2020-05-12 05:09:32 +02:00
|
|
|
|
2022-03-22 23:14:11 +01:00
|
|
|
let subtitle;
|
2022-04-01 16:36:10 +02:00
|
|
|
if (this.isVideoRoom) {
|
|
|
|
let videoText: string;
|
|
|
|
let videoActive: boolean;
|
|
|
|
let participantCount: number;
|
|
|
|
|
|
|
|
switch (this.state.videoStatus) {
|
|
|
|
case VideoStatus.Disconnected:
|
|
|
|
videoText = _t("Video");
|
|
|
|
videoActive = false;
|
|
|
|
participantCount = this.state.videoMembers.length;
|
2022-03-22 23:14:11 +01:00
|
|
|
break;
|
2022-04-01 16:36:10 +02:00
|
|
|
case VideoStatus.Connected:
|
|
|
|
videoText = _t("Connected");
|
|
|
|
videoActive = true;
|
|
|
|
participantCount = this.state.jitsiParticipants.length;
|
2022-03-22 23:14:11 +01:00
|
|
|
}
|
2022-04-01 16:36:10 +02:00
|
|
|
|
|
|
|
subtitle = (
|
|
|
|
<div className="mx_RoomTile_subtitle">
|
|
|
|
<span
|
|
|
|
className={classNames({
|
|
|
|
"mx_RoomTile_videoIndicator": true,
|
|
|
|
"mx_RoomTile_videoIndicator_active": videoActive,
|
|
|
|
})}
|
|
|
|
>
|
|
|
|
{ videoText }
|
|
|
|
</span>
|
|
|
|
{ participantCount ? <>
|
|
|
|
{ " · " }
|
|
|
|
<span
|
|
|
|
className="mx_RoomTile_videoParticipants"
|
|
|
|
aria-label={_t("%(count)s participants", { count: participantCount })}
|
|
|
|
>
|
|
|
|
{ participantCount }
|
|
|
|
</span>
|
|
|
|
</> : null }
|
|
|
|
</div>
|
|
|
|
);
|
2022-03-22 23:14:11 +01:00
|
|
|
} else if (this.showMessagePreview && this.state.messagePreview) {
|
|
|
|
subtitle = (
|
2021-04-13 18:02:22 +02:00
|
|
|
<div
|
2022-03-22 23:14:11 +01:00
|
|
|
className="mx_RoomTile_subtitle"
|
2021-04-13 18:02:22 +02:00
|
|
|
id={messagePreviewId(this.props.room.roomId)}
|
|
|
|
title={this.state.messagePreview}
|
|
|
|
>
|
2021-07-19 23:43:11 +02:00
|
|
|
{ this.state.messagePreview }
|
2020-07-24 21:09:26 +02:00
|
|
|
</div>
|
|
|
|
);
|
2020-05-12 00:20:26 +02:00
|
|
|
}
|
|
|
|
|
2022-03-22 23:14:11 +01:00
|
|
|
const titleClasses = classNames({
|
|
|
|
"mx_RoomTile_title": true,
|
|
|
|
"mx_RoomTile_titleWithSubtitle": !!subtitle,
|
|
|
|
"mx_RoomTile_titleHasUnreadEvents": this.notificationState.isUnread,
|
2020-06-05 05:21:04 +02:00
|
|
|
});
|
|
|
|
|
2022-03-22 23:14:11 +01:00
|
|
|
const titleContainer = this.props.isMinimized ? null : (
|
|
|
|
<div className="mx_RoomTile_titleContainer">
|
|
|
|
<div title={name} className={titleClasses} tabIndex={-1} dir="auto">
|
2021-07-19 23:43:11 +02:00
|
|
|
{ name }
|
2020-06-11 22:39:28 +02:00
|
|
|
</div>
|
2022-03-22 23:14:11 +01:00
|
|
|
{ subtitle }
|
2020-06-11 22:39:28 +02:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
|
2020-07-05 02:07:46 +02:00
|
|
|
let ariaLabel = name;
|
|
|
|
// The following labels are written in such a fashion to increase screen reader efficiency (speed).
|
|
|
|
if (this.props.tag === DefaultTagID.Invite) {
|
|
|
|
// append nothing
|
2021-04-15 17:33:49 +02:00
|
|
|
} else if (this.notificationState.hasMentions) {
|
2020-07-05 02:07:46 +02:00
|
|
|
ariaLabel += " " + _t("%(count)s unread messages including mentions.", {
|
2020-07-27 15:39:30 +02:00
|
|
|
count: this.notificationState.count,
|
2020-07-05 02:07:46 +02:00
|
|
|
});
|
2021-04-15 17:33:49 +02:00
|
|
|
} else if (this.notificationState.hasUnreadCount) {
|
2020-07-05 02:07:46 +02:00
|
|
|
ariaLabel += " " + _t("%(count)s unread messages.", {
|
2020-07-27 15:39:30 +02:00
|
|
|
count: this.notificationState.count,
|
2020-07-05 02:07:46 +02:00
|
|
|
});
|
2021-04-15 17:33:49 +02:00
|
|
|
} else if (this.notificationState.isUnread) {
|
2020-07-05 02:07:46 +02:00
|
|
|
ariaLabel += " " + _t("Unread messages.");
|
|
|
|
}
|
|
|
|
|
2020-07-05 20:38:45 +02:00
|
|
|
let ariaDescribedBy: string;
|
|
|
|
if (this.showMessagePreview) {
|
|
|
|
ariaDescribedBy = messagePreviewId(this.props.room.roomId);
|
|
|
|
}
|
|
|
|
|
2020-08-14 13:01:16 +02:00
|
|
|
const props: Partial<React.ComponentProps<typeof AccessibleTooltipButton>> = {};
|
2020-07-17 19:16:00 +02:00
|
|
|
let Button: React.ComponentType<React.ComponentProps<typeof AccessibleButton>> = AccessibleButton;
|
|
|
|
if (this.props.isMinimized) {
|
|
|
|
Button = AccessibleTooltipButton;
|
2020-08-14 13:01:16 +02:00
|
|
|
props.title = name;
|
|
|
|
// force the tooltip to hide whilst we are showing the context menu
|
|
|
|
props.forceHide = !!this.state.generalMenuPosition;
|
2020-07-17 19:16:00 +02:00
|
|
|
}
|
|
|
|
|
2020-05-08 20:53:05 +02:00
|
|
|
return (
|
|
|
|
<React.Fragment>
|
2020-07-07 11:34:42 +02:00
|
|
|
<RovingTabIndexWrapper inputRef={this.roomTileRef}>
|
2021-07-19 23:43:11 +02:00
|
|
|
{ ({ onFocus, isActive, ref }) =>
|
2020-07-17 19:16:00 +02:00
|
|
|
<Button
|
2020-08-14 13:01:16 +02:00
|
|
|
{...props}
|
2020-05-08 20:53:05 +02:00
|
|
|
onFocus={onFocus}
|
|
|
|
tabIndex={isActive ? 0 : -1}
|
|
|
|
inputRef={ref}
|
|
|
|
className={classes}
|
2020-05-12 00:29:32 +02:00
|
|
|
onClick={this.onTileClick}
|
2020-07-02 00:06:26 +02:00
|
|
|
onContextMenu={this.onContextMenu}
|
2020-07-05 02:07:46 +02:00
|
|
|
role="treeitem"
|
|
|
|
aria-label={ariaLabel}
|
|
|
|
aria-selected={this.state.selected}
|
2020-07-05 20:38:45 +02:00
|
|
|
aria-describedby={ariaDescribedBy}
|
2020-05-08 20:53:05 +02:00
|
|
|
>
|
2021-12-14 15:27:35 +01:00
|
|
|
<DecoratedRoomAvatar
|
|
|
|
room={this.props.room}
|
|
|
|
avatarSize={32}
|
|
|
|
displayBadge={this.props.isMinimized}
|
|
|
|
tooltipProps={{ tabIndex: isActive ? 0 : -1 }}
|
|
|
|
/>
|
2022-04-01 16:36:10 +02:00
|
|
|
{ titleContainer }
|
|
|
|
{ badge }
|
|
|
|
{ this.renderGeneralMenu() }
|
|
|
|
{ this.renderNotificationsMenu(isActive) }
|
2020-07-17 19:16:00 +02:00
|
|
|
</Button>
|
2020-05-08 20:53:05 +02:00
|
|
|
}
|
|
|
|
</RovingTabIndexWrapper>
|
|
|
|
</React.Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|