Skip to content

Commit

Permalink
settings: Add option to disable seeing typing notifications.
Browse files Browse the repository at this point in the history
This commit adds an option to the advanced section of
Preferences settings, that would allow users to choose
whether or not to receive typing notifications from other
users.

Fixes #29642
  • Loading branch information
roanster007 committed Apr 12, 2024
1 parent 10b77fa commit 65b4b59
Show file tree
Hide file tree
Showing 17 changed files with 177 additions and 4 deletions.
7 changes: 7 additions & 0 deletions api_docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ format used by the Zulip server that they are interacting with.

## Changes in Zulip 9.0

**Feature level 251**

* [`PATCH /realm/user_settings_defaults`](/api/update-realm-user-settings-defaults),
[`POST /register`](/api/register-queue), [`PATCH /settings`](/api/update-settings):
Added new `typing_notifications_enabled` option to allow users to decide whether
to receive typing notifications from other users or not.

**Feature level 250**

* [`GET /messages`](/api/get-messages),
Expand Down
1 change: 1 addition & 0 deletions web/src/realm_user_settings_defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export type RealmDefaultSettings = {
starred_message_counts: boolean;
translate_emoticons: boolean;
twenty_four_hour_time: boolean;
typing_notifications_enabled: boolean;
user_list_style: boolean;
web_escape_navigates_to_home_view: boolean;
web_font_size_px: number;
Expand Down
7 changes: 7 additions & 0 deletions web/src/server_events_dispatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,7 @@ export function dispatch_normal_event(event) {
"timezone",
"twenty_four_hour_time",
"translate_emoticons",
"typing_notifications_enabled",
"display_emoji_reaction_users",
"user_list_style",
"web_stream_unreads_count_display_policy",
Expand Down Expand Up @@ -801,6 +802,12 @@ export function dispatch_normal_event(event) {
if (event.property === "starred_message_counts") {
starred_messages_ui.rerender_ui();
}
if (
event.property === "typing_notifications_enabled" &&
!user_settings.typing_notifications_enabled
) {
typing_events.disable_typing_notification();
}
if (event.property === "fluid_layout_width") {
scroll_bar.set_layout_width();
}
Expand Down
2 changes: 2 additions & 0 deletions web/src/settings_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ export const get_all_preferences = (): DisplaySettings => ({
"dense_mode",
"high_contrast_mode",
"starred_message_counts",
"typing_notifications_enabled",
"fluid_layout_width",
],
},
Expand Down Expand Up @@ -570,6 +571,7 @@ export const preferences_settings_labels = {
defaultMessage: "Convert emoticons before sending (<code>:)</code> becomes 😃)",
}),
),
typing_notifications_enabled: $t({defaultMessage: "Show when other users are typing"}),
web_escape_navigates_to_home_view: $t({defaultMessage: "Escape key navigates to home view"}),
web_font_size_px: $t({defaultMessage: "Message-area font size (px)"}),
web_line_height_percent: $t({defaultMessage: "Message-area line height (%)"}),
Expand Down
8 changes: 8 additions & 0 deletions web/src/typing_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ export function get_topic_typists(stream_id: number, topic: string): number[] {
return muted_users.filter_muted_user_ids(typists);
}

export function clear_typing_data(): void {
for (const [, timer] of inbound_timer_dict.entries()) {
clearTimeout(timer);
}
inbound_timer_dict.clear();
typists_dict.clear();
}

// The next functions aren't pure data, but it is easy
// enough to mock the setTimeout/clearTimeout functions.
export function clear_inbound_timer(key: string): void {
Expand Down
5 changes: 5 additions & 0 deletions web/src/typing_events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,8 @@ export function display_notification(event: TypingEvent): void {
},
);
}

