refactor(notifications): collapse the push-rule matrices into compact controls, preserving every rule id
This commit is contained in:
parent
5843d75d89
commit
083c8e7149
3 changed files with 160 additions and 189 deletions
|
|
@ -6,7 +6,7 @@ import { AccountDataEvent } from '../../../../types/matrix/accountData';
|
||||||
import { NotificationModeSwitcher } from './NotificationModeSwitcher';
|
import { NotificationModeSwitcher } from './NotificationModeSwitcher';
|
||||||
import { SettingTile } from '../../../components/setting-tile';
|
import { SettingTile } from '../../../components/setting-tile';
|
||||||
import { SettingsSection } from '../SettingsSection';
|
import { SettingsSection } from '../SettingsSection';
|
||||||
import { PushRuleData, usePushRule } from '../../../hooks/usePushRule';
|
import { getPushRule, PushRuleData, usePushRule } from '../../../hooks/usePushRule';
|
||||||
import {
|
import {
|
||||||
getNotificationModeActions,
|
getNotificationModeActions,
|
||||||
NotificationMode,
|
NotificationMode,
|
||||||
|
|
@ -14,6 +14,22 @@ import {
|
||||||
} from '../../../hooks/useNotificationMode';
|
} from '../../../hooks/useNotificationMode';
|
||||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||||
|
|
||||||
|
// The four global underride rules that govern "all messages" notifications.
|
||||||
|
// They are written in lockstep behind one consolidated control so a single
|
||||||
|
// "Default for new chats" choice fans out to DM / encrypted DM / rooms /
|
||||||
|
// encrypted rooms. NEVER drop a ruleId here — a missing one silently stops
|
||||||
|
// notifying (e.g. encrypted rooms) for that surface.
|
||||||
|
const ALL_MESSAGE_RULES: {
|
||||||
|
ruleId: RuleId.DM | RuleId.EncryptedDM | RuleId.Message | RuleId.EncryptedMessage;
|
||||||
|
encrypted: boolean;
|
||||||
|
oneToOne: boolean;
|
||||||
|
}[] = [
|
||||||
|
{ ruleId: RuleId.DM, encrypted: false, oneToOne: true },
|
||||||
|
{ ruleId: RuleId.EncryptedDM, encrypted: true, oneToOne: true },
|
||||||
|
{ ruleId: RuleId.Message, encrypted: false, oneToOne: false },
|
||||||
|
{ ruleId: RuleId.EncryptedMessage, encrypted: true, oneToOne: false },
|
||||||
|
];
|
||||||
|
|
||||||
const getAllMessageDefaultRule = (
|
const getAllMessageDefaultRule = (
|
||||||
ruleId: RuleId,
|
ruleId: RuleId,
|
||||||
encrypted: boolean,
|
encrypted: boolean,
|
||||||
|
|
@ -43,29 +59,34 @@ const getAllMessageDefaultRule = (
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type PushRulesProps = {
|
function AllMessagesModeSwitcher({ pushRules }: { pushRules: IPushRules }) {
|
||||||
ruleId: RuleId.DM | RuleId.EncryptedDM | RuleId.Message | RuleId.EncryptedMessage;
|
|
||||||
pushRules: IPushRules;
|
|
||||||
encrypted?: boolean;
|
|
||||||
oneToOne?: boolean;
|
|
||||||
};
|
|
||||||
function AllMessagesModeSwitcher({
|
|
||||||
ruleId,
|
|
||||||
pushRules,
|
|
||||||
encrypted = false,
|
|
||||||
oneToOne = false,
|
|
||||||
}: PushRulesProps) {
|
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const defaultPushRuleData = getAllMessageDefaultRule(ruleId, encrypted, oneToOne);
|
|
||||||
const { kind, pushRule } = usePushRule(pushRules, ruleId) ?? defaultPushRuleData;
|
|
||||||
const getModeActions = useNotificationModeActions();
|
const getModeActions = useNotificationModeActions();
|
||||||
|
|
||||||
|
// Use the DM rule as the representative selected state — all four are kept in
|
||||||
|
// lockstep so any of them reflects the consolidated mode.
|
||||||
|
const representative = ALL_MESSAGE_RULES[0];
|
||||||
|
const defaultRepresentative = getAllMessageDefaultRule(
|
||||||
|
representative.ruleId,
|
||||||
|
representative.encrypted,
|
||||||
|
representative.oneToOne
|
||||||
|
);
|
||||||
|
const { pushRule } = usePushRule(pushRules, representative.ruleId) ?? defaultRepresentative;
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
async (mode: NotificationMode) => {
|
async (mode: NotificationMode) => {
|
||||||
const actions = getModeActions(mode);
|
const actions = getModeActions(mode);
|
||||||
await mx.setPushRuleActions('global', kind, ruleId, actions);
|
// Fan the choice across ALL four underride rules so encrypted rooms never
|
||||||
|
// silently fall out of sync.
|
||||||
|
await Promise.all(
|
||||||
|
ALL_MESSAGE_RULES.map(({ ruleId, encrypted, oneToOne }) => {
|
||||||
|
const { kind } =
|
||||||
|
getPushRule(pushRules, ruleId) ?? getAllMessageDefaultRule(ruleId, encrypted, oneToOne);
|
||||||
|
return mx.setPushRuleActions('global', kind, ruleId, actions);
|
||||||
|
})
|
||||||
|
);
|
||||||
},
|
},
|
||||||
[mx, getModeActions, kind, ruleId]
|
[mx, getModeActions, pushRules]
|
||||||
);
|
);
|
||||||
|
|
||||||
return <NotificationModeSwitcher pushRule={pushRule} onChange={handleChange} />;
|
return <NotificationModeSwitcher pushRule={pushRule} onChange={handleChange} />;
|
||||||
|
|
@ -82,33 +103,9 @@ export function AllMessagesNotifications() {
|
||||||
return (
|
return (
|
||||||
<SettingsSection label={t('Settings.all_messages')}>
|
<SettingsSection label={t('Settings.all_messages')}>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title={t('Settings.one_to_one')}
|
title={t('Settings.default_for_new_chats')}
|
||||||
after={<AllMessagesModeSwitcher pushRules={pushRules} ruleId={RuleId.DM} oneToOne />}
|
description={t('Settings.default_for_new_chats_desc')}
|
||||||
/>
|
after={<AllMessagesModeSwitcher pushRules={pushRules} />}
|
||||||
<SettingTile
|
|
||||||
title={t('Settings.one_to_one_encrypted')}
|
|
||||||
after={
|
|
||||||
<AllMessagesModeSwitcher
|
|
||||||
pushRules={pushRules}
|
|
||||||
ruleId={RuleId.EncryptedDM}
|
|
||||||
encrypted
|
|
||||||
oneToOne
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<SettingTile
|
|
||||||
title={t('Settings.rooms')}
|
|
||||||
after={<AllMessagesModeSwitcher pushRules={pushRules} ruleId={RuleId.Message} />}
|
|
||||||
/>
|
|
||||||
<SettingTile
|
|
||||||
title={t('Settings.rooms_encrypted')}
|
|
||||||
after={
|
|
||||||
<AllMessagesModeSwitcher
|
|
||||||
pushRules={pushRules}
|
|
||||||
ruleId={RuleId.EncryptedMessage}
|
|
||||||
encrypted
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,25 @@
|
||||||
import {
|
import { Box, color, config, Icon, Icons, IconSrc, Spinner, toRem } from 'folds';
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
config,
|
|
||||||
Icon,
|
|
||||||
Icons,
|
|
||||||
Menu,
|
|
||||||
MenuItem,
|
|
||||||
PopOut,
|
|
||||||
RectCords,
|
|
||||||
Spinner,
|
|
||||||
Text,
|
|
||||||
} from 'folds';
|
|
||||||
import { IPushRule } from 'matrix-js-sdk';
|
import { IPushRule } from 'matrix-js-sdk';
|
||||||
import React, { MouseEventHandler, useMemo, useState } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import FocusTrap from 'focus-trap-react';
|
|
||||||
import { NotificationMode, useNotificationActionsMode } from '../../../hooks/useNotificationMode';
|
import { NotificationMode, useNotificationActionsMode } from '../../../hooks/useNotificationMode';
|
||||||
import { stopPropagation } from '../../../utils/keyboard';
|
|
||||||
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
||||||
|
|
||||||
export const useNotificationModes = (): NotificationMode[] =>
|
export const useNotificationModes = (): NotificationMode[] =>
|
||||||
useMemo(() => [NotificationMode.NotifyLoud, NotificationMode.Notify, NotificationMode.OFF], []);
|
useMemo(() => [NotificationMode.NotifyLoud, NotificationMode.Notify, NotificationMode.OFF], []);
|
||||||
|
|
||||||
|
// Mirror the per-room bell language (getRoomNotificationModeIcon): loud = ring,
|
||||||
|
// silent = ping, off = mute.
|
||||||
|
const useNotificationModeIcon = (): Record<NotificationMode, IconSrc> =>
|
||||||
|
useMemo(
|
||||||
|
() => ({
|
||||||
|
[NotificationMode.NotifyLoud]: Icons.BellRing,
|
||||||
|
[NotificationMode.Notify]: Icons.BellPing,
|
||||||
|
[NotificationMode.OFF]: Icons.BellMute,
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const useNotificationModeStr = (): Record<NotificationMode, string> => {
|
const useNotificationModeStr = (): Record<NotificationMode, string> => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return useMemo(
|
return useMemo(
|
||||||
|
|
@ -40,81 +38,63 @@ type NotificationModeSwitcherProps = {
|
||||||
};
|
};
|
||||||
export function NotificationModeSwitcher({ pushRule, onChange }: NotificationModeSwitcherProps) {
|
export function NotificationModeSwitcher({ pushRule, onChange }: NotificationModeSwitcherProps) {
|
||||||
const modes = useNotificationModes();
|
const modes = useNotificationModes();
|
||||||
|
const modeToIcon = useNotificationModeIcon();
|
||||||
const modeToStr = useNotificationModeStr();
|
const modeToStr = useNotificationModeStr();
|
||||||
const selectedMode = useNotificationActionsMode(pushRule.actions);
|
const selectedMode = useNotificationActionsMode(pushRule.actions);
|
||||||
const [changeState, change] = useAsyncCallback(onChange);
|
const [changeState, change] = useAsyncCallback(onChange);
|
||||||
const changing = changeState.status === AsyncStatus.Loading;
|
const changing = changeState.status === AsyncStatus.Loading;
|
||||||
|
|
||||||
const [menuCords, setMenuCords] = useState<RectCords>();
|
|
||||||
|
|
||||||
const handleMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
|
||||||
setMenuCords(evt.currentTarget.getBoundingClientRect());
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSelect = (mode: NotificationMode) => {
|
|
||||||
setMenuCords(undefined);
|
|
||||||
change(mode);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Box
|
||||||
<Button
|
shrink="No"
|
||||||
size="300"
|
alignItems="Center"
|
||||||
variant="Secondary"
|
gap="0"
|
||||||
outlined
|
style={{
|
||||||
fill="Soft"
|
position: 'relative',
|
||||||
radii="300"
|
padding: toRem(2),
|
||||||
after={
|
borderRadius: config.radii.Pill,
|
||||||
changing ? (
|
backgroundColor: color.SurfaceVariant.Container,
|
||||||
<Spinner variant="Secondary" size="300" />
|
opacity: changing ? 0.6 : undefined,
|
||||||
) : (
|
|
||||||
<Icon size="300" src={Icons.ChevronBottom} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onClick={handleMenu}
|
|
||||||
disabled={changing}
|
|
||||||
>
|
|
||||||
<Text size="T300">{modeToStr[selectedMode]}</Text>
|
|
||||||
</Button>
|
|
||||||
<PopOut
|
|
||||||
anchor={menuCords}
|
|
||||||
offset={5}
|
|
||||||
position="Bottom"
|
|
||||||
align="End"
|
|
||||||
content={
|
|
||||||
<FocusTrap
|
|
||||||
focusTrapOptions={{
|
|
||||||
initialFocus: false,
|
|
||||||
onDeactivate: () => setMenuCords(undefined),
|
|
||||||
clickOutsideDeactivates: true,
|
|
||||||
isKeyForward: (evt: KeyboardEvent) =>
|
|
||||||
evt.key === 'ArrowDown' || evt.key === 'ArrowRight',
|
|
||||||
isKeyBackward: (evt: KeyboardEvent) =>
|
|
||||||
evt.key === 'ArrowUp' || evt.key === 'ArrowLeft',
|
|
||||||
escapeDeactivates: stopPropagation,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Menu>
|
{modes.map((mode) => {
|
||||||
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
const selected = mode === selectedMode;
|
||||||
{modes.map((mode) => (
|
return (
|
||||||
<MenuItem
|
<button
|
||||||
key={mode}
|
key={mode}
|
||||||
size="300"
|
type="button"
|
||||||
variant="Surface"
|
aria-label={modeToStr[mode]}
|
||||||
aria-selected={mode === selectedMode}
|
aria-pressed={selected}
|
||||||
radii="300"
|
title={modeToStr[mode]}
|
||||||
onClick={() => handleSelect(mode)}
|
disabled={changing}
|
||||||
|
onClick={() => change(mode)}
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: toRem(32),
|
||||||
|
height: toRem(28),
|
||||||
|
border: 'none',
|
||||||
|
cursor: changing ? 'default' : 'pointer',
|
||||||
|
borderRadius: config.radii.Pill,
|
||||||
|
backgroundColor: selected ? color.Primary.Main : 'transparent',
|
||||||
|
color: selected ? color.Primary.OnMain : color.SurfaceVariant.OnContainer,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Box grow="Yes">
|
<Icon
|
||||||
<Text size="T300">{modeToStr[mode]}</Text>
|
size="100"
|
||||||
</Box>
|
src={modeToIcon[mode]}
|
||||||
</MenuItem>
|
filled={selected}
|
||||||
))}
|
style={{ color: 'inherit' }}
|
||||||
</Box>
|
|
||||||
</Menu>
|
|
||||||
</FocusTrap>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{changing && (
|
||||||
|
<Box alignItems="Center" justifyContent="Center" style={{ position: 'absolute', inset: 0 }}>
|
||||||
|
<Spinner variant="Secondary" size="300" />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,13 @@ import { SettingTile } from '../../../components/setting-tile';
|
||||||
import { SettingsSection } from '../SettingsSection';
|
import { SettingsSection } from '../SettingsSection';
|
||||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||||
import { useAuthedUserId } from '../../../hooks/useAuthedUserId';
|
import { useAuthedUserId } from '../../../hooks/useAuthedUserId';
|
||||||
import { useUserProfile } from '../../../hooks/useUserProfile';
|
|
||||||
import { getMxIdLocalPart } from '../../../utils/matrix';
|
import { getMxIdLocalPart } from '../../../utils/matrix';
|
||||||
import { makePushRuleData, PushRuleData, usePushRule } from '../../../hooks/usePushRule';
|
import {
|
||||||
|
getPushRule,
|
||||||
|
makePushRuleData,
|
||||||
|
PushRuleData,
|
||||||
|
usePushRule,
|
||||||
|
} from '../../../hooks/usePushRule';
|
||||||
import {
|
import {
|
||||||
getNotificationModeActions,
|
getNotificationModeActions,
|
||||||
NotificationMode,
|
NotificationMode,
|
||||||
|
|
@ -89,23 +93,39 @@ const DefaultAtRoomNotification = makePushRuleData(
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
type PushRulesProps = {
|
type RuleGroupEntry = {
|
||||||
ruleId: RuleId;
|
ruleId: RuleId;
|
||||||
pushRules: IPushRules;
|
getDefault: () => PushRuleData;
|
||||||
defaultPushRuleData: PushRuleData;
|
|
||||||
};
|
};
|
||||||
function MentionModeSwitcher({ ruleId, pushRules, defaultPushRuleData }: PushRulesProps) {
|
|
||||||
const mx = useMatrixClient();
|
|
||||||
|
|
||||||
const { kind, pushRule } = usePushRule(pushRules, ruleId) ?? defaultPushRuleData;
|
// One consolidated "Mentions" control fans across the three personal-mention
|
||||||
|
// rules; one "@room" control fans across the two room-wide announcement rules.
|
||||||
|
// Every ruleId is still written behind the grouped control — a dropped ruleId
|
||||||
|
// silently breaks mention notifications.
|
||||||
|
type MentionGroupSwitcherProps = {
|
||||||
|
pushRules: IPushRules;
|
||||||
|
group: RuleGroupEntry[];
|
||||||
|
};
|
||||||
|
function MentionGroupSwitcher({ pushRules, group }: MentionGroupSwitcherProps) {
|
||||||
|
const mx = useMatrixClient();
|
||||||
const getModeActions = useNotificationModeActions(NOTIFY_MODE_OPS);
|
const getModeActions = useNotificationModeActions(NOTIFY_MODE_OPS);
|
||||||
|
|
||||||
|
// First rule in the group is the representative for the displayed mode; all
|
||||||
|
// rules in the group are written in lockstep.
|
||||||
|
const representative = group[0];
|
||||||
|
const { pushRule } = usePushRule(pushRules, representative.ruleId) ?? representative.getDefault();
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
async (mode: NotificationMode) => {
|
async (mode: NotificationMode) => {
|
||||||
const actions = getModeActions(mode);
|
const actions = getModeActions(mode);
|
||||||
await mx.setPushRuleActions('global', kind, ruleId, actions);
|
await Promise.all(
|
||||||
|
group.map(({ ruleId, getDefault }) => {
|
||||||
|
const { kind } = getPushRule(pushRules, ruleId) ?? getDefault();
|
||||||
|
return mx.setPushRuleActions('global', kind, ruleId, actions);
|
||||||
|
})
|
||||||
|
);
|
||||||
},
|
},
|
||||||
[mx, getModeActions, kind, ruleId]
|
[mx, getModeActions, pushRules, group]
|
||||||
);
|
);
|
||||||
|
|
||||||
return <NotificationModeSwitcher pushRule={pushRule} onChange={handleChange} />;
|
return <NotificationModeSwitcher pushRule={pushRule} onChange={handleChange} />;
|
||||||
|
|
@ -114,68 +134,42 @@ function MentionModeSwitcher({ ruleId, pushRules, defaultPushRuleData }: PushRul
|
||||||
export function SpecialMessagesNotifications() {
|
export function SpecialMessagesNotifications() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const userId = useAuthedUserId();
|
const userId = useAuthedUserId();
|
||||||
const { displayName } = useUserProfile(userId);
|
|
||||||
const pushRulesEvt = useAccountData(AccountDataEvent.PushRules);
|
const pushRulesEvt = useAccountData(AccountDataEvent.PushRules);
|
||||||
const pushRules = useMemo(
|
const pushRules = useMemo(
|
||||||
() => pushRulesEvt?.getContent<IPushRules>() ?? { global: {} },
|
() => pushRulesEvt?.getContent<IPushRules>() ?? { global: {} },
|
||||||
[pushRulesEvt]
|
[pushRulesEvt]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const username = getMxIdLocalPart(userId) ?? userId;
|
||||||
|
|
||||||
|
const mentionGroup = useMemo<RuleGroupEntry[]>(
|
||||||
|
() => [
|
||||||
|
{ ruleId: RuleId.IsUserMention, getDefault: () => getDefaultIsUserMention(userId) },
|
||||||
|
{ ruleId: RuleId.ContainsDisplayName, getDefault: () => DefaultContainsDisplayName },
|
||||||
|
{ ruleId: RuleId.ContainsUserName, getDefault: () => getDefaultContainsUsername(username) },
|
||||||
|
],
|
||||||
|
[userId, username]
|
||||||
|
);
|
||||||
|
|
||||||
|
const roomGroup = useMemo<RuleGroupEntry[]>(
|
||||||
|
() => [
|
||||||
|
{ ruleId: RuleId.IsRoomMention, getDefault: () => DefaultIsRoomMention },
|
||||||
|
{ ruleId: RuleId.AtRoomNotification, getDefault: () => DefaultAtRoomNotification },
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsSection label={t('Settings.special_messages')}>
|
<SettingsSection label={t('Settings.special_messages')}>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title={t('Settings.mention_user_id', { userId })}
|
title={t('Settings.notify_on_mention')}
|
||||||
after={
|
description={t('Settings.notify_on_mention_desc')}
|
||||||
<MentionModeSwitcher
|
after={<MentionGroupSwitcher pushRules={pushRules} group={mentionGroup} />}
|
||||||
pushRules={pushRules}
|
|
||||||
ruleId={RuleId.IsUserMention}
|
|
||||||
defaultPushRuleData={getDefaultIsUserMention(userId)}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title={
|
title={t('Settings.room_announcements')}
|
||||||
displayName
|
description={t('Settings.room_announcements_desc')}
|
||||||
? t('Settings.contains_displayname_value', { displayName })
|
after={<MentionGroupSwitcher pushRules={pushRules} group={roomGroup} />}
|
||||||
: t('Settings.contains_displayname')
|
|
||||||
}
|
|
||||||
after={
|
|
||||||
<MentionModeSwitcher
|
|
||||||
pushRules={pushRules}
|
|
||||||
ruleId={RuleId.ContainsDisplayName}
|
|
||||||
defaultPushRuleData={DefaultContainsDisplayName}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<SettingTile
|
|
||||||
title={t('Settings.contains_username', { username: getMxIdLocalPart(userId) })}
|
|
||||||
after={
|
|
||||||
<MentionModeSwitcher
|
|
||||||
pushRules={pushRules}
|
|
||||||
ruleId={RuleId.ContainsUserName}
|
|
||||||
defaultPushRuleData={getDefaultContainsUsername(getMxIdLocalPart(userId) ?? userId)}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<SettingTile
|
|
||||||
title={t('Settings.mention_room')}
|
|
||||||
after={
|
|
||||||
<MentionModeSwitcher
|
|
||||||
pushRules={pushRules}
|
|
||||||
ruleId={RuleId.IsRoomMention}
|
|
||||||
defaultPushRuleData={DefaultIsRoomMention}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<SettingTile
|
|
||||||
title={t('Settings.contains_room')}
|
|
||||||
after={
|
|
||||||
<MentionModeSwitcher
|
|
||||||
pushRules={pushRules}
|
|
||||||
ruleId={RuleId.AtRoomNotification}
|
|
||||||
defaultPushRuleData={DefaultAtRoomNotification}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue