Skip to content

Commit

Permalink
Merge pull request #3646 from Hywan/feat-ui-room-list-roominfo-update
Browse files Browse the repository at this point in the history
feat(ui): Trigger room list update only when necessary
  • Loading branch information
Hywan authored Jul 3, 2024
2 parents 6679cae + 77feed2 commit a957e70
Show file tree
Hide file tree
Showing 4 changed files with 342 additions and 32 deletions.
20 changes: 12 additions & 8 deletions crates/matrix-sdk-base/src/sliding_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ impl BaseClient {
let mut notifications = Default::default();
let mut rooms_account_data = account_data.rooms.clone();

let mut trigger_room_list_update = false;

for (room_id, response_room_data) in rooms {
let (room_info, joined_room, left_room, invited_room) = self
.process_sliding_sync_room(
Expand All @@ -163,6 +165,7 @@ impl BaseClient {
&mut changes,
&mut notifications,
&mut ambiguity_cache,
&mut trigger_room_list_update,
)
.await?;

Expand Down Expand Up @@ -292,12 +295,7 @@ impl BaseClient {

trace!("ready to submit changes to store");
store.save_changes(&changes).await?;
self.apply_changes(
&changes,
// The changes may result in a latest event update, which should trigger a room list
// re-ordering. This the room list should be notified by these changes.
true,
);
self.apply_changes(&changes, trigger_room_list_update);
trace!("applied changes");

// Now that all the rooms information have been saved, update the display name
Expand Down Expand Up @@ -327,6 +325,7 @@ impl BaseClient {
changes: &mut StateChanges,
notifications: &mut BTreeMap<OwnedRoomId, Vec<Notification>>,
ambiguity_cache: &mut AmbiguityCache,
trigger_room_list_update: &mut bool,
) -> Result<(RoomInfo, Option<JoinedRoomUpdate>, Option<LeftRoomUpdate>, Option<InvitedRoom>)>
{
let (raw_state_events, state_events): (Vec<_>, Vec<_>) = {
Expand Down Expand Up @@ -375,7 +374,7 @@ impl BaseClient {
.await?;
}

process_room_properties(room_data, &mut room_info);
process_room_properties(room_data, &mut room_info, trigger_room_list_update);

let timeline = self
.handle_timeline(
Expand Down Expand Up @@ -690,7 +689,11 @@ async fn cache_latest_events(
room.latest_encrypted_events.write().unwrap().extend(encrypted_events.into_iter().rev());
}

fn process_room_properties(room_data: &v4::SlidingSyncRoom, room_info: &mut RoomInfo) {
fn process_room_properties(
room_data: &v4::SlidingSyncRoom,
room_info: &mut RoomInfo,
trigger_room_list_update: &mut bool,
) {
// Handle the room's avatar.
//
// It can be updated via the state events, or via the
Expand Down Expand Up @@ -736,6 +739,7 @@ fn process_room_properties(room_data: &v4::SlidingSyncRoom, room_info: &mut Room

if let Some(recency_timestamp) = &room_data.timestamp {
room_info.update_recency_timestamp(*recency_timestamp);
*trigger_room_list_update = true;
}
}

Expand Down
10 changes: 8 additions & 2 deletions crates/matrix-sdk-ui/src/room_list_service/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

//! The `Room` type.

use core::fmt;
use std::{ops::Deref, sync::Arc};

use async_once_cell::OnceCell as AsyncOnceCell;
Expand All @@ -29,12 +30,17 @@ use crate::{
/// A room in the room list.
///
/// It's cheap to clone this type.
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct Room {
inner: Arc<RoomInner>,
}

#[derive(Debug)]
impl fmt::Debug for Room {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_tuple("Room").field(&self.id().to_owned()).finish()
}
}

struct RoomInner {
/// The Sliding Sync where everything comes from.
sliding_sync: Arc<SlidingSync>,
Expand Down
271 changes: 271 additions & 0 deletions crates/matrix-sdk-ui/tests/integration/room_list_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1653,6 +1653,277 @@ async fn test_dynamic_entries_stream() -> Result<(), Error> {
Ok(())
}

#[async_test]
async fn test_room_sorting() -> Result<(), Error> {
let (client, server, room_list) = new_room_list_service().await?;

let sync = room_list.sync();
pin_mut!(sync);

let all_rooms = room_list.all_rooms().await?;

let (stream, dynamic_entries) =
all_rooms.entries_with_dynamic_adapters(10, client.roominfo_update_receiver());
pin_mut!(stream);

sync_then_assert_request_and_fake_response! {
[server, room_list, sync]
states = Init => SettingUp,
assert request >= {
"lists": {
ALL_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
"pos": "0",
"lists": {
ALL_ROOMS: {
"count": 5,
},
},
"rooms": {
"!r0:bar.org": {
"initial": true,
"timestamp": 3,
"required_state": [
{
"content": {
"name": "Bbb"
},
"sender": "@example:bar.org",
"state_key": "",
"type": "m.room.name",
"event_id": "$s0",
"origin_server_ts": 3,
},
],
},
"!r1:bar.org": {
"initial": true,
"timestamp": 3,
"required_state": [
{
"content": {
"name": "Aaa"
},
"sender": "@example:bar.org",
"state_key": "",
"type": "m.room.name",
"event_id": "$s1",
"origin_server_ts": 3,
},
],
},
"!r2:bar.org": {
"initial": true,
"timestamp": 1,
},
"!r3:bar.org": {
"initial": true,
"timestamp": 4,
},
"!r4:bar.org": {
"initial": true,
"timestamp": 5,
},
},
},
};

// Ensure the dynamic entries' stream is pending because there is no filter set
// yet.
assert_pending!(stream);

// Now, let's define a filter.
dynamic_entries.set_filter(Box::new(new_filter_non_left()));

// Assert rooms are sorted by recency and by name!.
assert_entries_batch! {
[stream]
reset [
"!r4:bar.org", // recency of 5
"!r3:bar.org", // recency of 4
"!r1:bar.org", // recency of 3, but name comes before `!r0`
"!r0:bar.org", // recency of 3, but name comes after `!r1`
"!r2:bar.org", // recency of 1
];
end;
};

// Now we have:
//
// | index | room ID | recency | name |
// |-------|---------|---------|------|
// | 0 | !r4 | 5 | |
// | 1 | !r3 | 4 | |
// | 2 | !r1 | 3 | Aaa |
// | 3 | !r0 | 3 | Bbb |
// | 4 | !r2 | 1 | |

assert_pending!(stream);

sync_then_assert_request_and_fake_response! {
[server, room_list, sync]
states = SettingUp => Running,
assert request >= {
"lists": {
ALL_ROOMS: {
"ranges": [[0, 4]],
},
},
},
respond with = {
"pos": "1",
"lists": {
ALL_ROOMS: {
"count": 5,
},
},
"rooms": {
"!r0:bar.org": {
"timestamp": 7,
},
"!r1:bar.org": {
"timestamp": 6,
},
"!r2:bar.org": {
"timestamp": 9,
},
},
},
};

// Assert rooms are moving.
assert_entries_batch! {
[stream]
remove [ 3 ];
insert [ 0 ] [ "!r0:bar.org" ];
end;
};

// Now we have:
//
// | index | room ID | recency | name |
// |-------|---------|---------|------|
// | 0 | !r0 | 7 | Bbb |
// | 1 | !r4 | 5 | |
// | 2 | !r3 | 4 | |
// | 3 | !r1 | 3 | Aaa |
// | 4 | !r2 | 1 | |

assert_entries_batch! {
[stream]
remove [ 3 ];
insert [ 1 ] [ "!r1:bar.org" ];
end;
};

// Now we have:
//
// | index | room ID | recency | name |
// |-------|---------|---------|------|
// | 0 | !r0 | 7 | Bbb |
// | 1 | !r1 | 6 | Aaa |
// | 2 | !r4 | 5 | |
// | 3 | !r3 | 4 | |
// | 4 | !r2 | 1 | |

assert_entries_batch! {
[stream]
remove [ 4 ];
insert [ 0 ] [ "!r2:bar.org" ];
end;
};

// Now we have:
//
// | index | room ID | recency | name |
// |-------|---------|---------|------|
// | 0 | !r2 | 9 | |
// | 1 | !r0 | 7 | Bbb |
// | 2 | !r1 | 6 | Aaa |
// | 3 | !r4 | 5 | |
// | 4 | !r3 | 4 | |

assert_pending!(stream);

sync_then_assert_request_and_fake_response! {
[server, room_list, sync]
states = Running => Running,
assert request >= {
"lists": {
ALL_ROOMS: {
"ranges": [[0, 4]],
},
},
},
respond with = {
"pos": "2",
"lists": {
ALL_ROOMS: {
"count": 6,
},
},
"rooms": {
"!r6:bar.org": {
"initial": true,
"timestamp": 8,
},
"!r3:bar.org": {
"timestamp": 10,
},
},
},
};

assert_entries_batch! {
[stream]
insert [ 1 ] [ "!r6:bar.org" ];
end;
};

// Now we have:
//
// | index | room ID | recency | name |
// |-------|---------|---------|------|
// | 0 | !r2 | 9 | |
// | 1 | !r6 | 8 | |
// | 2 | !r0 | 7 | Bbb |
// | 3 | !r1 | 6 | Aaa |
// | 4 | !r4 | 5 | |
// | 5 | !r3 | 4 | |

assert_entries_batch! {
[stream]
remove [ 5 ];
insert [ 0 ] [ "!r3:bar.org" ];
end;
};

// Now we have:
//
// | index | room ID | recency | name |
// |-------|---------|---------|------|
// | 0 | !r3 | 10 | |
// | 1 | !r2 | 9 | |
// | 2 | !r6 | 8 | |
// | 3 | !r0 | 7 | Bbb |
// | 4 | !r1 | 6 | Aaa |
// | 5 | !r4 | 5 | |

assert_entries_batch! {
[stream]
set [ 2 ] [ "!r6:bar.org" ];
end;
};

assert_pending!(stream);

Ok(())
}

#[async_test]
async fn test_room() -> Result<(), Error> {
let (_, server, room_list) = new_room_list_service().await?;
Expand Down
Loading

0 comments on commit a957e70

Please sign in to comment.