-
-
Notifications
You must be signed in to change notification settings - Fork 273
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
Scrollable large single msg view #874
Conversation
05a030c
to
7d097eb
Compare
7d097eb
to
4553b4e
Compare
867849d
to
783b392
Compare
@Ezio-Sarthak This has been discussed on the stream? To clarify, I think it would be fine to include the "full view" and "raw view" options in the same popup for now, if we could make it clear how to toggle between them. |
783b392
to
46dd6af
Compare
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.
Thanks for working on this @Ezio-Sarthak. 👍
It works pretty well functionally. I am sure after some improvements the Tab
to switch context in popups would be extended to other popups as well in the future. The title is pretty huge currently and offsets the 'Full message view' text to one side of the header, is there any way to fix this?
Also, the message header inside the popup breaks on to another line, if the topic name is large, it's better to take care of this case as well(maybe use ellipsis?). for e.g, see my message here: #test here
I really like the style of your PR message above. 👍
I've dropped in a few comments in your PR, feel free to discuss further. :)
docs/hotkeys.md
Outdated
@@ -55,6 +55,7 @@ | |||
|Add/remove star status of the current message|<kbd>ctrl</kbd> + <kbd>s</kbd> / <kbd>*</kbd>| | |||
|Show/hide message information|<kbd>i</kbd>| | |||
|Show/hide edit history (from message information)|<kbd>e</kbd>| | |||
|View full message from message information box|<kbd>f</kbd>| |
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.
Since it's a toggle key, Show/hide would be more consistent here?
zulipterminal/ui_tools/views.py
Outdated
elif is_command_key('GO_UP', key): | ||
key = 'up' | ||
elif is_command_key('GO_DOWN', key): | ||
key = 'down' | ||
elif is_command_key('SCROLL_UP', key): | ||
key = 'page up' | ||
elif is_command_key('SCROLL_DOWN', key): | ||
key = 'page down' | ||
elif is_command_key('GO_TO_BOTTOM', key): | ||
key = 'end' |
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.
Are these lines necessary?
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.
Nope. I realized I need simply PopUpView
as base class for content. Thanks :)
zulipterminal/core.py
Outdated
self, message, message_links, time_mentions, | ||
'Full message view (tab: cycle raw/formatted content)' | ||
), |
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.
Are we using "view" in any other popup's header name?
'view' sounds good, but seems inconsistent with our other popups, and unnecessarily increases header length.
zulipterminal/ui_tools/views.py
Outdated
('Full message view', 'Press {} to view' | ||
.format(full_msg_keys))]), |
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.
I guess we already transitioned to f-strings. It would be better to use that instead of .format()
wherever possible. :)
zulipterminal/ui_tools/views.py
Outdated
response = controller.model.client.get_raw_message(message['id']) | ||
_content_raw = urwid.Text('N/A') | ||
if response['result'] == 'success': |
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.
It's good that you are taking care of the 'N/A' case. 👍
But, it's probably better to expand N/A to something clearer in any case. :)
46dd6af
to
68541d9
Compare
Hello @Ezio-Sarthak, it seems like you have referenced #543 in your pull request description, but you have not referenced them in your commit message description(s). When you reference an issue in a commit message, it automatically closes the corresponding issue when the commit is merged. Please run An example of a correctly-formatted commit:
Thank you for your contributions to Zulip! |
b1a437a
to
32d2c48
Compare
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.
@Ezio-Sarthak This works well but I'm a little wary of the hooks into the "tabs" which aren't rendered and use of CYCLE_COMPOSE_FOCUS
. I'm open to leaving that code in there since it does the switching, but it feels a bit strange, as if you've ripped out some code, which you sort of have?
Perhaps minor, but we might add some kind of check to ensure that we're not fetching the raw message multiple times - which I know the code currently satisfies.
It seems that footlinks don't show in the rendered version?
The rendered text is also indented to the left and right, which looks a little strange perhaps.
It would be good to have i
exit the view completely, like we do for edit history, if we're to be consistent.
zulipterminal/ui_tools/views.py
Outdated
@staticmethod | ||
def calculate_popup_height(widgets: List[Any], | ||
popup_width: int) -> int: | ||
""" | ||
Returns popup height. The popup height is calculated using urwid's | ||
.rows method on every widget. | ||
""" | ||
return sum(widget.rows((popup_width, )) for widget in widgets) |
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.
I was confused about this (and possibly other code) being identical to the PopUpView code, but you're re-implementing a different popup type here?
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.
Right. I forgot we could utilize the static method from PopUpView
in this. Thanks for pointing out :)
zulipterminal/core.py
Outdated
@@ -236,6 +237,19 @@ def show_about(self) -> None: | |||
'area:help' | |||
) | |||
|
|||
def show_full_msg( |
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.
I don't see a reason to shorten this?
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.
Thanks for pointing that out. Initially, it was show_full_msg_view
, but view
seemed obvious, so I skipped it. I'll change it to show_full_message
👍
zulipterminal/ui_tools/views.py
Outdated
+ self.contents['header'][0].widget_list), | ||
self.width | ||
) | ||
self.height = min(max_rows, height) |
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.
The height doesn't try and maximize to the available based on rendered and raw content, eg. if the raw is larger.
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.
True. It would be then good to first show the raw content then? (Since most likely the length of raw content is more than the formatted one).
On a side note, I'm a bit skeptical on whether to change the width/height of the popup upon switching. Is this something we want to achieve?
zulipterminal/ui_tools/views.py
Outdated
response = controller.model.client.get_raw_message(message['id']) | ||
_content_raw = 'Raw content unavailable :(' | ||
if response['result'] == 'success': | ||
_content_raw = response['raw_content'] |
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.
I know we have a pre-existing example of this, but network/zulip error handling shouldn't really be in the UI. We generally handle the rest in wrapped methods in the model. You could add a refactor to wrap the raw call like with other calls to client
.
zulipterminal/ui_tools/views.py
Outdated
|
||
max_cols, max_rows = controller.maximum_popup_dimensions() | ||
|
||
self.width = min(max_cols, self.contents['body'][0].width) |
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.
This seems to generate narrow popups, even when the base window is quite wide?
For large messages we want to display as much as we can :)
zulipterminal/ui_tools/views.py
Outdated
def _render_body(self) -> None: | ||
content = PopUpView(self.controller, | ||
[self.tab_contents[self.tab_focus]], | ||
'FULL_MSG_VIEW', 64, self.title) |
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.
Could you explain the logic here? What makes 64 special? This explains the narrow popup.
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.
I initially thought that 64 is the maximum width 😅. I'll refactor that using max_cols
from controller 👍
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.
PopUpView
already has both max_rows
and max_cols
present in its constructor, we don't need to pass those again, right?
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.
What I'm passing is the requested_width
(required parameter), as we want to display as much info on that view as we can. In my coming iteration, that 64 would be replaced by max_cols
. Hope I'm able to clarify 😅
tests/ui_tools/test_popups.py
Outdated
def mock_external_classes(self, mocker, msg_box, initial_index): | ||
self.controller = mocker.Mock() | ||
mocker.patch.object(self.controller, 'maximum_popup_dimensions', | ||
return_value=(64, 64)) |
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.
This seems conveniently similar to the hardcoded "magic" value in the actual code; maybe we should parametrize over things somehow so a test notices, or at least fix that width issue!
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.
(See my other comment)
tests/ui_tools/test_popups.py
Outdated
] | ||
) | ||
@pytest.mark.parametrize("tab_key", | ||
keys_for_command("CYCLE_COMPOSE_FOCUS")) |
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.
This is confusing to read, and in the code - it's not compose related.
32d2c48
to
b710767
Compare
41a9ff0
to
8d7fe5c
Compare
8d7fe5c
to
0a642bd
Compare
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.
@Ezio-Sarthak This is a big PR that's gone through various iterations now - phew!
zulipterminal/ui_tools/views.py
Outdated
elif is_command_key("MSG_INFO", key): | ||
self.controller.exit_popup() |
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.
I can see why this is necessary, but I'm unclear why we don't use it for the edit history popup, since that seems a close equivalent of this one.
There's no test for this?
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.
Ah. This didn't grab my attention before! I didn't expect this to be the case 😅. Thanks for pointing this out! I am actually expecting the opposite. What I expect is exiting of popup using either FULL_RENDERED_MESSAGE
(say) or GO_BACK
only
EDIT: Doubt cleared :)
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.
Good discussion! Thanks @preetmishra :)
0a642bd
to
da9ea59
Compare
zulipterminal/ui_tools/views.py
Outdated
if response is None: | ||
controller.report_error("Error: Couldn't fetch raw message content") |
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.
This is going to be a duplicate of the error handling in the model method?
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.
Ah yes. I'll simply return in that case 👍. Thanks for pointing out!
@Ezio-Sarthak I've merged the first feature, but given the report_error issue wanted to briefly pause here. The secondary reason is that the raw content commit is ripe for refactoring the existing code, though we can do that after this PR of course (but shouldn't forget!) |
This commit adds a model method that fetches raw message content using its ID. Errors and exceptions are handled accordingly. Tests added.
da9ea59
to
9acca87
Compare
@neiljp Thanks for your patience on this! I just pushed an updated version. 👍 |
9acca87
to
73b13af
Compare
This commit replaces instances of `get_raw_message` client call with newly added `fetch_raw_message_content` method wherever present. Tests amended.
docs/hotkeys.md regenerated.
This commit adds a popup class with header as message header, body as message (raw) content, and footer as potential footlinks and reactions. This would allow users to see full scrollable (raw) message content. In the rare case of fetch failure, a footer notification is shown with the error and the popup doesn't open in this case. Tests added (FullRawMsgView).
This commit adds keypress events for showing/hiding full raw message view in message information popup. Tests amended.
73b13af
to
5c835ca
Compare
@Ezio-Sarthak Thanks for the last update with the refactor to use the new model wrapper for the other cases 👍 I'm merging after fixing one small typo in that refactor 🎉 |
What does the PR do?! :
Note: currently true for every message
Commit flow:
Further discussions here on czo :)
Fixes #543.
Screenshots/GIFs:


Full Rendered Message View
Full Raw Message View