Wire up drag-drop file uploads for the thread view (#7860)
This commit is contained in:
parent
42e9ea4540
commit
8fccef86d8
30 changed files with 616 additions and 482 deletions
|
@ -78,6 +78,7 @@ import { copyPlaintext } from '../../../utils/strings';
|
|||
import { DecryptionFailureTracker } from '../../../DecryptionFailureTracker';
|
||||
import RedactedBody from '../messages/RedactedBody';
|
||||
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { shouldDisplayReply } from '../../../utils/Reply';
|
||||
|
||||
export type GetRelationsForEvent = (eventId: string, relationType: string, eventType: string) => Relations;
|
||||
|
||||
|
@ -1390,8 +1391,7 @@ export default class EventTile extends React.Component<IProps, IState> {
|
|||
? RelationType.Thread
|
||||
: undefined;
|
||||
|
||||
const replyChain = haveTileForEvent(this.props.mxEvent)
|
||||
&& ReplyChain.shouldDisplayReply(this.props.mxEvent, renderTarget)
|
||||
const replyChain = haveTileForEvent(this.props.mxEvent) && shouldDisplayReply(this.props.mxEvent, renderTarget)
|
||||
? <ReplyChain
|
||||
parentEv={this.props.mxEvent}
|
||||
onHeightChanged={this.props.onHeightChanged}
|
||||
|
|
|
@ -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, { createContext, ReactElement, useContext } from 'react';
|
||||
import React, { createContext, ReactElement, useContext, useRef } from 'react';
|
||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||
import { RelationType } from 'matrix-js-sdk/src/@types/event';
|
||||
|
@ -33,10 +33,10 @@ import LocationButton from '../location/LocationButton';
|
|||
import Modal from "../../../Modal";
|
||||
import PollCreateDialog from "../elements/PollCreateDialog";
|
||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||
import { ActionPayload } from '../../../dispatcher/payloads';
|
||||
import ContentMessages from '../../../ContentMessages';
|
||||
import MatrixClientContext from '../../../contexts/MatrixClientContext';
|
||||
import RoomContext from '../../../contexts/RoomContext';
|
||||
import { useDispatcher } from "../../../hooks/useDispatcher";
|
||||
|
||||
interface IProps {
|
||||
addEmoji: (emoji: string) => boolean;
|
||||
|
@ -189,50 +189,37 @@ interface IUploadButtonProps {
|
|||
relation?: IEventRelation | null;
|
||||
}
|
||||
|
||||
class UploadButton extends React.Component<IUploadButtonProps> {
|
||||
private uploadInput = React.createRef<HTMLInputElement>();
|
||||
private dispatcherRef: string;
|
||||
const UploadButton = ({ roomId, relation }: IUploadButtonProps) => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const roomContext = useContext(RoomContext);
|
||||
const overflowMenuCloser = useContext(OverflowMenuContext);
|
||||
const uploadInput = useRef<HTMLInputElement>();
|
||||
|
||||
constructor(props: IUploadButtonProps) {
|
||||
super(props);
|
||||
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
}
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
if (payload.action === "upload_file") {
|
||||
this.onUploadClick();
|
||||
}
|
||||
};
|
||||
|
||||
private onUploadClick = () => {
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
const onUploadClick = () => {
|
||||
if (cli.isGuest()) {
|
||||
dis.dispatch({ action: 'require_registration' });
|
||||
return;
|
||||
}
|
||||
this.uploadInput.current?.click();
|
||||
uploadInput.current?.click();
|
||||
overflowMenuCloser?.(); // close overflow menu
|
||||
};
|
||||
|
||||
private onUploadFileInputChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
useDispatcher(dis, payload => {
|
||||
if (roomContext.timelineRenderingType === payload.context && payload.action === "upload_file") {
|
||||
onUploadClick();
|
||||
}
|
||||
});
|
||||
|
||||
const onUploadFileInputChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (ev.target.files.length === 0) return;
|
||||
|
||||
// take a copy so we can safely reset the value of the form control
|
||||
// (Note it is a FileList: we can't use slice or sensible iteration).
|
||||
const tfiles = [];
|
||||
for (let i = 0; i < ev.target.files.length; ++i) {
|
||||
tfiles.push(ev.target.files[i]);
|
||||
}
|
||||
|
||||
// Take a copy, so we can safely reset the value of the form control
|
||||
ContentMessages.sharedInstance().sendContentListToRoom(
|
||||
tfiles,
|
||||
this.props.roomId,
|
||||
this.props.relation,
|
||||
MatrixClientPeg.get(),
|
||||
this.context.timelineRenderingType,
|
||||
Array.from(ev.target.files),
|
||||
roomId,
|
||||
relation,
|
||||
cli,
|
||||
roomContext.timelineRenderingType,
|
||||
);
|
||||
|
||||
// This is the onChange handler for a file form control, but we're
|
||||
|
@ -242,24 +229,22 @@ class UploadButton extends React.Component<IUploadButtonProps> {
|
|||
ev.target.value = '';
|
||||
};
|
||||
|
||||
render() {
|
||||
const uploadInputStyle = { display: 'none' };
|
||||
return <>
|
||||
<CollapsibleButton
|
||||
className="mx_MessageComposer_button mx_MessageComposer_upload"
|
||||
onClick={this.onUploadClick}
|
||||
title={_t('Attachment')}
|
||||
/>
|
||||
<input
|
||||
ref={this.uploadInput}
|
||||
type="file"
|
||||
style={uploadInputStyle}
|
||||
multiple
|
||||
onChange={this.onUploadFileInputChange}
|
||||
/>
|
||||
</>;
|
||||
}
|
||||
}
|
||||
const uploadInputStyle = { display: 'none' };
|
||||
return <>
|
||||
<CollapsibleButton
|
||||
className="mx_MessageComposer_button mx_MessageComposer_upload"
|
||||
onClick={onUploadClick}
|
||||
title={_t('Attachment')}
|
||||
/>
|
||||
<input
|
||||
ref={uploadInput}
|
||||
type="file"
|
||||
style={uploadInputStyle}
|
||||
multiple
|
||||
onChange={onUploadFileInputChange}
|
||||
/>
|
||||
</>;
|
||||
};
|
||||
|
||||
function showStickersButton(props: IProps): ReactElement {
|
||||
return (
|
||||
|
|
|
@ -36,7 +36,6 @@ import {
|
|||
} from '../../../editor/serialize';
|
||||
import BasicMessageComposer, { REGEX_EMOTICON } from "./BasicMessageComposer";
|
||||
import { CommandPartCreator, Part, PartCreator, SerializedPart } from '../../../editor/parts';
|
||||
import ReplyChain from "../elements/ReplyChain";
|
||||
import { findEditableEvent } from '../../../utils/EventUtils';
|
||||
import SendHistoryManager from "../../../SendHistoryManager";
|
||||
import { CommandCategories } from '../../../SlashCommands';
|
||||
|
@ -58,6 +57,7 @@ import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload
|
|||
import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
import { PosthogAnalytics } from "../../../PosthogAnalytics";
|
||||
import { getNestedReplyText, getRenderInMixin, makeReplyMixIn } from '../../../utils/Reply';
|
||||
|
||||
interface IAddReplyOpts {
|
||||
permalinkCreator?: RoomPermalinkCreator;
|
||||
|
@ -72,13 +72,13 @@ function addReplyToMessageContent(
|
|||
includeLegacyFallback: true,
|
||||
},
|
||||
): void {
|
||||
const replyContent = ReplyChain.makeReplyMixIn(replyToEvent, opts.renderIn);
|
||||
const replyContent = makeReplyMixIn(replyToEvent, opts.renderIn);
|
||||
Object.assign(content, replyContent);
|
||||
|
||||
if (opts.includeLegacyFallback) {
|
||||
// Part of Replies fallback support - prepend the text we're sending
|
||||
// with the text we're replying to
|
||||
const nestedReply = ReplyChain.getNestedReplyText(replyToEvent, opts.permalinkCreator);
|
||||
const nestedReply = getNestedReplyText(replyToEvent, opts.permalinkCreator);
|
||||
if (nestedReply) {
|
||||
if (content.formatted_body) {
|
||||
content.formatted_body = nestedReply.html + content.formatted_body;
|
||||
|
@ -132,7 +132,7 @@ export function createMessageContent(
|
|||
addReplyToMessageContent(content, replyToEvent, {
|
||||
permalinkCreator,
|
||||
includeLegacyFallback: true,
|
||||
renderIn: ReplyChain.getRenderInMixin(relation),
|
||||
renderIn: getRenderInMixin(relation),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -384,7 +384,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
|||
addReplyToMessageContent(content, replyToEvent, {
|
||||
permalinkCreator: this.props.permalinkCreator,
|
||||
includeLegacyFallback: true,
|
||||
renderIn: ReplyChain.getRenderInMixin(this.props.relation),
|
||||
renderIn: getRenderInMixin(this.props.relation),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue