From 22ba54ce5c36ea9670c070eb1137e049fbcbd6cf Mon Sep 17 00:00:00 2001
From: Josh Perez <60019601+josh-signal@users.noreply.github.com>
Date: Mon, 14 Sep 2020 18:16:57 -0400
Subject: [PATCH] Don't count muted convos in badge count by default
---
_locales/en/messages.json | 4 +++
js/background.js | 6 ++++
js/models/conversations.js | 8 +++++-
js/settings_start.js | 1 +
js/views/settings_view.js | 9 ++++++
libtextsecure/test/_test.js | 6 ++++
main.js | 2 ++
preload.js | 23 +++++++++++++++
settings.html | 4 +++
settings_preload.js | 6 ++++
ts/ConversationController.ts | 16 ++++++++---
ts/model-types.d.ts | 1 +
ts/util/lint/exceptions.json | 55 +++++++++++++++++++++---------------
ts/window.d.ts | 2 ++
14 files changed, 115 insertions(+), 28 deletions(-)
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 68b1b601de..cec91c6f54 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -3628,5 +3628,9 @@
"CompositionArea--attach-file": {
"message": "Attach file",
"description": "Aria label for file attachment button in composition area"
+ },
+ "countMutedConversationsDescription": {
+ "message": "Count muted conversations in badge count",
+ "description": "Description for counting muted conversations in badge setting"
}
}
diff --git a/js/background.js b/js/background.js
index 76ae4bcf54..9737bcf687 100644
--- a/js/background.js
+++ b/js/background.js
@@ -381,6 +381,12 @@
storage.put('notification-draw-attention', value),
getAudioNotification: () => storage.get('audio-notification'),
setAudioNotification: value => storage.put('audio-notification', value),
+ getCountMutedConversations: () =>
+ storage.get('badge-count-muted-conversations', false),
+ setCountMutedConversations: value => {
+ storage.put('badge-count-muted-conversations', value);
+ window.Whisper.events.trigger('updateUnreadCount');
+ },
getCallRingtoneNotification: () =>
storage.get('call-ringtone-notification', true),
setCallRingtoneNotification: value =>
diff --git a/js/models/conversations.js b/js/models/conversations.js
index 2e98052154..63ce676130 100644
--- a/js/models/conversations.js
+++ b/js/models/conversations.js
@@ -3107,8 +3107,14 @@
});
},
+ isMuted() {
+ return (
+ this.get('muteExpiresAt') && Date.now() < this.get('muteExpiresAt')
+ );
+ },
+
async notify(message, reaction) {
- if (this.get('muteExpiresAt') && Date.now() < this.get('muteExpiresAt')) {
+ if (this.isMuted()) {
return;
}
diff --git a/js/settings_start.js b/js/settings_start.js
index d40283fbd1..320e124db6 100644
--- a/js/settings_start.js
+++ b/js/settings_start.js
@@ -30,6 +30,7 @@ const getInitialData = async () => ({
notificationSetting: await window.getNotificationSetting(),
audioNotification: await window.getAudioNotification(),
notificationDrawAttention: await window.getNotificationDrawAttention(),
+ countMutedConversations: await window.getCountMutedConversations(),
spellCheck: await window.getSpellCheck(),
diff --git a/js/views/settings_view.js b/js/views/settings_view.js
index d76f28cd9f..e0bf507a57 100644
--- a/js/views/settings_view.js
+++ b/js/views/settings_view.js
@@ -127,6 +127,12 @@
setFn: window.setAudioNotification,
});
}
+ new CheckboxView({
+ el: this.$('.badge-count-muted-conversations-setting'),
+ name: 'badge-count-muted-conversations-setting',
+ value: window.initialData.countMutedConversations,
+ setFn: window.setCountMutedConversations,
+ });
new CheckboxView({
el: this.$('.spell-check-setting'),
name: 'spell-check-setting',
@@ -224,6 +230,9 @@
clearDataButton: i18n('clearDataButton'),
clearDataExplanation: i18n('clearDataExplanation'),
calling: i18n('calling'),
+ countMutedConversationsDescription: i18n(
+ 'countMutedConversationsDescription'
+ ),
alwaysRelayCallsDescription: i18n('alwaysRelayCallsDescription'),
alwaysRelayCallsDetail: i18n('alwaysRelayCallsDetail'),
callRingtoneNotificationDescription: i18n(
diff --git a/libtextsecure/test/_test.js b/libtextsecure/test/_test.js
index f5d68d5553..b5d9b1d08a 100644
--- a/libtextsecure/test/_test.js
+++ b/libtextsecure/test/_test.js
@@ -57,3 +57,9 @@ window.hexToArrayBuffer = str => {
};
window.MockSocket.prototype.addEventListener = () => null;
+
+window.Whisper = window.Whisper || {};
+window.Whisper.events = {
+ on() {},
+ trigger() {},
+};
diff --git a/main.js b/main.js
index 1d7ea69484..eb2d11b6d3 100644
--- a/main.js
+++ b/main.js
@@ -1262,6 +1262,8 @@ installSettingsGetter('notification-draw-attention');
installSettingsSetter('notification-draw-attention');
installSettingsGetter('audio-notification');
installSettingsSetter('audio-notification');
+installSettingsGetter('badge-count-muted-conversations');
+installSettingsSetter('badge-count-muted-conversations');
installSettingsGetter('spell-check');
installSettingsSetter('spell-check');
diff --git a/preload.js b/preload.js
index d3dec89d28..ee7a284394 100644
--- a/preload.js
+++ b/preload.js
@@ -163,6 +163,29 @@ try {
installSetter('notification-draw-attention', 'setNotificationDrawAttention');
installGetter('audio-notification', 'getAudioNotification');
installSetter('audio-notification', 'setAudioNotification');
+ installGetter(
+ 'badge-count-muted-conversations',
+ 'getCountMutedConversations'
+ );
+ installSetter(
+ 'badge-count-muted-conversations',
+ 'setCountMutedConversations'
+ );
+
+ window.getCountMutedConversations = () =>
+ new Promise((resolve, reject) => {
+ ipc.once(
+ 'get-success-badge-count-muted-conversations',
+ (_event, error, value) => {
+ if (error) {
+ return reject(new Error(error));
+ }
+
+ return resolve(value);
+ }
+ );
+ ipc.send('get-badge-count-muted-conversations');
+ });
installGetter('spell-check', 'getSpellCheck');
installSetter('spell-check', 'setSpellCheck');
diff --git a/settings.html b/settings.html
index ac1dd03230..958b416d26 100644
--- a/settings.html
+++ b/settings.html
@@ -102,6 +102,10 @@
{{ /isAudioNotificationSupported }}
+
diff --git a/settings_preload.js b/settings_preload.js
index 919160c99e..cce0b20e2d 100644
--- a/settings_preload.js
+++ b/settings_preload.js
@@ -70,6 +70,12 @@ window.getCallSystemNotification = makeGetter('call-system-notification');
window.setCallSystemNotification = makeSetter('call-system-notification');
window.getIncomingCallNotification = makeGetter('incoming-call-notification');
window.setIncomingCallNotification = makeSetter('incoming-call-notification');
+window.getCountMutedConversations = makeGetter(
+ 'badge-count-muted-conversations'
+);
+window.setCountMutedConversations = makeSetter(
+ 'badge-count-muted-conversations'
+);
window.getMediaPermissions = makeGetter('media-permissions');
window.setMediaPermissions = makeSetter('media-permissions');
diff --git a/ts/ConversationController.ts b/ts/ConversationController.ts
index c48c3cfb7c..12d3be6368 100644
--- a/ts/ConversationController.ts
+++ b/ts/ConversationController.ts
@@ -32,10 +32,13 @@ export function start(): void {
this.listenTo(conversations, 'add change:active_at', this.addActive);
this.listenTo(conversations, 'reset', () => this.reset([]));
- this.on(
- 'add remove change:unreadCount',
- debounce(this.updateUnreadCount.bind(this), 1000)
+ const debouncedUpdateUnreadCount = debounce(
+ this.updateUnreadCount.bind(this),
+ 1000
);
+
+ this.on('add remove change:unreadCount', debouncedUpdateUnreadCount);
+ window.Whisper.events.on('updateUnreadCount', debouncedUpdateUnreadCount);
},
addActive(model: ConversationModelType) {
if (model.get('active_at')) {
@@ -45,8 +48,13 @@ export function start(): void {
}
},
updateUnreadCount() {
+ const canCountMutedConversations = window.storage.get(
+ 'badge-count-muted-conversations'
+ );
const newUnreadCount = reduce(
- this.map((m: ConversationModelType) => m.get('unreadCount')),
+ this.map((m: ConversationModelType) =>
+ !canCountMutedConversations && m.isMuted() ? 0 : m.get('unreadCount')
+ ),
(item: number, memo: number) => (item || 0) + memo,
0
);
diff --git a/ts/model-types.d.ts b/ts/model-types.d.ts
index 9a76166c8b..de58f4982c 100644
--- a/ts/model-types.d.ts
+++ b/ts/model-types.d.ts
@@ -178,6 +178,7 @@ export declare class ConversationModelType extends Backbone.Model<
isFromOrAddedByTrustedContact(): boolean;
isBlocked(): boolean;
isMe(): boolean;
+ isMuted(): boolean;
isPrivate(): boolean;
isVerified(): boolean;
maybeRepairGroupV2(data: {
diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json
index ae387890be..214083fb1d 100644
--- a/ts/util/lint/exceptions.json
+++ b/ts/util/lint/exceptions.json
@@ -308,7 +308,7 @@
"rule": "jQuery-appendTo(",
"path": "js/settings_start.js",
"line": " window.view.$el.appendTo($body);",
- "lineNumber": 55,
+ "lineNumber": 56,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Interacting with already-existing DOM nodes"
@@ -994,17 +994,26 @@
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
- "line": " el: this.$('.spell-check-setting'),",
+ "line": " el: this.$('.badge-count-muted-conversations-setting'),",
"lineNumber": 131,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
},
+ {
+ "rule": "jQuery-$(",
+ "path": "js/views/settings_view.js",
+ "line": " el: this.$('.spell-check-setting'),",
+ "lineNumber": 137,
+ "reasonCategory": "usageTrusted",
+ "updated": "2020-08-21T11:29:29.636Z",
+ "reasonDetail": "Protected from arbitrary input"
+ },
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " const $msg = this.$('.spell-check-setting-message');",
- "lineNumber": 135,
+ "lineNumber": 141,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
@@ -1013,7 +1022,7 @@
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " el: this.$('.menu-bar-setting'),",
- "lineNumber": 148,
+ "lineNumber": 154,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
@@ -1022,15 +1031,6 @@
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " el: this.$('.always-relay-calls-setting'),",
- "lineNumber": 155,
- "reasonCategory": "usageTrusted",
- "updated": "2020-08-21T11:29:29.636Z",
- "reasonDetail": "Protected from arbitrary input"
- },
- {
- "rule": "jQuery-$(",
- "path": "js/views/settings_view.js",
- "line": " el: this.$('.call-ringtone-notification-setting'),",
"lineNumber": 161,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
@@ -1039,7 +1039,7 @@
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
- "line": " el: this.$('.call-system-notification-setting'),",
+ "line": " el: this.$('.call-ringtone-notification-setting'),",
"lineNumber": 167,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
@@ -1048,7 +1048,7 @@
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
- "line": " el: this.$('.incoming-call-notification-setting'),",
+ "line": " el: this.$('.call-system-notification-setting'),",
"lineNumber": 173,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
@@ -1057,17 +1057,26 @@
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
- "line": " el: this.$('.media-permissions'),",
+ "line": " el: this.$('.incoming-call-notification-setting'),",
"lineNumber": 179,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
},
+ {
+ "rule": "jQuery-$(",
+ "path": "js/views/settings_view.js",
+ "line": " el: this.$('.media-permissions'),",
+ "lineNumber": 185,
+ "reasonCategory": "usageTrusted",
+ "updated": "2020-08-21T11:29:29.636Z",
+ "reasonDetail": "Protected from arbitrary input"
+ },
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " el: this.$('.media-camera-permissions'),",
- "lineNumber": 184,
+ "lineNumber": 190,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
@@ -1076,7 +1085,7 @@
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " this.$('.sync-setting').append(syncView.el);",
- "lineNumber": 190,
+ "lineNumber": 196,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
@@ -1085,7 +1094,7 @@
"rule": "jQuery-append(",
"path": "js/views/settings_view.js",
"line": " this.$('.sync-setting').append(syncView.el);",
- "lineNumber": 190,
+ "lineNumber": 196,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Interacting with already-existing DOM nodes"
@@ -1094,7 +1103,7 @@
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " this.$('.sync').text(i18n('syncNow'));",
- "lineNumber": 271,
+ "lineNumber": 280,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
@@ -1112,7 +1121,7 @@
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " this.$('.sync').attr('disabled', 'disabled');",
- "lineNumber": 275,
+ "lineNumber": 284,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
@@ -1130,7 +1139,7 @@
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " this.$('.synced_at').hide();",
- "lineNumber": 287,
+ "lineNumber": 296,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
@@ -1148,7 +1157,7 @@
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " this.$('.sync_failed').hide();",
- "lineNumber": 292,
+ "lineNumber": 301,
"reasonCategory": "usageTrusted",
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
diff --git a/ts/window.d.ts b/ts/window.d.ts
index 2acf069dbe..9b300761ab 100644
--- a/ts/window.d.ts
+++ b/ts/window.d.ts
@@ -40,6 +40,7 @@ declare global {
getCallRingtoneNotification: () => Promise
;
getCallSystemNotification: () => Promise;
getConversations: () => ConversationModelCollectionType;
+ getCountMutedConversations: () => Promise;
getEnvironment: () => string;
getExpiration: () => string;
getGuid: () => string;
@@ -208,6 +209,7 @@ export type LoggerType = (...args: Array) => void;
export type WhisperType = {
events: {
+ on: (name: string, callback: (param1: any, param2?: any) => void) => void;
trigger: (name: string, param1: any, param2?: any) => void;
};
Database: {