-
Notifications
You must be signed in to change notification settings - Fork 258
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
sdk-ui: Add TimelineFocus::PinnedEvents
#3773
Conversation
ba74a50
to
dae69d2
Compare
TimelineFocus::PinnedEvents
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3773 +/- ##
==========================================
+ Coverage 84.03% 84.04% +0.01%
==========================================
Files 259 261 +2
Lines 27202 27334 +132
==========================================
+ Hits 22859 22974 +115
- Misses 4343 4360 +17 ☔ View full report in Codecov by Sentry. |
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.
Looks good! Some questions.
@@ -175,6 +176,27 @@ impl TimelineBuilder { | |||
let room = inner.room(); | |||
let client = room.client(); | |||
|
|||
let mut pinned_event_ids_stream = room.pinned_event_ids_stream(); |
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.
Can this line move inside the if
?
match origin { | ||
EventsOrigin::Sync => RemoteEventOrigin::Sync, | ||
// Special case for pinned events: when we receive new events what we'll do is | ||
// updated the cache for those events that are pinned and reload the |
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.
updated -> update
// updated the cache for those events that are pinned and reload the | ||
// list. | ||
match &*focus.clone() { | ||
TimelineFocus::PinnedEvents { .. } => { |
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.
So we ignore the events that appeared via AddTimelineEvents
and just refresh the whole list? Might be good to make this clear in the comment as I didn't quite get it.
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.
Ok, I'll try to come up with a better comment to explain this.
// Special case for pinned events: when we receive new events what we'll do is | ||
// updated the cache for those events that are pinned and reload the | ||
// list. | ||
match &*focus.clone() { |
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.
If you can, I would prefer an if let
here instead of match
, because the pinned case is currently making the normal case hard to see.
} | ||
|
||
if !event_ids_to_request.is_empty() { | ||
let semaphore = Arc::new(Semaphore::new(self.max_concurrent_requests)); |
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.
Can you extract the logic for performing-things-concurrently-with-a-limit into a separate function, and then pass in the list of inputs (event IDs) and a closure for the thing to do? Don't worry if not.
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 seems like I can't because I'd have to make the closure async and that's unstable.
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.
Normally when you want an async closure you can get away with a closure that returns a Future by doing:
|args| async { body }
Not sure 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.
I think I'll try doing this in a separate PR, since the team implementing the feature is a bit blocked without it merged.
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.
Yep, fine - thanks.
fn room_pinned_event_ids(&self) -> Vec<OwnedEventId>; | ||
|
||
/// Checks whether an event id is pinned in this room. | ||
fn room_is_pinned_event_id(&self, event_id: &EventId) -> bool; |
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 just is_pinned_event_id
or is_pinned_event
, or even is_pinned
.
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.
(Basically I think room
is not helpful 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.
The problem with these is there already are some existing methods in Room
that have these names and they access private properties, and then I had to create new methods to expose them in the PinnedEventsRoom
trait and use them in this file.
I can't just replace the existing methods because they need access to those private properties to work and they can't have the same name because the compiler will mix them up. Unless there's some way to distinguish between those?
A good example of this is PinnedEventsRoom::room_pinned_event_ids
and Room::pinned_event_ids
.
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.
Ok, I think I got it with 237ee9a.
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.
Looks good.
async fn room_event(&self, event_id: &EventId) -> Result<SyncTimelineEvent, PaginatorError>; | ||
|
||
/// Get the pinned event ids for a room. | ||
fn room_pinned_event_ids(&self) -> Vec<OwnedEventId>; |
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 suggest pinned_event_ids
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 as above, 237ee9a.
|
||
runtime.block_on( | ||
Mock::given(method("GET")) | ||
.and(path_regex(r"/_matrix/client/r0/rooms/.*/event/.*")) |
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.
Is it possible to make the mocked response slow? If so I think it would be helpful, to demonstrate that we are fast because we wait for the responses in parallel.
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 mocked response already has a delay of 50ms
. When tested agains the sequential approach, the concurrent one was 0.55s vs 5.3s.
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.
Perfect, thanks!
… stream and checking whether an event is pinned in the room or not
…nedEvents` to load the live pinned events for a room. Add `PinnedEventsLoader` to encapsulate this logic, being able to provide a max number of events to load and how many can be loaded at the same time. Also implement an event cache for it. Add `PinnedEventsRoom` trait to use it in the same way as `PaginableRoom`, only for pinned events.
237ee9a
to
4b33508
Compare
Changes
Create a new type of
TimelineFocus
,TimelineFocus::PinnedEvents
that will use the pinned event ids inRoomInfo
to load the associated events, cache them and sort them chronologically.Create
PinnedEventsRoom
trait to be able to provide the necessary data to the new timeline type.Change the
is_live
parameter used in theTimeline
code for aLiveTimelineUpdatesAllowed
enum to distinguish between timelines that need to process every update (live timeline), those who don't need to process any (the focused one) and those which may need to process some items (pinned events one).Add tests and a benchmark for the concurrent pinned event loading.
Public API changes documented in changelogs (optional)
Signed-off-by: