-
-
Notifications
You must be signed in to change notification settings - Fork 263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Disable cycling to recipients when editing PM #1504
base: main
Are you sure you want to change the base?
Changes from all commits
4fd0a50
9716ccc
9feb30d
4921b98
751db14
abab4f4
9b5ca86
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,8 @@ | |
import pytest | ||
from pytest import param as case | ||
from pytest_mock import MockerFixture | ||
from urwid import Widget | ||
from urwid import Text, Widget | ||
from urwid_readline import ReadlineEdit | ||
|
||
from zulipterminal.api_types import ( | ||
TYPING_STARTED_EXPIRY_PERIOD, | ||
|
@@ -420,7 +421,7 @@ def test_footer_notification_on_invalid_recipients( | |
), | ||
], | ||
) | ||
def test_update_recipients( | ||
def test_update_recipients_from_emails_in_widget( | ||
self, | ||
write_box: WriteBox, | ||
header: str, | ||
|
@@ -431,7 +432,7 @@ def test_update_recipients( | |
assert write_box.to_write_box is not None | ||
write_box.to_write_box.edit_text = header | ||
|
||
write_box.update_recipients(write_box.to_write_box) | ||
write_box.update_recipients_from_emails_in_widget(write_box.to_write_box) | ||
|
||
assert write_box.recipient_emails == expected_recipient_emails | ||
assert write_box.recipient_user_ids == expected_recipient_user_ids | ||
|
@@ -1662,6 +1663,16 @@ def test_keypress_typeahead_mode_autocomplete_key( | |
"HEADER_BOX_RECIPIENT", | ||
id="message_to_recipient_box", | ||
), | ||
case( | ||
"CONTAINER_MESSAGE", | ||
"MESSAGE_BOX_BODY", | ||
"private", | ||
True, | ||
True, | ||
"CONTAINER_MESSAGE", | ||
"MESSAGE_BOX_BODY", | ||
id="private_edit_box-no_cycle", | ||
), | ||
], | ||
) | ||
@pytest.mark.parametrize("tab_key", keys_for_command("CYCLE_COMPOSE_FOCUS")) | ||
|
@@ -1682,17 +1693,21 @@ def test_keypress_CYCLE_COMPOSE_FOCUS( | |
) -> None: | ||
mocker.patch(WRITEBOX + "._set_stream_write_box_style") | ||
|
||
if message_being_edited: | ||
write_box.msg_edit_state = _MessageEditState( | ||
message_id=10, old_topic="some old topic" | ||
) | ||
if box_type == "stream": | ||
if message_being_edited: | ||
mocker.patch(MODULE + ".EditModeButton") | ||
write_box.stream_box_edit_view(stream_id) | ||
write_box.msg_edit_state = _MessageEditState( | ||
message_id=10, old_topic="some old topic" | ||
) | ||
else: | ||
write_box.stream_box_view(stream_id) | ||
else: | ||
write_box.private_box_view() | ||
if message_being_edited: | ||
write_box.private_box_edit_view() | ||
else: | ||
write_box.private_box_view() | ||
size = widget_size(write_box) | ||
|
||
def focus_val(x: str) -> int: | ||
|
@@ -1718,6 +1733,41 @@ def focus_val(x: str) -> int: | |
expected_focus_col_name | ||
) | ||
|
||
@pytest.mark.parametrize("message_being_edited", [(True), (False)]) | ||
@pytest.mark.parametrize( | ||
"recipient_ids, expected_recipient_text", | ||
[ | ||
([], "To: "), | ||
([11], "To: Human 1 <[email protected]>"), | ||
( | ||
[11, 12], | ||
"To: Human 1 <[email protected]>, Human 2 <[email protected]>", | ||
), | ||
], | ||
) | ||
def test_private_box_recipient_editing( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I learnt that sometimes using double underscores in the test function names helps, not sure about this test name in particular. Would |
||
self, | ||
mocker: MockerFixture, | ||
write_box: WriteBox, | ||
user_dict: List[Dict[str, Any]], | ||
user_id_email_dict: Dict[int, str], | ||
recipient_ids: List[int], | ||
expected_recipient_text: str, | ||
message_being_edited: bool, | ||
) -> None: | ||
write_box.model.user_id_email_dict = user_id_email_dict | ||
write_box.model.user_dict = user_dict | ||
mocker.patch("urwid.connect_signal") | ||
|
||
if message_being_edited: | ||
write_box.private_box_edit_view(recipient_user_ids=recipient_ids) | ||
assert isinstance(write_box.to_write_box, Text) | ||
else: | ||
write_box.private_box_view(recipient_user_ids=recipient_ids) | ||
assert isinstance(write_box.to_write_box, ReadlineEdit) | ||
|
||
assert write_box.to_write_box.text == expected_recipient_text | ||
|
||
@pytest.mark.parametrize("key", keys_for_command("MARKDOWN_HELP")) | ||
def test_keypress_MARKDOWN_HELP( | ||
self, write_box: WriteBox, key: str, widget_size: Callable[[Widget], urwid_Size] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -173,41 +173,11 @@ def send_stop_typing_status(self) -> None: | |
self.idle_status_tracking = False | ||
self.sent_start_typing_status = False | ||
|
||
def private_box_view( | ||
self, | ||
*, | ||
recipient_user_ids: Optional[List[int]] = None, | ||
) -> None: | ||
def _setup_common_private_compose(self) -> None: | ||
self.set_editor_mode() | ||
|
||
self.compose_box_status = "open_with_private" | ||
|
||
if recipient_user_ids: | ||
self._set_regular_and_typing_recipient_user_ids(recipient_user_ids) | ||
self.recipient_emails = [ | ||
self.model.user_id_email_dict[user_id] | ||
for user_id in self.recipient_user_ids | ||
] | ||
recipient_info = ", ".join( | ||
[ | ||
f"{self.model.user_dict[email]['full_name']} <{email}>" | ||
for email in self.recipient_emails | ||
] | ||
) | ||
else: | ||
self._set_regular_and_typing_recipient_user_ids(None) | ||
self.recipient_emails = [] | ||
recipient_info = "" | ||
|
||
self.send_next_typing_update = datetime.now() | ||
self.to_write_box = ReadlineEdit("To: ", edit_text=recipient_info) | ||
self.to_write_box.enable_autocomplete( | ||
func=self._to_box_autocomplete, | ||
key=primary_key_for_command("AUTOCOMPLETE"), | ||
key_reverse=primary_key_for_command("AUTOCOMPLETE_REVERSE"), | ||
) | ||
self.to_write_box.set_completer_delims("") | ||
|
||
self.msg_write_box = ReadlineEdit( | ||
multiline=True, max_char=self.model.max_message_length | ||
) | ||
|
@@ -232,6 +202,50 @@ def private_box_view( | |
] | ||
self.focus_position = self.FOCUS_CONTAINER_MESSAGE | ||
|
||
def update_recipients_from_user_ids( | ||
self, recipient_user_ids: Optional[List[int]] = None | ||
) -> str: | ||
if recipient_user_ids: | ||
self._set_regular_and_typing_recipient_user_ids(recipient_user_ids) | ||
self.recipient_emails = [ | ||
self.model.user_id_email_dict[user_id] | ||
for user_id in self.recipient_user_ids | ||
] | ||
return ", ".join( | ||
[ | ||
f"{self.model.user_dict[email]['full_name']} <{email}>" | ||
for email in self.recipient_emails | ||
] | ||
) | ||
else: | ||
self._set_regular_and_typing_recipient_user_ids(None) | ||
self.recipient_emails = [] | ||
return "" | ||
|
||
def private_box_edit_view( | ||
self, | ||
*, | ||
recipient_user_ids: Optional[List[int]] = None, | ||
) -> None: | ||
self.recipient_info = self.update_recipients_from_user_ids(recipient_user_ids) | ||
self.to_write_box = urwid.Text("To: " + self.recipient_info) | ||
self._setup_common_private_compose() | ||
|
||
def private_box_view( | ||
self, | ||
*, | ||
recipient_user_ids: Optional[List[int]] = None, | ||
) -> None: | ||
self.send_next_typing_update = datetime.now() | ||
recipient_info = self.update_recipients_from_user_ids(recipient_user_ids) | ||
self.to_write_box = ReadlineEdit("To: ", edit_text=recipient_info) | ||
self.to_write_box.enable_autocomplete( | ||
func=self._to_box_autocomplete, | ||
key=primary_key_for_command("AUTOCOMPLETE"), | ||
key_reverse=primary_key_for_command("AUTOCOMPLETE_REVERSE"), | ||
) | ||
self.to_write_box.set_completer_delims("") | ||
self._setup_common_private_compose() | ||
start_period_delta = timedelta( | ||
milliseconds=self.model.typing_started_wait_period | ||
) | ||
|
@@ -265,7 +279,7 @@ def track_idleness_and_update_status() -> None: | |
|
||
urwid.connect_signal(self.msg_write_box, "change", on_type_send_status) | ||
|
||
def update_recipients(self, write_box: ReadlineEdit) -> None: | ||
def update_recipients_from_emails_in_widget(self, write_box: ReadlineEdit) -> None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed that this naming using 'in_widget' occurs only in this function in the codebase. Does it actually help us to differentiate it from valid emails, or is it redundant? |
||
self.recipient_emails = re.findall(REGEX_RECIPIENT_EMAIL, write_box.edit_text) | ||
self._set_regular_and_typing_recipient_user_ids( | ||
[self.model.user_dict[email]["user_id"] for email in self.recipient_emails] | ||
|
@@ -761,7 +775,7 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]: | |
) | ||
if not all_valid: | ||
return key | ||
self.update_recipients(self.to_write_box) | ||
self.update_recipients_from_emails_in_widget(self.to_write_box) | ||
if self.recipient_user_ids: | ||
success = self.model.send_private_message( | ||
recipients=self.recipient_user_ids, | ||
|
@@ -815,7 +829,7 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]: | |
) | ||
if not all_valid: | ||
return key | ||
self.update_recipients(self.to_write_box) | ||
self.update_recipients_from_emails_in_widget(self.to_write_box) | ||
this_draft: Composition = PrivateComposition( | ||
type="private", | ||
to=self.recipient_user_ids, | ||
|
@@ -893,14 +907,20 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]: | |
# We extract recipients' user_ids and emails only once we know | ||
# that all the recipients are valid, to avoid including any | ||
# invalid ones. | ||
self.update_recipients(self.to_write_box) | ||
self.update_recipients_from_emails_in_widget(self.to_write_box) | ||
|
||
if not self.msg_body_edit_enabled: | ||
return key | ||
if self.focus_position == self.FOCUS_CONTAINER_HEADER: | ||
self.focus_position = self.FOCUS_CONTAINER_MESSAGE | ||
else: | ||
self.focus_position = self.FOCUS_CONTAINER_HEADER | ||
if self.compose_box_status == "open_with_stream": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic is a bit tricky to read. I was thinking about refactoring the whole |
||
self.focus_position = self.FOCUS_CONTAINER_HEADER | ||
if ( | ||
self.compose_box_status == "open_with_private" | ||
and self.msg_edit_state is None | ||
): | ||
self.focus_position = self.FOCUS_CONTAINER_HEADER | ||
if self.compose_box_status == "open_with_stream": | ||
if self.msg_edit_state is not None: | ||
header.focus_col = self.FOCUS_HEADER_BOX_TOPIC | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1096,7 +1096,9 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]: | |
) | ||
|
||
if self.message["type"] == "private": | ||
self.keypress(size, primary_key_for_command("REPLY_MESSAGE")) | ||
self.model.controller.view.write_box.private_box_edit_view( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change doesn't have a test. It didn't have a test in the PR that I refined, but maybe it's worth thinking about adding one? How would we test this? (didn't look into it yet) |
||
recipient_user_ids=self.recipient_ids, | ||
) | ||
elif self.message["type"] == "stream": | ||
self.model.controller.view.write_box.stream_box_edit_view( | ||
stream_id=self.stream_id, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test ids could be added, I assume.