Merge branch 'develop' into sort-imports

Signed-off-by: Aaron Raimist <aaron@raim.ist>
This commit is contained in:
Aaron Raimist 2021-12-09 08:34:20 +00:00
commit 7b94e13a84
642 changed files with 30052 additions and 8035 deletions

View file

@ -16,17 +16,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { useEffect } from 'react';
import React, { ReactElement, useEffect } from 'react';
import { EventStatus, MatrixEvent } from 'matrix-js-sdk/src/models/event';
import classNames from 'classnames';
import type { Relations } from 'matrix-js-sdk/src/models/relations';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
import dis from '../../../dispatcher/dispatcher';
import { Action } from '../../../dispatcher/actions';
import { RightPanelPhases } from '../../../stores/RightPanelStorePhases';
import { aboveLeftOf, ContextMenu, ContextMenuTooltipButton, useContextMenu } from '../../structures/ContextMenu';
import ContextMenu, { aboveLeftOf, ContextMenuTooltipButton, useContextMenu } from '../../structures/ContextMenu';
import { isContentActionable, canEditContent } from '../../../utils/EventUtils';
import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
import Toolbar from "../../../accessibility/Toolbar";
@ -40,6 +38,9 @@ import DownloadActionButton from "./DownloadActionButton";
import SettingsStore from '../../../settings/SettingsStore';
import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks';
import ReplyChain from '../elements/ReplyChain';
import { dispatchShowThreadEvent } from '../../../dispatcher/dispatch-actions/threads';
import ReactionPicker from "../emojipicker/ReactionPicker";
import { MsgType } from 'matrix-js-sdk/src/@types/event';
interface IOptionsButtonProps {
mxEvent: MatrixEvent;
@ -48,46 +49,58 @@ interface IOptionsButtonProps {
getReplyChain: () => ReplyChain;
permalinkCreator: RoomPermalinkCreator;
onFocusChange: (menuDisplayed: boolean) => void;
getRelationsForEvent?: (
eventId: string,
relationType: string,
eventType: string
) => Relations;
}
const OptionsButton: React.FC<IOptionsButtonProps> =
({ mxEvent, getTile, getReplyChain, permalinkCreator, onFocusChange }) => {
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
const [onFocus, isActive, ref] = useRovingTabIndex(button);
useEffect(() => {
onFocusChange(menuDisplayed);
}, [onFocusChange, menuDisplayed]);
const OptionsButton: React.FC<IOptionsButtonProps> = ({
mxEvent,
getTile,
getReplyChain,
permalinkCreator,
onFocusChange,
getRelationsForEvent,
}) => {
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
const [onFocus, isActive, ref] = useRovingTabIndex(button);
useEffect(() => {
onFocusChange(menuDisplayed);
}, [onFocusChange, menuDisplayed]);
let contextMenu;
if (menuDisplayed) {
const tile = getTile && getTile();
const replyChain = getReplyChain && getReplyChain();
let contextMenu: ReactElement | null;
if (menuDisplayed) {
const tile = getTile && getTile();
const replyChain = getReplyChain && getReplyChain();
const buttonRect = button.current.getBoundingClientRect();
contextMenu = <MessageContextMenu
{...aboveLeftOf(buttonRect)}
mxEvent={mxEvent}
permalinkCreator={permalinkCreator}
eventTileOps={tile && tile.getEventTileOps ? tile.getEventTileOps() : undefined}
collapseReplyChain={replyChain && replyChain.canCollapse() ? replyChain.collapse : undefined}
onFinished={closeMenu}
/>;
}
const buttonRect = button.current.getBoundingClientRect();
contextMenu = <MessageContextMenu
{...aboveLeftOf(buttonRect)}
mxEvent={mxEvent}
permalinkCreator={permalinkCreator}
eventTileOps={tile && tile.getEventTileOps ? tile.getEventTileOps() : undefined}
collapseReplyChain={replyChain && replyChain.canCollapse() ? replyChain.collapse : undefined}
onFinished={closeMenu}
getRelationsForEvent={getRelationsForEvent}
/>;
}
return <React.Fragment>
<ContextMenuTooltipButton
className="mx_MessageActionBar_maskButton mx_MessageActionBar_optionsButton"
title={_t("Options")}
onClick={openMenu}
isExpanded={menuDisplayed}
inputRef={ref}
onFocus={onFocus}
tabIndex={isActive ? 0 : -1}
/>
return <React.Fragment>
<ContextMenuTooltipButton
className="mx_MessageActionBar_maskButton mx_MessageActionBar_optionsButton"
title={_t("Options")}
onClick={openMenu}
isExpanded={menuDisplayed}
inputRef={ref}
onFocus={onFocus}
tabIndex={isActive ? 0 : -1}
/>
{ contextMenu }
</React.Fragment>;
};
{ contextMenu }
</React.Fragment>;
};
interface IReactButtonProps {
mxEvent: MatrixEvent;
@ -105,7 +118,6 @@ const ReactButton: React.FC<IReactButtonProps> = ({ mxEvent, reactions, onFocusC
let contextMenu;
if (menuDisplayed) {
const buttonRect = button.current.getBoundingClientRect();
const ReactionPicker = sdk.getComponent('emojipicker.ReactionPicker');
contextMenu = <ContextMenu {...aboveLeftOf(buttonRect)} onFinished={closeMenu} managed={false}>
<ReactionPicker mxEvent={mxEvent} reactions={reactions} onFinished={closeMenu} />
</ContextMenu>;
@ -136,6 +148,11 @@ interface IMessageActionBarProps {
onFocusChange?: (menuDisplayed: boolean) => void;
toggleThreadExpanded: () => void;
isQuoteExpanded?: boolean;
getRelationsForEvent?: (
eventId: string,
relationType: string,
eventType: string
) => Relations;
}
@replaceableComponent("views.messages.MessageActionBar")
@ -194,13 +211,10 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
};
private onThreadClick = (): void => {
dispatchShowThreadEvent(this.props.mxEvent);
dis.dispatch({
action: Action.SetRightPanelPhase,
phase: RightPanelPhases.ThreadView,
allowClose: false,
refireParams: {
event: this.props.mxEvent,
},
action: Action.FocusSendMessageComposer,
context: TimelineRenderingType.Thread,
});
};
@ -212,6 +226,21 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
});
};
private readonly forbiddenThreadHeadMsgType = [
MsgType.KeyVerificationRequest,
];
private get showReplyInThreadAction(): boolean {
const isThreadEnabled = SettingsStore.getValue("feature_thread");
const inNotThreadTimeline = this.context.timelineRenderingType !== TimelineRenderingType.Thread;
const isAllowedMessageType = !this.forbiddenThreadHeadMsgType.includes(
this.props.mxEvent.getContent().msgtype as MsgType,
);
return isThreadEnabled && inNotThreadTimeline && isAllowedMessageType;
}
/**
* Runs a given fn on the set of possible events to test. The first event
* that passes the checkFn will have fn executed on it. Both functions take
@ -296,11 +325,10 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
onClick={this.onReplyClick}
key="reply"
/>
{ (SettingsStore.getValue("feature_thread")
&& this.context.timelineRenderingType !== TimelineRenderingType.Thread) && (
{ (this.showReplyInThreadAction) && (
<RovingAccessibleTooltipButton
className="mx_MessageActionBar_maskButton mx_MessageActionBar_threadButton"
title={_t("Thread")}
title={_t("Reply in thread")}
onClick={this.onThreadClick}
key="thread"
/>
@ -333,7 +361,7 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
) {
toolbarOpts.unshift(<RovingAccessibleTooltipButton
className="mx_MessageActionBar_maskButton mx_MessageActionBar_threadButton"
title={_t("Thread")}
title={_t("Reply in thread")}
onClick={this.onThreadClick}
key="thread"
/>);
@ -365,6 +393,7 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
permalinkCreator={this.props.permalinkCreator}
onFocusChange={this.onFocusChange}
key="menu"
getRelationsForEvent={this.props.getRelationsForEvent}
/>);
}