hotkey: Add Shift + V shortcut to toggle read receipts modal.

The read receipts option, resides under the triple-dot message actions
menu. This made the process of viewing the read receipts take up
multiple steps, even via a keyboard-driven workflow.

Via this commit, now while focused on any message in a message feed,
and pressing `Shift` + `V`, efficiently brings up the read receipts
for that message.

Fixes part of #24716.

Co-Authored-by: SameepAher <sameepaher@gmail.com>
This commit is contained in:
Sayam Samal
2024-02-13 14:14:39 +05:30
committed by Tim Abbott
parent c6feafe298
commit eae148b67a
6 changed files with 41 additions and 5 deletions

View File

@@ -148,6 +148,9 @@ in the Zulip app to add more to your repertoire as needed.
* **Show message sender's user card**: <kbd>U</kbd>
* **View read receipts**: <kbd>Shift</kbd> + <kbd>V</kbd> — Same shortcut
also closes the read receipts menu (if open).
* **View image**: <kbd>V</kbd>
* **Edit message or view message source**: <kbd>E</kbd>

View File

@@ -42,6 +42,7 @@ import * as playground_links_popover from "./playground_links_popover";
import * as popover_menus from "./popover_menus";
import * as popovers from "./popovers";
import * as reactions from "./reactions";
import * as read_receipts from "./read_receipts";
import * as recent_view_ui from "./recent_view_ui";
import * as recent_view_util from "./recent_view_util";
import * as scheduled_messages_overlay_ui from "./scheduled_messages_overlay_ui";
@@ -92,6 +93,7 @@ const keydown_shift_mappings = {
40: {name: "down_arrow", message_view_only: false}, // down arrow
72: {name: "view_edit_history", message_view_only: true}, // 'H'
78: {name: "narrow_to_next_unread_followed_topic", message_view_only: false}, // 'N'
86: {name: "toggle_read_receipts", message_view_only: true}, // 'V'
};
const keydown_unshift_mappings = {
@@ -715,8 +717,18 @@ export function process_hotkey(e, hotkey) {
return emoji_picker.navigate(event_name);
}
// modals.any_active() and modals.active_modal() both query the dom to
// find and retrieve any active modal. Thus, we limit the number of calls
// to the DOM by storing these values as constansts to be reused.
const is_any_modal_active = modals.any_active();
const active_modal = is_any_modal_active ? modals.active_modal() : null;
// `list_util` will process the event in send later modal.
if (modals.any_active() && modals.active_modal() !== "#send_later_modal") {
if (is_any_modal_active && active_modal !== "#send_later_modal") {
if (event_name === "toggle_read_receipts" && active_modal === "#read_receipts_modal") {
read_receipts.hide_user_list();
return true;
}
return false;
}
@@ -890,7 +902,7 @@ export function process_hotkey(e, hotkey) {
}
// Prevent navigation in the background when the overlays are active.
if (overlays.any_active() || modals.any_active()) {
if (overlays.any_active() || is_any_modal_active) {
if (event_name === "view_selected_stream" && overlays.streams_open()) {
stream_settings_ui.view_stream();
return true;
@@ -1146,6 +1158,10 @@ export function process_hotkey(e, hotkey) {
stream_popover.build_move_topic_to_stream_popover(msg.stream_id, msg.topic, false, msg);
return true;
}
case "toggle_read_receipts": {
read_receipts.show_user_list(msg.id);
return true;
}
case "zoom_to_message_near": {
// The following code is essentially equivalent to
// `window.location = hashutil.by_conversation_and_time_url(msg)`

View File

@@ -93,3 +93,7 @@ export function show_user_list(message_id: number): void {
},
});
}
export function hide_user_list(): void {
modals.close_if_open("read_receipts_modal");
}

View File

@@ -224,6 +224,10 @@
<td class="definition">{{t "Show message sender's user card" }}</td>
<td><span class="hotkey"><kbd>U</kbd></span></td>
</tr>
<tr>
<td class="definition">{{t 'View read receipts' }}</td>
<td><span class="hotkey"><kbd>Shift</kbd> + <kbd>V</kbd></span></td>
</tr>
<tr>
<td class="definition">{{t 'Show images in thread' }}</td>
<td><span class="hotkey"><kbd>V</kbd></span></td>

View File

@@ -104,7 +104,8 @@
{{#if should_display_read_receipts_option}}
<li>
<a class="view_read_receipts" data-message-id="{{message_id}}" tabindex="0">
<i class="zulip-icon zulip-icon-readreceipts" aria-label="{{t 'View read receipts' }}"></i> {{t "View read receipts" }}
<i class="zulip-icon zulip-icon-readreceipts" aria-label="{{t 'View read receipts' }}"></i>
{{t "View read receipts" }} <span class="hotkey-hint">(V)</span>
</a>
</li>
{{/if}}

View File

@@ -81,6 +81,7 @@ const popovers = mock_esm("../src/user_card_popover", {
},
});
const reactions = mock_esm("../src/reactions");
const read_receipts = mock_esm("../src/read_receipts");
const search = mock_esm("../src/search");
const settings_data = mock_esm("../src/settings_data");
const stream_list = mock_esm("../src/stream_list");
@@ -185,6 +186,7 @@ run_test("mappings", () => {
assert.equal(map_down(46).name, "delete");
assert.equal(map_down(13, true).name, "enter");
assert.equal(map_down(78, true).name, "narrow_to_next_unread_followed_topic");
assert.equal(map_down(86, true).name, "toggle_read_receipts"); // Shift + V
assert.equal(map_press(47).name, "search"); // slash
assert.equal(map_press(106).name, "vim_down"); // j
@@ -363,7 +365,7 @@ run_test("modal open", ({override}) => {
run_test("misc", ({override}) => {
// Next, test keys that only work on a selected message.
const message_view_only_keys = "@+>RjJkKsuvi:GM";
const message_view_only_keys = "@+>RjJkKsuvVi:GM";
// Check that they do nothing without a selected message
with_overrides(({override}) => {
@@ -374,7 +376,7 @@ run_test("misc", ({override}) => {
// Check that they do nothing while in the settings overlay
with_overrides(({override}) => {
override(overlays, "settings_open", () => true);
assert_unmapped("@*+->rRjJkKsSuvi:GM");
assert_unmapped("@*+->rRjJkKsSuvVi:GM");
});
// TODO: Similar check for being in the subs page
@@ -413,6 +415,12 @@ run_test("misc", ({override}) => {
override(message_edit, "can_move_message", () => false);
assert_unmapped("m");
assert_mapping("V", read_receipts, "show_user_list", true, true);
override(modals, "any_active", () => true);
override(modals, "active_modal", () => "#read_receipts_modal");
assert_mapping("V", read_receipts, "hide_user_list", true, true);
});
run_test("lightbox overlay open", ({override}) => {