mirror of
https://github.com/zulip/zulip.git
synced 2025-11-19 22:19:48 +00:00
user_settings: Add option to not mark messages as read on scroll.
These changes introduces an new user option where it allows users read messages and scroll through their feed without marking those messages as read. Fixes: #22804.
This commit is contained in:
@@ -168,6 +168,8 @@ export function build_page() {
|
||||
settings_config.common_message_policy_values.by_admins_only.code,
|
||||
...settings_org.get_organization_settings_options(),
|
||||
demote_inactive_streams_values: settings_config.demote_inactive_streams_values,
|
||||
web_mark_read_on_scroll_policy_values:
|
||||
settings_config.web_mark_read_on_scroll_policy_values,
|
||||
user_list_style_values: settings_config.user_list_style_values,
|
||||
color_scheme_values: settings_config.color_scheme_values,
|
||||
default_view_values: settings_config.default_view_values,
|
||||
|
||||
@@ -7,7 +7,9 @@ import {MessageListView} from "./message_list_view";
|
||||
import * as narrow_banner from "./narrow_banner";
|
||||
import * as narrow_state from "./narrow_state";
|
||||
import {page_params} from "./page_params";
|
||||
import {web_mark_read_on_scroll_policy_values} from "./settings_config";
|
||||
import * as stream_data from "./stream_data";
|
||||
import {user_settings} from "./user_settings";
|
||||
|
||||
export class MessageList {
|
||||
// A MessageList is the main interface for a message feed that is
|
||||
@@ -173,11 +175,29 @@ export class MessageList {
|
||||
|
||||
can_mark_messages_read() {
|
||||
/* Automatically marking messages as read can be disabled for
|
||||
two different reasons:
|
||||
three different reasons:
|
||||
* The view is structurally a search view, encoded in the
|
||||
properties of the message_list_data object.
|
||||
* The user recently marked messages in the view as unread, and
|
||||
we don't want to lose that state.
|
||||
* The user has "Mark messages as read on scroll" option
|
||||
turned on in their user settings.
|
||||
*/
|
||||
return (
|
||||
this.data.can_mark_messages_read() &&
|
||||
!this.reading_prevented &&
|
||||
!(
|
||||
user_settings.web_mark_read_on_scroll_policy ===
|
||||
web_mark_read_on_scroll_policy_values.never.code
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
can_mark_messages_read_without_setting() {
|
||||
/*
|
||||
Similar to can_mark_messages_read() above, this is a helper
|
||||
function to check if messages can be automatically read without
|
||||
the "Do not mark messages as read on scroll" setting.
|
||||
*/
|
||||
return this.data.can_mark_messages_read() && !this.reading_prevented;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ export type RealmDefaultSettings = {
|
||||
translate_emoticons: boolean;
|
||||
twenty_four_hour_time: boolean;
|
||||
user_list_style: boolean;
|
||||
web_mark_read_on_scroll_policy: number;
|
||||
wildcard_mentions_notify: boolean;
|
||||
};
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ import * as sub_store from "./sub_store";
|
||||
import * as submessage from "./submessage";
|
||||
import * as typing_events from "./typing_events";
|
||||
import * as unread_ops from "./unread_ops";
|
||||
import * as unread_ui from "./unread_ui";
|
||||
import * as user_events from "./user_events";
|
||||
import * as user_group_edit from "./user_group_edit";
|
||||
import * as user_groups from "./user_groups";
|
||||
@@ -625,6 +626,7 @@ export function dispatch_normal_event(event) {
|
||||
"default_view",
|
||||
"demote_inactive_streams",
|
||||
"dense_mode",
|
||||
"web_mark_read_on_scroll_policy",
|
||||
"emojiset",
|
||||
"escape_navigates_to_default_view",
|
||||
"fluid_layout_width",
|
||||
@@ -675,6 +677,9 @@ export function dispatch_normal_event(event) {
|
||||
$("body").toggleClass("less_dense_mode");
|
||||
$("body").toggleClass("more_dense_mode");
|
||||
}
|
||||
if (event.property === "web_mark_read_on_scroll_policy") {
|
||||
unread_ui.update_unread_banner();
|
||||
}
|
||||
if (event.property === "color_scheme") {
|
||||
$("body").fadeOut(300);
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -88,6 +88,8 @@ export function build_page() {
|
||||
can_create_new_bots: settings_bots.can_create_new_bots(),
|
||||
settings_label,
|
||||
demote_inactive_streams_values: settings_config.demote_inactive_streams_values,
|
||||
web_mark_read_on_scroll_policy_values:
|
||||
settings_config.web_mark_read_on_scroll_policy_values,
|
||||
user_list_style_values: settings_config.user_list_style_values,
|
||||
color_scheme_values: settings_config.color_scheme_values,
|
||||
default_view_values: settings_config.default_view_values,
|
||||
|
||||
@@ -39,6 +39,22 @@ export const demote_inactive_streams_values = {
|
||||
},
|
||||
};
|
||||
|
||||
export const web_mark_read_on_scroll_policy_values = {
|
||||
always: {
|
||||
code: 1,
|
||||
description: $t({defaultMessage: "Always"}),
|
||||
},
|
||||
// The `conversation_only` option is not yet implemented.
|
||||
// conversation_only: {
|
||||
// code: 2,
|
||||
// description: $t({defaultMessage: "Only in conversation views"}),
|
||||
// },
|
||||
never: {
|
||||
code: 3,
|
||||
description: $t({defaultMessage: "Never"}),
|
||||
},
|
||||
};
|
||||
|
||||
export const user_list_style_values = {
|
||||
compact: {
|
||||
code: 1,
|
||||
|
||||
@@ -166,6 +166,9 @@ export function set_up(settings_panel) {
|
||||
$container
|
||||
.find(".setting_twenty_four_hour_time")
|
||||
.val(JSON.stringify(settings_object.twenty_four_hour_time));
|
||||
$container
|
||||
.find(".setting_web_mark_read_on_scroll_policy")
|
||||
.val(settings_object.web_mark_read_on_scroll_policy);
|
||||
$container
|
||||
.find(`.setting_emojiset_choice[value="${CSS.escape(settings_object.emojiset)}"]`)
|
||||
.prop("checked", true);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import $ from "jquery";
|
||||
|
||||
import render_mark_as_read_disabled_banner from "../templates/mark_as_read_disabled_banner.hbs";
|
||||
import render_mark_as_read_turned_off_banner from "../templates/mark_as_read_turned_off_banner.hbs";
|
||||
|
||||
import * as activity from "./activity";
|
||||
@@ -7,13 +8,31 @@ import * as message_lists from "./message_lists";
|
||||
import * as notifications from "./notifications";
|
||||
import {page_params} from "./page_params";
|
||||
import * as pm_list from "./pm_list";
|
||||
import {web_mark_read_on_scroll_policy_values} from "./settings_config";
|
||||
import * as stream_list from "./stream_list";
|
||||
import * as top_left_corner from "./top_left_corner";
|
||||
import * as topic_list from "./topic_list";
|
||||
import * as unread from "./unread";
|
||||
import {notify_server_messages_read} from "./unread_ops";
|
||||
import {user_settings} from "./user_settings";
|
||||
|
||||
let user_closed_unread_banner = false;
|
||||
|
||||
export function update_unread_banner() {
|
||||
if (
|
||||
user_settings.web_mark_read_on_scroll_policy ===
|
||||
web_mark_read_on_scroll_policy_values.never.code
|
||||
) {
|
||||
$("#mark_as_read_turned_off_banner").html(render_mark_as_read_disabled_banner());
|
||||
} else {
|
||||
$("#mark_as_read_turned_off_banner").html(render_mark_as_read_turned_off_banner());
|
||||
|
||||
if (message_lists.current.can_mark_messages_read_without_setting()) {
|
||||
hide_unread_banner();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function hide_unread_banner() {
|
||||
// Use visibility instead of hide() to prevent messages on the screen from
|
||||
// shifting vertically.
|
||||
@@ -96,10 +115,7 @@ export function should_display_bankruptcy_banner() {
|
||||
|
||||
export function initialize() {
|
||||
update_unread_counts();
|
||||
|
||||
$("#mark_as_read_turned_off_banner").html(render_mark_as_read_turned_off_banner());
|
||||
hide_unread_banner();
|
||||
$("#mark_view_read").on("click", () => {
|
||||
$("body").on("click", "#mark_view_read", () => {
|
||||
// Mark all messages in the current view as read.
|
||||
//
|
||||
// BUG: This logic only supports marking messages visible in
|
||||
@@ -114,8 +130,15 @@ export function initialize() {
|
||||
|
||||
hide_unread_banner();
|
||||
});
|
||||
$("#mark_as_read_close").on("click", () => {
|
||||
$("body").on("click", "#mark_as_read_close", () => {
|
||||
hide_unread_banner();
|
||||
user_closed_unread_banner = true;
|
||||
});
|
||||
|
||||
// The combination of these functions in sequence ensures we have
|
||||
// at least one copy of the unread banner in the DOM, invisible;
|
||||
// this somewhat strange pattern allows our CSS to reserve space for
|
||||
// the banner, to avoid scroll position jumps when it is shown/hidden.
|
||||
update_unread_banner();
|
||||
hide_unread_banner();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ export type UserSettings = (StreamNotificationSettings & PmNotificationSettings)
|
||||
desktop_icon_count_display: number;
|
||||
demote_inactive_streams: number;
|
||||
dense_mode: boolean;
|
||||
web_mark_read_on_scroll_policy: number;
|
||||
email_notifications_batching_period_seconds: number;
|
||||
emojiset: string;
|
||||
enable_digest_emails: boolean;
|
||||
|
||||
12
web/templates/mark_as_read_disabled_banner.hbs
Normal file
12
web/templates/mark_as_read_disabled_banner.hbs
Normal file
@@ -0,0 +1,12 @@
|
||||
<p id="mark_as_read_turned_off_content">
|
||||
{{#tr}}
|
||||
Your Zulip app is <z-link>configured</z-link> to not mark messages as read on scroll.
|
||||
{{#*inline "z-link"}}<a href='help/marking-messages-as-read'>{{> @partial-block}}</a>{{/inline}}
|
||||
{{/tr}}
|
||||
</p>
|
||||
<div id="mark_as_read_controls">
|
||||
<button id="mark_view_read" class="btn btn-warning">
|
||||
{{t 'Mark as read' }}
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" id="mark_as_read_close" class="close">×</button>
|
||||
@@ -2,7 +2,7 @@
|
||||
{{t 'To preserve your reading state, this view does not mark messages as read.' }}
|
||||
</p>
|
||||
<div id="mark_as_read_controls">
|
||||
<button id="mark_view_read" class="btn btn-warning" title="{{t 'Mark as read' }}">
|
||||
<button id="mark_view_read" class="btn btn-warning">
|
||||
{{t 'Mark as read' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -80,6 +80,15 @@
|
||||
{{> settings_save_discard_widget section_name="advanced-settings" show_only_indicator=(not for_realm_settings) }}
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="web_mark_read_on_scroll_policy" class="dropdown-title">{{t "Mark messages as read on scroll" }}
|
||||
{{> ../help_link_widget link="/help/marking-messages-as-read" }}
|
||||
</label>
|
||||
<select name="web_mark_read_on_scroll_policy" class="setting_web_mark_read_on_scroll_policy prop-element settings_select bootstrap-focus-style" id="{{prefix}}web_mark_read_on_scroll_policy" data-setting-widget-type="number">
|
||||
{{> dropdown_options_widget option_values=web_mark_read_on_scroll_policy_values}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label class="title">{{t "User list style" }}</label>
|
||||
<div class="user_list_style_values grey-box prop-element" id="{{prefix}}user_list_style" data-setting-widget-type="radio-group" data-setting-choice-type="number">
|
||||
|
||||
@@ -71,6 +71,7 @@ mock_esm("../src/top_left_corner", {
|
||||
const typing_events = mock_esm("../src/typing_events");
|
||||
const ui = mock_esm("../src/ui");
|
||||
const unread_ops = mock_esm("../src/unread_ops");
|
||||
const unread_ui = mock_esm("../src/unread_ui");
|
||||
const user_events = mock_esm("../src/user_events");
|
||||
const user_groups = mock_esm("../src/user_groups");
|
||||
const user_group_edit = mock_esm("../src/user_group_edit");
|
||||
@@ -823,6 +824,12 @@ run_test("user_settings", ({override}) => {
|
||||
assert_same(user_settings.high_contrast_mode, true);
|
||||
assert_same(toggled, ["high-contrast"]);
|
||||
|
||||
event = event_fixtures.user_settings__web_mark_read_on_scroll_policy;
|
||||
user_settings.web_mark_read_on_scroll_policy = 3;
|
||||
override(unread_ui, "update_unread_banner", noop);
|
||||
dispatch(event);
|
||||
assert_same(user_settings.web_mark_read_on_scroll_policy, 1);
|
||||
|
||||
event = event_fixtures.user_settings__dense_mode;
|
||||
user_settings.dense_mode = false;
|
||||
toggled = [];
|
||||
|
||||
@@ -963,6 +963,13 @@ exports.fixtures = {
|
||||
value: 2,
|
||||
},
|
||||
|
||||
user_settings__web_mark_read_on_scroll_policy: {
|
||||
type: "user_settings",
|
||||
op: "update",
|
||||
property: "web_mark_read_on_scroll_policy",
|
||||
value: 1,
|
||||
},
|
||||
|
||||
user_status__set_status_emoji: {
|
||||
type: "user_status",
|
||||
user_id: test_user.user_id,
|
||||
|
||||
Reference in New Issue
Block a user