Make composer able to reply in thread or in room timeline
This commit is contained in:
parent
dca268e67a
commit
95d1b06abb
5 changed files with 31 additions and 12 deletions
|
@ -136,6 +136,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
|||
<MessageComposer
|
||||
room={this.props.room}
|
||||
resizeNotifier={this.props.resizeNotifier}
|
||||
replyInThread={true}
|
||||
replyToEvent={this.state?.thread?.replyToEvent}
|
||||
showReplyPreview={false}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
|
|
|
@ -19,6 +19,7 @@ import React from 'react';
|
|||
import { _t } from '../../../languageHandler';
|
||||
import dis from '../../../dispatcher/dispatcher';
|
||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||
import { UNSTABLE_ELEMENT_REPLY_IN_THREAD } from "matrix-js-sdk/src/@types/event";
|
||||
import { makeUserPermalink, RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { Layout } from "../../../settings/Layout";
|
||||
|
@ -206,12 +207,13 @@ export default class ReplyThread extends React.Component<IProps, IState> {
|
|||
return { body, html };
|
||||
}
|
||||
|
||||
public static makeReplyMixIn(ev: MatrixEvent) {
|
||||
public static makeReplyMixIn(ev: MatrixEvent, replyInThread: boolean) {
|
||||
if (!ev) return {};
|
||||
return {
|
||||
'm.relates_to': {
|
||||
'm.in_reply_to': {
|
||||
'event_id': ev.getId(),
|
||||
[UNSTABLE_ELEMENT_REPLY_IN_THREAD.name]: replyInThread,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -183,6 +183,7 @@ interface IProps {
|
|||
resizeNotifier: ResizeNotifier;
|
||||
permalinkCreator: RoomPermalinkCreator;
|
||||
replyToEvent?: MatrixEvent;
|
||||
replyInThread?: boolean;
|
||||
showReplyPreview?: boolean;
|
||||
e2eStatus?: E2EStatus;
|
||||
compact?: boolean;
|
||||
|
@ -204,6 +205,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
|||
private voiceRecordingButton: VoiceRecordComposerTile;
|
||||
|
||||
static defaultProps = {
|
||||
replyInThread: false,
|
||||
showReplyPreview: true,
|
||||
compact: false,
|
||||
};
|
||||
|
@ -383,6 +385,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
|||
room={this.props.room}
|
||||
placeholder={this.renderPlaceholderText()}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
replyInThread={this.props.replyInThread}
|
||||
replyToEvent={this.props.replyToEvent}
|
||||
onChange={this.onChange}
|
||||
disabled={this.state.haveRecording}
|
||||
|
|
|
@ -57,15 +57,16 @@ import { ActionPayload } from "../../../dispatcher/payloads";
|
|||
|
||||
function addReplyToMessageContent(
|
||||
content: IContent,
|
||||
repliedToEvent: MatrixEvent,
|
||||
replyToEvent: MatrixEvent,
|
||||
replyInThread: boolean,
|
||||
permalinkCreator: RoomPermalinkCreator,
|
||||
): void {
|
||||
const replyContent = ReplyThread.makeReplyMixIn(repliedToEvent);
|
||||
const replyContent = ReplyThread.makeReplyMixIn(replyToEvent, replyInThread);
|
||||
Object.assign(content, replyContent);
|
||||
|
||||
// Part of Replies fallback support - prepend the text we're sending
|
||||
// with the text we're replying to
|
||||
const nestedReply = ReplyThread.getNestedReplyText(repliedToEvent, permalinkCreator);
|
||||
const nestedReply = ReplyThread.getNestedReplyText(replyToEvent, permalinkCreator);
|
||||
if (nestedReply) {
|
||||
if (content.formatted_body) {
|
||||
content.formatted_body = nestedReply.html + content.formatted_body;
|
||||
|
@ -77,8 +78,9 @@ function addReplyToMessageContent(
|
|||
// exported for tests
|
||||
export function createMessageContent(
|
||||
model: EditorModel,
|
||||
permalinkCreator: RoomPermalinkCreator,
|
||||
replyToEvent: MatrixEvent,
|
||||
replyInThread: boolean,
|
||||
permalinkCreator: RoomPermalinkCreator,
|
||||
): IContent {
|
||||
const isEmote = containsEmote(model);
|
||||
if (isEmote) {
|
||||
|
@ -101,7 +103,7 @@ export function createMessageContent(
|
|||
}
|
||||
|
||||
if (replyToEvent) {
|
||||
addReplyToMessageContent(content, replyToEvent, permalinkCreator);
|
||||
addReplyToMessageContent(content, replyToEvent, replyInThread, permalinkCreator);
|
||||
}
|
||||
|
||||
return content;
|
||||
|
@ -129,6 +131,7 @@ interface IProps {
|
|||
room: Room;
|
||||
placeholder?: string;
|
||||
permalinkCreator: RoomPermalinkCreator;
|
||||
replyInThread?: boolean;
|
||||
replyToEvent?: MatrixEvent;
|
||||
disabled?: boolean;
|
||||
onChange?(model: EditorModel): void;
|
||||
|
@ -357,7 +360,12 @@ export default class SendMessageComposer extends React.Component<IProps> {
|
|||
if (cmd.category === CommandCategories.messages) {
|
||||
content = await this.runSlashCommand(cmd, args);
|
||||
if (replyToEvent) {
|
||||
addReplyToMessageContent(content, replyToEvent, this.props.permalinkCreator);
|
||||
addReplyToMessageContent(
|
||||
content,
|
||||
replyToEvent,
|
||||
this.props.replyInThread,
|
||||
this.props.permalinkCreator,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.runSlashCommand(cmd, args);
|
||||
|
@ -400,7 +408,12 @@ export default class SendMessageComposer extends React.Component<IProps> {
|
|||
const startTime = CountlyAnalytics.getTimestamp();
|
||||
const { roomId } = this.props.room;
|
||||
if (!content) {
|
||||
content = createMessageContent(this.model, this.props.permalinkCreator, replyToEvent);
|
||||
content = createMessageContent(
|
||||
this.model,
|
||||
replyToEvent,
|
||||
this.props.replyInThread,
|
||||
this.props.permalinkCreator,
|
||||
);
|
||||
}
|
||||
// don't bother sending an empty message
|
||||
if (!content.body.trim()) return;
|
||||
|
|
|
@ -46,7 +46,7 @@ describe('<SendMessageComposer/>', () => {
|
|||
const model = new EditorModel([], createPartCreator(), createRenderer());
|
||||
model.update("hello world", "insertText", { offset: 11, atNodeEnd: true });
|
||||
|
||||
const content = createMessageContent(model, permalinkCreator);
|
||||
const content = createMessageContent(model, null, false, permalinkCreator);
|
||||
|
||||
expect(content).toEqual({
|
||||
body: "hello world",
|
||||
|
@ -58,7 +58,7 @@ describe('<SendMessageComposer/>', () => {
|
|||
const model = new EditorModel([], createPartCreator(), createRenderer());
|
||||
model.update("hello *world*", "insertText", { offset: 13, atNodeEnd: true });
|
||||
|
||||
const content = createMessageContent(model, permalinkCreator);
|
||||
const content = createMessageContent(model, null, false, permalinkCreator);
|
||||
|
||||
expect(content).toEqual({
|
||||
body: "hello *world*",
|
||||
|
@ -72,7 +72,7 @@ describe('<SendMessageComposer/>', () => {
|
|||
const model = new EditorModel([], createPartCreator(), createRenderer());
|
||||
model.update("/me blinks __quickly__", "insertText", { offset: 22, atNodeEnd: true });
|
||||
|
||||
const content = createMessageContent(model, permalinkCreator);
|
||||
const content = createMessageContent(model, null, false, permalinkCreator);
|
||||
|
||||
expect(content).toEqual({
|
||||
body: "blinks __quickly__",
|
||||
|
@ -86,7 +86,7 @@ describe('<SendMessageComposer/>', () => {
|
|||
const model = new EditorModel([], createPartCreator(), createRenderer());
|
||||
model.update("//dev/null is my favourite place", "insertText", { offset: 32, atNodeEnd: true });
|
||||
|
||||
const content = createMessageContent(model, permalinkCreator);
|
||||
const content = createMessageContent(model, null, false, permalinkCreator);
|
||||
|
||||
expect(content).toEqual({
|
||||
body: "/dev/null is my favourite place",
|
||||
|
|
Loading…
Reference in a new issue