diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 90634ebeda1..e14ea83df62 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -1651,6 +1651,10 @@
"message": "You can add notes for yourself in this conversation. If your account has any linked devices, new notes will be synced.",
"description": "Description for the Note to Self conversation"
},
+ "notificationDrawAttention": {
+ "message": "Draw attention to this window when a notification arrives",
+ "description": "Label text for the setting that controls whether new notifications draw attention to the window"
+ },
"hideMenuBar": {
"message": "Hide menu bar",
"description": "Label text for menu bar visibility setting"
diff --git a/js/background.js b/js/background.js
index edb7daf5185..380b8dfc3da 100644
--- a/js/background.js
+++ b/js/background.js
@@ -373,6 +373,10 @@
storage.get('notification-setting', 'message'),
setNotificationSetting: value =>
storage.put('notification-setting', value),
+ getNotificationDrawAttention: () =>
+ storage.get('notification-draw-attention', true),
+ setNotificationDrawAttention: value =>
+ storage.put('notification-draw-attention', value),
getAudioNotification: () => storage.get('audio-notification'),
setAudioNotification: value => storage.put('audio-notification', value),
getCallRingtoneNotification: () =>
diff --git a/js/notifications.js b/js/notifications.js
index 9664d8cdd1a..a63676886af 100644
--- a/js/notifications.js
+++ b/js/notifications.js
@@ -153,7 +153,13 @@
message = i18n('newMessage');
}
- drawAttention();
+ const shouldDrawAttention = storage.get(
+ 'notification-draw-attention',
+ true
+ );
+ if (shouldDrawAttention) {
+ drawAttention();
+ }
this.lastNotification = window.Signal.Services.notify({
platform: window.platform,
diff --git a/js/settings_start.js b/js/settings_start.js
index 204b19b9bab..a945f3c2f15 100644
--- a/js/settings_start.js
+++ b/js/settings_start.js
@@ -36,6 +36,7 @@ const getInitialData = async () => ({
notificationSetting: await window.getNotificationSetting(),
audioNotification: await window.getAudioNotification(),
+ notificationDrawAttention: await window.getNotificationDrawAttention(),
spellCheck: await window.getSpellCheck(),
diff --git a/js/views/settings_view.js b/js/views/settings_view.js
index 56f7a3c4620..2a5a82ac041 100644
--- a/js/views/settings_view.js
+++ b/js/views/settings_view.js
@@ -113,6 +113,14 @@
window.setThemeSetting(theme);
},
});
+ if (Settings.isDrawAttentionSupported()) {
+ new CheckboxView({
+ el: this.$('.draw-attention-setting'),
+ name: 'draw-attention-setting',
+ value: window.initialData.notificationDrawAttention,
+ setFn: window.setNotificationDrawAttention,
+ });
+ }
if (Settings.isAudioNotificationSupported()) {
new CheckboxView({
el: this.$('.audio-notification-setting'),
@@ -204,9 +212,11 @@
nameAndMessage: i18n('nameAndMessage'),
noNameOrMessage: i18n('noNameOrMessage'),
nameOnly: i18n('nameOnly'),
+ notificationDrawAttention: i18n('notificationDrawAttention'),
audioNotificationDescription: i18n('audioNotificationDescription'),
isAudioNotificationSupported: Settings.isAudioNotificationSupported(),
isHideMenuBarSupported: Settings.isHideMenuBarSupported(),
+ isDrawAttentionSupported: Settings.isDrawAttentionSupported(),
hasSystemTheme: true,
themeLight: i18n('themeLight'),
themeDark: i18n('themeDark'),
diff --git a/main.js b/main.js
index aa305c3428f..91eacdeb54a 100644
--- a/main.js
+++ b/main.js
@@ -64,10 +64,6 @@ const startInTray = process.argv.some(arg => arg === '--start-in-tray');
const usingTrayIcon =
startInTray || process.argv.some(arg => arg === '--use-tray-icon');
-const disableFlashFrame = process.argv.some(
- arg => arg === '--disable-flash-frame'
-);
-
const config = require('./app/config');
// Very important to put before the single instance check, since it is based on the
@@ -1165,9 +1161,6 @@ ipc.on('draw-attention', () => {
if (!mainWindow) {
return;
}
- if (disableFlashFrame) {
- return;
- }
if (process.platform === 'win32' || process.platform === 'linux') {
mainWindow.flashFrame(true);
@@ -1262,6 +1255,8 @@ installSettingsSetter('hide-menu-bar');
installSettingsGetter('notification-setting');
installSettingsSetter('notification-setting');
+installSettingsGetter('notification-draw-attention');
+installSettingsSetter('notification-draw-attention');
installSettingsGetter('audio-notification');
installSettingsSetter('audio-notification');
diff --git a/preload.js b/preload.js
index 1c7f3d7c1e8..0a491faef16 100644
--- a/preload.js
+++ b/preload.js
@@ -149,6 +149,8 @@ try {
installGetter('notification-setting', 'getNotificationSetting');
installSetter('notification-setting', 'setNotificationSetting');
+ installGetter('notification-draw-attention', 'getNotificationDrawAttention');
+ installSetter('notification-draw-attention', 'setNotificationDrawAttention');
installGetter('audio-notification', 'getAudioNotification');
installSetter('audio-notification', 'setAudioNotification');
diff --git a/settings.html b/settings.html
index a6956f45123..ac1dd03230a 100644
--- a/settings.html
+++ b/settings.html
@@ -88,6 +88,13 @@
+ {{ #isDrawAttentionSupported }}
+
+
+
+
+
+ {{ /isDrawAttentionSupported }}
{{ #isAudioNotificationSupported }}
diff --git a/settings_preload.js b/settings_preload.js
index 0aba2765274..919160c99e1 100644
--- a/settings_preload.js
+++ b/settings_preload.js
@@ -60,6 +60,8 @@ window.setAlwaysRelayCalls = makeSetter('always-relay-calls');
window.getNotificationSetting = makeGetter('notification-setting');
window.setNotificationSetting = makeSetter('notification-setting');
+window.getNotificationDrawAttention = makeGetter('notification-draw-attention');
+window.setNotificationDrawAttention = makeSetter('notification-draw-attention');
window.getAudioNotification = makeGetter('audio-notification');
window.setAudioNotification = makeSetter('audio-notification');
window.getCallRingtoneNotification = makeGetter('call-ringtone-notification');
diff --git a/ts/test/types/Settings_test.ts b/ts/test/types/Settings_test.ts
index 714b1342ed3..3772b5abb3a 100644
--- a/ts/test/types/Settings_test.ts
+++ b/ts/test/types/Settings_test.ts
@@ -191,4 +191,65 @@ describe('Settings', () => {
});
});
});
+ describe('isDrawAttentionSupported', () => {
+ context('on macOS', () => {
+ beforeEach(() => {
+ sandbox.stub(process, 'platform').value('darwin');
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return false', () => {
+ assert.isFalse(Settings.isDrawAttentionSupported());
+ });
+ });
+
+ context('on Windows', () => {
+ context('version 7', () => {
+ beforeEach(() => {
+ sandbox.stub(process, 'platform').value('win32');
+ sandbox.stub(os, 'release').returns('7.0.0');
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return true', () => {
+ assert.isTrue(Settings.isDrawAttentionSupported());
+ });
+ });
+
+ context('version 8+', () => {
+ beforeEach(() => {
+ sandbox.stub(process, 'platform').value('win32');
+ sandbox.stub(os, 'release').returns('8.0.0');
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return true', () => {
+ assert.isTrue(Settings.isDrawAttentionSupported());
+ });
+ });
+ });
+
+ context('on Linux', () => {
+ beforeEach(() => {
+ sandbox.stub(process, 'platform').value('linux');
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return true', () => {
+ assert.isTrue(Settings.isDrawAttentionSupported());
+ });
+ });
+ });
});
diff --git a/ts/types/Settings.ts b/ts/types/Settings.ts
index 5231bdf0fa8..0d6ca05d927 100644
--- a/ts/types/Settings.ts
+++ b/ts/types/Settings.ts
@@ -12,3 +12,6 @@ export const isNotificationGroupingSupported = () =>
// the "hide menu bar" option is specific to Windows and Linux
export const isHideMenuBarSupported = () => !OS.isMacOS();
+
+// the "draw attention on notification" option is specific to Windows and Linux
+export const isDrawAttentionSupported = () => !OS.isMacOS();
diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json
index 4b0aeb64360..933baa258d1 100644
--- a/ts/util/lint/exceptions.json
+++ b/ts/util/lint/exceptions.json
@@ -324,9 +324,9 @@
"rule": "jQuery-appendTo(",
"path": "js/settings_start.js",
"line": " window.view.$el.appendTo($body);",
- "lineNumber": 63,
+ "lineNumber": 64,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Interacting with already-existing DOM nodes"
},
{
@@ -911,141 +911,154 @@
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
- "line": " el: this.$('.audio-notification-setting'),",
+ "line": " el: this.$('.draw-attention-setting'),",
"lineNumber": 118,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "updated": "2020-08-21T11:29:29.636Z",
+ "reasonDetail": "Protected from arbitrary input"
+ },
+ {
+ "rule": "jQuery-$(",
+ "path": "js/views/settings_view.js",
+ "line": " el: this.$('.audio-notification-setting'),",
+ "lineNumber": 126,
+ "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": 125,
+ "lineNumber": 133,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "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": 129,
+ "lineNumber": 137,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z"
+ "updated": "2020-08-21T11:29:29.636Z",
+ "reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " el: this.$('.menu-bar-setting'),",
- "lineNumber": 142,
+ "lineNumber": 150,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " el: this.$('.always-relay-calls-setting'),",
- "lineNumber": 149,
+ "lineNumber": 157,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "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": 155,
+ "lineNumber": 163,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z"
+ "updated": "2020-08-21T11:29:29.636Z",
+ "reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " el: this.$('.call-system-notification-setting'),",
- "lineNumber": 161,
+ "lineNumber": 169,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z"
+ "updated": "2020-08-21T11:29:29.636Z",
+ "reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " el: this.$('.incoming-call-notification-setting'),",
- "lineNumber": 167,
+ "lineNumber": 175,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z"
+ "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": 173,
+ "lineNumber": 181,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "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": 178,
+ "lineNumber": 186,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " this.$('.sync-setting').append(syncView.el);",
- "lineNumber": 184,
+ "lineNumber": 192,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-append(",
"path": "js/views/settings_view.js",
"line": " this.$('.sync-setting').append(syncView.el);",
- "lineNumber": 184,
+ "lineNumber": 192,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Interacting with already-existing DOM nodes"
},
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " this.$('.sync').text(i18n('syncNow'));",
- "lineNumber": 263,
+ "lineNumber": 273,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " this.$('.sync').attr('disabled', 'disabled');",
- "lineNumber": 267,
+ "lineNumber": 277,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " this.$('.synced_at').hide();",
- "lineNumber": 279,
+ "lineNumber": 289,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
"line": " this.$('.sync_failed').hide();",
- "lineNumber": 284,
+ "lineNumber": 294,
"reasonCategory": "usageTrusted",
- "updated": "2020-06-02T21:51:34.813Z",
+ "updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Protected from arbitrary input"
},
{