From 286d44bf3347bd99061117ccfa332040b8817f16 Mon Sep 17 00:00:00 2001 From: Karl Stolley Date: Wed, 6 Mar 2024 10:25:31 -0600 Subject: [PATCH] settings: Add new web information density settings. Note that these settings are not operative at present, and are only visible in the settings UI in the development environment. --- api_docs/changelog.md | 10 +++ version.py | 2 +- web/src/admin.js | 1 + web/src/realm_user_settings_defaults.ts | 2 + web/src/server_events_dispatch.js | 2 + web/src/settings.js | 1 + web/src/settings_config.ts | 21 ++++- web/src/settings_preferences.js | 24 +++--- web/src/user_settings.ts | 2 + web/styles/settings.css | 21 +++++ web/templates/settings/display_settings.hbs | 14 ++++ .../settings/settings_numeric_input.hbs | 18 ++++ web/tests/i18n.test.js | 3 + ...lmuserdefault_web_font_size_px_and_more.py | 32 +++++++ zerver/models/users.py | 11 +++ zerver/openapi/zulip.yaml | 84 +++++++++++++++++++ zerver/tests/test_events.py | 4 + zerver/tests/test_realm.py | 2 + zerver/tests/test_settings.py | 2 + zerver/views/realm.py | 2 + zerver/views/user_settings.py | 2 + 21 files changed, 247 insertions(+), 13 deletions(-) create mode 100644 web/templates/settings/settings_numeric_input.hbs create mode 100644 zerver/migrations/0505_realmuserdefault_web_font_size_px_and_more.py diff --git a/api_docs/changelog.md b/api_docs/changelog.md index 78100e78cc..0f56d1e14b 100644 --- a/api_docs/changelog.md +++ b/api_docs/changelog.md @@ -20,6 +20,16 @@ format used by the Zulip server that they are interacting with. ## Changes in Zulip 9.0 +**Feature level 245** + +* [`PATCH + /realm/user_settings_defaults`](/api/update-realm-user-settings-defaults) + [`POST /register`](/api/register-queue), [`GET + /events`](/api/get-events), [`PATCH + /settings`](/api/update-settings): Added new `web_font_size_px` and + `web_line_height_percent` settings to allow users to control the + styling of the web application. + **Feature level 244** * [`POST /register`](/api/register-queue), [`GET /events`](/api/get-events), diff --git a/version.py b/version.py index bcaf71c261..2a77d57bb7 100644 --- a/version.py +++ b/version.py @@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.9.3" # Changes should be accompanied by documentation explaining what the # new level means in api_docs/changelog.md, as well as "**Changes**" # entries in the endpoint's documentation in `zulip.yaml`. -API_FEATURE_LEVEL = 244 +API_FEATURE_LEVEL = 245 # Bump the minor PROVISION_VERSION to indicate that folks should provision # only when going from an old version of the code to a newer version. Bump diff --git a/web/src/admin.js b/web/src/admin.js index 80dd3a4ea8..73a47ecb8b 100644 --- a/web/src/admin.js +++ b/web/src/admin.js @@ -190,6 +190,7 @@ export function build_page() { web_home_view_values: settings_config.web_home_view_values, settings_object: realm_user_settings_defaults, display_settings: settings_config.get_all_preferences(), + information_density_settings: settings_config.get_information_density_preferences(), settings_label: settings_config.realm_user_settings_defaults_labels, desktop_icon_count_display_values: settings_config.desktop_icon_count_display_values, enable_sound_select: diff --git a/web/src/realm_user_settings_defaults.ts b/web/src/realm_user_settings_defaults.ts index aacdd77918..cb5a8c918c 100644 --- a/web/src/realm_user_settings_defaults.ts +++ b/web/src/realm_user_settings_defaults.ts @@ -1,5 +1,7 @@ export type RealmDefaultSettings = { color_scheme: number; + web_font_size_px: number; + web_line_height_percent: number; default_language: string; web_home_view: string; desktop_icon_count_display: number; diff --git a/web/src/server_events_dispatch.js b/web/src/server_events_dispatch.js index e33b9b39b4..c428e55633 100644 --- a/web/src/server_events_dispatch.js +++ b/web/src/server_events_dispatch.js @@ -693,6 +693,8 @@ export function dispatch_normal_event(event) { const user_display_settings = [ "color_scheme", + "web_font_size_px", + "web_line_height_percent", "default_language", "web_home_view", "demote_inactive_streams", diff --git a/web/src/settings.js b/web/src/settings.js index a073d33803..41b1702672 100644 --- a/web/src/settings.js +++ b/web/src/settings.js @@ -119,6 +119,7 @@ export function build_page() { show_push_notifications_tooltip: settings_config.all_notifications(user_settings).show_push_notifications_tooltip, display_settings: settings_config.get_all_preferences(), + information_density_settings: settings_config.get_information_density_preferences(), user_can_change_name: settings_data.user_can_change_name(), user_can_change_avatar: settings_data.user_can_change_avatar(), user_can_change_email: settings_data.user_can_change_email(), diff --git a/web/src/settings_config.ts b/web/src/settings_config.ts index 0264381b02..821422b6ab 100644 --- a/web/src/settings_config.ts +++ b/web/src/settings_config.ts @@ -133,9 +133,12 @@ export type DisplaySettings = { settings: { user_display_settings: string[]; }; + render_group?: boolean; render_only: { - high_contrast_mode: boolean; - dense_mode: boolean; + high_contrast_mode?: boolean; + dense_mode?: boolean; + web_font_size_px?: boolean; + web_line_height_percent?: boolean; }; }; @@ -155,6 +158,18 @@ export const get_all_preferences = (): DisplaySettings => ({ }, }); +/* istanbul ignore next */ +export const get_information_density_preferences = (): DisplaySettings => ({ + render_group: page_params.development_environment, + render_only: { + web_font_size_px: page_params.development_environment, + web_line_height_percent: page_params.development_environment, + }, + settings: { + user_display_settings: ["web_font_size_px", "web_line_height_percent"], + }, +}); + export const email_address_visibility_values = { everyone: { code: 1, @@ -555,6 +570,8 @@ export const preferences_settings_labels = { }), ), 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 (%)"}), default_language_settings_label: $t({defaultMessage: "Language"}), }; diff --git a/web/src/settings_preferences.js b/web/src/settings_preferences.js index 862b418b2c..389935bb99 100644 --- a/web/src/settings_preferences.js +++ b/web/src/settings_preferences.js @@ -193,16 +193,20 @@ export function set_up(settings_panel) { // Common handler for sending requests to the server when an input // element is changed. - $container.on("change", "input[type=checkbox], select", function (e) { - const $input_elem = $(e.currentTarget); - const setting = $input_elem.attr("name"); - const data = {}; - data[setting] = settings_components.get_input_element_value(this); - const $status_element = $input_elem - .closest(".subsection-parent") - .find(".alert-notification"); - change_display_setting(data, $status_element); - }); + $container.on( + "change", + "input[type=checkbox], .information-density-settings input[type=text], select", + function (e) { + const $input_elem = $(e.currentTarget); + const setting = $input_elem.attr("name"); + const data = {}; + data[setting] = settings_components.get_input_element_value(this); + const $status_element = $input_elem + .closest(".subsection-parent") + .find(".alert-notification"); + change_display_setting(data, $status_element); + }, + ); $container.find(".setting_emojiset_choice").on("click", function () { const data = {emojiset: $(this).val()}; diff --git a/web/src/user_settings.ts b/web/src/user_settings.ts index cd7dddb9f0..cdc47f391f 100644 --- a/web/src/user_settings.ts +++ b/web/src/user_settings.ts @@ -60,6 +60,8 @@ export type UserSettings = (StreamNotificationSettings & automatically_unmute_topics_in_muted_streams_policy: number; automatically_follow_topics_where_mentioned: boolean; timezone: string; + web_font_size_px: number; + web_line_height_percent: number; }; export let user_settings: UserSettings; diff --git a/web/styles/settings.css b/web/styles/settings.css index 668382d686..bc0c2c6f2b 100644 --- a/web/styles/settings.css +++ b/web/styles/settings.css @@ -493,6 +493,27 @@ input[type="checkbox"] { } } +.information-density-settings { + max-width: 325px; + + .input-group { + display: flex; + gap: 5px; + align-items: baseline; + + label { + flex: 1 0 max-content; + } + + .settings_text_input { + width: 0; + flex: 0 0 8ch; + margin-left: auto; + text-align: right; + } + } +} + #stream-specific-notify-table .unmute_stream { position: relative; left: 3px; diff --git a/web/templates/settings/display_settings.hbs b/web/templates/settings/display_settings.hbs index 17215f38e9..2830b6de0b 100644 --- a/web/templates/settings/display_settings.hbs +++ b/web/templates/settings/display_settings.hbs @@ -155,6 +155,20 @@ + {{#if information_density_settings.render_group}} +
+
{{t "Information density settings"}}
+ {{#each information_density_settings.settings.user_display_settings}} + {{> settings_numeric_input + setting_name=this + setting_value=(lookup ../settings_object this) + label=(lookup ../settings_label this) + render_only=(lookup ../information_density_settings.render_only this) + prefix=../prefix}} + {{/each}} +
+ {{/if}} + {{#each display_settings.settings.user_display_settings}} {{> settings_checkbox setting_name=this diff --git a/web/templates/settings/settings_numeric_input.hbs b/web/templates/settings/settings_numeric_input.hbs new file mode 100644 index 0000000000..e9828df946 --- /dev/null +++ b/web/templates/settings/settings_numeric_input.hbs @@ -0,0 +1,18 @@ +{{#unless (eq render_only false)}} + +{{/unless}} diff --git a/web/tests/i18n.test.js b/web/tests/i18n.test.js index 881ab66acf..f914310ff1 100644 --- a/web/tests/i18n.test.js +++ b/web/tests/i18n.test.js @@ -89,6 +89,9 @@ run_test("tr_tag", ({mock_template}) => { const args = { botserverrc: "botserverrc", date_joined_text: "Mar 21, 2022", + information_density_settings: { + settings: {}, + }, display_settings: { settings: {}, }, diff --git a/zerver/migrations/0505_realmuserdefault_web_font_size_px_and_more.py b/zerver/migrations/0505_realmuserdefault_web_font_size_px_and_more.py new file mode 100644 index 0000000000..e60bac9199 --- /dev/null +++ b/zerver/migrations/0505_realmuserdefault_web_font_size_px_and_more.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2.11 on 2024-03-26 20:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("zerver", "0504_customprofilefield_required"), + ] + + operations = [ + migrations.AddField( + model_name="realmuserdefault", + name="web_font_size_px", + field=models.PositiveSmallIntegerField(default=14), + ), + migrations.AddField( + model_name="realmuserdefault", + name="web_line_height_percent", + field=models.PositiveSmallIntegerField(default=122), + ), + migrations.AddField( + model_name="userprofile", + name="web_font_size_px", + field=models.PositiveSmallIntegerField(default=14), + ), + migrations.AddField( + model_name="userprofile", + name="web_line_height_percent", + field=models.PositiveSmallIntegerField(default=122), + ), + ] diff --git a/zerver/models/users.py b/zerver/models/users.py index b4b081a19e..6638277751 100644 --- a/zerver/models/users.py +++ b/zerver/models/users.py @@ -78,6 +78,15 @@ class UserBaseSettings(models.Model): COLOR_SCHEME_CHOICES = [COLOR_SCHEME_AUTOMATIC, COLOR_SCHEME_NIGHT, COLOR_SCHEME_LIGHT] color_scheme = models.PositiveSmallIntegerField(default=COLOR_SCHEME_AUTOMATIC) + # Information density is established through + # adjustments to the font size and line height. + WEB_FONT_SIZE_PX_LEGACY = 14 + WEB_LINE_HEIGHT_PERCENT_LEGACY = 122 + web_font_size_px = models.PositiveSmallIntegerField(default=WEB_FONT_SIZE_PX_LEGACY) + web_line_height_percent = models.PositiveSmallIntegerField( + default=WEB_LINE_HEIGHT_PERCENT_LEGACY + ) + # UI setting controlling Zulip's behavior of demoting in the sort # order and graying out streams with no recent traffic. The # default behavior, automatic, enables this behavior once a user @@ -314,6 +323,8 @@ class UserBaseSettings(models.Model): web_mark_read_on_scroll_policy=int, user_list_style=int, web_stream_unreads_count_display_policy=int, + web_font_size_px=int, + web_line_height_percent=int, ) modern_notification_settings: Dict[str, Any] = dict( diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml index d397930933..a43ac6d1b5 100644 --- a/zerver/openapi/zulip.yaml +++ b/zerver/openapi/zulip.yaml @@ -10549,6 +10549,25 @@ paths: - 2 - 3 example: 1 + web_font_size_px: + description: | + User-configured primary `font-size` for the web application, in pixels. + + **Changes**: New in Zulip 9.0 (feature level 245). Previously, font size was + only adjustable via browser zoom. Note that this setting was not fully + implemented at this feature level. + type: integer + example: 14 + web_line_height_percent: + description: | + User-configured primary `line-height` for the web application, in percent, so a + value of 120 represents a `line-height` of 1.2. + + **Changes**: New in Zulip 9.0 (feature level 245). Previously, line height was + not user-configurable. Note that this setting was not fully implemented at this + feature level. + type: integer + example: 122 color_scheme: description: | Controls which [color theme](/help/dark-theme) to use. @@ -10953,6 +10972,10 @@ paths: contentType: application/json web_mark_read_on_scroll_policy: contentType: application/json + web_font_size_px: + contentType: application/json + web_line_height_percent: + contentType: application/json color_scheme: contentType: application/json enable_drafts_synchronization: @@ -12991,6 +13014,25 @@ paths: description: | This setting is reserved for use to control variations in Zulip's design to help visually impaired users. + web_font_size_px: + description: | + User-configured primary `font-size` for the web application, in pixels. + + **Changes**: New in Zulip 9.0 (feature level 245). Previously, font size was + only adjustable via browser zoom. Note that this setting was not fully + implemented at this feature level. + type: integer + example: 14 + web_line_height_percent: + description: | + User-configured primary `line-height` for the web application, in percent, so a + value of 120 represents a `line-height` of 1.2. + + **Changes**: New in Zulip 9.0 (feature level 245). Previously, line height was + not user-configurable. Note that this setting was not fully implemented at this + feature level. + type: integer + example: 122 color_scheme: type: integer description: | @@ -15263,6 +15305,25 @@ paths: description: | This setting is reserved for use to control variations in Zulip's design to help visually impaired users. + web_font_size_px: + description: | + User-configured primary `font-size` for the web application, in pixels. + + **Changes**: New in Zulip 9.0 (feature level 245). Previously, font size was + only adjustable via browser zoom. Note that this setting was not fully + implemented at this feature level. + type: integer + example: 14 + web_line_height_percent: + description: | + User-configured primary `line-height` for the web application, in percent, so a + value of 120 represents a `line-height` of 1.2. + + **Changes**: New in Zulip 9.0 (feature level 245). Previously, line height was + not user-configurable. Note that this setting was not fully implemented at this + feature level. + type: integer + example: 122 color_scheme: type: integer description: | @@ -16337,6 +16398,25 @@ paths: the `PATCH /settings/display` endpoint. type: boolean example: true + web_font_size_px: + description: | + User-configured primary `font-size` for the web application, in pixels. + + **Changes**: New in Zulip 9.0 (feature level 245). Previously, font size was + only adjustable via browser zoom. Note that this setting was not fully + implemented at this feature level. + type: integer + example: 14 + web_line_height_percent: + description: | + User-configured primary `line-height` for the web application, in percent, so a + value of 120 represents a `line-height` of 1.2. + + **Changes**: New in Zulip 9.0 (feature level 245). Previously, line height was + not user-configurable. Note that this setting was not fully implemented at this + feature level. + type: integer + example: 122 color_scheme: description: | Controls which [color theme](/help/dark-theme) to use. @@ -16859,6 +16939,10 @@ paths: contentType: application/json high_contrast_mode: contentType: application/json + web_font_size_px: + contentType: application/json + web_line_height_percent: + contentType: application/json color_scheme: contentType: application/json enable_drafts_synchronization: diff --git a/zerver/tests/test_events.py b/zerver/tests/test_events.py index 7b57a796c9..ad5f04306c 100644 --- a/zerver/tests/test_events.py +++ b/zerver/tests/test_events.py @@ -3713,6 +3713,8 @@ class RealmPropertyActionTest(BaseAction): def do_set_realm_user_default_setting_test(self, name: str) -> None: bool_tests: List[bool] = [True, False, True] test_values: Dict[str, Any] = dict( + web_font_size_px=[UserProfile.WEB_FONT_SIZE_PX_LEGACY], + web_line_height_percent=[UserProfile.WEB_LINE_HEIGHT_PERCENT_LEGACY], color_scheme=UserProfile.COLOR_SCHEME_CHOICES, web_home_view=["recent_topics", "inbox", "all_messages"], emojiset=[emojiset["key"] for emojiset in RealmUserDefault.emojiset_choices()], @@ -3854,6 +3856,8 @@ class UserDisplayActionTest(BaseAction): web_mark_read_on_scroll_policy=[2, 3, 1], user_list_style=[1, 2, 3], web_stream_unreads_count_display_policy=[1, 2, 3], + web_font_size_px=[12, 16, 18], + web_line_height_percent=[105, 120, 160], color_scheme=[2, 3, 1], email_address_visibility=[5, 4, 1, 2, 3], ) diff --git a/zerver/tests/test_realm.py b/zerver/tests/test_realm.py index 7cec9b3dc1..3a2e4677eb 100644 --- a/zerver/tests/test_realm.py +++ b/zerver/tests/test_realm.py @@ -1579,6 +1579,8 @@ class RealmAPITest(ZulipTestCase): def do_test_realm_default_setting_update_api(self, name: str) -> None: bool_tests: List[bool] = [False, True] test_values: Dict[str, Any] = dict( + web_font_size_px=[UserProfile.WEB_FONT_SIZE_PX_LEGACY], + web_line_height_percent=[UserProfile.WEB_LINE_HEIGHT_PERCENT_LEGACY], color_scheme=UserProfile.COLOR_SCHEME_CHOICES, web_home_view=["recent_topics", "inbox", "all_messages"], emojiset=[emojiset["key"] for emojiset in RealmUserDefault.emojiset_choices()], diff --git a/zerver/tests/test_settings.py b/zerver/tests/test_settings.py index 2862388040..fbb0486234 100644 --- a/zerver/tests/test_settings.py +++ b/zerver/tests/test_settings.py @@ -352,6 +352,8 @@ class ChangeSettingsTest(ZulipTestCase): web_mark_read_on_scroll_policy=2, user_list_style=2, web_stream_unreads_count_display_policy=2, + web_font_size_px=14, + web_line_height_percent=122, color_scheme=2, email_notifications_batching_period_seconds=100, notification_sound="ding", diff --git a/zerver/views/realm.py b/zerver/views/realm.py index 0e368dc1e4..cada34a8f0 100644 --- a/zerver/views/realm.py +++ b/zerver/views/realm.py @@ -529,6 +529,8 @@ def update_realm_user_settings_defaults( color_scheme: Optional[int] = REQ( json_validator=check_int_in(UserProfile.COLOR_SCHEME_CHOICES), default=None ), + web_font_size_px: Optional[int] = REQ(json_validator=check_int, default=None), + web_line_height_percent: Optional[int] = REQ(json_validator=check_int, default=None), translate_emoticons: Optional[bool] = REQ(json_validator=check_bool, default=None), display_emoji_reaction_users: Optional[bool] = REQ(json_validator=check_bool, default=None), web_home_view: Optional[str] = REQ( diff --git a/zerver/views/user_settings.py b/zerver/views/user_settings.py index e25cc5e9a2..d5475f0552 100644 --- a/zerver/views/user_settings.py +++ b/zerver/views/user_settings.py @@ -213,6 +213,8 @@ def json_change_settings( color_scheme: Optional[int] = REQ( json_validator=check_int_in(UserProfile.COLOR_SCHEME_CHOICES), default=None ), + web_font_size_px: Optional[int] = REQ(json_validator=check_int, default=None), + web_line_height_percent: Optional[int] = REQ(json_validator=check_int, default=None), translate_emoticons: Optional[bool] = REQ(json_validator=check_bool, default=None), display_emoji_reaction_users: Optional[bool] = REQ(json_validator=check_bool, default=None), default_language: Optional[str] = REQ(default=None),