|
| 1 | +/* |
| 2 | +Copyright 2021 The Matrix.org Foundation C.I.C. |
| 3 | +
|
| 4 | +Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +you may not use this file except in compliance with the License. |
| 6 | +You may obtain a copy of the License at |
| 7 | +
|
| 8 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +
|
| 10 | +Unless required by applicable law or agreed to in writing, software |
| 11 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +See the License for the specific language governing permissions and |
| 14 | +limitations under the License. |
| 15 | +*/ |
| 16 | + |
| 17 | +import { logger } from "matrix-js-sdk/src/logger"; |
| 18 | +import { Room } from "matrix-js-sdk/src/models/room"; |
| 19 | +import React, { useContext } from "react"; |
| 20 | + |
| 21 | +import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; |
| 22 | +import RoomListActions from "../../../actions/RoomListActions"; |
| 23 | +import MatrixClientContext from "../../../contexts/MatrixClientContext"; |
| 24 | +import dis from "../../../dispatcher/dispatcher"; |
| 25 | +import { useEventEmitterState } from "../../../hooks/useEventEmitter"; |
| 26 | +import { getKeyBindingsManager } from "../../../KeyBindingsManager"; |
| 27 | +import { _t } from "../../../languageHandler"; |
| 28 | +import { DefaultTagID, TagID } from "../../../stores/room-list/models"; |
| 29 | +import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore"; |
| 30 | +import DMRoomMap from "../../../utils/DMRoomMap"; |
| 31 | +import { IProps as IContextMenuProps } from "../../structures/ContextMenu"; |
| 32 | +import IconizedContextMenu, { |
| 33 | + IconizedContextMenuCheckbox, |
| 34 | + IconizedContextMenuOption, |
| 35 | + IconizedContextMenuOptionList, |
| 36 | +} from "../context_menus/IconizedContextMenu"; |
| 37 | +import { ButtonEvent } from "../elements/AccessibleButton"; |
| 38 | + |
| 39 | +interface IProps extends IContextMenuProps { |
| 40 | + room: Room; |
| 41 | + onPostFavoriteClick?: (event: ButtonEvent) => void; |
| 42 | + onPostLowPriorityClick?: (event: ButtonEvent) => void; |
| 43 | + onPostInviteClick?: (event: ButtonEvent) => void; |
| 44 | + onPostCopyLinkClick?: (event: ButtonEvent) => void; |
| 45 | + onPostSettingsClick?: (event: ButtonEvent) => void; |
| 46 | + onPostForgetClick?: (event: ButtonEvent) => void; |
| 47 | + onPostLeaveClick?: (event: ButtonEvent) => void; |
| 48 | +} |
| 49 | + |
| 50 | +export const RoomGeneralContextMenu = ({ |
| 51 | + room, onFinished, |
| 52 | + onPostFavoriteClick, onPostLowPriorityClick, onPostInviteClick, onPostCopyLinkClick, onPostSettingsClick, |
| 53 | + onPostLeaveClick, onPostForgetClick, ...props |
| 54 | +}: IProps) => { |
| 55 | + const cli = useContext(MatrixClientContext); |
| 56 | + const roomTags = useEventEmitterState( |
| 57 | + RoomListStore.instance, |
| 58 | + LISTS_UPDATE_EVENT, |
| 59 | + () => RoomListStore.instance.getTagsForRoom(room), |
| 60 | + ); |
| 61 | + const isDm = DMRoomMap.shared().getUserIdForRoomId(room.roomId); |
| 62 | + const wrapHandler = ( |
| 63 | + handler: (ev: ButtonEvent) => void, |
| 64 | + postHandler?: (ev: ButtonEvent) => void, |
| 65 | + persistent = false, |
| 66 | + ): (ev: ButtonEvent) => void => { |
| 67 | + return (ev: ButtonEvent) => { |
| 68 | + ev.preventDefault(); |
| 69 | + ev.stopPropagation(); |
| 70 | + |
| 71 | + handler(ev); |
| 72 | + |
| 73 | + const action = getKeyBindingsManager().getAccessibilityAction(ev as React.KeyboardEvent); |
| 74 | + if (!persistent || action === KeyBindingAction.Enter) { |
| 75 | + onFinished(); |
| 76 | + } |
| 77 | + postHandler?.(ev); |
| 78 | + }; |
| 79 | + }; |
| 80 | + |
| 81 | + const onTagRoom = (ev: ButtonEvent, tagId: TagID) => { |
| 82 | + if (tagId === DefaultTagID.Favourite || tagId === DefaultTagID.LowPriority) { |
| 83 | + const inverseTag = tagId === DefaultTagID.Favourite ? DefaultTagID.LowPriority : DefaultTagID.Favourite; |
| 84 | + const isApplied = RoomListStore.instance.getTagsForRoom(room).includes(tagId); |
| 85 | + const removeTag = isApplied ? tagId : inverseTag; |
| 86 | + const addTag = isApplied ? null : tagId; |
| 87 | + dis.dispatch(RoomListActions.tagRoom(cli, room, removeTag, addTag, undefined, 0)); |
| 88 | + } else { |
| 89 | + logger.warn(`Unexpected tag ${tagId} applied to ${room.roomId}`); |
| 90 | + } |
| 91 | + }; |
| 92 | + |
| 93 | + const isFavorite = roomTags.includes(DefaultTagID.Favourite); |
| 94 | + const favoriteOption: JSX.Element = <IconizedContextMenuCheckbox |
| 95 | + onClick={wrapHandler((ev) => |
| 96 | + onTagRoom(ev, DefaultTagID.Favourite), onPostFavoriteClick, true)} |
| 97 | + active={isFavorite} |
| 98 | + label={isFavorite ? _t("Favourited") : _t("Favourite")} |
| 99 | + iconClassName="mx_RoomGeneralContextMenu_iconStar" |
| 100 | + />; |
| 101 | + |
| 102 | + const isLowPriority = roomTags.includes(DefaultTagID.LowPriority); |
| 103 | + const lowPriorityOption: JSX.Element = <IconizedContextMenuCheckbox |
| 104 | + onClick={wrapHandler((ev) => |
| 105 | + onTagRoom(ev, DefaultTagID.LowPriority), onPostLowPriorityClick, true)} |
| 106 | + active={isLowPriority} |
| 107 | + label={_t("Low Priority")} |
| 108 | + iconClassName="mx_RoomGeneralContextMenu_iconArrowDown" |
| 109 | + />; |
| 110 | + |
| 111 | + let inviteOption: JSX.Element; |
| 112 | + if (room.canInvite(cli.getUserId()) && !isDm) { |
| 113 | + inviteOption = <IconizedContextMenuOption |
| 114 | + onClick={wrapHandler(() => dis.dispatch({ |
| 115 | + action: "view_invite", |
| 116 | + roomId: room.roomId, |
| 117 | + }), onPostInviteClick)} |
| 118 | + label={_t("Invite")} |
| 119 | + iconClassName="mx_RoomGeneralContextMenu_iconInvite" |
| 120 | + />; |
| 121 | + } |
| 122 | + |
| 123 | + let copyLinkOption: JSX.Element; |
| 124 | + if (!isDm) { |
| 125 | + copyLinkOption = <IconizedContextMenuOption |
| 126 | + onClick={wrapHandler(() => dis.dispatch({ |
| 127 | + action: "copy_room", |
| 128 | + room_id: room.roomId, |
| 129 | + }), onPostCopyLinkClick)} |
| 130 | + label={_t("Copy room link")} |
| 131 | + iconClassName="mx_RoomGeneralContextMenu_iconCopyLink" |
| 132 | + />; |
| 133 | + } |
| 134 | + |
| 135 | + const settingsOption: JSX.Element = <IconizedContextMenuOption |
| 136 | + onClick={wrapHandler(() => dis.dispatch({ |
| 137 | + action: "open_room_settings", |
| 138 | + room_id: room.roomId, |
| 139 | + }), onPostSettingsClick)} |
| 140 | + label={_t("Settings")} |
| 141 | + iconClassName="mx_RoomGeneralContextMenu_iconSettings" |
| 142 | + />; |
| 143 | + |
| 144 | + let leaveOption: JSX.Element; |
| 145 | + if (roomTags.includes(DefaultTagID.Archived)) { |
| 146 | + leaveOption = <IconizedContextMenuOption |
| 147 | + iconClassName="mx_RoomGeneralContextMenu_iconSignOut" |
| 148 | + label={_t("Forget Room")} |
| 149 | + className="mx_IconizedContextMenu_option_red" |
| 150 | + onClick={wrapHandler(() => dis.dispatch({ |
| 151 | + action: "forget_room", |
| 152 | + room_id: room.roomId, |
| 153 | + }), onPostForgetClick)} |
| 154 | + />; |
| 155 | + } else { |
| 156 | + leaveOption = <IconizedContextMenuOption |
| 157 | + onClick={wrapHandler(() => dis.dispatch({ |
| 158 | + action: "leave_room", |
| 159 | + room_id: room.roomId, |
| 160 | + }), onPostLeaveClick)} |
| 161 | + label={_t("Leave")} |
| 162 | + className="mx_IconizedContextMenu_option_red" |
| 163 | + iconClassName="mx_RoomGeneralContextMenu_iconSignOut" |
| 164 | + />; |
| 165 | + } |
| 166 | + |
| 167 | + return <IconizedContextMenu |
| 168 | + {...props} |
| 169 | + onFinished={onFinished} |
| 170 | + className="mx_RoomGeneralContextMenu" |
| 171 | + compact |
| 172 | + > |
| 173 | + { !roomTags.includes(DefaultTagID.Archived) && ( |
| 174 | + <IconizedContextMenuOptionList> |
| 175 | + { favoriteOption } |
| 176 | + { lowPriorityOption } |
| 177 | + { inviteOption } |
| 178 | + { copyLinkOption } |
| 179 | + { settingsOption } |
| 180 | + </IconizedContextMenuOptionList> |
| 181 | + ) } |
| 182 | + <IconizedContextMenuOptionList red> |
| 183 | + { leaveOption } |
| 184 | + </IconizedContextMenuOptionList> |
| 185 | + </IconizedContextMenu>; |
| 186 | +}; |
0 commit comments