notifications: Allow only notifiable in unread count.

This commit adds a new setting to the user's notification settings that
will change the behaviour of the unread count in the title bar and
desktop application.

When enabled, the title bar will show the count of unread private messages
and mentions. When disabled, the title bar will act as before, showing
the total number of unread messages.

Fixes #1736.
This commit is contained in:
David Wood 2019-06-29 21:00:44 +01:00 committed by Tim Abbott
parent ca23740478
commit 9bace3f2cd
13 changed files with 110 additions and 10 deletions

View File

@ -1,9 +1,9 @@
set_global('Handlebars', global.make_handlebars()); set_global('Handlebars', global.make_handlebars());
zrequire('templates'); zrequire('templates');
zrequire('settings_notifications');
set_global('i18n', global.stub_i18n); set_global('i18n', global.stub_i18n);
set_global('page_params', {}); set_global('page_params', {});
zrequire('settings_notifications');
zrequire('stream_edit'); zrequire('stream_edit');
const { JSDOM } = require("jsdom"); const { JSDOM } = require("jsdom");

View File

@ -130,8 +130,16 @@ exports.permission_state = function () {
var new_message_count = 0; var new_message_count = 0;
exports.update_title_count = function (count) { exports.update_title_count = function (res) {
new_message_count = count; var only_show_notifiable = page_params.desktop_icon_count_display ===
settings_notifications.desktop_icon_count_display_values.notifiable.code;
if (only_show_notifiable) {
// DESKTOP_ICON_COUNT_DISPLAY_NOTIFIABLE
new_message_count = res.mentioned_message_count + res.private_message_count;
} else {
// DESKTOP_ICON_COUNT_DISPLAY_MESSAGES
new_message_count = res.home_unread_messages;
}
exports.redraw_title(); exports.redraw_title();
}; };

View File

@ -101,6 +101,7 @@ function setup_settings_label() {
enable_online_push_notifications: i18n.t("Send mobile notifications even if I'm online (useful for testing)"), enable_online_push_notifications: i18n.t("Send mobile notifications even if I'm online (useful for testing)"),
enable_sounds: i18n.t("Audible desktop notifications"), enable_sounds: i18n.t("Audible desktop notifications"),
pm_content_in_desktop_notifications: i18n.t("Include content of private messages in desktop notifications"), pm_content_in_desktop_notifications: i18n.t("Include content of private messages in desktop notifications"),
desktop_icon_count_display: i18n.t("Unread messages counted in desktop app tray and webapp favicon"),
// other_notification_settings // other_notification_settings
enable_digest_emails: i18n.t("Send digest emails when I'm away"), enable_digest_emails: i18n.t("Send digest emails when I'm away"),
@ -135,6 +136,7 @@ exports.build_page = function () {
settings_label: settings.settings_label, settings_label: settings.settings_label,
demote_inactive_streams_values: settings_display.demote_inactive_streams_values, demote_inactive_streams_values: settings_display.demote_inactive_streams_values,
notification_settings: settings_notifications.all_notifications.settings, notification_settings: settings_notifications.all_notifications.settings,
desktop_icon_count_display_values: settings_notifications.desktop_icon_count_display_values,
push_notification_tooltip: push_notification_tooltip:
settings_notifications.all_notifications.push_notification_tooltip, settings_notifications.all_notifications.push_notification_tooltip,
display_settings: settings_display.all_display_settings, display_settings: settings_display.all_display_settings,

View File

@ -32,6 +32,7 @@ var email_notification_settings = [
]; ];
var other_notification_settings = desktop_notification_settings.concat( var other_notification_settings = desktop_notification_settings.concat(
["desktop_icon_count_display"],
mobile_notification_settings, mobile_notification_settings,
email_notification_settings, email_notification_settings,
["notification_sound"] ["notification_sound"]
@ -63,12 +64,29 @@ exports.all_notifications = {
}, },
}; };
exports.desktop_icon_count_display_values = {
messages: {
code: 1,
description: i18n.t("All unreads"),
},
notifiable: {
code: 2,
description: i18n.t("Private messages and mentions"),
},
};
function change_notification_setting(setting, setting_data, status_element) { function change_notification_setting(setting, setting_data, status_element) {
var data = {}; var data = {};
data[setting] = JSON.stringify(setting_data); data[setting] = JSON.stringify(setting_data);
settings_ui.do_settings_change(channel.patch, '/json/settings/notifications', data, status_element); settings_ui.do_settings_change(channel.patch, '/json/settings/notifications', data, status_element);
} }
function update_desktop_icon_count_display() {
$("#desktop_icon_count_display").val(page_params.desktop_icon_count_display);
var res = unread.get_counts();
notifications.update_title_count(res);
}
exports.set_enable_digest_emails_visibility = function () { exports.set_enable_digest_emails_visibility = function () {
if (page_params.realm_digest_emails_enabled) { if (page_params.realm_digest_emails_enabled) {
$('#enable_digest_emails_label').parent().show(); $('#enable_digest_emails_label').parent().show();
@ -83,9 +101,11 @@ exports.set_up = function () {
$("#" + sub_setting).change(function () { $("#" + sub_setting).change(function () {
var value; var value;
// `notification_sound` and `desktop_icon_count_display` are not booleans.
if (sub_setting === "notification_sound") { if (sub_setting === "notification_sound") {
// `notification_sound` is not a boolean.
value = $(this).val(); value = $(this).val();
} else if (sub_setting === "desktop_icon_count_display") {
value = parseInt($(this).val(), 10);
} else { } else {
value = $(this).prop('checked'); value = $(this).prop('checked');
} }
@ -95,6 +115,8 @@ exports.set_up = function () {
}); });
}); });
update_desktop_icon_count_display();
$("#play_notification_sound").click(function () { $("#play_notification_sound").click(function () {
$("#notifications-area").find("audio")[0].play(); $("#notifications-area").find("audio")[0].play();
}); });
@ -121,7 +143,11 @@ exports.update_page = function () {
// If push notifications are disabled at the realm level, // If push notifications are disabled at the realm level,
// we should just leave the checkbox always off. // we should just leave the checkbox always off.
return; return;
} else if (setting === 'desktop_icon_count_display') {
update_desktop_icon_count_display();
return;
} }
$("#" + setting).prop('checked', page_params[setting]); $("#" + setting).prop('checked', page_params[setting]);
}); });
}; };

