Fix commands and added more

This commit is contained in:
Ajay Bura 2022-08-27 20:48:53 +05:30
parent 33949dbdb1
commit 77f976392f
6 changed files with 282 additions and 60 deletions

View file

@ -11,7 +11,7 @@ import { selectRoom, openReusableContextMenu } from '../../../client/action/navi
import * as roomActions from '../../../client/action/room'; import * as roomActions from '../../../client/action/room';
import { import {
getUsername, getUsernameOfRoomMember, getPowerLabel, hasDMWith, hasDevices getUsername, getUsernameOfRoomMember, getPowerLabel, hasDMWith, hasDevices,
} from '../../../util/matrixUtil'; } from '../../../util/matrixUtil';
import { getEventCords } from '../../../util/common'; import { getEventCords } from '../../../util/common';
import colorMXID from '../../../util/colorMXID'; import colorMXID from '../../../util/colorMXID';
@ -209,19 +209,18 @@ function ProfileFooter({ roomId, userId, onRequestClose }) {
}; };
const toggleIgnore = async () => { const toggleIgnore = async () => {
const ignoredUsers = mx.getIgnoredUsers(); const isIgnored = mx.getIgnoredUsers().includes(userId);
const uIndex = ignoredUsers.indexOf(userId);
if (uIndex >= 0) {
if (uIndex === -1) return;
ignoredUsers.splice(uIndex, 1);
} else ignoredUsers.push(userId);
try { try {
setIsIgnoring(true); setIsIgnoring(true);
await mx.setIgnoredUsers(ignoredUsers); if (isIgnored) {
await roomActions.unignore([userId]);
} else {
await roomActions.ignore([userId]);
}
if (isMountedRef.current === false) return; if (isMountedRef.current === false) return;
setIsUserIgnored(uIndex < 0); setIsUserIgnored(!isIgnored);
setIsIgnoring(false); setIsIgnoring(false);
} catch { } catch {
setIsIgnoring(false); setIsIgnoring(false);

View file

@ -8,13 +8,6 @@ import twemoji from 'twemoji';
import { twemojify } from '../../../util/twemojify'; import { twemojify } from '../../../util/twemojify';
import initMatrix from '../../../client/initMatrix'; 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 { getEmojiForCompletion } from '../emoji-board/custom-emoji';
import AsyncSearch from '../../../util/AsyncSearch'; import AsyncSearch from '../../../util/AsyncSearch';
@ -22,37 +15,7 @@ import Text from '../../atoms/text/Text';
import ScrollView from '../../atoms/scroll/ScrollView'; import ScrollView from '../../atoms/scroll/ScrollView';
import FollowingMembers from '../../molecules/following-members/FollowingMembers'; import FollowingMembers from '../../molecules/following-members/FollowingMembers';
import { addRecentEmoji, getRecentEmojis } from '../emoji-board/recent'; import { addRecentEmoji, getRecentEmojis } from '../emoji-board/recent';
import commands from './commands';
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),
}];
function CmdItem({ onClick, children }) { function CmdItem({ onClick, children }) {
return ( return (
@ -71,16 +34,16 @@ function renderSuggestions({ prefix, option, suggestions }, fireCmd) {
const cmdOptString = (typeof option === 'string') ? `/${option}` : '/?'; const cmdOptString = (typeof option === 'string') ? `/${option}` : '/?';
return cmds.map((cmd) => ( return cmds.map((cmd) => (
<CmdItem <CmdItem
key={cmd.name} key={cmd}
onClick={() => { onClick={() => {
fireCmd({ fireCmd({
prefix: cmdPrefix, prefix: cmdPrefix,
option, option,
result: cmd, result: commands[cmd],
}); });
}} }}
> >
<Text variant="b2">{`${cmd.name}${cmd.isOptions ? cmdOptString : ''}`}</Text> <Text variant="b2">{`${cmd}${cmd.isOptions ? cmdOptString : ''}`}</Text>
</CmdItem> </CmdItem>
)); ));
} }
@ -209,8 +172,8 @@ function RoomViewCmdBar({ roomId, roomTimeline, viewEvent }) {
const mx = initMatrix.matrixClient; const mx = initMatrix.matrixClient;
const setupSearch = { const setupSearch = {
'/': () => { '/': () => {
asyncSearch.setup(commands, { keys: ['name'], isContain: true }); asyncSearch.setup(Object.keys(commands), { isContain: true });
setCmd({ prefix, suggestions: commands }); setCmd({ prefix, suggestions: Object.keys(commands) });
}, },
':': () => { ':': () => {
const parentIds = initMatrix.roomList.getAllParentSpaces(roomId); const parentIds = initMatrix.roomList.getAllParentSpaces(roomId);
@ -242,8 +205,9 @@ function RoomViewCmdBar({ roomId, roomTimeline, viewEvent }) {
} }
function fireCmd(myCmd) { function fireCmd(myCmd) {
if (myCmd.prefix === '/') { 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.prefix === ':') {
if (!myCmd.result.mxc) addRecentEmoji(myCmd.result.unicode); if (!myCmd.result.mxc) addRecentEmoji(myCmd.result.unicode);

View file

@ -33,6 +33,8 @@ import MarkdownIC from '../../../../public/res/ic/outlined/markdown.svg';
import FileIC from '../../../../public/res/ic/outlined/file.svg'; import FileIC from '../../../../public/res/ic/outlined/file.svg';
import CrossIC from '../../../../public/res/ic/outlined/cross.svg'; import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
import commands from './commands';
const CMD_REGEX = /(^\/|:|@)(\S*)$/; const CMD_REGEX = /(^\/|:|@)(\S*)$/;
let isTyping = false; let isTyping = false;
let isCmdActivated = false; let isCmdActivated = false;
@ -182,9 +184,27 @@ function RoomViewInput({
}; };
}, [roomId]); }, [roomId]);
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]) {
console.log('Invalid command');
return;
}
commands[cmdName].exe(roomId, cmdData);
};
const sendMessage = async () => { const sendMessage = async () => {
requestAnimationFrame(() => deactivateCmdAndEmit()); requestAnimationFrame(() => deactivateCmdAndEmit());
const msgBody = textAreaRef.current.value; const msgBody = textAreaRef.current.value;
if (msgBody.startsWith('/')) {
processCommand(msgBody.trim());
textAreaRef.current.value = '';
textAreaRef.current.style.height = 'unset';
return;
}
if (roomsInput.isSending(roomId)) return; if (roomsInput.isSending(roomId)) return;
if (msgBody.trim() === '' && attachment === null) return; if (msgBody.trim() === '' && attachment === null) return;
sendIsTyping(false); sendIsTyping(false);
@ -201,7 +221,6 @@ function RoomViewInput({
focusInput(); focusInput();
textAreaRef.current.value = roomsInput.getMessage(roomId); textAreaRef.current.value = roomsInput.getMessage(roomId);
viewEvent.emit('message_sent');
textAreaRef.current.style.height = 'unset'; textAreaRef.current.style.height = 'unset';
if (replyTo !== null) setReplyTo(null); if (replyTo !== null) setReplyTo(null);
}; };

View file

@ -0,0 +1,174 @@
import initMatrix from '../../../client/initMatrix';
import { toggleMarkdown } from '../../../client/action/settings';
import * as roomActions from '../../../client/action/room';
import { hasDMWith, hasDevices } from '../../../util/matrixUtil';
import { selectRoom } from '../../../client/action/navigation';
const MXID_REG = /^@\S+:\S+$/;
const ROOM_ID_ALIAS_REG = /^(#|!)\S+:\S+$/;
const ROOM_ID_REG = /^!\S+:\S+$/;
const MXC_REG = /^mxc:\/\/\S+$/;
const commands = {
me: {
name: 'me',
description: 'Display action',
exe: (roomId, data) => {
const body = data.trim();
if (body === '') return undefined;
return body;
},
},
shrug: {
name: 'shrug',
description: 'Send ¯\\_(ツ)_/¯ as message',
exe: (roomId, data) => (
`¯\\_(ツ)_/¯${data.trim() !== '' ? ` ${data}` : ''}`
),
},
markdown: {
name: 'markdown',
description: 'Toggle markdown for messages',
exe: () => toggleMarkdown(),
},
startdm: {
name: 'startdm',
description: 'Start DM with user id. Example: /startdm @johndoe.matrix.org',
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 #cinny:matrix.org',
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 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 @johndoe:matrix.org',
exe: (roomId, data) => {
const rawIds = data.split(' ');
const userIds = rawIds.filter((id) => id.match(MXID_REG));
userIds.map((id) => roomActions.invite(roomId, id));
},
},
disinvite: {
name: 'disinvite',
description: 'Disinvite user to room. Example: /disinvite @johndoe:matrix.org',
exe: (roomId, data) => {
const rawIds = data.split(' ');
const userIds = rawIds.filter((id) => id.match(MXID_REG));
userIds.map((id) => roomActions.kick(roomId, id));
},
},
kick: {
name: 'kick',
description: 'Kick user from room. Example: /kick @johndoe:matrix.org',
exe: (roomId, data) => {
const rawIds = data.split(' ');
const userIds = rawIds.filter((id) => id.match(MXID_REG));
userIds.map((id) => roomActions.kick(roomId, id));
},
},
ban: {
name: 'ban',
description: 'Ban user from room. Example: /ban @johndoe:matrix.org',
exe: (roomId, data) => {
const rawIds = data.split(' ');
const userIds = rawIds.filter((id) => id.match(MXID_REG));
userIds.map((id) => roomActions.ban(roomId, id));
},
},
unban: {
name: 'unban',
description: 'Unban user from room. Example: /unban @johndoe:matrix.org',
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 @johndoe:matrix.org',
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 @johndoe:matrix.org',
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);
},
},
};
export default commands;

View file

@ -6,7 +6,7 @@ import { getIdServer } from '../../util/matrixUtil';
/** /**
* https://github.com/matrix-org/matrix-react-sdk/blob/1e6c6e9d800890c732d60429449bc280de01a647/src/Rooms.js#L73 * https://github.com/matrix-org/matrix-react-sdk/blob/1e6c6e9d800890c732d60429449bc280de01a647/src/Rooms.js#L73
* @param {string} roomId Id of room to add * @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 * @returns {Promise} A promise
*/ */
function addRoomToMDirect(roomId, userId) { function addRoomToMDirect(roomId, userId) {
@ -79,13 +79,23 @@ function guessDMRoomTargetId(room, myUserId) {
return oldestMember.userId; 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 {string} roomId
* @param {boolean} isDM * @param {boolean} isDM
* @param {string[]} via * @param {string[]} via
*/ */
async function join(roomIdOrAlias, isDM, via) { async function join(roomIdOrAlias, isDM = false, via = undefined) {
const mx = initMatrix.matrixClient; const mx = initMatrix.matrixClient;
const roomIdParts = roomIdOrAlias.split(':'); const roomIdParts = roomIdOrAlias.split(':');
const viaServers = via || [roomIdParts[1]]; 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 = { const options = {
is_direct: true, is_direct: true,
invite: [userId], invite: Array.isArray(userIdOrIds) ? userIdOrIds : [userIdOrIds],
visibility: 'private', visibility: 'private',
preset: 'trusted_private_chat', preset: 'trusted_private_chat',
initial_state: [], initial_state: [],
@ -290,6 +300,21 @@ async function unban(roomId, userId) {
return result; 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) { async function setPowerLevel(roomId, userId, powerLevel) {
const mx = initMatrix.matrixClient; const mx = initMatrix.matrixClient;
const room = mx.getRoom(roomId); const room = mx.getRoom(roomId);
@ -300,9 +325,37 @@ async function setPowerLevel(roomId, userId, powerLevel) {
return result; 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 { export {
convertToDm,
convertToRoom,
join, leave, join, leave,
createDM, createRoom, createDM, createRoom,
invite, kick, ban, unban, invite, kick, ban, unban,
ignore, unignore,
setPowerLevel, setPowerLevel,
setMyRoomNick, setMyRoomAvatar,
}; };

View file

@ -257,10 +257,10 @@ class RoomList extends EventEmitter {
const latestMDirects = this.getMDirects(); const latestMDirects = this.getMDirects();
latestMDirects.forEach((directId) => { latestMDirects.forEach((directId) => {
const myRoom = this.matrixClient.getRoom(directId);
if (this.mDirects.has(directId)) return; if (this.mDirects.has(directId)) return;
this.mDirects.add(directId); this.mDirects.add(directId);
const myRoom = this.matrixClient.getRoom(directId);
if (myRoom === null) return; if (myRoom === null) return;
if (myRoom.getMyMembership() === 'join') { if (myRoom.getMyMembership() === 'join') {
this.directs.add(directId); this.directs.add(directId);
@ -268,6 +268,19 @@ class RoomList extends EventEmitter {
this.emit(cons.events.roomList.ROOMLIST_UPDATED); 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) => { this.matrixClient.on('Room.name', (room) => {