mirror of https://github.com/zulip/zulip.git
settings: Add setting to control how animated images are played.
Previously animated images were automatically played in the message feed of the web app. Now that we have still thumbnails available for them, we can add a new personal setting, "web_animate_image_previews", which controls how the animated images would be played in the web app message feed -- always played, on hover, or only in the image viewer. Fixes #31016.
This commit is contained in:
parent
1c30ea1819
commit
66a96bee71
|
@ -20,6 +20,14 @@ format used by the Zulip server that they are interacting with.
|
||||||
|
|
||||||
## Changes in Zulip 9.0
|
## Changes in Zulip 9.0
|
||||||
|
|
||||||
|
**Feature level 275**
|
||||||
|
|
||||||
|
* [`POST /register`](/api/register-queue), [`PATCH
|
||||||
|
/settings`](/api/update-settings), [`PATCH
|
||||||
|
/realm/user_settings_defaults`](/api/update-realm-user-settings-defaults):
|
||||||
|
Added new `web_animate_image_previews` setting, which controls how
|
||||||
|
animated images should be played in the web/desktop app message feed.
|
||||||
|
|
||||||
**Feature level 274**
|
**Feature level 274**
|
||||||
|
|
||||||
* [`GET /events`](/api/get-events): `delete_message` events are now
|
* [`GET /events`](/api/get-events): `delete_message` events are now
|
||||||
|
|
|
@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
|
||||||
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
||||||
# entries in the endpoint's documentation in `zulip.yaml`.
|
# entries in the endpoint's documentation in `zulip.yaml`.
|
||||||
|
|
||||||
API_FEATURE_LEVEL = 274 # Last bumped for `delete_message` event.
|
API_FEATURE_LEVEL = 275 # Last bumped for `web_animate_image_previews` setting.
|
||||||
|
|
||||||
|
|
||||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||||
|
|
|
@ -194,6 +194,7 @@ export function build_page() {
|
||||||
user_list_style_values: settings_config.user_list_style_values,
|
user_list_style_values: settings_config.user_list_style_values,
|
||||||
web_stream_unreads_count_display_policy_values:
|
web_stream_unreads_count_display_policy_values:
|
||||||
settings_config.web_stream_unreads_count_display_policy_values,
|
settings_config.web_stream_unreads_count_display_policy_values,
|
||||||
|
web_animate_image_previews_values: settings_config.web_animate_image_previews_values,
|
||||||
color_scheme_values: settings_config.color_scheme_values,
|
color_scheme_values: settings_config.color_scheme_values,
|
||||||
web_home_view_values: settings_config.web_home_view_values,
|
web_home_view_values: settings_config.web_home_view_values,
|
||||||
settings_object: realm_user_settings_defaults,
|
settings_object: realm_user_settings_defaults,
|
||||||
|
|
|
@ -119,6 +119,7 @@ export function initialize() {
|
||||||
// Inline image, video and twitter previews.
|
// Inline image, video and twitter previews.
|
||||||
if (
|
if (
|
||||||
$target.is("img.message_inline_image") ||
|
$target.is("img.message_inline_image") ||
|
||||||
|
$target.is(".message_inline_animated_image_still") ||
|
||||||
$target.is("video") ||
|
$target.is("video") ||
|
||||||
$target.is(".message_inline_video") ||
|
$target.is(".message_inline_video") ||
|
||||||
$target.is("img.twitter-avatar")
|
$target.is("img.twitter-avatar")
|
||||||
|
|
|
@ -580,7 +580,7 @@ export function initialize(): void {
|
||||||
|
|
||||||
$("#main_div, #compose .preview_content").on(
|
$("#main_div, #compose .preview_content").on(
|
||||||
"click",
|
"click",
|
||||||
".message_inline_image:not(.message_inline_video) a",
|
".message_inline_image:not(.message_inline_video) a, .message_inline_animated_image_still",
|
||||||
function (e) {
|
function (e) {
|
||||||
// prevent the link from opening in a new page.
|
// prevent the link from opening in a new page.
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
|
@ -6,6 +6,8 @@ import render_edit_content_button from "../templates/edit_content_button.hbs";
|
||||||
import * as message_edit from "./message_edit";
|
import * as message_edit from "./message_edit";
|
||||||
import * as message_lists from "./message_lists";
|
import * as message_lists from "./message_lists";
|
||||||
import * as rows from "./rows";
|
import * as rows from "./rows";
|
||||||
|
import * as thumbnail from "./thumbnail";
|
||||||
|
import {user_settings} from "./user_settings";
|
||||||
|
|
||||||
let $current_message_hover;
|
let $current_message_hover;
|
||||||
export function message_unhover() {
|
export function message_unhover() {
|
||||||
|
@ -73,6 +75,40 @@ export function initialize() {
|
||||||
$row.removeClass("sender_info_hovered");
|
$row.removeClass("sender_info_hovered");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#main_div").on(
|
||||||
|
"mouseover",
|
||||||
|
'.message-list div.message_inline_image img[data-animated="true"]',
|
||||||
|
function () {
|
||||||
|
if (user_settings.web_animate_image_previews !== "on_hover") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const $img = $(this);
|
||||||
|
$img.closest(".message_inline_image").removeClass(
|
||||||
|
"message_inline_animated_image_still",
|
||||||
|
);
|
||||||
|
$img.attr(
|
||||||
|
"src",
|
||||||
|
$img.attr("src").replace(/\/[^/]+$/, "/" + thumbnail.animated_format.name),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
$("#main_div").on(
|
||||||
|
"mouseout",
|
||||||
|
'.message-list div.message_inline_image img[data-animated="true"]',
|
||||||
|
function () {
|
||||||
|
if (user_settings.web_animate_image_previews !== "on_hover") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const $img = $(this);
|
||||||
|
$img.closest(".message_inline_image").addClass("message_inline_animated_image_still");
|
||||||
|
$img.attr(
|
||||||
|
"src",
|
||||||
|
$img.attr("src").replace(/\/[^/]+$/, "/" + thumbnail.preferred_format.name),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
function handle_video_preview_mouseenter($elem) {
|
function handle_video_preview_mouseenter($elem) {
|
||||||
// Set image height and css vars for play button position, if not done already
|
// Set image height and css vars for play button position, if not done already
|
||||||
const setPosition = !$elem.data("entered-before");
|
const setPosition = !$elem.data("entered-before");
|
||||||
|
|
|
@ -52,6 +52,7 @@ export const realm_default_settings_schema = z.object({
|
||||||
translate_emoticons: z.boolean(),
|
translate_emoticons: z.boolean(),
|
||||||
twenty_four_hour_time: z.boolean(),
|
twenty_four_hour_time: z.boolean(),
|
||||||
user_list_style: z.number(),
|
user_list_style: z.number(),
|
||||||
|
web_animate_image_previews: z.string(),
|
||||||
web_channel_default_view: z.number(),
|
web_channel_default_view: z.number(),
|
||||||
web_escape_navigates_to_home_view: z.boolean(),
|
web_escape_navigates_to_home_view: z.boolean(),
|
||||||
web_font_size_px: z.number(),
|
web_font_size_px: z.number(),
|
||||||
|
|
|
@ -345,7 +345,21 @@ export const update_elements = ($content: JQuery): void => {
|
||||||
const $inline_img_thumbnail = $(this);
|
const $inline_img_thumbnail = $(this);
|
||||||
let thumbnail_name = thumbnail.preferred_format.name;
|
let thumbnail_name = thumbnail.preferred_format.name;
|
||||||
if ($inline_img_thumbnail.attr("data-animated") === "true") {
|
if ($inline_img_thumbnail.attr("data-animated") === "true") {
|
||||||
thumbnail_name = thumbnail.animated_format.name;
|
if (
|
||||||
|
user_settings.web_animate_image_previews === "always" ||
|
||||||
|
// Treat on_hover as "always" on mobile web, where
|
||||||
|
// hovering is impossible and there's much less on
|
||||||
|
// the screen.
|
||||||
|
(user_settings.web_animate_image_previews === "on_hover" && util.is_mobile())
|
||||||
|
) {
|
||||||
|
thumbnail_name = thumbnail.animated_format.name;
|
||||||
|
} else {
|
||||||
|
// If we're showing a still thumbnail, show a play
|
||||||
|
// button so that users that it can be played.
|
||||||
|
$inline_img_thumbnail
|
||||||
|
.closest(".message_inline_image")
|
||||||
|
.addClass("message_inline_animated_image_still");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$inline_img_thumbnail.attr(
|
$inline_img_thumbnail.attr(
|
||||||
"src",
|
"src",
|
||||||
|
|
|
@ -728,6 +728,7 @@ export function dispatch_normal_event(event) {
|
||||||
"translate_emoticons",
|
"translate_emoticons",
|
||||||
"display_emoji_reaction_users",
|
"display_emoji_reaction_users",
|
||||||
"user_list_style",
|
"user_list_style",
|
||||||
|
"web_animate_image_previews",
|
||||||
"web_stream_unreads_count_display_policy",
|
"web_stream_unreads_count_display_policy",
|
||||||
"starred_message_counts",
|
"starred_message_counts",
|
||||||
"send_stream_typing_notifications",
|
"send_stream_typing_notifications",
|
||||||
|
@ -779,6 +780,12 @@ export function dispatch_normal_event(event) {
|
||||||
stream_list.update_streams_sidebar();
|
stream_list.update_streams_sidebar();
|
||||||
stream_list_sort.set_filter_out_inactives();
|
stream_list_sort.set_filter_out_inactives();
|
||||||
}
|
}
|
||||||
|
if (event.property === "web_animate_image_previews") {
|
||||||
|
// Rerender the whole message list UI
|
||||||
|
for (const msg_list of message_lists.all_rendered_message_lists()) {
|
||||||
|
msg_list.rerender();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (event.property === "web_stream_unreads_count_display_policy") {
|
if (event.property === "web_stream_unreads_count_display_policy") {
|
||||||
stream_list.update_dom_unread_counts_visibility();
|
stream_list.update_dom_unread_counts_visibility();
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,7 @@ export function build_page() {
|
||||||
settings_config.web_mark_read_on_scroll_policy_values,
|
settings_config.web_mark_read_on_scroll_policy_values,
|
||||||
web_channel_default_view_values: settings_config.web_channel_default_view_values,
|
web_channel_default_view_values: settings_config.web_channel_default_view_values,
|
||||||
user_list_style_values: settings_config.user_list_style_values,
|
user_list_style_values: settings_config.user_list_style_values,
|
||||||
|
web_animate_image_previews_values: settings_config.web_animate_image_previews_values,
|
||||||
web_stream_unreads_count_display_policy_values:
|
web_stream_unreads_count_display_policy_values:
|
||||||
settings_config.web_stream_unreads_count_display_policy_values,
|
settings_config.web_stream_unreads_count_display_policy_values,
|
||||||
color_scheme_values: settings_config.color_scheme_values,
|
color_scheme_values: settings_config.color_scheme_values,
|
||||||
|
|
|
@ -84,6 +84,21 @@ export const user_list_style_values = {
|
||||||
// },
|
// },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const web_animate_image_previews_values = {
|
||||||
|
always: {
|
||||||
|
code: "always",
|
||||||
|
description: $t({defaultMessage: "Always"}),
|
||||||
|
},
|
||||||
|
on_hover: {
|
||||||
|
code: "on_hover",
|
||||||
|
description: $t({defaultMessage: "On hover"}),
|
||||||
|
},
|
||||||
|
never: {
|
||||||
|
code: "never",
|
||||||
|
description: $t({defaultMessage: "Only in image viewer"}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const web_stream_unreads_count_display_policy_values = {
|
export const web_stream_unreads_count_display_policy_values = {
|
||||||
all_streams: {
|
all_streams: {
|
||||||
code: 1,
|
code: 1,
|
||||||
|
|
|
@ -230,6 +230,9 @@ export function set_up(settings_panel: SettingsPanel): void {
|
||||||
.find(`.setting_user_list_style_choice[value=${settings_object.user_list_style}]`)
|
.find(`.setting_user_list_style_choice[value=${settings_object.user_list_style}]`)
|
||||||
.prop("checked", true);
|
.prop("checked", true);
|
||||||
|
|
||||||
|
$container
|
||||||
|
.find(".setting_web_animate_image_previews")
|
||||||
|
.val(settings_object.web_animate_image_previews);
|
||||||
$container
|
$container
|
||||||
.find(".setting_web_stream_unreads_count_display_policy")
|
.find(".setting_web_stream_unreads_count_display_policy")
|
||||||
.val(settings_object.web_stream_unreads_count_display_policy);
|
.val(settings_object.web_stream_unreads_count_display_policy);
|
||||||
|
|
|
@ -71,6 +71,7 @@ export const user_settings_schema = stream_notification_settings_schema
|
||||||
translate_emoticons: z.boolean(),
|
translate_emoticons: z.boolean(),
|
||||||
twenty_four_hour_time: z.boolean(),
|
twenty_four_hour_time: z.boolean(),
|
||||||
user_list_style: z.number(),
|
user_list_style: z.number(),
|
||||||
|
web_animate_image_previews: z.enum(["always", "on_hover", "never"]),
|
||||||
web_channel_default_view: z.number(),
|
web_channel_default_view: z.number(),
|
||||||
web_escape_navigates_to_home_view: z.boolean(),
|
web_escape_navigates_to_home_view: z.boolean(),
|
||||||
web_font_size_px: z.number(),
|
web_font_size_px: z.number(),
|
||||||
|
|
|
@ -564,7 +564,8 @@
|
||||||
float: none;
|
float: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message_inline_video {
|
.message_inline_video,
|
||||||
|
.message_inline_animated_image_still {
|
||||||
&:hover {
|
&:hover {
|
||||||
&::after {
|
&::after {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
|
|
|
@ -35,6 +35,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group thinner setting-next-is-related">
|
||||||
|
<label for="web_animate_image_previews" class="settings-field-label">{{t "Play animated images" }}</label>
|
||||||
|
<select name="web_animate_image_previews" class="setting_web_animate_image_previews prop-element settings_select bootstrap-focus-style" id="{{prefix}}web_animate_image_previews" data-setting-widget-type="string">
|
||||||
|
{{> dropdown_options_widget option_values=web_animate_image_previews_values}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<label for="web_stream_unreads_count_display_policy" class="settings-field-label">{{t "Show unread counts for" }}</label>
|
<label for="web_stream_unreads_count_display_policy" class="settings-field-label">{{t "Show unread counts for" }}</label>
|
||||||
<select name="web_stream_unreads_count_display_policy" class="setting_web_stream_unreads_count_display_policy prop-element bootstrap-focus-style settings_select" id="{{prefix}}web_stream_unreads_count_display_policy" data-setting-widget-type="number">
|
<select name="web_stream_unreads_count_display_policy" class="setting_web_stream_unreads_count_display_policy prop-element bootstrap-focus-style settings_select" id="{{prefix}}web_stream_unreads_count_display_policy" data-setting-widget-type="number">
|
||||||
|
|
|
@ -1031,6 +1031,26 @@ run_test("user_settings", ({override}) => {
|
||||||
dispatch(event);
|
dispatch(event);
|
||||||
assert.equal(user_settings.web_home_view, "inbox");
|
assert.equal(user_settings.web_home_view, "inbox");
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
event = event_fixtures.user_settings__web_animate_image_previews_always;
|
||||||
|
user_settings.web_animate_image_previews = "on_hover";
|
||||||
|
dispatch(event);
|
||||||
|
assert.equal(user_settings.web_animate_image_previews, "always");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
event = event_fixtures.user_settings__web_animate_image_previews_on_hover;
|
||||||
|
user_settings.web_animate_image_previews = "never";
|
||||||
|
dispatch(event);
|
||||||
|
assert.equal(user_settings.web_animate_image_previews, "on_hover");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
event = event_fixtures.user_settings__web_animate_image_previews_never;
|
||||||
|
user_settings.web_animate_image_previews = "always";
|
||||||
|
dispatch(event);
|
||||||
|
assert.equal(user_settings.web_animate_image_previews, "never");
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const stub = make_stub();
|
const stub = make_stub();
|
||||||
|
|
|
@ -1023,6 +1023,27 @@ exports.fixtures = {
|
||||||
value: 2,
|
value: 2,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
user_settings__web_animate_image_previews_always: {
|
||||||
|
type: "user_settings",
|
||||||
|
op: "update",
|
||||||
|
property: "web_animate_image_previews",
|
||||||
|
value: "always",
|
||||||
|
},
|
||||||
|
|
||||||
|
user_settings__web_animate_image_previews_never: {
|
||||||
|
type: "user_settings",
|
||||||
|
op: "update",
|
||||||
|
property: "web_animate_image_previews",
|
||||||
|
value: "never",
|
||||||
|
},
|
||||||
|
|
||||||
|
user_settings__web_animate_image_previews_on_hover: {
|
||||||
|
type: "user_settings",
|
||||||
|
op: "update",
|
||||||
|
property: "web_animate_image_previews",
|
||||||
|
value: "on_hover",
|
||||||
|
},
|
||||||
|
|
||||||
user_settings__web_channel_default_view: {
|
user_settings__web_channel_default_view: {
|
||||||
type: "user_settings",
|
type: "user_settings",
|
||||||
op: "update",
|
op: "update",
|
||||||
|
|
|
@ -201,7 +201,7 @@ run_test("message_inline_video", () => {
|
||||||
window.GestureEvent = false;
|
window.GestureEvent = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
run_test("message_inline_animated_image", ({override}) => {
|
run_test("message_inline_animated_image_still", ({override}) => {
|
||||||
const $content = get_content_element();
|
const $content = get_content_element();
|
||||||
const $elem = $.create("img");
|
const $elem = $.create("img");
|
||||||
|
|
||||||
|
@ -213,6 +213,13 @@ run_test("message_inline_animated_image", ({override}) => {
|
||||||
$array([$elem]),
|
$array([$elem]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const $stub = $.create("div.message_inline_image");
|
||||||
|
|
||||||
|
$elem.closest = (closest_opts) => {
|
||||||
|
assert.equal(closest_opts, ".message_inline_image");
|
||||||
|
return $stub;
|
||||||
|
};
|
||||||
|
|
||||||
const thumbnail_formats = [
|
const thumbnail_formats = [
|
||||||
{
|
{
|
||||||
name: "840x560-anim.webp",
|
name: "840x560-anim.webp",
|
||||||
|
@ -257,9 +264,22 @@ run_test("message_inline_animated_image", ({override}) => {
|
||||||
rm.update_elements($content);
|
rm.update_elements($content);
|
||||||
assert.equal($elem.attr("src"), "/path/to/840x560.webp");
|
assert.equal($elem.attr("src"), "/path/to/840x560.webp");
|
||||||
|
|
||||||
|
// Now verify the behavior for animated images.
|
||||||
$elem.attr("data-animated", "true");
|
$elem.attr("data-animated", "true");
|
||||||
|
override(user_settings, "web_animate_image_previews", "always");
|
||||||
rm.update_elements($content);
|
rm.update_elements($content);
|
||||||
assert.equal($elem.attr("src"), "/path/to/840x560-anim.webp");
|
assert.equal($elem.attr("src"), "/path/to/840x560-anim.webp");
|
||||||
|
|
||||||
|
// And verify the different behavior for other values of the animation setting.
|
||||||
|
override(user_settings, "web_animate_image_previews", "on_hover");
|
||||||
|
rm.update_elements($content);
|
||||||
|
assert.equal($elem.attr("src"), "/path/to/840x560.webp");
|
||||||
|
assert.equal($stub.hasClass("message_inline_animated_image_still"), true);
|
||||||
|
|
||||||
|
override(user_settings, "web_animate_image_previews", "never");
|
||||||
|
rm.update_elements($content);
|
||||||
|
assert.equal($elem.attr("src"), "/path/to/840x560.webp");
|
||||||
|
assert.equal($stub.hasClass("message_inline_animated_image_still"), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
run_test("user-mention", () => {
|
run_test("user-mention", () => {
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-20 10:56
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("zerver", "0557_change_information_density_defaults"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="realmuserdefault",
|
||||||
|
name="web_animate_image_previews",
|
||||||
|
field=models.TextField(default="on_hover"),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="userprofile",
|
||||||
|
name="web_animate_image_previews",
|
||||||
|
field=models.TextField(default="on_hover"),
|
||||||
|
),
|
||||||
|
]
|
|
@ -89,6 +89,9 @@ class UserBaseSettings(models.Model):
|
||||||
default=WEB_LINE_HEIGHT_PERCENT_DEFAULT
|
default=WEB_LINE_HEIGHT_PERCENT_DEFAULT
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# UI setting to control how animated images are played.
|
||||||
|
web_animate_image_previews = models.TextField(default="on_hover")
|
||||||
|
|
||||||
# UI setting controlling Zulip's behavior of demoting in the sort
|
# UI setting controlling Zulip's behavior of demoting in the sort
|
||||||
# order and graying out streams with no recent traffic. The
|
# order and graying out streams with no recent traffic. The
|
||||||
# default behavior, automatic, enables this behavior once a user
|
# default behavior, automatic, enables this behavior once a user
|
||||||
|
@ -350,6 +353,7 @@ class UserBaseSettings(models.Model):
|
||||||
web_mark_read_on_scroll_policy=int,
|
web_mark_read_on_scroll_policy=int,
|
||||||
web_channel_default_view=int,
|
web_channel_default_view=int,
|
||||||
user_list_style=int,
|
user_list_style=int,
|
||||||
|
web_animate_image_previews=str,
|
||||||
web_stream_unreads_count_display_policy=int,
|
web_stream_unreads_count_display_policy=int,
|
||||||
web_font_size_px=int,
|
web_font_size_px=int,
|
||||||
web_line_height_percent=int,
|
web_line_height_percent=int,
|
||||||
|
|
|
@ -11334,6 +11334,23 @@ paths:
|
||||||
- 2
|
- 2
|
||||||
- 3
|
- 3
|
||||||
example: 1
|
example: 1
|
||||||
|
web_animate_image_previews:
|
||||||
|
description: |
|
||||||
|
Controls how animated images should be played in the message feed in the web/desktop application.
|
||||||
|
|
||||||
|
- "always" - Always play the animated images in the message feed.
|
||||||
|
- "on_hover" - Play the animated images on hover over them in the message feed.
|
||||||
|
- "never" - Never play animated images in the message feed.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 9.0 (feature level 275). Previously, animated images
|
||||||
|
always used to play in the message feed by default. This setting controls this
|
||||||
|
behaviour.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- always
|
||||||
|
- on_hover
|
||||||
|
- never
|
||||||
|
example: on_hover
|
||||||
web_stream_unreads_count_display_policy:
|
web_stream_unreads_count_display_policy:
|
||||||
description: |
|
description: |
|
||||||
Configuration for which channels should be displayed with a numeric unread count in the left sidebar.
|
Configuration for which channels should be displayed with a numeric unread count in the left sidebar.
|
||||||
|
@ -14304,6 +14321,16 @@ paths:
|
||||||
- 3 - With avatar and status
|
- 3 - With avatar and status
|
||||||
|
|
||||||
**Changes**: New in Zulip 6.0 (feature level 141).
|
**Changes**: New in Zulip 6.0 (feature level 141).
|
||||||
|
web_animate_image_previews:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
Controls how animated images should be played in the message feed in the web/desktop application.
|
||||||
|
|
||||||
|
- "always" - Always play the animated images in the message feed.
|
||||||
|
- "on_hover" - Play the animated images on hover over them in the message feed.
|
||||||
|
- "never" - Never play animated images in the message feed.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 9.0 (feature level 275).
|
||||||
web_stream_unreads_count_display_policy:
|
web_stream_unreads_count_display_policy:
|
||||||
type: integer
|
type: integer
|
||||||
description: |
|
description: |
|
||||||
|
@ -16766,6 +16793,16 @@ paths:
|
||||||
- 3 - With avatar and status
|
- 3 - With avatar and status
|
||||||
|
|
||||||
**Changes**: New in Zulip 6.0 (feature level 141).
|
**Changes**: New in Zulip 6.0 (feature level 141).
|
||||||
|
web_animate_image_previews:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
Controls how animated images should be played in the message feed in the web/desktop application.
|
||||||
|
|
||||||
|
- "always" - Always play the animated images in the message feed.
|
||||||
|
- "on_hover" - Play the animated images on hover over them in the message feed.
|
||||||
|
- "never" - Never play animated images in the message feed.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 9.0 (feature level 275).
|
||||||
web_stream_unreads_count_display_policy:
|
web_stream_unreads_count_display_policy:
|
||||||
type: integer
|
type: integer
|
||||||
description: |
|
description: |
|
||||||
|
@ -17967,6 +18004,21 @@ paths:
|
||||||
- 2
|
- 2
|
||||||
- 3
|
- 3
|
||||||
example: 1
|
example: 1
|
||||||
|
web_animate_image_previews:
|
||||||
|
description: |
|
||||||
|
Controls how animated images should be played in the message feed in the web/desktop application.
|
||||||
|
|
||||||
|
- "always" - Always play the animated images in the message feed.
|
||||||
|
- "on_hover" - Play the animated images on hover over them in the message feed.
|
||||||
|
- "never" - Never play animated images in the message feed.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 9.0 (feature level 275).
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- always
|
||||||
|
- on_hover
|
||||||
|
- never
|
||||||
|
example: on_hover
|
||||||
web_stream_unreads_count_display_policy:
|
web_stream_unreads_count_display_policy:
|
||||||
description: |
|
description: |
|
||||||
Configuration for which channels should be displayed with a numeric unread count in the left sidebar.
|
Configuration for which channels should be displayed with a numeric unread count in the left sidebar.
|
||||||
|
|
|
@ -775,6 +775,7 @@ class TestRealmAuditLog(ZulipTestCase):
|
||||||
value: bool | int | str
|
value: bool | int | str
|
||||||
test_values = dict(
|
test_values = dict(
|
||||||
default_language="de",
|
default_language="de",
|
||||||
|
web_animate_image_previews="on_hover",
|
||||||
web_home_view="all_messages",
|
web_home_view="all_messages",
|
||||||
emojiset="twitter",
|
emojiset="twitter",
|
||||||
notification_sound="ding",
|
notification_sound="ding",
|
||||||
|
|
|
@ -3787,6 +3787,7 @@ class RealmPropertyActionTest(BaseAction):
|
||||||
web_mark_read_on_scroll_policy=UserProfile.WEB_MARK_READ_ON_SCROLL_POLICY_CHOICES,
|
web_mark_read_on_scroll_policy=UserProfile.WEB_MARK_READ_ON_SCROLL_POLICY_CHOICES,
|
||||||
web_channel_default_view=UserProfile.WEB_CHANNEL_DEFAULT_VIEW_CHOICES,
|
web_channel_default_view=UserProfile.WEB_CHANNEL_DEFAULT_VIEW_CHOICES,
|
||||||
user_list_style=UserProfile.USER_LIST_STYLE_CHOICES,
|
user_list_style=UserProfile.USER_LIST_STYLE_CHOICES,
|
||||||
|
web_animate_image_previews=["always", "on_hover", "never"],
|
||||||
web_stream_unreads_count_display_policy=UserProfile.WEB_STREAM_UNREADS_COUNT_DISPLAY_POLICY_CHOICES,
|
web_stream_unreads_count_display_policy=UserProfile.WEB_STREAM_UNREADS_COUNT_DISPLAY_POLICY_CHOICES,
|
||||||
desktop_icon_count_display=UserProfile.DESKTOP_ICON_COUNT_DISPLAY_CHOICES,
|
desktop_icon_count_display=UserProfile.DESKTOP_ICON_COUNT_DISPLAY_CHOICES,
|
||||||
notification_sound=["zulip", "ding"],
|
notification_sound=["zulip", "ding"],
|
||||||
|
@ -3916,6 +3917,7 @@ class UserDisplayActionTest(BaseAction):
|
||||||
web_mark_read_on_scroll_policy=[2, 3, 1],
|
web_mark_read_on_scroll_policy=[2, 3, 1],
|
||||||
web_channel_default_view=[2, 1],
|
web_channel_default_view=[2, 1],
|
||||||
user_list_style=[1, 2, 3],
|
user_list_style=[1, 2, 3],
|
||||||
|
web_animate_image_previews=["always", "on_hover", "never"],
|
||||||
web_stream_unreads_count_display_policy=[1, 2, 3],
|
web_stream_unreads_count_display_policy=[1, 2, 3],
|
||||||
web_font_size_px=[12, 16, 18],
|
web_font_size_px=[12, 16, 18],
|
||||||
web_line_height_percent=[105, 120, 160],
|
web_line_height_percent=[105, 120, 160],
|
||||||
|
|
|
@ -1946,6 +1946,7 @@ class RealmAPITest(ZulipTestCase):
|
||||||
web_mark_read_on_scroll_policy=UserProfile.WEB_MARK_READ_ON_SCROLL_POLICY_CHOICES,
|
web_mark_read_on_scroll_policy=UserProfile.WEB_MARK_READ_ON_SCROLL_POLICY_CHOICES,
|
||||||
web_channel_default_view=UserProfile.WEB_CHANNEL_DEFAULT_VIEW_CHOICES,
|
web_channel_default_view=UserProfile.WEB_CHANNEL_DEFAULT_VIEW_CHOICES,
|
||||||
user_list_style=UserProfile.USER_LIST_STYLE_CHOICES,
|
user_list_style=UserProfile.USER_LIST_STYLE_CHOICES,
|
||||||
|
web_animate_image_previews=["always", "on_hover", "never"],
|
||||||
web_stream_unreads_count_display_policy=UserProfile.WEB_STREAM_UNREADS_COUNT_DISPLAY_POLICY_CHOICES,
|
web_stream_unreads_count_display_policy=UserProfile.WEB_STREAM_UNREADS_COUNT_DISPLAY_POLICY_CHOICES,
|
||||||
desktop_icon_count_display=UserProfile.DESKTOP_ICON_COUNT_DISPLAY_CHOICES,
|
desktop_icon_count_display=UserProfile.DESKTOP_ICON_COUNT_DISPLAY_CHOICES,
|
||||||
notification_sound=["zulip", "ding"],
|
notification_sound=["zulip", "ding"],
|
||||||
|
|
|
@ -360,6 +360,7 @@ class ChangeSettingsTest(ZulipTestCase):
|
||||||
web_mark_read_on_scroll_policy=2,
|
web_mark_read_on_scroll_policy=2,
|
||||||
web_channel_default_view=2,
|
web_channel_default_view=2,
|
||||||
user_list_style=2,
|
user_list_style=2,
|
||||||
|
web_animate_image_previews="on_hover",
|
||||||
web_stream_unreads_count_display_policy=2,
|
web_stream_unreads_count_display_policy=2,
|
||||||
web_font_size_px=14,
|
web_font_size_px=14,
|
||||||
web_line_height_percent=122,
|
web_line_height_percent=122,
|
||||||
|
@ -415,6 +416,7 @@ class ChangeSettingsTest(ZulipTestCase):
|
||||||
web_mark_read_on_scroll_policy=10,
|
web_mark_read_on_scroll_policy=10,
|
||||||
web_channel_default_view=10,
|
web_channel_default_view=10,
|
||||||
user_list_style=10,
|
user_list_style=10,
|
||||||
|
web_animate_image_previews="invalid_value",
|
||||||
web_stream_unreads_count_display_policy=10,
|
web_stream_unreads_count_display_policy=10,
|
||||||
color_scheme=10,
|
color_scheme=10,
|
||||||
notification_sound="invalid_sound",
|
notification_sound="invalid_sound",
|
||||||
|
|
|
@ -638,6 +638,7 @@ def update_realm_user_settings_defaults(
|
||||||
Annotated[int, check_int_in_validator(UserProfile.USER_LIST_STYLE_CHOICES)]
|
Annotated[int, check_int_in_validator(UserProfile.USER_LIST_STYLE_CHOICES)]
|
||||||
]
|
]
|
||||||
| None = None,
|
| None = None,
|
||||||
|
web_animate_image_previews: Literal["always", "on_hover", "never"] | None = None,
|
||||||
email_address_visibility: Json[
|
email_address_visibility: Json[
|
||||||
Annotated[int, check_int_in_validator(UserProfile.EMAIL_ADDRESS_VISIBILITY_TYPES)]
|
Annotated[int, check_int_in_validator(UserProfile.EMAIL_ADDRESS_VISIBILITY_TYPES)]
|
||||||
]
|
]
|
||||||
|
|
|
@ -161,6 +161,7 @@ def confirm_email_change(request: HttpRequest, confirmation_key: str) -> HttpRes
|
||||||
|
|
||||||
emojiset_choices = {emojiset["key"] for emojiset in UserProfile.emojiset_choices()}
|
emojiset_choices = {emojiset["key"] for emojiset in UserProfile.emojiset_choices()}
|
||||||
web_home_view_options = ["recent_topics", "inbox", "all_messages"]
|
web_home_view_options = ["recent_topics", "inbox", "all_messages"]
|
||||||
|
web_animate_image_previews_options = ["always", "on_hover", "never"]
|
||||||
|
|
||||||
|
|
||||||
def check_settings_values(
|
def check_settings_values(
|
||||||
|
@ -329,6 +330,9 @@ def json_change_settings(
|
||||||
user_list_style: int | None = REQ(
|
user_list_style: int | None = REQ(
|
||||||
json_validator=check_int_in(UserProfile.USER_LIST_STYLE_CHOICES), default=None
|
json_validator=check_int_in(UserProfile.USER_LIST_STYLE_CHOICES), default=None
|
||||||
),
|
),
|
||||||
|
web_animate_image_previews: str | None = REQ(
|
||||||
|
str_validator=check_string_in(web_animate_image_previews_options), default=None
|
||||||
|
),
|
||||||
email_address_visibility: int | None = REQ(
|
email_address_visibility: int | None = REQ(
|
||||||
json_validator=check_int_in(UserProfile.EMAIL_ADDRESS_VISIBILITY_TYPES), default=None
|
json_validator=check_int_in(UserProfile.EMAIL_ADDRESS_VISIBILITY_TYPES), default=None
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in New Issue