diff --git a/protos/Backups.proto b/protos/Backups.proto index 8377cfdc07..267aa51261 100644 --- a/protos/Backups.proto +++ b/protos/Backups.proto @@ -138,6 +138,8 @@ message AccountData { bool allowSealedSenderFromAnyone = 30; bool allowAutomaticKeyVerification = 31; bool hasSeenAdminDeleteEducationDialog = 32; + optional bool includeMutedChatsInBadge = 34; // If unset, consider this disabled + optional bool reactionNotifications = 35; // If unset, consider this enabled optional bool notifyForCallsIfMuted = 36; // If unset, consider this disabled optional bool notifyForMentionsIfMuted = 37; // If unset, consider this enabled optional bool notifyForRepliesIfMuted = 38; // If unset, consider this enabled diff --git a/protos/SignalStorage.proto b/protos/SignalStorage.proto index 6c9617472a..20cc866161 100644 --- a/protos/SignalStorage.proto +++ b/protos/SignalStorage.proto @@ -312,6 +312,8 @@ message AccountRecord { optional bool releaseNotesChatBlocked = 50; optional bool releaseNotesChatMarkedUnread = 51; optional uint64 releaseNotesChatBlockedAt = 52; // only set if known (>0) + OptionalBool includeMutedChatsInBadge = 54; // If unset, consider this off + OptionalBool reactionNotifications = 55; // If unset, consider this on OptionalBool notifyForCallsIfMuted = 56; // If unset, consider this off OptionalBool notifyForMentionsIfMuted = 57; // If unset, consider this on OptionalBool notifyForRepliesIfMuted = 58; // If unset, consider this on diff --git a/ts/services/backups/export.preload.ts b/ts/services/backups/export.preload.ts index 67cca0424d..362dcccafa 100644 --- a/ts/services/backups/export.preload.ts +++ b/ts/services/backups/export.preload.ts @@ -1101,6 +1101,9 @@ export class BackupExportStream extends Readable { itemStorage.get('hasSeenGroupStoryEducationSheet') ?? null, hasSeenAdminDeleteEducationDialog: itemStorage.get('hasSeenAdminDeleteEducationDialog') ?? null, + includeMutedChatsInBadge: + itemStorage.get('badge-count-muted-conversations') ?? null, + reactionNotifications: itemStorage.get('reaction-notification') ?? null, phoneNumberSharingMode, // Note that this should be called before `toDefaultChatStyle` because // it builds `customColorIdByUuid` diff --git a/ts/services/backups/import.preload.ts b/ts/services/backups/import.preload.ts index 460d7e6427..56a1bddfcb 100644 --- a/ts/services/backups/import.preload.ts +++ b/ts/services/backups/import.preload.ts @@ -939,6 +939,17 @@ export class BackupImportStream extends Writable { 'hasSeenAdminDeleteEducationDialog', accountSettings?.hasSeenAdminDeleteEducationDialog === true ); + await itemStorage.put( + 'badge-count-muted-conversations', + // unset should be treated as false + accountSettings?.includeMutedChatsInBadge === true + ); + + await itemStorage.put( + 'reaction-notification', + // unset should be treated as true + accountSettings?.reactionNotifications !== false + ); await itemStorage.put( 'preferredReactionEmoji', accountSettings?.preferredReactionEmoji?.map(emoji => { diff --git a/ts/services/storageRecordOps.preload.ts b/ts/services/storageRecordOps.preload.ts index 1af89f6b9f..11393a5478 100644 --- a/ts/services/storageRecordOps.preload.ts +++ b/ts/services/storageRecordOps.preload.ts @@ -661,6 +661,13 @@ export function toAccountRecord({ hasSeenAdminDeleteEducationDialog: itemStorage.get('hasSeenAdminDeleteEducationDialog') ?? null, + includeMutedChatsInBadge: toOptionalBool( + itemStorage.get('badge-count-muted-conversations') + ), + reactionNotifications: toOptionalBool( + itemStorage.get('reaction-notification') + ), + avatarColor: ourConversation.get('colorFromPrimary') ?? null, automaticKeyVerificationDisabled: itemStorage.get('hasKeyTransparencyDisabled') === true, @@ -1684,6 +1691,8 @@ export async function mergeAccountRecord( hasSeenAdminDeleteEducationDialog, hasSetMyStoriesPrivacy, hasViewedOnboardingStory, + includeMutedChatsInBadge, + reactionNotifications, storiesDisabled, storyViewReceiptsEnabled, username, @@ -1990,6 +1999,23 @@ export async function mergeAccountRecord( 'hasSeenAdminDeleteEducationDialog', hasSeenAdminDeleteEducationDialog ?? false ); + { + // default to false (exclude muted chats) + const countMutedConversations = + fromOptionalBool(includeMutedChatsInBadge) ?? false; + const previous = itemStorage.get('badge-count-muted-conversations', false); + await itemStorage.put( + 'badge-count-muted-conversations', + countMutedConversations + ); + if (previous !== countMutedConversations) { + window.Whisper.events.emit('updateUnreadCount'); + } + } + await itemStorage.put( + 'reaction-notification', + fromOptionalBool(reactionNotifications) ?? true + ); { await itemStorage.put( 'hasKeyTransparencyDisabled', diff --git a/ts/state/smart/Preferences.preload.tsx b/ts/state/smart/Preferences.preload.tsx index 7a5a633e8c..2ef2e4c38e 100644 --- a/ts/state/smart/Preferences.preload.tsx +++ b/ts/state/smart/Preferences.preload.tsx @@ -767,6 +767,9 @@ export function SmartPreferences(): JSX.Element | null { NOTIFICATION_SETTING_DEFAULTS['badge-count-muted-conversations'], () => { window.Whisper.events.emit('updateUnreadCount'); + const account = + window.ConversationController.getOurConversationOrThrow(); + account.captureChange('badge-count-muted-conversations'); } ); const [hasHideMenuBar, onHideMenuBarChange] = createItemsAccess( @@ -789,7 +792,12 @@ export function SmartPreferences(): JSX.Element | null { const [hasReactionNotifications, onReactionNotificationsChange] = createItemsAccess( 'reaction-notification', - NOTIFICATION_SETTING_DEFAULTS['reaction-notification'] + NOTIFICATION_SETTING_DEFAULTS['reaction-notification'], + () => { + const account = + window.ConversationController.getOurConversationOrThrow(); + account.captureChange('reaction-notification'); + } ); const [notificationContent, onNotificationContentChange] = createItemsAccess( diff --git a/ts/test-helpers/generateBackup.node.ts b/ts/test-helpers/generateBackup.node.ts index 24d2c33eb1..62daa6be3f 100644 --- a/ts/test-helpers/generateBackup.node.ts +++ b/ts/test-helpers/generateBackup.node.ts @@ -135,6 +135,8 @@ function* createRecords({ hasSeenGroupStoryEducationSheet: true, hasCompletedUsernameOnboarding: true, hasSeenAdminDeleteEducationDialog: false, + includeMutedChatsInBadge: true, + reactionNotifications: true, phoneNumberSharingMode: Backups.AccountData.PhoneNumberSharingMode.EVERYBODY, defaultChatStyle: {