Skip to content

Commit 58d970e

Browse files
committed
model/views: Add Visual desktop notification checkbox in Stream Info.
This commit adds a new checkbox 'Visual desktop notification' in the Stream settings section inside StreamInfoView. It uses subscription from initial_data to set the initial state of the checkbox, and henceforth events to sync its settings between ZT <-> server. The condition for notify_user() has also been refined to interact properly with the checkbox settings and according to the points mentioned in issue #666. Tests amended. Partially Fixes #887.
1 parent a3825cf commit 58d970e

File tree

4 files changed

+70
-25
lines changed

4 files changed

+70
-25
lines changed

tests/model/test_model.py

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -994,50 +994,65 @@ def test__update_topic_index(self, topic_name, topic_order_initial,
994994
assert model.index['topics'][86] == topic_order_final
995995

996996
# TODO: Ideally message_fixture would use standardized ids?
997-
@pytest.mark.parametrize(['user_id', 'vary_each_msg', 'stream_setting',
998-
'types_when_notify_called'], [
997+
@pytest.mark.parametrize(['user_id', 'vary_each_msg',
998+
'desktop_notification_status',
999+
'types_when_notify_called',
1000+
'is_stream_muted',
1001+
'is_topic_muted'], [
9991002
(5140, {'flags': ['mentioned', 'wildcard_mentioned']}, True,
1000-
[]), # message_fixture sender_id is 5140
1003+
[], False, False), # message_fixture sender_id is 5140
10011004
(5179, {'flags': ['mentioned']}, False,
1002-
['stream', 'private']),
1005+
['stream', 'private'], False, False),
10031006
(5179, {'flags': ['wildcard_mentioned']}, False,
1004-
['stream', 'private']),
1007+
['stream', 'private'], False, False),
10051008
(5179, {'flags': []}, True,
1006-
['stream']),
1009+
['stream'], False, False),
10071010
(5179, {'flags': []}, False,
1008-
['private']),
1011+
['private'], False, False),
1012+
(5140, {'flags': []}, True,
1013+
['stream'], True, True),
1014+
(5179, {'flags': ['mentioned']}, True,
1015+
['stream'], True, True),
10091016
], ids=[
10101017
'not_notified_since_self_message',
10111018
'notified_stream_and_private_since_directly_mentioned',
10121019
'notified_stream_and_private_since_wildcard_mentioned',
10131020
'notified_stream_since_stream_has_desktop_notifications',
10141021
'notified_private_since_private_message',
1022+
'not_notified_stream_since_muted_stream',
1023+
'notified_muted_stream_since_directly_mentioned',
10151024
])
10161025
def test_notify_users_calling_msg_type(self, mocker, model,
10171026
message_fixture,
10181027
user_id,
10191028
vary_each_msg,
1020-
stream_setting,
1021-
types_when_notify_called):
1029+
desktop_notification_status,
1030+
types_when_notify_called,
1031+
is_stream_muted,
1032+
is_topic_muted):
10221033
message_fixture.update(vary_each_msg)
10231034
model.user_id = user_id
1024-
if 'stream_id' in message_fixture:
1025-
model.stream_dict.update(
1026-
{message_fixture['stream_id']:
1027-
{'desktop_notifications': stream_setting}}
1028-
)
1035+
mocker.patch('zulipterminal.model.Model.'
1036+
'is_desktop_notifications_enabled',
1037+
return_value=desktop_notification_status)
1038+
mocker.patch('zulipterminal.model.Model.'
1039+
'is_muted_stream', return_value=is_stream_muted)
1040+
mocker.patch('zulipterminal.model.Model.'
1041+
'is_muted_topic', return_value=is_topic_muted)
10291042
notify = mocker.patch('zulipterminal.model.notify')
10301043

10311044
model.notify_user(message_fixture)
10321045

1046+
target = None
10331047
if message_fixture['type'] in types_when_notify_called:
10341048
who = message_fixture['type']
1035-
if who == 'stream':
1049+
if who == 'stream' and not is_stream_muted and not is_topic_muted:
10361050
target = 'PTEST -> Test'
10371051
elif who == 'private':
10381052
target = 'you'
10391053
if len(message_fixture['display_recipient']) > 2:
10401054
target += ', Bar Bar'
1055+
if target is not None:
10411056
title = f"Test Organization Name:\nFoo Foo (to {target})"
10421057
# TODO: Test message content too?
10431058
notify.assert_called_once_with(title, mocker.ANY)