View File

@ -55,8 +55,8 @@ exports.update_unread_counts = function () {
top_left_corner.update_dom_with_unread_counts(res); top_left_corner.update_dom_with_unread_counts(res);
stream_list.update_dom_with_unread_counts(res); stream_list.update_dom_with_unread_counts(res);
pm_list.update_dom_with_unread_counts(res); pm_list.update_dom_with_unread_counts(res);
notifications.update_title_count(res.home_unread_messages);
notifications.update_pm_count(res.private_message_count); notifications.update_pm_count(res.private_message_count);
notifications.update_title_count(res);
exports.set_count_toggle_button($("#streamlist-toggle-unreadcount"), exports.set_count_toggle_button($("#streamlist-toggle-unreadcount"),
res.home_unread_messages); res.home_unread_messages);

View File

@ -1545,6 +1545,7 @@ body:not(.night-mode) #account-settings .custom_user_field .datepicker {
pointer-events: all; pointer-events: all;
} }
#desktop_icon_count_display,
#id_realm_waiting_period_setting, #id_realm_waiting_period_setting,
#id_realm_create_stream_policy, #id_realm_create_stream_policy,
#id_realm_invite_to_stream_policy, #id_realm_invite_to_stream_policy,

View File

@ -35,7 +35,7 @@
{{/each}} {{/each}}
</div> </div>
<div id="other_notifications"> <div id="other_notifications" class="m-10 inline-block">
<h3 class="inline-block">{{t "Other notification settings" }}</h3> <h3 class="inline-block">{{t "Other notification settings" }}</h3>
<div class="alert-notification" id="other-notify-settings-status"></div> <div class="alert-notification" id="other-notify-settings-status"></div>
@ -67,6 +67,15 @@
</a> </a>
</div> </div>
<div class="input-group">
<label for="desktop_icon_count_display" class="dropdown-title">{{ settings_label.desktop_icon_count_display }}</label>
<select name="desktop_icon_count_display" id="desktop_icon_count_display" class="prop-element">
{{#each desktop_icon_count_display_values}}
<option value="{{this.code}}">{{this.description}}</option>
{{/each}}
</select>
</div>
<h5>{{t "Mobile" }}</h5> <h5>{{t "Mobile" }}</h5>
{{#each notification_settings.mobile_notification_settings}} {{#each notification_settings.mobile_notification_settings}}

View File

@ -3645,8 +3645,8 @@ def do_create_realm(string_id: str, name: str,
"signups", realm.display_subdomain, signup_message) "signups", realm.display_subdomain, signup_message)
return realm return realm
def do_change_notification_settings(user_profile: UserProfile, name: str, value: Union[bool, str], def do_change_notification_settings(user_profile: UserProfile, name: str,
log: bool=True) -> None: value: Union[bool, int, str], log: bool=True) -> None:
"""Takes in a UserProfile object, the name of a global notification """Takes in a UserProfile object, the name of a global notification
preference to update, and the value to update to preference to update, and the value to update to
""" """

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-06-29 18:22
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('zerver', '0234_add_external_account_custom_profile_field'),
]
operations = [
migrations.AddField(
model_name='userprofile',
name='desktop_icon_count_display',
field=models.PositiveSmallIntegerField(default=1),
),
]

View File

@ -850,6 +850,11 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
enable_offline_push_notifications = models.BooleanField(default=True) # type: bool enable_offline_push_notifications = models.BooleanField(default=True) # type: bool
enable_online_push_notifications = models.BooleanField(default=False) # type: bool enable_online_push_notifications = models.BooleanField(default=False) # type: bool
DESKTOP_ICON_COUNT_DISPLAY_MESSAGES = 1
DESKTOP_ICON_COUNT_DISPLAY_NOTIFIABLE = 2
desktop_icon_count_display = models.PositiveSmallIntegerField(
default=DESKTOP_ICON_COUNT_DISPLAY_MESSAGES) # type: int
enable_digest_emails = models.BooleanField(default=True) # type: bool enable_digest_emails = models.BooleanField(default=True) # type: bool
enable_login_emails = models.BooleanField(default=True) # type: bool enable_login_emails = models.BooleanField(default=True) # type: bool
realm_name_in_notifications = models.BooleanField(default=False) # type: bool realm_name_in_notifications = models.BooleanField(default=False) # type: bool
@ -981,6 +986,7 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
message_content_in_email_notifications=bool, message_content_in_email_notifications=bool,
notification_sound=str, notification_sound=str,
pm_content_in_desktop_notifications=bool, pm_content_in_desktop_notifications=bool,
desktop_icon_count_display=int,
realm_name_in_notifications=bool, realm_name_in_notifications=bool,
) )

