From ac155bbf4cac3324b29d66311289bbb06c0a1534 Mon Sep 17 00:00:00 2001
From: Ajay Bura <32841439+ajbura@users.noreply.github.com>
Date: Sat, 3 Sep 2022 21:46:40 +0530
Subject: [PATCH] Fix commands (#791)
* Fix commands and added more
* Add /me & /shrug commands
* Add help command
* Fix cmd descriptions
* Add reason in command
---
.../profile-viewer/ProfileViewer.jsx | 17 +-
src/app/organisms/room/RoomViewCmdBar.jsx | 54 +----
src/app/organisms/room/RoomViewInput.jsx | 41 +++-
src/app/organisms/room/commands.jsx | 211 ++++++++++++++++++
src/app/organisms/room/commands.scss | 10 +
src/client/action/room.js | 65 +++++-
src/client/state/RoomList.js | 15 +-
src/client/state/RoomsInput.js | 10 +-
8 files changed, 351 insertions(+), 72 deletions(-)
create mode 100644 src/app/organisms/room/commands.jsx
create mode 100644 src/app/organisms/room/commands.scss
diff --git a/src/app/organisms/profile-viewer/ProfileViewer.jsx b/src/app/organisms/profile-viewer/ProfileViewer.jsx
index 26e3968..fec9189 100644
--- a/src/app/organisms/profile-viewer/ProfileViewer.jsx
+++ b/src/app/organisms/profile-viewer/ProfileViewer.jsx
@@ -11,7 +11,7 @@ import { selectRoom, openReusableContextMenu } from '../../../client/action/navi
import * as roomActions from '../../../client/action/room';
import {
- getUsername, getUsernameOfRoomMember, getPowerLabel, hasDMWith, hasDevices
+ getUsername, getUsernameOfRoomMember, getPowerLabel, hasDMWith, hasDevices,
} from '../../../util/matrixUtil';
import { getEventCords } from '../../../util/common';
import colorMXID from '../../../util/colorMXID';
@@ -209,19 +209,18 @@ function ProfileFooter({ roomId, userId, onRequestClose }) {
};
const toggleIgnore = async () => {
- const ignoredUsers = mx.getIgnoredUsers();
- const uIndex = ignoredUsers.indexOf(userId);
- if (uIndex >= 0) {
- if (uIndex === -1) return;
- ignoredUsers.splice(uIndex, 1);
- } else ignoredUsers.push(userId);
+ const isIgnored = mx.getIgnoredUsers().includes(userId);
try {
setIsIgnoring(true);
- await mx.setIgnoredUsers(ignoredUsers);
+ if (isIgnored) {
+ await roomActions.unignore([userId]);
+ } else {
+ await roomActions.ignore([userId]);
+ }
if (isMountedRef.current === false) return;
- setIsUserIgnored(uIndex < 0);
+ setIsUserIgnored(!isIgnored);
setIsIgnoring(false);
} catch {
setIsIgnoring(false);
diff --git a/src/app/organisms/room/RoomViewCmdBar.jsx b/src/app/organisms/room/RoomViewCmdBar.jsx
index 68919aa..8c390a0 100644
--- a/src/app/organisms/room/RoomViewCmdBar.jsx
+++ b/src/app/organisms/room/RoomViewCmdBar.jsx
@@ -8,13 +8,6 @@ import twemoji from 'twemoji';
import { twemojify } from '../../../util/twemojify';
import initMatrix from '../../../client/initMatrix';
-import { toggleMarkdown } from '../../../client/action/settings';
-import * as roomActions from '../../../client/action/room';
-import {
- openCreateRoom,
- openPublicRooms,
- openInviteUser,
-} from '../../../client/action/navigation';
import { getEmojiForCompletion } from '../emoji-board/custom-emoji';
import AsyncSearch from '../../../util/AsyncSearch';
@@ -22,37 +15,7 @@ import Text from '../../atoms/text/Text';
import ScrollView from '../../atoms/scroll/ScrollView';
import FollowingMembers from '../../molecules/following-members/FollowingMembers';
import { addRecentEmoji, getRecentEmojis } from '../emoji-board/recent';
-
-const commands = [{
- name: 'markdown',
- description: 'Toggle markdown for messages.',
- exe: () => toggleMarkdown(),
-}, {
- name: 'startDM',
- isOptions: true,
- description: 'Start direct message with user. Example: /startDM/@johndoe.matrix.org',
- exe: (roomId, searchTerm) => openInviteUser(undefined, searchTerm),
-}, {
- name: 'createRoom',
- description: 'Create new room',
- exe: () => openCreateRoom(),
-}, {
- name: 'join',
- isOptions: true,
- description: 'Join room with alias. Example: /join/#cinny:matrix.org',
- exe: (roomId, searchTerm) => openPublicRooms(searchTerm),
-}, {
- name: 'leave',
- description: 'Leave current room',
- exe: (roomId) => {
- roomActions.leave(roomId);
- },
-}, {
- name: 'invite',
- isOptions: true,
- description: 'Invite user to room. Example: /invite/@johndoe:matrix.org',
- exe: (roomId, searchTerm) => openInviteUser(roomId, searchTerm),
-}];
+import commands from './commands';
function CmdItem({ onClick, children }) {
return (
@@ -71,16 +34,16 @@ function renderSuggestions({ prefix, option, suggestions }, fireCmd) {
const cmdOptString = (typeof option === 'string') ? `/${option}` : '/?';
return cmds.map((cmd) => (
{
fireCmd({
prefix: cmdPrefix,
option,
- result: cmd,
+ result: commands[cmd],
});
}}
>
- {`${cmd.name}${cmd.isOptions ? cmdOptString : ''}`}
+ {`${cmd}${cmd.isOptions ? cmdOptString : ''}`}
));
}
@@ -209,8 +172,8 @@ function RoomViewCmdBar({ roomId, roomTimeline, viewEvent }) {
const mx = initMatrix.matrixClient;
const setupSearch = {
'/': () => {
- asyncSearch.setup(commands, { keys: ['name'], isContain: true });
- setCmd({ prefix, suggestions: commands });
+ asyncSearch.setup(Object.keys(commands), { isContain: true });
+ setCmd({ prefix, suggestions: Object.keys(commands) });
},
':': () => {
const parentIds = initMatrix.roomList.getAllParentSpaces(roomId);
@@ -242,8 +205,9 @@ function RoomViewCmdBar({ roomId, roomTimeline, viewEvent }) {
}
function fireCmd(myCmd) {
if (myCmd.prefix === '/') {
- myCmd.result.exe(roomId, myCmd.option);
- viewEvent.emit('cmd_fired');
+ viewEvent.emit('cmd_fired', {
+ replace: `/${myCmd.result.name}`,
+ });
}
if (myCmd.prefix === ':') {
if (!myCmd.result.mxc) addRecentEmoji(myCmd.result.unicode);
diff --git a/src/app/organisms/room/RoomViewInput.jsx b/src/app/organisms/room/RoomViewInput.jsx
index 930eae1..0a0a171 100644
--- a/src/app/organisms/room/RoomViewInput.jsx
+++ b/src/app/organisms/room/RoomViewInput.jsx
@@ -21,6 +21,7 @@ import ScrollView from '../../atoms/scroll/ScrollView';
import { MessageReply } from '../../molecules/message/Message';
import StickerBoard from '../sticker-board/StickerBoard';
+import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog';
import CirclePlusIC from '../../../../public/res/ic/outlined/circle-plus.svg';
import EmojiIC from '../../../../public/res/ic/outlined/emoji.svg';
@@ -33,6 +34,8 @@ import MarkdownIC from '../../../../public/res/ic/outlined/markdown.svg';
import FileIC from '../../../../public/res/ic/outlined/file.svg';
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
+import commands from './commands';
+
const CMD_REGEX = /(^\/|:|@)(\S*)$/;
let isTyping = false;
let isCmdActivated = false;
@@ -182,30 +185,54 @@ function RoomViewInput({
};
}, [roomId]);
- const sendMessage = async () => {
- requestAnimationFrame(() => deactivateCmdAndEmit());
- const msgBody = textAreaRef.current.value;
+ const sendBody = async (body, msgType = 'm.text') => {
if (roomsInput.isSending(roomId)) return;
- if (msgBody.trim() === '' && attachment === null) return;
sendIsTyping(false);
- roomsInput.setMessage(roomId, msgBody);
+ roomsInput.setMessage(roomId, body);
if (attachment !== null) {
roomsInput.setAttachment(roomId, attachment);
}
textAreaRef.current.disabled = true;
textAreaRef.current.style.cursor = 'not-allowed';
- await roomsInput.sendInput(roomId);
+ await roomsInput.sendInput(roomId, msgType);
textAreaRef.current.disabled = false;
textAreaRef.current.style.cursor = 'unset';
focusInput();
textAreaRef.current.value = roomsInput.getMessage(roomId);
- viewEvent.emit('message_sent');
textAreaRef.current.style.height = 'unset';
if (replyTo !== null) setReplyTo(null);
};
+ const processCommand = (cmdBody) => {
+ const spaceIndex = cmdBody.indexOf(' ');
+ const cmdName = cmdBody.slice(1, spaceIndex > -1 ? spaceIndex : undefined);
+ const cmdData = spaceIndex > -1 ? cmdBody.slice(spaceIndex + 1) : '';
+ if (!commands[cmdName]) {
+ confirmDialog('Invalid Command', `"${cmdName}" is not a valid command.`, 'Alright');
+ return;
+ }
+ if (['me', 'shrug'].includes(cmdName)) {
+ commands[cmdName].exe(roomId, cmdData, (message, msgType) => sendBody(message, msgType));
+ return;
+ }
+ commands[cmdName].exe(roomId, cmdData);
+ };
+
+ const sendMessage = async () => {
+ requestAnimationFrame(() => deactivateCmdAndEmit());
+ const msgBody = textAreaRef.current.value.trim();
+ if (msgBody.startsWith('/')) {
+ processCommand(msgBody.trim());
+ textAreaRef.current.value = '';
+ textAreaRef.current.style.height = 'unset';
+ return;
+ }
+ if (msgBody === '' && attachment === null) return;
+ sendBody(msgBody, 'm.text');
+ };
+
const handleSendSticker = async (data) => {
roomsInput.sendSticker(roomId, data);
};
diff --git a/src/app/organisms/room/commands.jsx b/src/app/organisms/room/commands.jsx
new file mode 100644
index 0000000..410fd74
--- /dev/null
+++ b/src/app/organisms/room/commands.jsx
@@ -0,0 +1,211 @@
+import React from 'react';
+import './commands.scss';
+
+import initMatrix from '../../../client/initMatrix';
+import * as roomActions from '../../../client/action/room';
+import { hasDMWith, hasDevices } from '../../../util/matrixUtil';
+import { selectRoom, openReusableDialog } from '../../../client/action/navigation';
+
+import Text from '../../atoms/text/Text';
+import SettingTile from '../../molecules/setting-tile/SettingTile';
+
+const MXID_REG = /^@\S+:\S+$/;
+const ROOM_ID_ALIAS_REG = /^(#|!)\S+:\S+$/;
+const ROOM_ID_REG = /^!\S+:\S+$/;
+const MXC_REG = /^mxc:\/\/\S+$/;
+
+export function processMxidAndReason(data) {
+ let reason;
+ let idData = data;
+ const reasonMatch = data.match(/\s-r\s/);
+ if (reasonMatch) {
+ idData = data.slice(0, reasonMatch.index);
+ reason = data.slice(reasonMatch.index + reasonMatch[0].length);
+ if (reason.trim() === '') reason = undefined;
+ }
+ const rawIds = idData.split(' ');
+ const userIds = rawIds.filter((id) => id.match(MXID_REG));
+ return {
+ userIds,
+ reason,
+ };
+}
+
+const commands = {
+ me: {
+ name: 'me',
+ description: 'Display action',
+ exe: (roomId, data, onSuccess) => {
+ const body = data.trim();
+ if (body === '') return;
+ onSuccess(body, 'm.emote');
+ },
+ },
+ shrug: {
+ name: 'shrug',
+ description: 'Send ¯\\_(ツ)_/¯ as message',
+ exe: (roomId, data, onSuccess) => onSuccess(
+ `¯\\_(ツ)_/¯${data.trim() !== '' ? ` ${data}` : ''}`,
+ 'm.text',
+ ),
+ },
+ help: {
+ name: 'help',
+ description: 'View all commands',
+ // eslint-disable-next-line no-use-before-define
+ exe: () => openHelpDialog(),
+ },
+ startdm: {
+ name: 'startdm',
+ description: 'Start DM with user. Example: /startdm userId1 userId2',
+ exe: async (roomId, data) => {
+ const mx = initMatrix.matrixClient;
+ const rawIds = data.split(' ');
+ const userIds = rawIds.filter((id) => id.match(MXID_REG) && id !== mx.getUserId());
+ if (userIds.length === 0) return;
+ if (userIds.length === 1) {
+ const dmRoomId = hasDMWith(userIds[0]);
+ if (dmRoomId) {
+ selectRoom(dmRoomId);
+ return;
+ }
+ }
+ const devices = await Promise.all(userIds.map(hasDevices));
+ const isEncrypt = devices.every((hasDevice) => hasDevice);
+ const result = await roomActions.createDM(userIds, isEncrypt);
+ selectRoom(result.room_id);
+ },
+ },
+ join: {
+ name: 'join',
+ description: 'Join room with alias. Example: /join alias1 alias2',
+ exe: (roomId, data) => {
+ const rawIds = data.split(' ');
+ const roomIds = rawIds.filter((id) => id.match(ROOM_ID_ALIAS_REG));
+ roomIds.map((id) => roomActions.join(id));
+ },
+ },
+ leave: {
+ name: 'leave',
+ description: 'Leave current room.',
+ exe: (roomId, data) => {
+ if (data.trim() === '') {
+ roomActions.leave(roomId);
+ return;
+ }
+ const rawIds = data.split(' ');
+ const roomIds = rawIds.filter((id) => id.match(ROOM_ID_REG));
+ roomIds.map((id) => roomActions.leave(id));
+ },
+ },
+ invite: {
+ name: 'invite',
+ description: 'Invite user to room. Example: /invite userId1 userId2 [-r reason]',
+ exe: (roomId, data) => {
+ const { userIds, reason } = processMxidAndReason(data);
+ userIds.map((id) => roomActions.invite(roomId, id, reason));
+ },
+ },
+ disinvite: {
+ name: 'disinvite',
+ description: 'Disinvite user to room. Example: /disinvite userId1 userId2 [-r reason]',
+ exe: (roomId, data) => {
+ const { userIds, reason } = processMxidAndReason(data);
+ userIds.map((id) => roomActions.kick(roomId, id, reason));
+ },
+ },
+ kick: {
+ name: 'kick',
+ description: 'Kick user from room. Example: /kick userId1 userId2 [-r reason]',
+ exe: (roomId, data) => {
+ const { userIds, reason } = processMxidAndReason(data);
+ userIds.map((id) => roomActions.kick(roomId, id, reason));
+ },
+ },
+ ban: {
+ name: 'ban',
+ description: 'Ban user from room. Example: /ban userId1 userId2 [-r reason]',
+ exe: (roomId, data) => {
+ const { userIds, reason } = processMxidAndReason(data);
+ userIds.map((id) => roomActions.ban(roomId, id, reason));
+ },
+ },
+ unban: {
+ name: 'unban',
+ description: 'Unban user from room. Example: /unban userId1 userId2',
+ exe: (roomId, data) => {
+ const rawIds = data.split(' ');
+ const userIds = rawIds.filter((id) => id.match(MXID_REG));
+ userIds.map((id) => roomActions.unban(roomId, id));
+ },
+ },
+ ignore: {
+ name: 'ignore',
+ description: 'Ignore user. Example: /ignore userId1 userId2',
+ exe: (roomId, data) => {
+ const rawIds = data.split(' ');
+ const userIds = rawIds.filter((id) => id.match(MXID_REG));
+ if (userIds.length > 0) roomActions.ignore(userIds);
+ },
+ },
+ unignore: {
+ name: 'unignore',
+ description: 'Unignore user. Example: /unignore userId1 userId2',
+ exe: (roomId, data) => {
+ const rawIds = data.split(' ');
+ const userIds = rawIds.filter((id) => id.match(MXID_REG));
+ if (userIds.length > 0) roomActions.unignore(userIds);
+ },
+ },
+ myroomnick: {
+ name: 'myroomnick',
+ description: 'Change my room nick',
+ exe: (roomId, data) => {
+ const nick = data.trim();
+ if (nick === '') return;
+ roomActions.setMyRoomNick(roomId, nick);
+ },
+ },
+ myroomavatar: {
+ name: 'myroomavatar',
+ description: 'Change my room avatar. Example /myroomavatar mxc://xyzabc',
+ exe: (roomId, data) => {
+ if (data.match(MXC_REG)) {
+ roomActions.setMyRoomAvatar(roomId, data);
+ }
+ },
+ },
+ converttodm: {
+ name: 'converttodm',
+ description: 'Convert room to direct message',
+ exe: (roomId) => {
+ roomActions.convertToDm(roomId);
+ },
+ },
+ converttoroom: {
+ name: 'converttoroom',
+ description: 'Convert direct message to room',
+ exe: (roomId) => {
+ roomActions.convertToRoom(roomId);
+ },
+ },
+};
+
+function openHelpDialog() {
+ openReusableDialog(
+ Commands,
+ () => (
+
+ {Object.keys(commands).map((cmdName) => (
+ {commands[cmdName].description}}
+ />
+ ))}
+
+ ),
+ );
+}
+
+export default commands;
diff --git a/src/app/organisms/room/commands.scss b/src/app/organisms/room/commands.scss
new file mode 100644
index 0000000..6283937
--- /dev/null
+++ b/src/app/organisms/room/commands.scss
@@ -0,0 +1,10 @@
+.commands-dialog {
+ & > * {
+ padding: var(--sp-tight) var(--sp-normal);
+ border-bottom: 1px solid var(--bg-surface-border);
+ &:last-child {
+ border-bottom: none;
+ margin-bottom: var(--sp-extra-loose);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/client/action/room.js b/src/client/action/room.js
index 1fe721d..a0a7525 100644
--- a/src/client/action/room.js
+++ b/src/client/action/room.js
@@ -6,7 +6,7 @@ import { getIdServer } from '../../util/matrixUtil';
/**
* https://github.com/matrix-org/matrix-react-sdk/blob/1e6c6e9d800890c732d60429449bc280de01a647/src/Rooms.js#L73
* @param {string} roomId Id of room to add
- * @param {string} userId User id to which dm
+ * @param {string} userId User id to which dm || undefined to remove
* @returns {Promise} A promise
*/
function addRoomToMDirect(roomId, userId) {
@@ -79,13 +79,23 @@ function guessDMRoomTargetId(room, myUserId) {
return oldestMember.userId;
}
+function convertToDm(roomId) {
+ const mx = initMatrix.matrixClient;
+ const room = mx.getRoom(roomId);
+ return addRoomToMDirect(roomId, guessDMRoomTargetId(room, mx.getUserId()));
+}
+
+function convertToRoom(roomId) {
+ return addRoomToMDirect(roomId, undefined);
+}
+
/**
*
* @param {string} roomId
* @param {boolean} isDM
* @param {string[]} via
*/
-async function join(roomIdOrAlias, isDM, via) {
+async function join(roomIdOrAlias, isDM = false, via = undefined) {
const mx = initMatrix.matrixClient;
const roomIdParts = roomIdOrAlias.split(':');
const viaServers = via || [roomIdParts[1]];
@@ -150,10 +160,10 @@ async function create(options, isDM = false) {
}
}
-async function createDM(userId, isEncrypted = true) {
+async function createDM(userIdOrIds, isEncrypted = true) {
const options = {
is_direct: true,
- invite: [userId],
+ invite: Array.isArray(userIdOrIds) ? userIdOrIds : [userIdOrIds],
visibility: 'private',
preset: 'trusted_private_chat',
initial_state: [],
@@ -262,10 +272,10 @@ async function createRoom(opts) {
return result;
}
-async function invite(roomId, userId) {
+async function invite(roomId, userId, reason) {
const mx = initMatrix.matrixClient;
- const result = await mx.invite(roomId, userId);
+ const result = await mx.invite(roomId, userId, undefined, reason);
return result;
}
@@ -290,6 +300,21 @@ async function unban(roomId, userId) {
return result;
}
+async function ignore(userIds) {
+ const mx = initMatrix.matrixClient;
+
+ let ignoredUsers = mx.getIgnoredUsers().concat(userIds);
+ ignoredUsers = [...new Set(ignoredUsers)];
+ await mx.setIgnoredUsers(ignoredUsers);
+}
+
+async function unignore(userIds) {
+ const mx = initMatrix.matrixClient;
+
+ const ignoredUsers = mx.getIgnoredUsers();
+ await mx.setIgnoredUsers(ignoredUsers.filter((id) => !userIds.includes(id)));
+}
+
async function setPowerLevel(roomId, userId, powerLevel) {
const mx = initMatrix.matrixClient;
const room = mx.getRoom(roomId);
@@ -300,9 +325,37 @@ async function setPowerLevel(roomId, userId, powerLevel) {
return result;
}
+async function setMyRoomNick(roomId, nick) {
+ const mx = initMatrix.matrixClient;
+ const room = mx.getRoom(roomId);
+ const mEvent = room.currentState.getStateEvents('m.room.member', mx.getUserId());
+ const content = mEvent?.getContent();
+ if (!content) return;
+ await mx.sendStateEvent(roomId, 'm.room.member', {
+ ...content,
+ displayname: nick,
+ }, mx.getUserId());
+}
+
+async function setMyRoomAvatar(roomId, mxc) {
+ const mx = initMatrix.matrixClient;
+ const room = mx.getRoom(roomId);
+ const mEvent = room.currentState.getStateEvents('m.room.member', mx.getUserId());
+ const content = mEvent?.getContent();
+ if (!content) return;
+ await mx.sendStateEvent(roomId, 'm.room.member', {
+ ...content,
+ avatar_url: mxc,
+ }, mx.getUserId());
+}
+
export {
+ convertToDm,
+ convertToRoom,
join, leave,
createDM, createRoom,
invite, kick, ban, unban,
+ ignore, unignore,
setPowerLevel,
+ setMyRoomNick, setMyRoomAvatar,
};
diff --git a/src/client/state/RoomList.js b/src/client/state/RoomList.js
index b24379b..a157048 100644
--- a/src/client/state/RoomList.js
+++ b/src/client/state/RoomList.js
@@ -257,10 +257,10 @@ class RoomList extends EventEmitter {
const latestMDirects = this.getMDirects();
latestMDirects.forEach((directId) => {
- const myRoom = this.matrixClient.getRoom(directId);
if (this.mDirects.has(directId)) return;
this.mDirects.add(directId);
+ const myRoom = this.matrixClient.getRoom(directId);
if (myRoom === null) return;
if (myRoom.getMyMembership() === 'join') {
this.directs.add(directId);
@@ -268,6 +268,19 @@ class RoomList extends EventEmitter {
this.emit(cons.events.roomList.ROOMLIST_UPDATED);
}
});
+
+ [...this.directs].forEach((directId) => {
+ if (latestMDirects.has(directId)) return;
+ this.mDirects.delete(directId);
+
+ const myRoom = this.matrixClient.getRoom(directId);
+ if (myRoom === null) return;
+ if (myRoom.getMyMembership() === 'join') {
+ this.directs.delete(directId);
+ this.rooms.add(directId);
+ this.emit(cons.events.roomList.ROOMLIST_UPDATED);
+ }
+ });
});
this.matrixClient.on('Room.name', (room) => {
diff --git a/src/client/state/RoomsInput.js b/src/client/state/RoomsInput.js
index 03dd074..4277b2f 100644
--- a/src/client/state/RoomsInput.js
+++ b/src/client/state/RoomsInput.js
@@ -274,7 +274,7 @@ class RoomsInput extends EventEmitter {
return this.roomIdToInput.get(roomId)?.isSending || false;
}
- async sendInput(roomId) {
+ async sendInput(roomId, msgType) {
const room = this.matrixClient.getRoom(roomId);
const input = this.getInput(roomId);
input.isSending = true;
@@ -288,7 +288,7 @@ class RoomsInput extends EventEmitter {
const rawMessage = input.message;
let content = {
body: rawMessage,
- msgtype: 'm.text',
+ msgtype: msgType ?? 'm.text',
};
// Apply formatting if relevant
@@ -459,12 +459,14 @@ class RoomsInput extends EventEmitter {
const room = this.matrixClient.getRoom(roomId);
const isReply = typeof mEvent.getWireContent()['m.relates_to']?.['m.in_reply_to'] !== 'undefined';
+ const msgtype = mEvent.getWireContent().msgtype ?? 'm.text';
+
const content = {
body: ` * ${editedBody}`,
- msgtype: 'm.text',
+ msgtype,
'm.new_content': {
body: editedBody,
- msgtype: 'm.text',
+ msgtype,
},
'm.relates_to': {
event_id: mEvent.getId(),