Skip to content

Commit 28afba8

Browse files
committed
core/boxes: Improve handling of pressing Esc during message compose.
Introduces variable MAX_MESSAGE_LENGTH_CONFIRMATION_POPUP to set a threshold for maximum length of message in compose box beyond which it prompts a confirmation popup instead of the current instant exit when Esc is pressed. Fixes #1342.
1 parent 764fb72 commit 28afba8

File tree

4 files changed

+98
-9
lines changed

4 files changed

+98
-9
lines changed

tests/ui_tools/test_boxes.py

+54-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@
2121
)
2222
from zulipterminal.config.ui_mappings import StreamAccessType
2323
from zulipterminal.helper import Index, MinimalUserData
24-
from zulipterminal.ui_tools.boxes import PanelSearchBox, WriteBox, _MessageEditState
24+
from zulipterminal.ui_tools.boxes import (
25+
MAX_MESSAGE_LENGTH_CONFIRMATION_POPUP,
26+
PanelSearchBox,
27+
WriteBox,
28+
_MessageEditState,
29+
)
2530
from zulipterminal.urwid_types import urwid_Size
2631

2732

@@ -232,7 +237,7 @@ def test_not_calling_send_private_message_without_recipients(
232237
assert not write_box.model.send_private_message.called
233238

234239
@pytest.mark.parametrize("key", keys_for_command("GO_BACK"))
235-
def test__compose_attributes_reset_for_private_compose(
240+
def test__compose_attributes_reset_for_private_compose__no_popup(
236241
self,
237242
key: str,
238243
mocker: MockerFixture,
@@ -243,17 +248,39 @@ def test__compose_attributes_reset_for_private_compose(
243248
mocker.patch("urwid.connect_signal")
244249
write_box.model.user_id_email_dict = user_id_email_dict
245250
write_box.private_box_view(recipient_user_ids=[11])
246-
write_box.msg_write_box.edit_text = "random text"
251+
252+
write_box.msg_write_box.edit_text = "." * (MAX_MESSAGE_LENGTH_CONFIRMATION_POPUP - 1)
247253

248254
size = widget_size(write_box)
249255
write_box.keypress(size, key)
250256

257+
write_box.view.controller.exit_compose_confirmation_popup.assert_not_called()
251258
assert write_box.to_write_box is None
252259
assert write_box.msg_write_box.edit_text == ""
253260
assert write_box.compose_box_status == "closed"
254261

255262
@pytest.mark.parametrize("key", keys_for_command("GO_BACK"))
256-
def test__compose_attributes_reset_for_stream_compose(
263+
def test__compose_attributes_reset_for_private_compose__popup(
264+
self,
265+
key: str,
266+
mocker: MockerFixture,
267+
write_box: WriteBox,
268+
widget_size: Callable[[Widget], urwid_Size],
269+
user_id_email_dict: Dict[int, str],
270+
) -> None:
271+
mocker.patch("urwid.connect_signal")
272+
write_box.model.user_id_email_dict = user_id_email_dict
273+
write_box.private_box_view(recipient_user_ids=[11])
274+
275+
write_box.msg_write_box.edit_text = "." * MAX_MESSAGE_LENGTH_CONFIRMATION_POPUP
276+
277+
size = widget_size(write_box)
278+
write_box.keypress(size, key)
279+
280+
write_box.view.controller.exit_compose_confirmation_popup.assert_called_once()
281+
282+
@pytest.mark.parametrize("key", keys_for_command("GO_BACK"))
283+
def test__compose_attributes_reset_for_stream_compose__no_popup(
257284
self,
258285
key: str,
259286
mocker: MockerFixture,
@@ -262,15 +289,35 @@ def test__compose_attributes_reset_for_stream_compose(
262289
) -> None:
263290
mocker.patch(WRITEBOX + "._set_stream_write_box_style")
264291
write_box.stream_box_view(stream_id=1)
265-
write_box.msg_write_box.edit_text = "random text"
292+
293+
write_box.msg_write_box.edit_text = "." * (MAX_MESSAGE_LENGTH_CONFIRMATION_POPUP - 1)
266294

267295
size = widget_size(write_box)
268296
write_box.keypress(size, key)
269297

298+
write_box.view.controller.exit_compose_confirmation_popup.assert_not_called()
270299
assert write_box.stream_id is None
271300
assert write_box.msg_write_box.edit_text == ""
272301
assert write_box.compose_box_status == "closed"
273302

303+
@pytest.mark.parametrize("key", keys_for_command("GO_BACK"))
304+
def test__compose_attributes_reset_for_stream_compose__popup(
305+
self,
306+
key: str,
307+
mocker: MockerFixture,
308+
write_box: WriteBox,
309+
widget_size: Callable[[Widget], urwid_Size],
310+
) -> None:
311+
mocker.patch(WRITEBOX + "._set_stream_write_box_style")
312+
write_box.stream_box_view(stream_id=1)
313+
314+
write_box.msg_write_box.edit_text = "." * MAX_MESSAGE_LENGTH_CONFIRMATION_POPUP
315+
316+
size = widget_size(write_box)
317+
write_box.keypress(size, key)
318+
319+
write_box.view.controller.exit_compose_confirmation_popup.assert_called_once_with()
320+
274321
@pytest.mark.parametrize(
275322
["raw_recipients", "tidied_recipients"],
276323
[
@@ -1516,13 +1563,15 @@ def test_keypress_SEND_MESSAGE_no_topic(
15161563
)
15171564
def test_keypress_typeahead_mode_autocomplete_key(
15181565
self,
1566+
mocker: MockerFixture,
15191567
write_box: WriteBox,
15201568
widget_size: Callable[[Widget], urwid_Size],
15211569
current_typeahead_mode: bool,
15221570
expected_typeahead_mode: bool,
15231571
expect_footer_was_reset: bool,
15241572
key: str,
15251573
) -> None:
1574+
write_box.msg_write_box = mocker.Mock(edit_text="")
15261575
write_box.is_in_typeahead_mode = current_typeahead_mode
15271576
size = widget_size(write_box)
15281577

zulipterminal/core.py

+15
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,21 @@ def stream_muting_confirmation_popup(
527527
mute_this_stream = partial(self.model.toggle_stream_muted_status, stream_id)
528528
self.loop.widget = PopUpConfirmationView(self, question, mute_this_stream)
529529

530+
def exit_compose_confirmation_popup(self) -> None:
531+
question = urwid.Text(
532+
(
533+
"bold",
534+
"Please confirm that you wish to exit the compose box.\n"
535+
"(You can save the message as a draft upon returning to compose)",
536+
),
537+
"center",
538+
)
539+
write_box = self.view.write_box
540+
popup_view = PopUpConfirmationView(
541+
self, question, write_box.exit_compose_box, location="center"
542+
)
543+
self.loop.widget = popup_view
544+
530545
def copy_to_clipboard(self, text: str, text_category: str) -> None:
531546
try:
532547
pyperclip.copy(text)

zulipterminal/ui_tools/boxes.py

+28-4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
from zulipterminal.urwid_types import urwid_Size
4949

5050

51+
MAX_MESSAGE_LENGTH_CONFIRMATION_POPUP = 15
52+
53+
5154
class _MessageEditState(NamedTuple):
5255
message_id: int
5356
old_topic: str
@@ -708,10 +711,19 @@ def autocomplete_emojis(
708711

709712
return emoji_typeahead, emojis
710713

714+
def exit_compose_box(self) -> None:
715+
self.is_in_typeahead_mode = False
716+
self.view.set_footer_text()
717+
self._set_compose_attributes_to_defaults()
718+
self.view.controller.exit_editor_mode()
719+
self.main_view(False)
720+
self.view.middle_column.set_focus("body")
721+
711722
def keypress(self, size: urwid_Size, key: str) -> Optional[str]:
712723
if self.is_in_typeahead_mode and not (
713724
is_command_key("AUTOCOMPLETE", key)
714725
or is_command_key("AUTOCOMPLETE_REVERSE", key)
726+
or is_command_key("GO_BACK", key)
715727
):
716728
# set default footer when done with autocomplete
717729
self.is_in_typeahead_mode = False
@@ -798,11 +810,23 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]:
798810
"Cannot narrow to message without specifying recipients."
799811
)
800812
elif is_command_key("GO_BACK", key):
813+
saved_draft = self.model.session_draft_message()
801814
self.send_stop_typing_status()
802-
self._set_compose_attributes_to_defaults()
803-
self.view.controller.exit_editor_mode()
804-
self.main_view(False)
805-
self.view.middle_column.set_focus("body")
815+
816+
if (
817+
self.msg_edit_state is None
818+
and len(self.msg_write_box.edit_text)
819+
>= MAX_MESSAGE_LENGTH_CONFIRMATION_POPUP
820+
):
821+
if (
822+
saved_draft is None
823+
or self.msg_write_box.edit_text != saved_draft.get("content")
824+
):
825+
self.view.controller.exit_compose_confirmation_popup()
826+
else:
827+
self.exit_compose_box()
828+
else:
829+
self.exit_compose_box()
806830
elif is_command_key("MARKDOWN_HELP", key):
807831
self.view.controller.show_markdown_help()
808832
return key

zulipterminal/ui_tools/messages.py

+1
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,7 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]:
11101110
write_box.msg_edit_state = _MessageEditState(
11111111
message_id=msg_id, old_topic=self.message["subject"]
11121112
)
1113+
print(msg + " :it reached here \n")
11131114
write_box.msg_write_box.set_edit_text(msg)
11141115
write_box.msg_write_box.set_edit_pos(len(msg))
11151116
write_box.msg_body_edit_enabled = msg_body_edit_enabled

0 commit comments

Comments
 (0)