Skip to content

Commit 113c495

Browse files
committed
bugfix: ui: Use a queue to manage footer reset durations.
Currently, if multiple calls are made to set the footer along with a duration to reset it (for example, when tries to edit an uneditable message too often by pressing the key too many times) then it leads to repeated footer updates because all those calls lead to resetting the footer. The goal of this commit is to change that, and reset the footer only once, by ignoring other updates. A queue is maintained containing number of sleep threads currently active, and if there are none left then the footer is reset. This ensures that only the last call to set_footer_text() resets the footer, thus avoiding multiple resets. Also, note that it is not strictly necessary to store the duration in the queue, we could any number we like. However it is kept this way in case we would like to do more with this in the future, say, spacing out tight reset calls with only a small duration between them. Test added. Fixes zulip#647.
1 parent 166cb0c commit 113c495

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

tests/ui/test_ui.py

+17
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import time
2+
from concurrent.futures import ThreadPoolExecutor
3+
14
import pytest
25

36
from zulipterminal.config.keys import keys_for_command
@@ -86,6 +89,20 @@ def test__reset_footer_text(self, view, mocker, duration=46.2):
8689
mock_sleep.assert_called_once_with(duration)
8790
view.set_footer_text.assert_called_once_with()
8891

92+
def test__reset_footer_text_multiple_reset_attempts(self, view,
93+
mocker):
94+
time.sleep = mocker.Mock(side_effect=time.sleep)
95+
mocker.patch('zulipterminal.ui.View.set_footer_text')
96+
97+
# Multiple simultaneous calls for resetting footer.
98+
with ThreadPoolExecutor(max_workers=3) as executor:
99+
executor.submit(view._reset_footer_text, duration=0.5)
100+
executor.submit(view._reset_footer_text, duration=0.5)
101+
executor.submit(view._reset_footer_text, duration=0.5)
102+
103+
view.set_footer_text.assert_called_once_with()
104+
assert time.sleep.call_count == 3
105+
89106
@pytest.mark.parametrize('suggestions, state, truncated, footer_text', [
90107
([], None, False, [' [No matches found]']),
91108
(['some', 'text'], None, False, [[' '], ' some ', ' text ']),

zulipterminal/ui.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import queue
12
import random
23
import re
34
import time
@@ -33,6 +34,7 @@ def __init__(self, controller: Any) -> None:
3334
self.unpinned_streams = self.model.unpinned_streams
3435
self.write_box = WriteBox(self)
3536
self.search_box = SearchBox(self.controller)
37+
self.footer_reset_threads = queue.Queue() # type: queue.Queue[float]
3638

3739
self.message_view = None # type: Any
3840

@@ -86,8 +88,12 @@ def set_footer_text(self, text_list: Optional[List[Any]]=None,
8688
@asynch
8789
def _reset_footer_text(self, duration: float) -> None:
8890
assert duration > 0
91+
self.footer_reset_threads.put(duration)
8992
time.sleep(duration)
90-
self.set_footer_text()
93+
self.footer_reset_threads.get()
94+
95+
if self.footer_reset_threads.empty():
96+
self.set_footer_text()
9197

9298
@asynch
9399
def set_typeahead_footer(self, suggestions: List[str],

0 commit comments

Comments
 (0)