--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
+<g>
+ <path d="M12,22c1.1,0,2-0.9,2-2h-4C10,21.1,10.9,22,12,22z"/>
+ <path d="M20.1,18.1L20.1,18.1L16,14L9.2,7.2L7.8,5.8L5.9,3.9L4.5,5.3l2.1,2.1C6.2,8.2,6,9.1,6,10v6H4v2h13.2l1.5,1.5L20.1,18.1z
+ M8,16v-6c0-0.4,0.1-0.7,0.1-1l7,7H8z"/>
+ <path d="M12,6c2.2,0,4,1.8,4,4v1.2l2,2V10c0-3-2.2-5.4-5-5.9V3h-2v1.1c-0.6,0.1-1.1,0.3-1.6,0.5L11,6.1C11.3,6.1,11.6,6,12,6z"/>
+</g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
+<g>
+ <circle cx="17" cy="8" r="3"/>
+ <path d="M12,22c1.1,0,2-0.9,2-2h-4C10,21.1,10.9,22,12,22z"/>
+ <path d="M18,12.9C17.7,13,17.3,13,17,13s-0.7,0-1-0.1V16H8v-6c0-2.2,1.8-4,4-4c0.1,0,0.3,0,0.4,0c0.3-0.7,0.7-1.3,1.3-1.8
+ c-0.2-0.1-0.5-0.1-0.7-0.2V3h-2v1.1C8.2,4.6,6,7,6,10v6H4v2h16v-2h-2V12.9z"/>
+ <path d="M6.3,4.3L4.9,2.9C3.1,4.7,2,7.2,2,10h2C4,7.8,4.9,5.8,6.3,4.3z"/>
+</g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
+<g>
+ <path d="M12,22c1.1,0,2-0.9,2-2h-4C10,21.1,10.9,22,12,22z"/>
+ <path d="M18,10c0-3-2.2-5.4-5-5.9V3h-2v1.1C8.2,4.6,6,7,6,10v6H4v2h16v-2h-2V10z M16,16H8v-6c0-2.2,1.8-4,4-4s4,1.8,4,4V16z"/>
+ <path d="M6.3,4.3L4.9,2.9C3.1,4.7,2,7.2,2,10h2C4,7.8,4.9,5.8,6.3,4.3z"/>
+ <path d="M19.1,2.9l-1.4,1.4C19.1,5.8,20,7.8,20,10h2C22,7.2,20.9,4.7,19.1,2.9z"/>
+</g>
+</svg>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<g>
- <path d="M12,4c2.8,0,5,2.2,5,5v4v0.8l0.6,0.6l0.6,0.6H5.8l0.6-0.6L7,13.8V13V9C7,6.2,9.2,4,12,4 M12,2C8.1,2,5,5.1,5,9v4l-2,2v2h18
- v-2l-2-2V9C19,5.1,15.9,2,12,2L12,2z"/>
- <path d="M9,19c0,1.7,1.3,3,3,3s3-1.3,3-3H9z"/>
+ <path d="M12,22c1.1,0,2-0.9,2-2h-4C10,21.1,10.9,22,12,22z"/>
+ <path d="M18,16v-6c0-3-2.2-5.4-5-5.9V3h-2v1.1C8.2,4.6,6,7,6,10v6H4v2h16v-2H18z M16,16H8v-6c0-2.2,1.8-4,4-4s4,1.8,4,4V16z"/>
</g>
</svg>
--- /dev/null
+import React, { useState, useEffect, useRef } from 'react';
+import './RoomOptions.scss';
+
+import initMatrix from '../../../client/initMatrix';
+import cons from '../../../client/state/cons';
+import navigation from '../../../client/state/navigation';
+import { openInviteUser } from '../../../client/action/navigation';
+import * as roomActions from '../../../client/action/room';
+
+import ContextMenu, { MenuHeader, MenuItem } from '../../atoms/context-menu/ContextMenu';
+
+import BellIC from '../../../../public/res/ic/outlined/bell.svg';
+import BellRingIC from '../../../../public/res/ic/outlined/bell-ring.svg';
+import BellPingIC from '../../../../public/res/ic/outlined/bell-ping.svg';
+import BellOffIC from '../../../../public/res/ic/outlined/bell-off.svg';
+import AddUserIC from '../../../../public/res/ic/outlined/add-user.svg';
+import LeaveArrowIC from '../../../../public/res/ic/outlined/leave-arrow.svg';
+
+function getNotifState(roomId) {
+ const mx = initMatrix.matrixClient;
+ const pushRule = mx.getRoomPushRule('global', roomId);
+
+ if (typeof pushRule === 'undefined') {
+ const overridePushRules = mx.getAccountData('m.push_rules')?.getContent()?.global?.override;
+ if (typeof overridePushRules === 'undefined') return 0;
+
+ const isMuteOverride = overridePushRules.find((rule) => (
+ rule.rule_id === roomId
+ && rule.actions[0] === 'dont_notify'
+ && rule.conditions[0].kind === 'event_match'
+ ));
+
+ return isMuteOverride ? cons.notifs.MUTE : cons.notifs.DEFAULT;
+ }
+ if (pushRule.actions[0] === 'notify') return cons.notifs.ALL_MESSAGES;
+ return cons.notifs.MENTIONS_AND_KEYWORDS;
+}
+
+function setRoomNotifMute(roomId) {
+ const mx = initMatrix.matrixClient;
+ const roomPushRule = mx.getRoomPushRule('global', roomId);
+
+ const promises = [];
+ if (roomPushRule) {
+ promises.push(mx.deletePushRule('global', 'room', roomPushRule.rule_id));
+ }
+
+ promises.push(mx.addPushRule('global', 'override', roomId, {
+ conditions: [
+ {
+ kind: 'event_match',
+ key: 'room_id',
+ pattern: roomId,
+ },
+ ],
+ actions: [
+ 'dont_notify',
+ ],
+ }));
+
+ return Promise.all(promises);
+}
+
+function setRoomNotifsState(newState, roomId) {
+ const mx = initMatrix.matrixClient;
+ const promises = [];
+
+ const oldState = getNotifState(roomId);
+ if (oldState === cons.notifs.MUTE) {
+ promises.push(mx.deletePushRule('global', 'override', roomId));
+ }
+
+ if (newState === cons.notifs.DEFAULT) {
+ const roomPushRule = mx.getRoomPushRule('global', roomId);
+ if (roomPushRule) {
+ promises.push(mx.deletePushRule('global', 'room', roomPushRule.rule_id));
+ }
+ return Promise.all(promises);
+ }
+
+ if (newState === cons.notifs.MENTIONS_AND_KEYWORDS) {
+ promises.push(mx.addPushRule('global', 'room', roomId, {
+ actions: [
+ 'dont_notify',
+ ],
+ }));
+ promises.push(mx.setPushRuleEnabled('global', 'room', roomId, true));
+ return Promise.all(promises);
+ }
+
+ // cons.notifs.ALL_MESSAGES
+ promises.push(mx.addPushRule('global', 'room', roomId, {
+ actions: [
+ 'notify',
+ {
+ set_tweak: 'sound',
+ value: 'default',
+ },
+ ],
+ }));
+
+ promises.push(mx.setPushRuleEnabled('global', 'room', roomId, true));
+
+ return Promise.all(promises);
+}
+
+function setRoomNotifPushRule(notifState, roomId) {
+ if (notifState === cons.notifs.MUTE) {
+ setRoomNotifMute(roomId);
+ return;
+ }
+ setRoomNotifsState(notifState, roomId);
+}
+
+let isRoomOptionVisible = false;
+let roomId = null;
+function RoomOptions() {
+ const openerRef = useRef(null);
+ const [notifState, setNotifState] = useState(cons.notifs.DEFAULT);
+
+ function openRoomOptions(cords, rId) {
+ if (roomId !== null || isRoomOptionVisible) {
+ roomId = null;
+ if (cords.detail === 0) openerRef.current.click();
+ return;
+ }
+ openerRef.current.style.transform = `translate(${cords.x}px, ${cords.y}px)`;
+ roomId = rId;
+ setNotifState(getNotifState(roomId));
+ openerRef.current.click();
+ }
+
+ function afterRoomOptionsToggle(isVisible) {
+ isRoomOptionVisible = isVisible;
+ if (!isVisible) {
+ setTimeout(() => {
+ if (!isRoomOptionVisible) roomId = null;
+ }, 500);
+ }
+ }
+
+ useEffect(() => {
+ navigation.on(cons.events.navigation.ROOMOPTIONS_OPENED, openRoomOptions);
+ return () => {
+ navigation.on(cons.events.navigation.ROOMOPTIONS_OPENED, openRoomOptions);
+ };
+ }, []);
+
+ const handleInviteClick = () => openInviteUser(roomId);
+ const handleLeaveClick = () => {
+ if (confirm('Are you really want to leave this room?')) roomActions.leave(roomId);
+ };
+
+ function setNotif(nState, currentNState) {
+ if (nState === currentNState) return;
+ setRoomNotifPushRule(nState, roomId);
+ setNotifState(nState);
+ }
+
+ return (
+ <ContextMenu
+ afterToggle={afterRoomOptionsToggle}
+ maxWidth={298}
+ content={(toggleMenu) => (
+ <>
+ <MenuHeader>{`Options for ${initMatrix.matrixClient.getRoom(roomId)?.name}`}</MenuHeader>
+ <MenuItem
+ iconSrc={AddUserIC}
+ onClick={() => {
+ handleInviteClick(); toggleMenu();
+ }}
+ >
+ Invite
+ </MenuItem>
+ <MenuItem iconSrc={LeaveArrowIC} variant="danger" onClick={handleLeaveClick}>Leave</MenuItem>
+ <MenuHeader>Notification</MenuHeader>
+ <MenuItem
+ variant={notifState === cons.notifs.DEFAULT ? 'positive' : 'surface'}
+ iconSrc={BellIC}
+ onClick={() => setNotif(cons.notifs.DEFAULT, notifState)}
+ >
+ Default
+ </MenuItem>
+ <MenuItem
+ variant={notifState === cons.notifs.ALL_MESSAGES ? 'positive' : 'surface'}
+ iconSrc={BellRingIC}
+ onClick={() => setNotif(cons.notifs.ALL_MESSAGES, notifState)}
+ >
+ All messages
+ </MenuItem>
+ <MenuItem
+ variant={notifState === cons.notifs.MENTIONS_AND_KEYWORDS ? 'positive' : 'surface'}
+ iconSrc={BellPingIC}
+ onClick={() => setNotif(cons.notifs.MENTIONS_AND_KEYWORDS, notifState)}
+ >
+ Mentions & Keywords
+ </MenuItem>
+ <MenuItem
+ variant={notifState === cons.notifs.MUTE ? 'positive' : 'surface'}
+ iconSrc={BellOffIC}
+ onClick={() => setNotif(cons.notifs.MUTE, notifState)}
+ >
+ Mute
+ </MenuItem>
+ </>
+ )}
+ render={(toggleMenu) => (
+ <input
+ ref={openerRef}
+ onClick={toggleMenu}
+ type="button"
+ style={{
+ width: '32px',
+ height: '32px',
+ backgroundColor: 'transparent',
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ padding: 0,
+ border: 'none',
+ visibility: 'hidden',
+ }}
+ />
+ )}
+ />
+ );
+}
+
+export default RoomOptions;
--- /dev/null
+.context-menu__item {
+ position: relative;
+}
+
+.context-menu__item .btn-positive::before {
+ content: '';
+ display: inline-block;
+ width: 3px;
+ height: 12px;
+ background: var(--bg-positive);
+ border-radius: 0 4px 4px 0;
+ position: absolute;
+ left: 0;
+
+ [dir=rtl] & {
+ left: unset;
+ right: 0;
+ border-radius: 4px 0 0 4px;
+ }
+}
\ No newline at end of file
});
}
+function openRoomOptions(cords, roomId) {
+ appDispatcher.dispatch({
+ type: cons.actions.navigation.OPEN_ROOMOPTIONS,
+ cords,
+ roomId,
+ });
+}
+
export {
selectTab,
selectSpace,
openSettings,
openEmojiBoard,
openReadReceipts,
+ openRoomOptions,
};
const lastTimelineEvent = room.timeline[room.timeline.length - 1];
if (lastTimelineEvent.getId() !== event.getId()) return;
+ if (event.getSender() === this.matrixClient.getUserId()) return;
this.emit(cons.events.roomList.EVENT_ARRIVED, room.roomId);
});
}
HOME: 'home',
DIRECTS: 'dm',
},
+ notifs: {
+ DEFAULT: 'default',
+ ALL_MESSAGES: 'all_messages',
+ MENTIONS_AND_KEYWORDS: 'mentions_and_keywords',
+ MUTE: 'mute',
+ },
actions: {
navigation: {
SELECT_TAB: 'SELECT_TAB',
OPEN_SETTINGS: 'OPEN_SETTINGS',
OPEN_EMOJIBOARD: 'OPEN_EMOJIBOARD',
OPEN_READRECEIPTS: 'OPEN_READRECEIPTS',
+ OPEN_ROOMOPTIONS: 'OPEN_ROOMOPTIONS',
},
room: {
JOIN: 'JOIN',
SETTINGS_OPENED: 'SETTINGS_OPENED',
EMOJIBOARD_OPENED: 'EMOJIBOARD_OPENED',
READRECEIPTS_OPENED: 'READRECEIPTS_OPENED',
+ ROOMOPTIONS_OPENED: 'ROOMOPTIONS_OPENED',
},
roomList: {
ROOMLIST_UPDATED: 'ROOMLIST_UPDATED',
action.eventId,
);
},
+ [cons.actions.navigation.OPEN_ROOMOPTIONS]: () => {
+ this.emit(
+ cons.events.navigation.ROOMOPTIONS_OPENED,
+ action.cords,
+ action.roomId,
+ );
+ },
};
actions[action.type]?.();
}
|| dt2.getYear() !== dt1.getYear()
);
}
+
+export function getEventCords(ev) {
+ const boxInfo = ev.target.getBoundingClientRect();
+ return {
+ x: boxInfo.x,
+ y: boxInfo.y,
+ detail: ev.detail,
+ };
+}