Refactor MessageComposerButtons (#7668)

This commit is contained in:
Andy Balaam 2022-01-31 09:19:26 +00:00 committed by GitHub
parent 7c20eb9b74
commit b5a56698d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 153 additions and 82 deletions

View file

@ -17,7 +17,7 @@ limitations under the License.
import classNames from 'classnames';
import { IEventRelation } from "matrix-js-sdk/src/models/event";
import { M_POLL_START } from "matrix-events-sdk";
import React, { useContext } from 'react';
import React, { ReactElement, useContext } from 'react';
import { Room } from 'matrix-js-sdk/src/models/room';
import { MatrixClient } from 'matrix-js-sdk/src/client';
@ -56,85 +56,55 @@ const MessageComposerButtons: React.FC<IProps> = (props: IProps) => {
const matrixClient: MatrixClient = useContext(MatrixClientContext);
const { room, roomId } = useContext(RoomContext);
if (props.haveRecording) {
return null;
}
let uploadButtonIndex = 0;
const buttons: JSX.Element[] = [];
buttons.push(
<PollButton
key="polls"
room={room}
narrowMode={props.narrowMode}
/>,
return (
props.haveRecording
? null
: props.narrowMode
? narrowMode(props, room, roomId, matrixClient)
: wideMode(props, room, roomId, matrixClient)
);
uploadButtonIndex = buttons.length;
buttons.push(
<UploadButton key="controls_upload" roomId={roomId} relation={props.relation} />,
);
if (props.showLocationButton) {
const sender = room.getMember(matrixClient.getUserId());
buttons.push(
<LocationButton
key="location"
roomId={roomId}
sender={sender}
menuPosition={props.menuPosition}
narrowMode={props.narrowMode}
/>,
);
}
buttons.push(
<EmojiButton key="emoji_button" addEmoji={props.addEmoji} menuPosition={props.menuPosition} narrowMode={props.narrowMode} />,
);
if (props.showStickersButton) {
let title: string;
if (!props.narrowMode) {
title = props.isStickerPickerOpen ? _t("Hide Stickers") : _t("Show Stickers");
}
};
buttons.push(
<AccessibleTooltipButton
id='stickersButton'
key="controls_stickers"
className="mx_MessageComposer_button mx_MessageComposer_stickers"
onClick={() => props.setStickerPickerOpen(!props.isStickerPickerOpen)}
title={title}
label={props.narrowMode ? _t("Send a sticker") : null}
/>,
);
}
function wideMode(
props: IProps,
room: Room,
roomId: string,
matrixClient: MatrixClient,
): ReactElement {
return <>
{ pollButton(props, room) }
{ uploadButton(props, roomId) }
{ showLocationButton(props, room, roomId, matrixClient) }
{ emojiButton(props) }
{ showStickersButton(props) }
{ voiceRecordingButton(props) }
</>;
}
// XXX: the recording UI does not work well in narrow mode, so we hide this button for now
if (!props.narrowMode) {
buttons.push(
<CollapsibleButton
key="voice_message_send"
className="mx_MessageComposer_button mx_MessageComposer_voiceMessage"
onClick={props.onRecordStartEndClick}
title={_t("Send voice message")}
narrowMode={props.narrowMode}
/>,
);
}
if (!props.narrowMode) {
return <>{ buttons }</>;
}
const classnames = classNames({
function narrowMode(
props: IProps,
room: Room,
roomId: string,
matrixClient: MatrixClient,
): ReactElement {
const moreOptionsClasses = classNames({
mx_MessageComposer_button: true,
mx_MessageComposer_buttonMenu: true,
mx_MessageComposer_closeButtonMenu: props.isMenuOpen,
});
// we render the uploadButton at top level as it is a very common interaction, splice it out of the rest
const [uploadButton] = buttons.splice(uploadButtonIndex, 1);
const moreButtons = [
pollButton(props, room),
showLocationButton(props, room, roomId, matrixClient),
emojiButton(props),
showStickersButton(props),
voiceRecordingButton(props),
].filter(x => x);
return <>
{ uploadButton }
{ uploadButton(props, roomId) }
<AccessibleTooltipButton
className={classnames}
className={moreOptionsClasses}
onClick={props.toggleButtonMenu}
title={_t("More options")}
tooltip={false}
@ -145,28 +115,50 @@ const MessageComposerButtons: React.FC<IProps> = (props: IProps) => {
{...props.menuPosition}
wrapperClassName="mx_MessageComposer_Menu"
>
{ buttons.map((button, index) => (
<MenuItem className="mx_CallContextMenu_item" key={index} onClick={props.toggleButtonMenu}>
{ moreButtons.map((button, index) => (
<MenuItem
className="mx_CallContextMenu_item"
key={index}
onClick={props.toggleButtonMenu}
>
{ button }
</MenuItem>
)) }
</ContextMenu>
) }
</>;
};
}
function emojiButton(props: IProps): ReactElement {
return <EmojiButton
key="emoji_button"
addEmoji={props.addEmoji}
menuPosition={props.menuPosition}
narrowMode={props.narrowMode}
/>;
}
interface IEmojiButtonProps extends Pick<ICollapsibleButtonProps, "narrowMode"> {
addEmoji: (unicode: string) => boolean;
menuPosition: AboveLeftOf;
}
const EmojiButton: React.FC<IEmojiButtonProps> = ({ addEmoji, menuPosition, narrowMode }) => {
const EmojiButton: React.FC<IEmojiButtonProps> = (
{ addEmoji, menuPosition, narrowMode },
) => {
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
let contextMenu: React.ReactElement | null = null;
if (menuDisplayed) {
const position = menuPosition ?? aboveLeftOf(button.current.getBoundingClientRect());
contextMenu = <ContextMenu {...position} onFinished={closeMenu} managed={false}>
const position = (
menuPosition ?? aboveLeftOf(button.current.getBoundingClientRect())
);
contextMenu = <ContextMenu
{...position}
onFinished={closeMenu}
managed={false}
>
<EmojiPicker onChoose={addEmoji} showQuickReactions={true} />
</ContextMenu>;
}
@ -193,6 +185,14 @@ const EmojiButton: React.FC<IEmojiButtonProps> = ({ addEmoji, menuPosition, narr
</React.Fragment>;
};
function uploadButton(props: IProps, roomId: string): ReactElement {
return <UploadButton
key="controls_upload"
roomId={roomId}
relation={props.relation}
/>;
}
interface IUploadButtonProps {
roomId: string;
relation?: IEventRelation | null;
@ -270,6 +270,51 @@ class UploadButton extends React.Component<IUploadButtonProps> {
);
}
}
function showStickersButton(props: IProps): ReactElement {
return (
props.showStickersButton
? <AccessibleTooltipButton
id='stickersButton'
key="controls_stickers"
className="mx_MessageComposer_button mx_MessageComposer_stickers"
onClick={() => props.setStickerPickerOpen(!props.isStickerPickerOpen)}
title={
props.narrowMode
? null
: props.isStickerPickerOpen
? _t("Hide Stickers")
: _t("Show Stickers")
}
label={props.narrowMode ? _t("Send a sticker") : null}
/>
: null
);
}
function voiceRecordingButton(props: IProps): ReactElement {
// XXX: recording UI does not work well in narrow mode, so hide for now
return (
props.narrowMode
? null
: <CollapsibleButton
key="voice_message_send"
className="mx_MessageComposer_button mx_MessageComposer_voiceMessage"
onClick={props.onRecordStartEndClick}
title={_t("Send voice message")}
narrowMode={props.narrowMode}
/>
);
}
function pollButton(props: IProps, room: Room): ReactElement {
return <PollButton
key="polls"
room={room}
narrowMode={props.narrowMode}
/>;
}
interface IPollButtonProps extends Pick<ICollapsibleButtonProps, "narrowMode"> {
room: Room;
}
@ -281,10 +326,17 @@ class PollButton extends React.PureComponent<IPollButtonProps> {
MatrixClientPeg.get().getUserId(),
);
if (!canSend) {
Modal.createTrackedDialog('Polls', 'permissions error: cannot start', ErrorDialog, {
title: _t("Permission Required"),
description: _t("You do not have permission to start polls in this room."),
});
Modal.createTrackedDialog(
'Polls',
'permissions error: cannot start',
ErrorDialog,
{
title: _t("Permission Required"),
description: _t(
"You do not have permission to start polls in this room.",
),
},
);
} else {
Modal.createTrackedDialog(
'Polls',
@ -312,4 +364,23 @@ class PollButton extends React.PureComponent<IPollButtonProps> {
}
}
function showLocationButton(
props: IProps,
room: Room,
roomId: string,
matrixClient: MatrixClient,
): ReactElement {
return (
props.showLocationButton
? <LocationButton
key="location"
roomId={roomId}
sender={room.getMember(matrixClient.getUserId())}
menuPosition={props.menuPosition}
narrowMode={props.narrowMode}
/>
: null
);
}
export default MessageComposerButtons;

View file

@ -1694,11 +1694,11 @@
"You do not have permission to post to this room": "You do not have permission to post to this room",
"%(seconds)ss left": "%(seconds)ss left",
"Send voice message": "Send voice message",
"Add emoji": "Add emoji",
"Upload file": "Upload file",
"Hide Stickers": "Hide Stickers",
"Show Stickers": "Show Stickers",
"Send a sticker": "Send a sticker",
"Add emoji": "Add emoji",
"Upload file": "Upload file",
"You do not have permission to start polls in this room.": "You do not have permission to start polls in this room.",
"Create poll": "Create poll",
"Bold": "Bold",