mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-09-07 13:51:08 +01:00
Add reset notification settings action
Co-authored-by: trevor-signal <131492920+trevor-signal@users.noreply.github.com>
This commit is contained in:
co-authored by
trevor-signal
parent
9861e36837
commit
55e9cba5fd
@@ -8232,6 +8232,22 @@
|
||||
"messageformat": "App badge",
|
||||
"description": "Preferences > Notifications > App Badge Section > Title"
|
||||
},
|
||||
"icu:Preferences__Notifications__Reset__title": {
|
||||
"messageformat": "Reset notification settings to default, including custom settings for your chats.",
|
||||
"description": "Preferences > Notifications > Reset Section > Text of the row that restores the default notification settings"
|
||||
},
|
||||
"icu:Preferences__Notifications__Reset__button": {
|
||||
"messageformat": "Reset",
|
||||
"description": "Preferences > Notifications > Reset Section > Label of the button that restores the default notification settings"
|
||||
},
|
||||
"icu:Preferences__Notifications__Reset__modal--body": {
|
||||
"messageformat": "Reset all notification settings to default for all chats?",
|
||||
"description": "Preferences > Notifications > Reset Section > Confirmation Modal > Body. The modal has no visible title, so this is the only text in it."
|
||||
},
|
||||
"icu:Preferences__Notifications__Reset__modal--confirm": {
|
||||
"messageformat": "Reset",
|
||||
"description": "Preferences > Notifications > Reset Section > Confirmation Modal > Label of the button that confirms restoring the default notification settings"
|
||||
},
|
||||
"icu:PlaintextExport--PreferencesRow--Header": {
|
||||
"messageformat": "Export chat history",
|
||||
"description": "Shown in the Preferences/Chats page, header for a row"
|
||||
|
||||
@@ -632,6 +632,7 @@ export default {
|
||||
onReactionNotificationsChange: action('onReactionNotificationsChange'),
|
||||
onReadReceiptsChange: action('onReadReceiptsChange'),
|
||||
onRelayCallsChange: action('onRelayCallsChange'),
|
||||
onResetNotificationSettings: action('onResetNotificationSettings'),
|
||||
onSealedSenderIndicatorsChange: action('onSealedSenderIndicatorsChange'),
|
||||
onSelectedCameraChange: action('onSelectedCameraChange'),
|
||||
onSelectedMicrophoneChange: action('onSelectedMicrophoneChange'),
|
||||
|
||||
@@ -100,6 +100,7 @@ import type { VisibleRemoteMegaphoneType } from '../types/Megaphone.std.ts';
|
||||
import { TitlebarDragArea } from './TitlebarDragArea.dom.tsx';
|
||||
import type { PreferredBadgeSelectorType } from '../state/selectors/badges.preload.ts';
|
||||
import { Emoji } from '../axo/emoji.std.ts';
|
||||
import { AxoAlertDialog } from '../axo/AxoAlertDialog.dom.tsx';
|
||||
import { AxoConfirmDialog } from '../axo/AxoConfirmDialog.dom.tsx';
|
||||
import moment from 'moment';
|
||||
import { AxoItem } from '../axo/items/AxoItem.dom.tsx';
|
||||
@@ -364,6 +365,7 @@ type PropsFunctionType = {
|
||||
onReactionNotificationsChange: CheckboxChangeHandlerType;
|
||||
onReadReceiptsChange: CheckboxChangeHandlerType;
|
||||
onRelayCallsChange: CheckboxChangeHandlerType;
|
||||
onResetNotificationSettings: () => unknown;
|
||||
onSealedSenderIndicatorsChange: CheckboxChangeHandlerType;
|
||||
onSelectedCameraChange: SelectChangeHandlerType<string | undefined>;
|
||||
onSelectedMicrophoneChange: SelectChangeHandlerType<AudioDevice | undefined>;
|
||||
@@ -561,6 +563,7 @@ export function Preferences({
|
||||
onReactionNotificationsChange,
|
||||
onReadReceiptsChange,
|
||||
onRelayCallsChange,
|
||||
onResetNotificationSettings,
|
||||
onSealedSenderIndicatorsChange,
|
||||
onSelectedCameraChange,
|
||||
onSelectedMicrophoneChange,
|
||||
@@ -658,6 +661,8 @@ export function Preferences({
|
||||
const [confirmStoriesOff, setConfirmStoriesOff] = useState(false);
|
||||
const [confirmContentProtection, setConfirmContentProtection] =
|
||||
useState(false);
|
||||
const [confirmResetNotifications, setConfirmResetNotifications] =
|
||||
useState(false);
|
||||
const [showSyncFailed, setShowSyncFailed] = useState(false);
|
||||
const [nowSyncing, setNowSyncing] = useState(false);
|
||||
const [showDisappearingTimerDialog, setShowDisappearingTimerDialog] =
|
||||
@@ -1608,6 +1613,46 @@ export function Preferences({
|
||||
}
|
||||
/>
|
||||
</List>
|
||||
|
||||
<List>
|
||||
<ItemWithAction
|
||||
title={i18n('icu:Preferences__Notifications__Reset__title')}
|
||||
action={
|
||||
<AxoItem.Action
|
||||
variant="subtle-destructive"
|
||||
onClick={() => setConfirmResetNotifications(true)}
|
||||
>
|
||||
{i18n('icu:Preferences__Notifications__Reset__button')}
|
||||
</AxoItem.Action>
|
||||
}
|
||||
/>
|
||||
<AxoAlertDialog.Root
|
||||
open={confirmResetNotifications}
|
||||
onOpenChange={setConfirmResetNotifications}
|
||||
>
|
||||
<AxoAlertDialog.Content escape="cancel-is-noop">
|
||||
<AxoAlertDialog.Title screenReaderOnly>
|
||||
{i18n('icu:Preferences__Notifications__Reset__title')}
|
||||
</AxoAlertDialog.Title>
|
||||
<AxoAlertDialog.Body>
|
||||
<AxoAlertDialog.Description>
|
||||
{i18n('icu:Preferences__Notifications__Reset__modal--body')}
|
||||
</AxoAlertDialog.Description>
|
||||
</AxoAlertDialog.Body>
|
||||
<AxoAlertDialog.Footer>
|
||||
<AxoAlertDialog.Cancel />
|
||||
<AxoAlertDialog.Action
|
||||
variant="strong-destructive"
|
||||
onClick={onResetNotificationSettings}
|
||||
>
|
||||
{i18n(
|
||||
'icu:Preferences__Notifications__Reset__modal--confirm'
|
||||
)}
|
||||
</AxoAlertDialog.Action>
|
||||
</AxoAlertDialog.Footer>
|
||||
</AxoAlertDialog.Content>
|
||||
</AxoAlertDialog.Root>
|
||||
</List>
|
||||
</ListGroup>
|
||||
);
|
||||
content = (
|
||||
|
||||
@@ -32,7 +32,10 @@ import {
|
||||
} from '../util/migrations.preload.ts';
|
||||
import { drop } from '../util/drop.std.ts';
|
||||
import { isShallowEqual } from '../util/isShallowEqual.std.ts';
|
||||
import type { NotifyWhileMutedKey } from '../util/notifyWhileMuted.std.ts';
|
||||
import type {
|
||||
NotifyWhileMutedFields,
|
||||
NotifyWhileMutedKey,
|
||||
} from '../util/notifyWhileMuted.std.ts';
|
||||
import { NOTIFY_WHILE_MUTED_FIELDS } from '../util/notifyWhileMuted.std.ts';
|
||||
import { getInitials } from '../util/getInitials.std.ts';
|
||||
import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary.std.ts';
|
||||
@@ -6125,6 +6128,22 @@ export class ConversationModel {
|
||||
this.captureChange(attributeName);
|
||||
}
|
||||
|
||||
resetNotifyWhileMuted(): void {
|
||||
const attributeNames = Object.values(NOTIFY_WHILE_MUTED_FIELDS);
|
||||
if (attributeNames.every(name => this.get(name) === undefined)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set({
|
||||
notifyForCallsIfMuted: undefined,
|
||||
notifyForMentionsIfMuted: undefined,
|
||||
notifyForRepliesIfMuted: undefined,
|
||||
} satisfies Record<keyof NotifyWhileMutedFields, undefined>);
|
||||
|
||||
drop(DataWriter.updateConversation(this.attributes));
|
||||
this.captureChange('resetNotifyWhileMuted');
|
||||
}
|
||||
|
||||
acknowledgeGroupMemberNameCollisions(
|
||||
groupNameCollisions: ReadonlyDeep<GroupNameCollisionsWithIdsByTitle>
|
||||
): void {
|
||||
|
||||
@@ -1234,6 +1234,7 @@ export const actions = {
|
||||
repairOldestMessage,
|
||||
replaceAvatar,
|
||||
resetAllChatColors,
|
||||
resetAllNotifyWhileMuted,
|
||||
copyMessageText,
|
||||
retryDeleteForEveryone,
|
||||
retryMessageSend,
|
||||
@@ -2403,6 +2404,14 @@ function resetAllChatColors(): ThunkAction<
|
||||
};
|
||||
}
|
||||
|
||||
function resetAllNotifyWhileMuted(): NoopActionType {
|
||||
for (const conversation of window.ConversationController.getAll()) {
|
||||
conversation.resetNotifyWhileMuted();
|
||||
}
|
||||
|
||||
return noopAction('resetAllNotifyWhileMuted');
|
||||
}
|
||||
|
||||
function kickOffAttachmentDownload(
|
||||
options: Readonly<{ messageId: string }>
|
||||
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
||||
|
||||
@@ -129,6 +129,20 @@ import { pinReminderService } from '../../services/pinReminder.preload.ts';
|
||||
|
||||
const DEFAULT_NOTIFICATION_SETTING = 'message';
|
||||
|
||||
// Defaults for the settings that "Reset notification settings" restores
|
||||
const NOTIFICATION_SETTING_DEFAULTS = {
|
||||
'notification-setting': DEFAULT_NOTIFICATION_SETTING,
|
||||
'call-system-notification': true,
|
||||
'reaction-notification': true,
|
||||
'notification-draw-attention': false,
|
||||
'audio-notification': false,
|
||||
audioMessage: false,
|
||||
'badge-count-muted-conversations': false,
|
||||
notifyForCallsIfMuted: undefined,
|
||||
notifyForMentionsIfMuted: undefined,
|
||||
notifyForRepliesIfMuted: undefined,
|
||||
} as const satisfies Partial<StorageAccessType>;
|
||||
|
||||
function renderUpdateDialog(
|
||||
props: Readonly<{ containerWidthBreakpoint: WidthBreakpoint }>
|
||||
): JSX.Element {
|
||||
@@ -228,8 +242,11 @@ export function SmartPreferences(): JSX.Element | null {
|
||||
setGlobalDefaultConversationColor,
|
||||
toggleNavTabsCollapse,
|
||||
} = useItemsActions();
|
||||
const { removeCustomColorOnConversations, resetAllChatColors } =
|
||||
useConversationsActions();
|
||||
const {
|
||||
removeCustomColorOnConversations,
|
||||
resetAllChatColors,
|
||||
resetAllNotifyWhileMuted: resetAllPerChatNotifyWhileMutedSettings,
|
||||
} = useConversationsActions();
|
||||
const { startUpdate } = useUpdatesActions();
|
||||
const { changeLocation } = useNavActions();
|
||||
const { showToast, openFileInFolder } = useToastActions();
|
||||
@@ -720,7 +737,7 @@ export function SmartPreferences(): JSX.Element | null {
|
||||
|
||||
const [hasAudioNotifications, onAudioNotificationsChange] = createItemsAccess(
|
||||
'audio-notification',
|
||||
false
|
||||
NOTIFICATION_SETTING_DEFAULTS['audio-notification']
|
||||
);
|
||||
const [hasAutoConvertEmoji, onAutoConvertEmojiChange] = createItemsAccess(
|
||||
'autoConvertEmoji',
|
||||
@@ -738,16 +755,20 @@ export function SmartPreferences(): JSX.Element | null {
|
||||
);
|
||||
const [hasCallNotifications, onCallNotificationsChange] = createItemsAccess(
|
||||
'call-system-notification',
|
||||
true
|
||||
NOTIFICATION_SETTING_DEFAULTS['call-system-notification']
|
||||
);
|
||||
const [hasIncomingCallNotifications, onIncomingCallNotificationsChange] =
|
||||
createItemsAccess('incoming-call-notification', true);
|
||||
const [hasCallRingtoneNotification, onCallRingtoneNotificationChange] =
|
||||
createItemsAccess('call-ringtone-notification', true);
|
||||
const [hasCountMutedConversations, onCountMutedConversationsChange] =
|
||||
createItemsAccess('badge-count-muted-conversations', false, () => {
|
||||
window.Whisper.events.emit('updateUnreadCount');
|
||||
});
|
||||
createItemsAccess(
|
||||
'badge-count-muted-conversations',
|
||||
NOTIFICATION_SETTING_DEFAULTS['badge-count-muted-conversations'],
|
||||
() => {
|
||||
window.Whisper.events.emit('updateUnreadCount');
|
||||
}
|
||||
);
|
||||
const [hasHideMenuBar, onHideMenuBarChange] = createItemsAccess(
|
||||
'hide-menu-bar',
|
||||
false,
|
||||
@@ -758,16 +779,22 @@ export function SmartPreferences(): JSX.Element | null {
|
||||
);
|
||||
const [hasMessageAudio, onMessageAudioChange] = createItemsAccess(
|
||||
'audioMessage',
|
||||
false
|
||||
NOTIFICATION_SETTING_DEFAULTS.audioMessage
|
||||
);
|
||||
const [hasNotificationAttention, onNotificationAttentionChange] =
|
||||
createItemsAccess('notification-draw-attention', false);
|
||||
createItemsAccess(
|
||||
'notification-draw-attention',
|
||||
NOTIFICATION_SETTING_DEFAULTS['notification-draw-attention']
|
||||
);
|
||||
const [hasReactionNotifications, onReactionNotificationsChange] =
|
||||
createItemsAccess('reaction-notification', true);
|
||||
createItemsAccess(
|
||||
'reaction-notification',
|
||||
NOTIFICATION_SETTING_DEFAULTS['reaction-notification']
|
||||
);
|
||||
|
||||
const [notificationContent, onNotificationContentChange] = createItemsAccess(
|
||||
'notification-setting',
|
||||
'message'
|
||||
NOTIFICATION_SETTING_DEFAULTS['notification-setting']
|
||||
);
|
||||
const hasNotifications = notificationContent !== 'off';
|
||||
const onNotificationsChange = (value: boolean) => {
|
||||
@@ -788,6 +815,41 @@ export function SmartPreferences(): JSX.Element | null {
|
||||
account.captureChange(itemKey);
|
||||
};
|
||||
|
||||
const onResetNotificationSettings = () => {
|
||||
// Reset global settings
|
||||
onNotificationContentChange(
|
||||
NOTIFICATION_SETTING_DEFAULTS['notification-setting']
|
||||
);
|
||||
onCallNotificationsChange(
|
||||
NOTIFICATION_SETTING_DEFAULTS['call-system-notification']
|
||||
);
|
||||
onReactionNotificationsChange(
|
||||
NOTIFICATION_SETTING_DEFAULTS['reaction-notification']
|
||||
);
|
||||
onNotificationAttentionChange(
|
||||
NOTIFICATION_SETTING_DEFAULTS['notification-draw-attention']
|
||||
);
|
||||
onAudioNotificationsChange(
|
||||
NOTIFICATION_SETTING_DEFAULTS['audio-notification']
|
||||
);
|
||||
onMessageAudioChange(NOTIFICATION_SETTING_DEFAULTS.audioMessage);
|
||||
onCountMutedConversationsChange(
|
||||
NOTIFICATION_SETTING_DEFAULTS['badge-count-muted-conversations']
|
||||
);
|
||||
|
||||
const account = window.ConversationController.getOurConversationOrThrow();
|
||||
for (const itemKey of Object.values(NOTIFY_WHILE_MUTED_FIELDS)) {
|
||||
if (itemStorage.get(itemKey) === NOTIFICATION_SETTING_DEFAULTS[itemKey]) {
|
||||
continue;
|
||||
}
|
||||
drop(itemStorage.put(itemKey, NOTIFICATION_SETTING_DEFAULTS[itemKey]));
|
||||
account.captureChange(itemKey);
|
||||
}
|
||||
|
||||
// Reset per-chat settings
|
||||
resetAllPerChatNotifyWhileMutedSettings();
|
||||
};
|
||||
|
||||
const [hasPinReminders, onPinRemindersChange] = createItemsAccess(
|
||||
'pinReminders',
|
||||
true,
|
||||
@@ -1082,6 +1144,7 @@ export function SmartPreferences(): JSX.Element | null {
|
||||
onReactionNotificationsChange={onReactionNotificationsChange}
|
||||
onReadReceiptsChange={onReadReceiptsChange}
|
||||
onRelayCallsChange={onRelayCallsChange}
|
||||
onResetNotificationSettings={onResetNotificationSettings}
|
||||
onSealedSenderIndicatorsChange={onSealedSenderIndicatorsChange}
|
||||
onSelectedCameraChange={onSelectedCameraChange}
|
||||
onSelectedMicrophoneChange={onSelectedMicrophoneChange}
|
||||
|
||||
Reference in New Issue
Block a user