tests/ui_tools/test_popups.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,8 @@ def mock_external_classes(self, mocker, monkeypatch):
572572
return_value=(64, 64))
573573
self.controller.model.is_muted_stream.return_value = False
574574
self.controller.model.is_pinned_stream.return_value = False
575+
(self.controller.model.is_desktop_notifications_enabled.
576+
return_value) = False
575577
mocker.patch(VIEWS + ".urwid.SimpleFocusListWalker", return_value=[])
576578
self.stream_id = 10
577579
self.controller.model.stream_dict = {
@@ -669,7 +671,7 @@ def test_keypress_navigation(self, mocker, widget_size,
669671

670672
@pytest.mark.parametrize('key', (*keys_for_command('ENTER'), ' '))
671673
def test_checkbox_toggle_mute_stream(self, mocker, key, widget_size):
672-
mute_checkbox = self.stream_info_view.widgets[7]
674+
mute_checkbox = self.stream_info_view.widgets[-3]
673675
toggle_mute_status = self.controller.model.toggle_stream_muted_status
674676
stream_id = self.stream_info_view.stream_id
675677
size = widget_size(mute_checkbox)
@@ -680,7 +682,7 @@ def test_checkbox_toggle_mute_stream(self, mocker, key, widget_size):
680682

681683
@pytest.mark.parametrize('key', (*keys_for_command('ENTER'), ' '))
682684
def test_checkbox_toggle_pin_stream(self, mocker, key, widget_size):
683-
pin_checkbox = self.stream_info_view.widgets[8]
685+
pin_checkbox = self.stream_info_view.widgets[-2]
684686
toggle_pin_status = self.controller.model.toggle_stream_pinned_status
685687
stream_id = self.stream_info_view.stream_id
686688
size = widget_size(pin_checkbox)
@@ -689,6 +691,19 @@ def test_checkbox_toggle_pin_stream(self, mocker, key, widget_size):
689691

690692
toggle_pin_status.assert_called_once_with(stream_id)
691693

694+
@pytest.mark.parametrize('key', (*keys_for_command('ENTER'), ' '))
695+
def test_checkbox_toggle_desktop_notification(self, mocker,
696+
key, widget_size):
697+
desktop_notify_checkbox = self.stream_info_view.widgets[-1]
698+
toggle_desktop_notify_status = (
699+
self.controller.model.toggle_stream_desktop_notification)
700+
stream_id = self.stream_info_view.stream_id
701+
size = widget_size(desktop_notify_checkbox)
702+
703+
desktop_notify_checkbox.keypress(size, key)
704+
705+
toggle_desktop_notify_status.assert_called_once_with(stream_id)
706+
692707

693708
class TestStreamMembersView:
694709
@pytest.fixture(autouse=True)

zulipterminal/model.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -977,13 +977,16 @@ def notify_user(self, message: Message) -> str:
977977
if recip['id'] not in (self.user_id, message['sender_id'])
978978
]
979979
recipient = ', '.join(extra_targets)
980-
elif message['type'] == 'stream' and (
981-
{'mentioned', 'wildcard_mentioned'}.intersection(
982-
set(message['flags'])
983-
)
984-
or self.stream_dict[message['stream_id']]['desktop_notifications']
985-
):
986-
recipient = '{display_recipient} -> {subject}'.format(**message)
980+
elif message['type'] == 'stream':
981+
stream_id = message['stream_id']
982+
if ({'mentioned', 'wildcard_mentioned'}.intersection(
983+
set(message['flags']))
984+
or (self.is_desktop_notifications_enabled(stream_id)
985+
and not self.is_muted_stream(stream_id)
986+
and not self.is_muted_topic(
987+
stream_id, message['subject']))):
988+
recipient = '{display_recipient} -> {subject}'.format(
989+
**message)
987990

988991
if recipient:
989992
return notify(f"{self.server_name}:\n"

zulipterminal/ui_tools/views.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,12 @@ def __init__(self, controller: Any, stream_id: int) -> None:
11401140
checked_symbol=CHECK_MARK)
11411141
urwid.connect_signal(pinned_setting, 'change',
11421142
self.toggle_pinned_status)
1143+
desktop_notification = urwid.CheckBox(
1144+
label="Visual desktop notification",
1145+
state=controller.model.is_desktop_notifications_enabled(stream_id),
1146+
checked_symbol=CHECK_MARK)
1147+
urwid.connect_signal(desktop_notification, 'change',
1148+
self.toggle_desktop_notification)
11431149

11441150
footlinks, footlinks_width = MessageBox.footlinks_view(
11451151
message_links=message_links,
@@ -1152,7 +1158,7 @@ def __init__(self, controller: Any, stream_id: int) -> None:
11521158
# Add 4 to checkbox label to accommodate the checkbox itself.
11531159
popup_width = max(popup_width, len(muted_setting.label) + 4,
11541160
len(pinned_setting.label) + 4, desc.pack()[0],
1155-
footlinks_width)
1161+
footlinks_width, len(desktop_notification.label) + 4)
11561162
self.widgets = self.make_table_with_categories(stream_info_content,
11571163
column_widths)
11581164

@@ -1166,6 +1172,7 @@ def __init__(self, controller: Any, stream_id: int) -> None:
11661172

11671173
self.widgets.append(muted_setting)
11681174
self.widgets.append(pinned_setting)
1175+
self.widgets.append(desktop_notification)
11691176
super().__init__(controller, self.widgets, 'STREAM_DESC', popup_width,
11701177
title)
11711178

@@ -1175,6 +1182,11 @@ def toggle_mute_status(self, button: Any, new_state: bool) -> None:
11751182
def toggle_pinned_status(self, button: Any, new_state: bool) -> None:
11761183
self.controller.model.toggle_stream_pinned_status(self.stream_id)
11771184

1185+
def toggle_desktop_notification(self, button: Any,
1186+
new_state: bool) -> None:
1187+
self.controller.model.toggle_stream_desktop_notification(
1188+
self.stream_id)
1189+
11781190
def keypress(self, size: urwid_Size, key: str) -> str:
11791191
if is_command_key('STREAM_MEMBERS', key):
11801192
self.controller.show_stream_members(stream_id=self.stream_id)

0 commit comments

Comments
 (0)