export function disable_typing_notification(): void {
typing_data.clear_typing_data();
render_notifications_for_narrow();
}
1 change: 1 addition & 0 deletions web/src/user_settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export type UserSettings = (StreamNotificationSettings &
timezone: string;
translate_emoticons: boolean;
twenty_four_hour_time: boolean;
typing_notifications_enabled: boolean;
user_list_style: number;
web_escape_navigates_to_home_view: boolean;
web_font_size_px: number;
Expand Down
11 changes: 11 additions & 0 deletions web/tests/dispatch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,17 @@ run_test("user_settings", ({override}) => {
dispatch(event);
assert_same(user_settings.starred_message_counts, true);

event = event_fixtures.user_settings__typing_notifications_enabled;
user_settings.typing_notifications_enabled = false;
dispatch(event);
assert_same(user_settings.typing_notifications_enabled, true);

event = event_fixtures.user_settings__typing_notifications_disabled;
override(typing_events, "disable_typing_notification", noop);
user_settings.typing_notifications_enabled = true;
dispatch(event);
assert_same(user_settings.typing_notifications_enabled, false);

override(scroll_bar, "set_layout_width", noop);
event = event_fixtures.user_settings__fluid_layout_width;
user_settings.fluid_layout_width = false;
Expand Down
14 changes: 14 additions & 0 deletions web/tests/lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,20 @@ exports.fixtures = {
value: true,
},

user_settings__typing_notifications_enabled: {
type: "user_settings",
op: "update",
property: "typing_notifications_enabled",
value: true,
},

user_settings__typing_notifications_disabled: {
type: "user_settings",
op: "update",
property: "typing_notifications_enabled",
value: false,
},

user_settings__user_list_style: {
type: "user_settings",
op: "update",
Expand Down
16 changes: 16 additions & 0 deletions web/tests/typing_data.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ test("basics", () => {
// test duplicate ids in a groups
typing_data.add_typist(typing_data.get_direct_message_conversation_key([20, 40, 20]), 20);
assert.deepEqual(typing_data.get_group_typists([20, 40]), [20]);

// test clearing out typing data
typing_data.clear_typing_data();
assert.deepEqual(typing_data.get_group_typists(), []);
assert.deepEqual(typing_data.get_all_direct_message_typists(), []);
assert.deepEqual(typing_data.get_topic_typists(stream_id, topic), []);
});

test("muted_typists_excluded", () => {
Expand Down Expand Up @@ -181,6 +187,16 @@ test("timers", () => {
timer_set: true,
});

// clearing out typing data
kickstart();
typing_data.clear_typing_data();
assert.deepEqual(events, {
f: stub_f,
timer_cleared: true,
timer_set: true,
});

kickstart();
// first time clearing, we clear
clear();
assert.deepEqual(events, {
Expand Down
12 changes: 8 additions & 4 deletions zerver/actions/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ def do_send_typing_notification(
)

# Only deliver the notification to active user recipients
user_ids_to_notify = [user.id for user in recipient_user_profiles if user.is_active]
user_ids_to_notify = [
user.id
for user in recipient_user_profiles
if user.is_active and user.typing_notifications_enabled
]

send_event(realm, event, user_ids_to_notify)

Expand Down Expand Up @@ -91,9 +95,9 @@ def do_send_stream_typing_notification(
return

user_ids_to_notify = set(
subscriptions_query.exclude(user_profile__long_term_idle=True).values_list(
"user_profile_id", flat=True
)
subscriptions_query.exclude(user_profile__long_term_idle=True)
.exclude(user_profile__typing_notifications_enabled=False)
.values_list("user_profile_id", flat=True)
)

send_event(sender.realm, event, user_ids_to_notify)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 4.2.12 on 2024-04-12 16:01

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("zerver", "0506_realm_require_unique_names"),
]

operations = [
migrations.AddField(
model_name="realmuserdefault",
name="typing_notifications_enabled",
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name="userprofile",
name="typing_notifications_enabled",
field=models.BooleanField(default=True),
),
]
2 changes: 2 additions & 0 deletions zerver/models/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class UserBaseSettings(models.Model):
display_emoji_reaction_users = models.BooleanField(default=True)
twenty_four_hour_time = models.BooleanField(default=False)
starred_message_counts = models.BooleanField(default=True)
typing_notifications_enabled = models.BooleanField(default=True)
COLOR_SCHEME_AUTOMATIC = 1
COLOR_SCHEME_NIGHT = 2
COLOR_SCHEME_LIGHT = 3
Expand Down Expand Up @@ -320,6 +321,7 @@ class UserBaseSettings(models.Model):
send_private_typing_notifications=bool,
send_read_receipts=bool,
send_stream_typing_notifications=bool,
typing_notifications_enabled=bool,
web_mark_read_on_scroll_policy=int,
user_list_style=int,
web_stream_unreads_count_display_policy=int,
Expand Down
38 changes: 38 additions & 0 deletions zerver/openapi/zulip.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10570,6 +10570,11 @@ paths:
messages](/help/star-a-message#display-the-number-of-starred-messages).
type: boolean
example: true
typing_notifications_enabled:
description: |
Whether users should receive typing notifications from other users or not.
type: boolean
example: true
fluid_layout_width:
description: |
Whether to use the [maximum available screen width](/help/enable-full-width-display)
Expand Down Expand Up @@ -11017,6 +11022,8 @@ paths:
contentType: application/json
starred_message_counts:
contentType: application/json
typing_notifications_enabled:
contentType: application/json
fluid_layout_width:
contentType: application/json
high_contrast_mode:
Expand Down Expand Up @@ -13368,6 +13375,10 @@ paths:
description: |
Whether clients should display the [number of starred
messages](/help/star-a-message#display-the-number-of-starred-messages).
typing_notifications_enabled:
type: boolean
description: |
Whether users should receive typing notifications from other users or not.
fluid_layout_width:
type: boolean
description: |
Expand Down Expand Up @@ -14442,6 +14453,16 @@ paths:
client capability and access the `user_settings` object instead.

[capabilities]: /api/register-queue#parameter-client_capabilities
typing_notifications_enabled:
type: boolean
description: |
Present if the user has chosen to receive typing notifications from
other users.

By default user receives typing notifications from other users.

**Changes**: New in Zulip 9.0 (feature level 251). Previously, there
was no such option for users to disable typing notifications.
enter_sends:
deprecated: true
type: boolean
Expand Down Expand Up @@ -15670,6 +15691,10 @@ paths:
description: |
Whether clients should display the [number of starred
messages](/help/star-a-message#display-the-number-of-starred-messages).
typing_notifications_enabled:
type: boolean
description: |
Whether users should receive typing notifications from other users or not.
fluid_layout_width:
type: boolean
description: |
Expand Down Expand Up @@ -16755,6 +16780,17 @@ paths:
the `PATCH /settings/display` endpoint.
type: boolean
example: true
typing_notifications_enabled:
description: |
Present if the user has chosen to receive typing notifications from
other users.

By default user receives typing notifications from other users.

**Changes**: New in Zulip 9.0 (feature level 251). Previously, there
was no such option for users to disable typing notifications.
type: boolean
example: true
fluid_layout_width:
description: |
Whether to use the [maximum available screen width](/help/enable-full-width-display)
Expand Down Expand Up @@ -17310,6 +17346,8 @@ paths:
contentType: application/json
starred_message_counts:
contentType: application/json
typing_notifications_enabled:
contentType: application/json
fluid_layout_width:
contentType: application/json
high_contrast_mode:
Expand Down
33 changes: 33 additions & 0 deletions zerver/tests/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,3 +585,36 @@ def test_send_stream_typing_notifications_setting(self) -> None:
result = self.api_post(sender, "/api/v1/typing", params)
self.assert_json_error(result, "User has disabled typing notifications for stream messages")
self.assertEqual(events, [])

def test_typing_notifications_disabled(self) -> None:
sender = self.example_user("hamlet")
stream_name = self.get_streams(sender)[0]
stream_id = self.get_stream_id(stream_name)
topic_name = "Some topic"

aaron = self.example_user("aaron")
iago = self.example_user("iago")
for user in [aaron, iago]:
self.subscribe(user, stream_name)

aaron.typing_notifications_enabled = False
aaron.save()

params = dict(
type="stream",
op="start",
stream_id=str(stream_id),
topic=topic_name,
)

with self.capture_send_event_calls(expected_num_events=1) as events:
result = self.api_post(sender, "/api/v1/typing", params)
self.assert_json_success(result)
self.assert_length(events, 1)

event_user_ids = set(events[0]["users"])

# Only users who have typing notifications enabled would receive
# notifications.
self.assertNotIn(aaron.id, event_user_ids)
self.assertIn(iago.id, event_user_ids)
1 change: 1 addition & 0 deletions zerver/views/realm.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ def update_realm_user_settings_defaults(
default=None,
),
starred_message_counts: Optional[bool] = REQ(json_validator=check_bool, default=None),
typing_notifications_enabled: Optional[bool] = REQ(json_validator=check_bool, default=None),
web_stream_unreads_count_display_policy: Optional[int] = REQ(
json_validator=check_int_in(UserProfile.WEB_STREAM_UNREADS_COUNT_DISPLAY_POLICY_CHOICES),
default=None,
Expand Down
1 change: 1 addition & 0 deletions zerver/views/user_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ def json_change_settings(
default=None,
),
starred_message_counts: Optional[bool] = REQ(json_validator=check_bool, default=None),
typing_notifications_enabled: Optional[bool] = REQ(json_validator=check_bool, default=None),
fluid_layout_width: Optional[bool] = REQ(json_validator=check_bool, default=None),
high_contrast_mode: Optional[bool] = REQ(json_validator=check_bool, default=None),
color_scheme: Optional[int] = REQ(
Expand Down

0 comments on commit 65b4b59

Please sign in to comment.