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 to receive typing notifications from other
users.

Fixes #29642
  • Loading branch information
roanster007 committed Apr 15, 2024
1 parent a2e3d37 commit 65334ba
Show file tree
Hide file tree
Showing 17 changed files with 187 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 notification events from other users.

**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_disabled: {
type: "user_settings",
op: "update",
property: "typing_notifications_enabled",
value: false,
},

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

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
48 changes: 48 additions & 0 deletions zerver/openapi/zulip.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10570,6 +10570,13 @@ paths:
messages](/help/star-a-message#display-the-number-of-starred-messages).
type: boolean
example: true
typing_notifications_enabled:
description: |
Whether the user is configured to receive typing notifications from other users.
The server will only deliver typing notifications events to users who for whom this
is enabled.
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 +11024,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 +13377,12 @@ 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 the user is configured to receive typing notifications from other users.
The server will only deliver typing notifications events to users who for whom this
is enabled.
fluid_layout_width:
type: boolean
description: |
Expand Down Expand Up @@ -14442,6 +14457,18 @@ paths:
client capability and access the `user_settings` object instead.

[capabilities]: /api/register-queue#parameter-client_capabilities
typing_notifications_enabled:
type: boolean
description: |
Whether the user is configured to receive typing notifications from other
users. The server will only deliver typing notifications events to users who
for whom this is enabled.

By default, this is set to true, enabling user to receive typing
notifications from other users.

**Changes**: New in Zulip 9.0 (feature level 251). Previously, there were
only options to disable sending typing notifications.
enter_sends:
deprecated: true
type: boolean
Expand Down Expand Up @@ -15670,6 +15697,12 @@ 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 the user is configured to receive typing notifications from other users.
The server will only deliver typing notifications events to users who for whom this
is enabled.
fluid_layout_width:
type: boolean
description: |
Expand Down Expand Up @@ -16755,6 +16788,19 @@ paths:
the `PATCH /settings/display` endpoint.
type: boolean
example: true
typing_notifications_enabled:
description: |
Whether the user is configured to receive typing notifications from other users.
The server will only deliver typing notifications events to users who for whom this
is enabled.

By default, this is set to true, enabling user to receive typing
notifications from other users.

**Changes**: New in Zulip 9.0 (feature level 251). Previously, there were only
options to disable sending 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 +17356,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 65334ba

Please sign in to comment.