import React, { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { ConditionKind, IPushRules, PushRuleCondition, PushRuleKind, RuleId } from 'matrix-js-sdk'; import { useAccountData } from '../../../hooks/useAccountData'; import { AccountDataEvent } from '../../../../types/matrix/accountData'; import { NotificationModeSwitcher } from './NotificationModeSwitcher'; import { SettingTile } from '../../../components/setting-tile'; import { SettingsSection } from '../SettingsSection'; import { getPushRule, PushRuleData, usePushRule } from '../../../hooks/usePushRule'; import { getNotificationModeActions, NotificationMode, useNotificationModeActions, } from '../../../hooks/useNotificationMode'; 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 = ( ruleId: RuleId, encrypted: boolean, oneToOne: boolean ): PushRuleData => { const conditions: PushRuleCondition[] = []; if (oneToOne) conditions.push({ kind: ConditionKind.RoomMemberCount, is: '2', }); conditions.push({ kind: ConditionKind.EventMatch, key: 'type', pattern: encrypted ? 'm.room.encrypted' : 'm.room.message', }); return { kind: PushRuleKind.Underride, pushRule: { rule_id: ruleId, default: true, enabled: true, conditions, actions: getNotificationModeActions(NotificationMode.NotifyLoud), }, }; }; function AllMessagesModeSwitcher({ pushRules }: { pushRules: IPushRules }) { const mx = useMatrixClient(); 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( async (mode: NotificationMode) => { const actions = getModeActions(mode); // 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, pushRules] ); return ; } export function AllMessagesNotifications() { const { t } = useTranslation(); const pushRulesEvt = useAccountData(AccountDataEvent.PushRules); const pushRules = useMemo( () => pushRulesEvt?.getContent() ?? { global: {} }, [pushRulesEvt] ); return ( } /> ); }