mirror of
https://github.com/array-in-a-matrix/xinny.git
synced 2024-05-17 20:00:17 -04:00
8583ab19f0
* Add options to display/ignore usersId's * Update string * Hide search icon in encrypted rooms (#763) * Fix styles
240 lines
7.8 KiB
JavaScript
240 lines
7.8 KiB
JavaScript
import React from 'react';
|
|
import './KeywordNotification.scss';
|
|
|
|
import initMatrix from '../../../client/initMatrix';
|
|
import { openReusableContextMenu } from '../../../client/action/navigation';
|
|
import { getEventCords } from '../../../util/common';
|
|
|
|
import Text from '../../atoms/text/Text';
|
|
import Chip from '../../atoms/chip/Chip';
|
|
import Input from '../../atoms/input/Input';
|
|
import Button from '../../atoms/button/Button';
|
|
import { MenuHeader } from '../../atoms/context-menu/ContextMenu';
|
|
import SettingTile from '../setting-tile/SettingTile';
|
|
|
|
import NotificationSelector from './NotificationSelector';
|
|
|
|
import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
|
|
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
|
|
|
|
import { useAccountData } from '../../hooks/useAccountData';
|
|
import {
|
|
notifType, typeToLabel, getActionType, getTypeActions,
|
|
} from './GlobalNotification';
|
|
|
|
const DISPLAY_NAME = '.m.rule.contains_display_name';
|
|
const ROOM_PING = '.m.rule.roomnotif';
|
|
const USERNAME = '.m.rule.contains_user_name';
|
|
const KEYWORD = 'keyword';
|
|
|
|
function useKeywordNotif() {
|
|
const mx = initMatrix.matrixClient;
|
|
const pushRules = useAccountData('m.push_rules')?.getContent();
|
|
const override = pushRules?.global?.override ?? [];
|
|
const content = pushRules?.global?.content ?? [];
|
|
|
|
const rulesToType = {
|
|
[DISPLAY_NAME]: notifType.NOISY,
|
|
[ROOM_PING]: notifType.NOISY,
|
|
[USERNAME]: notifType.NOISY,
|
|
};
|
|
|
|
const setRule = (rule, type) => {
|
|
const evtContent = pushRules ?? {};
|
|
if (!evtContent.global) evtContent.global = {};
|
|
if (!evtContent.global.override) evtContent.global.override = [];
|
|
if (!evtContent.global.content) evtContent.global.content = [];
|
|
const or = evtContent.global.override;
|
|
const ct = evtContent.global.content;
|
|
|
|
if (rule === DISPLAY_NAME || rule === ROOM_PING) {
|
|
let orRule = or.find((r) => r?.rule_id === rule);
|
|
if (!orRule) {
|
|
orRule = {
|
|
conditions: [],
|
|
actions: [],
|
|
rule_id: rule,
|
|
default: true,
|
|
enabled: true,
|
|
};
|
|
or.push(orRule);
|
|
}
|
|
if (rule === DISPLAY_NAME) {
|
|
orRule.conditions = [{ kind: 'contains_display_name' }];
|
|
orRule.actions = getTypeActions(type, true);
|
|
} else {
|
|
orRule.conditions = [
|
|
{ kind: 'event_match', key: 'content.body', pattern: '@room' },
|
|
{ kind: 'sender_notification_permission', key: 'room' },
|
|
];
|
|
orRule.actions = getTypeActions(type, true);
|
|
}
|
|
} else if (rule === USERNAME) {
|
|
let usernameRule = ct.find((r) => r?.rule_id === rule);
|
|
if (!usernameRule) {
|
|
const userId = mx.getUserId();
|
|
const username = userId.match(/^@?(\S+):(\S+)$/)?.[1] ?? userId;
|
|
usernameRule = {
|
|
actions: [],
|
|
default: true,
|
|
enabled: true,
|
|
pattern: username,
|
|
rule_id: rule,
|
|
};
|
|
ct.push(usernameRule);
|
|
}
|
|
usernameRule.actions = getTypeActions(type, true);
|
|
} else {
|
|
const keyRules = ct.filter((r) => r.rule_id !== USERNAME);
|
|
keyRules.forEach((r) => {
|
|
// eslint-disable-next-line no-param-reassign
|
|
r.actions = getTypeActions(type, true);
|
|
});
|
|
}
|
|
|
|
mx.setAccountData('m.push_rules', evtContent);
|
|
};
|
|
|
|
const addKeyword = (keyword) => {
|
|
if (content.find((r) => r.rule_id === keyword)) return;
|
|
content.push({
|
|
rule_id: keyword,
|
|
pattern: keyword,
|
|
enabled: true,
|
|
default: false,
|
|
actions: getTypeActions(rulesToType[KEYWORD] ?? notifType.NOISY, true),
|
|
});
|
|
mx.setAccountData('m.push_rules', pushRules);
|
|
};
|
|
const removeKeyword = (rule) => {
|
|
pushRules.global.content = content.filter((r) => r.rule_id !== rule.rule_id);
|
|
mx.setAccountData('m.push_rules', pushRules);
|
|
};
|
|
|
|
const dsRule = override.find((rule) => rule.rule_id === DISPLAY_NAME);
|
|
const roomRule = override.find((rule) => rule.rule_id === ROOM_PING);
|
|
const usernameRule = content.find((rule) => rule.rule_id === USERNAME);
|
|
const keywordRule = content.find((rule) => rule.rule_id !== USERNAME);
|
|
|
|
if (dsRule) rulesToType[DISPLAY_NAME] = getActionType(dsRule);
|
|
if (roomRule) rulesToType[ROOM_PING] = getActionType(roomRule);
|
|
if (usernameRule) rulesToType[USERNAME] = getActionType(usernameRule);
|
|
if (keywordRule) rulesToType[KEYWORD] = getActionType(keywordRule);
|
|
|
|
return {
|
|
rulesToType,
|
|
pushRules,
|
|
setRule,
|
|
addKeyword,
|
|
removeKeyword,
|
|
};
|
|
}
|
|
|
|
function GlobalNotification() {
|
|
const {
|
|
rulesToType,
|
|
pushRules,
|
|
setRule,
|
|
addKeyword,
|
|
removeKeyword,
|
|
} = useKeywordNotif();
|
|
|
|
const keywordRules = pushRules?.global?.content.filter((r) => r.rule_id !== USERNAME) ?? [];
|
|
|
|
const onSelect = (evt, rule) => {
|
|
openReusableContextMenu(
|
|
'bottom',
|
|
getEventCords(evt, '.btn-surface'),
|
|
(requestClose) => (
|
|
<NotificationSelector
|
|
value={rulesToType[rule]}
|
|
onSelect={(value) => {
|
|
if (rulesToType[rule] !== value) setRule(rule, value);
|
|
requestClose();
|
|
}}
|
|
/>
|
|
),
|
|
);
|
|
};
|
|
|
|
const handleSubmit = (evt) => {
|
|
evt.preventDefault();
|
|
const { keywordInput } = evt.target.elements;
|
|
const value = keywordInput.value.trim();
|
|
if (value === '') return;
|
|
addKeyword(value);
|
|
keywordInput.value = '';
|
|
};
|
|
|
|
return (
|
|
<div className="keyword-notification">
|
|
<MenuHeader>Mentions & keywords</MenuHeader>
|
|
<SettingTile
|
|
title="Message containing my display name"
|
|
options={(
|
|
<Button onClick={(evt) => onSelect(evt, DISPLAY_NAME)} iconSrc={ChevronBottomIC}>
|
|
{ typeToLabel[rulesToType[DISPLAY_NAME]] }
|
|
</Button>
|
|
)}
|
|
content={<Text variant="b3">Default notification settings for all message containing your display name.</Text>}
|
|
/>
|
|
<SettingTile
|
|
title="Message containing my username"
|
|
options={(
|
|
<Button onClick={(evt) => onSelect(evt, USERNAME)} iconSrc={ChevronBottomIC}>
|
|
{ typeToLabel[rulesToType[USERNAME]] }
|
|
</Button>
|
|
)}
|
|
content={<Text variant="b3">Default notification settings for all message containing your username.</Text>}
|
|
/>
|
|
<SettingTile
|
|
title="Message containing @room"
|
|
options={(
|
|
<Button onClick={(evt) => onSelect(evt, ROOM_PING)} iconSrc={ChevronBottomIC}>
|
|
{typeToLabel[rulesToType[ROOM_PING]]}
|
|
</Button>
|
|
)}
|
|
content={<Text variant="b3">Default notification settings for all messages containing @room.</Text>}
|
|
/>
|
|
{ rulesToType[KEYWORD] && (
|
|
<SettingTile
|
|
title="Message containing keywords"
|
|
options={(
|
|
<Button onClick={(evt) => onSelect(evt, KEYWORD)} iconSrc={ChevronBottomIC}>
|
|
{typeToLabel[rulesToType[KEYWORD]]}
|
|
</Button>
|
|
)}
|
|
content={<Text variant="b3">Default notification settings for all message containing keywords.</Text>}
|
|
/>
|
|
)}
|
|
<SettingTile
|
|
title="Keywords"
|
|
content={(
|
|
<div className="keyword-notification__keyword">
|
|
<Text variant="b3">Get notification when a message contains keyword.</Text>
|
|
<form onSubmit={handleSubmit}>
|
|
<Input name="keywordInput" required />
|
|
<Button variant="primary" type="submit">Add</Button>
|
|
</form>
|
|
{keywordRules.length > 0 && (
|
|
<div>
|
|
{keywordRules.map((rule) => (
|
|
<Chip
|
|
iconSrc={CrossIC}
|
|
key={rule.rule_id}
|
|
text={rule.pattern}
|
|
iconColor={CrossIC}
|
|
onClick={() => removeKeyword(rule)}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default GlobalNotification;
|