View File

@ -1869,8 +1869,8 @@ class EventsRegisterTest(ZulipTestCase):
@slow("Actually runs several full-stack fetching tests") @slow("Actually runs several full-stack fetching tests")
def test_change_notification_settings(self) -> None: def test_change_notification_settings(self) -> None:
for notification_setting, v in self.user_profile.notification_setting_types.items(): for notification_setting, v in self.user_profile.notification_setting_types.items():
if notification_setting == "notification_sound": if notification_setting in ["notification_sound", "desktop_icon_count_display"]:
# notification_sound is tested in its own test # These settings are tested in their own tests.
continue continue
schema_checker = self.check_events_dict([ schema_checker = self.check_events_dict([
@ -1910,6 +1910,32 @@ class EventsRegisterTest(ZulipTestCase):
error = schema_checker('events[0]', events[0]) error = schema_checker('events[0]', events[0])
self.assert_on_error(error) self.assert_on_error(error)
def test_change_desktop_icon_count_display(self) -> None:
notification_setting = "desktop_icon_count_display"
schema_checker = self.check_events_dict([
('type', equals('update_global_notifications')),
('notification_name', equals(notification_setting)),
('user', check_string),
('setting', equals(2)),
])
events = self.do_test(lambda: do_change_notification_settings(
self.user_profile, notification_setting, 2, log=False))
error = schema_checker('events[0]', events[0])
self.assert_on_error(error)
schema_checker = self.check_events_dict([
('type', equals('update_global_notifications')),
('notification_name', equals(notification_setting)),
('user', check_string),
('setting', equals(1)),
])
events = self.do_test(lambda: do_change_notification_settings(
self.user_profile, notification_setting, 1, log=False))
error = schema_checker('events[0]', events[0])
self.assert_on_error(error)
def test_realm_update_plan_type(self) -> None: def test_realm_update_plan_type(self) -> None:
realm = self.user_profile.realm realm = self.user_profile.realm

View File

@ -62,6 +62,7 @@ class HomeTest(ZulipTestCase):
"delivery_email", "delivery_email",
"demote_inactive_streams", "demote_inactive_streams",
"dense_mode", "dense_mode",
"desktop_icon_count_display",
"development_environment", "development_environment",
"email", "email",
"emojiset", "emojiset",

View File

@ -172,6 +172,7 @@ def json_change_notify_settings(
enable_login_emails: Optional[bool]=REQ(validator=check_bool, default=None), enable_login_emails: Optional[bool]=REQ(validator=check_bool, default=None),
message_content_in_email_notifications: Optional[bool]=REQ(validator=check_bool, default=None), message_content_in_email_notifications: Optional[bool]=REQ(validator=check_bool, default=None),
pm_content_in_desktop_notifications: Optional[bool]=REQ(validator=check_bool, default=None), pm_content_in_desktop_notifications: Optional[bool]=REQ(validator=check_bool, default=None),
desktop_icon_count_display: Optional[int]=REQ(validator=check_int, default=None),
realm_name_in_notifications: Optional[bool]=REQ(validator=check_bool, default=None) realm_name_in_notifications: Optional[bool]=REQ(validator=check_bool, default=None)
) -> HttpResponse: ) -> HttpResponse:
result = {} result = {}