-
Notifications
You must be signed in to change notification settings - Fork 18
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
Display read receipts next to each message as a row of Avatars for users who have seen that message #162
base: main
Are you sure you want to change the base?
Conversation
[WIP] Will try to change sequencer to follow GenUI's way of creating a list of 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.
A great start, thanks!
I suggested some minor API changes that will make things clearer and less error-prone. After those changes are made, it should be ready to merge.
Using the existing Alternatively, we can create a separate function (or further modify |
Co-authored-by: Kevin Boos <1139460+kevinaboos@users.noreply.github.com>
Co-authored-by: Kevin Boos <1139460+kevinaboos@users.noreply.github.com>
Co-authored-by: Kevin Boos <1139460+kevinaboos@users.noreply.github.com>
…brix into read_receipt_display
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 refactoring the code; it does look nicer now.
I'm not sure how thoroughly you tested this, but I experience quite a few bugs or odd behaviors on my machine when testing it.
First, the on-hover tooltip is frequently cut off, so let's reposition that differently.
Second, the tooltip also doesn't disappear properly when you hover out of the avatar row:
Third, the log is absolutely filled with these messages:
src/sliding_sync.rs:433:21 - Sending get user profile request: ...
which indicates that you're not correctly using the user profile cache, as I see tons of duplicate requests. If you use the cache correctly (and do not re-draw the AvatarRow until a cache update is received), then you should see only one request max per unknown user ID.
Finally, and most importantly, the displayed read receipt info is actually incorrect and/or incomplete. If you scroll through any larger public room (e.g., Element Web/Desktop, Matrix HQ, etc) you'll see a total mismatch between the read receipts displayed on Robrix and the read receipts displayed by Element in the same room. Not sure what you're doing to cause this, but please look into the correctness/accuracy of the read receipts. Perhaps they're not getting updated?
Read receipts also seem to be completely missing for quite a few messages: I see them in Element but not in Robrix. Please investigate; this is probably related to the above issue too.
Finally, address all the compiler warnings that your PR has added (the main branch currently has 5 warnings, which you can ignore).
pub fn set_avatar_and_get_username( | ||
cx: &mut Cx, | ||
avatar: AvatarRef, |
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 think you missed my point that this should be a method implemented on the Avatar
type, with a typical WidgetRef-style wrapper that is implemented for AvatarRef
and just calls this inner function. That is the canonical Makepad way of doing things.
/// Returns Hit event when mouse in | ||
fn hit(&mut self, cx: &mut Cx, event: &Event, sweep_area: Area) -> Hit { |
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 docs and/or function name here need to be improved, because I can't understand what this function is doing or how I should be using it just by reading the docs alone (which is the goal).
/// Returns an option of Hit event when mouse in | ||
pub fn hit(&mut self, cx: &mut Cx, event: &Event, sweep_area: Area) -> Option<Hit> { |
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.
same comment here:
the docs and/or function name here need to be improved, because I can't understand what this function is doing or how I should be using it just by reading the docs alone (which is the goal).
@@ -2577,10 +2593,10 @@ fn draw_replied_to_message( | |||
let (in_reply_to_username, is_avatar_fully_drawn) = set_avatar_and_get_username( | |||
cx, | |||
replied_to_message_view | |||
.avatar(id!(replied_to_message_content.reply_preview_avatar)), | |||
.avatar(id!(replied_to_message_content.reply_preview_avatar)), |
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 indentation was previously correct, please undo.
fn data_to_widget(&mut self, cx: &mut Cx, nodes: &[LiveNode], path: &[LiveId]) {} | ||
} | ||
impl AvatarRow { | ||
fn set_range(&mut self, cx: &mut Cx, total_num_seen: usize) { |
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 still don't understand why we need this function ... see my other review comment within fn set_avatar_row()
.
Having this as a separate function invites someone to accidentally invoke it without understanding what other steps need to be simultaneously undertaken, i.e., it's easy to mis-use this.
All of this is just a fancy way of saying "use defensive programming techniques", in which you employ a design/implementation strategy that prevents a developer from accidentally making mistakes (yourself included). That is one of Rust's design goals as well.
pub fn set_avatar_row<'a, T>(&mut self, cx: &mut Cx, room_id: &RoomId, event_id: Option<&EventId>, receipts_len: usize, receipts_iter: T) | ||
where T:Iterator<Item = (&'a OwnedUserId, &'a Receipt)> { |
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 function can be simplified in two ways.
- There's no need for generics here. Just directly accept the IndexMap of read receipts, which will also allow you do to number 2 below.
- Remove the
receipts_len
parameter, since that is completely unnecessary and error-prone, as it's separate from (and redundant with) theIndexMap
of read receipts.
impl Widget for AvatarRow { | ||
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) { | ||
let uid = self.widget_uid(); | ||
for button in self.buttons.iter_mut() { |
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.
isn't this a very expensive way to check for a hit? Surely we should just be checking the full area of the AvatarRow as a single "whole" entity, instead of checking each button.
Unless, that is, you're going to allow each mini avatar in the AvatarRow to be individually-clickable ... which is fine, but I don't think you're doing that.
for v in self.buttons.iter_mut() { | ||
let _ = v.draw(cx, scope); | ||
} | ||
if self.total_num_seen > 5 { |
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.
extract this 5
into a const and place that const at the top of this file. You can name it MAX_VISIBLE_AVATARS_IN_READ_RECEIPT_ROW
or something similar.
See the programming rule of no magic numbers.
pub fn set_avatar_row<'a, T>(&mut self, cx: &mut Cx, room_id: &RoomId, event_id: Option<&EventId>, receipts_len: usize, receipts_iter: T) | ||
where T:Iterator<Item = (&'a OwnedUserId, &'a Receipt)> { | ||
if let Some(ref mut inner) = self.borrow_mut() { | ||
inner.set_range(cx, receipts_len); |
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.
set_range should not be a separate function, as that overcomplicates the API. You should directly set the total_num_seen
within this set_avatar_row()
fn based on the len()
of the read receipts IndexMap
, as that guarantees that the value will always be correct/accurate.
@@ -419,7 +420,7 @@ live_design! { | |||
|
|||
message_annotations = <MessageAnnotations> {} | |||
} | |||
|
|||
avatar_row = <AvatarRow> {width: 40, height: 30, margin: { top: (12.0) }, hover_actions_enabled:true } |
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.
formatting fixes
avatar_row = <AvatarRow> {width: 40, height: 30, margin: { top: (12.0) }, hover_actions_enabled:true } | |
avatar_row = <AvatarRow> { | |
width: 40, | |
height: 30, | |
margin: { top: (12.0) }, | |
hover_actions_enabled: true, | |
} |
Fixes #153