From 29343233b7a60bd8c02e2d88ea89bb4017620f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Mon, 11 May 2026 11:22:13 +0200 Subject: [PATCH] refactor: Make `SpaceRoom::new_from_known` async so we can properly compute `is_dm` --- crates/matrix-sdk-ui/src/spaces/leave.rs | 2 +- crates/matrix-sdk-ui/src/spaces/mod.rs | 70 ++++++++++++-------- crates/matrix-sdk-ui/src/spaces/room.rs | 8 +-- crates/matrix-sdk-ui/src/spaces/room_list.rs | 38 ++++++----- 4 files changed, 71 insertions(+), 47 deletions(-) diff --git a/crates/matrix-sdk-ui/src/spaces/leave.rs b/crates/matrix-sdk-ui/src/spaces/leave.rs index 4240a6d50..5514d7162 100644 --- a/crates/matrix-sdk-ui/src/spaces/leave.rs +++ b/crates/matrix-sdk-ui/src/spaces/leave.rs @@ -102,7 +102,7 @@ impl LeaveSpaceHandle { let is_last_owner = joined_owner_ids == [room.own_user_id()]; rooms.push(LeaveSpaceRoom { - space_room: SpaceRoom::new_from_known(&room, 0), + space_room: SpaceRoom::new_from_known(&room, 0).await, is_last_owner, are_creators_privileged, }); diff --git a/crates/matrix-sdk-ui/src/spaces/mod.rs b/crates/matrix-sdk-ui/src/spaces/mod.rs index e5d4df96b..3958a4d21 100644 --- a/crates/matrix-sdk-ui/src/spaces/mod.rs +++ b/crates/matrix-sdk-ui/src/spaces/mod.rs @@ -318,7 +318,7 @@ impl SpaceService { { let room_id = room.room_id(); editable_spaces - .push(SpaceRoom::new_from_known(room, graph.children_of(room_id).len() as u64)); + .push(SpaceRoom::new_from_known(room, graph.children_of(room_id).len() as u64).await); } } @@ -334,14 +334,22 @@ impl SpaceService { pub async fn joined_parents_of_child(&self, child_id: &RoomId) -> Vec { let graph = &self.space_state.lock().await.graph; - graph + let rooms = graph .parents_of(child_id) .into_iter() - .filter_map(|parent_id| self.client.get_room(parent_id)) - .map(|room| { - SpaceRoom::new_from_known(&room, graph.children_of(room.room_id()).len() as u64) - }) - .collect() + .filter_map(|parent_id| self.client.get_room(parent_id)); + + Self::space_rooms_from_known_rooms(rooms, graph).await + } + + async fn space_rooms_from_known_rooms(iter: impl Iterator, graph: &SpaceGraph) -> Vec { + let mut result = Vec::new(); + + for room in iter { + result.push(SpaceRoom::new_from_known(&room, graph.children_of(room.room_id()).len() as u64).await); + } + + result } /// Returns the corresponding `SpaceRoom` for the given room ID, or `None` @@ -352,7 +360,7 @@ impl SpaceService { if graph.has_node(room_id) && let Some(room) = self.client.get_room(room_id) { - Some(SpaceRoom::new_from_known(&room, graph.children_of(room.room_id()).len() as u64)) + Some(SpaceRoom::new_from_known(&room, graph.children_of(room.room_id()).len() as u64).await) } else { None } @@ -583,15 +591,14 @@ impl SpaceService { }) .collect::>(); - let top_level_spaces = top_level_space_rooms - .iter() - .map(|room| { - SpaceRoom::new_from_known(room, graph.children_of(room.room_id()).len() as u64) - }) - .collect(); + let mut top_level_spaces = Vec::new(); + + for room in &top_level_space_rooms { + top_level_spaces.push(SpaceRoom::new_from_known(room, graph.children_of(room.room_id()).len() as u64).await); + } let space_filters = - Self::build_space_filters(client, &graph, top_level_space_rooms, space_child_states); + Self::build_space_filters(client, &graph, top_level_space_rooms, space_child_states).await; (top_level_spaces, space_filters, graph) } @@ -604,7 +611,7 @@ impl SpaceService { /// and second level ones so while the former are already sorted at this /// point the latter need to be manually taken care of here though the use /// of the collected `m.space.child` state event details. - fn build_space_filters( + async fn build_space_filters( client: &Client, graph: &SpaceGraph, top_level_space_rooms: Vec<&Room>, @@ -619,22 +626,14 @@ impl SpaceService { .collect::>(); filters.push(SpaceFilter { - space_room: SpaceRoom::new_from_known(top_level_space, children.len() as u64), + space_room: SpaceRoom::new_from_known(top_level_space, children.len() as u64).await, level: 0, descendants: children.clone(), }); filters.append( - &mut children - .iter() - .filter_map(|id| client.get_room(id)) - .filter(|room| room.is_space()) - .map(|room| { - SpaceRoom::new_from_known( - &room, - graph.children_of(room.room_id()).len() as u64, - ) - }) + &mut children_rooms(&client, &children, graph).await + .into_iter() .sorted_by(|a, b| { let a_state = space_child_states.get(&a.room_id).cloned(); let b_state = space_child_states.get(&b.room_id).cloned(); @@ -657,6 +656,23 @@ impl SpaceService { } } +async fn children_rooms(client: &Client, children: &[OwnedRoomId], graph: &SpaceGraph) -> Vec { + let mut result = Vec::new(); + for child_room_id in children { + let Some(room) = client.get_room(child_room_id) else { + continue; + }; + + if !room.is_space() { + continue; + } + + let space_room = SpaceRoom::new_from_known(&room, graph.children_of(room.room_id()).len() as u64).await; + result.push(space_room); + } + result +} + // MSC3230: lexicographically by `order` and then by room ID fn compare_top_level_space_rooms( a: (&RoomId, Option<&SpaceChildOrder>), diff --git a/crates/matrix-sdk-ui/src/spaces/room.rs b/crates/matrix-sdk-ui/src/spaces/room.rs index 743cee37c..f8f74b90e 100644 --- a/crates/matrix-sdk-ui/src/spaces/room.rs +++ b/crates/matrix-sdk-ui/src/spaces/room.rs @@ -116,14 +116,14 @@ impl SpaceRoom { } /// Build a `SpaceRoom` from a room already known to this client. - pub(crate) fn new_from_known(known_room: &Room, children_count: u64) -> Self { + pub(crate) async fn new_from_known(known_room: &Room, children_count: u64) -> Self { let room_info = known_room.clone_info(); let name = room_info.name().map(ToOwned::to_owned); let display_name = matrix_sdk_base::Room::compute_display_name_with_fields( name.clone(), room_info.canonical_alias(), - room_info.heroes().to_vec(), + known_room.heroes(), known_room.joined_members_count(), ) .to_string(); @@ -145,10 +145,10 @@ impl SpaceRoom { is_direct: Some(known_room.direct_targets_length() != 0), children_count, state: Some(known_room.state()), - heroes: Some(room_info.heroes().to_vec()), + heroes: Some(known_room.heroes()), via: vec![], suggested: false, - is_dm: Some(known_room.is_dm()), + is_dm: known_room.compute_is_dm().await.ok(), } } diff --git a/crates/matrix-sdk-ui/src/spaces/room_list.rs b/crates/matrix-sdk-ui/src/spaces/room_list.rs index 688af5635..c83356be3 100644 --- a/crates/matrix-sdk-ui/src/spaces/room_list.rs +++ b/crates/matrix-sdk-ui/src/spaces/room_list.rs @@ -144,24 +144,32 @@ impl SpaceRoomList { continue; } - let mut mutable_rooms = rooms.lock(); - - updates.iter_all_room_ids().for_each(|updated_room_id| { + let mut to_set = Vec::new(); + for updated_room_id in updates.iter_all_room_ids() { + let mutable_rooms = rooms.lock(); if let Some((position, room)) = mutable_rooms - .clone() .iter() .find_position(|room| &room.room_id == updated_room_id) - && let Some(updated_room) = client.get_room(updated_room_id) { - mutable_rooms.set( - position, - SpaceRoom::new_from_known( - &updated_room, - room.children_count, - ), - ); + to_set.push((position, room.clone())); } - }) + drop(mutable_rooms); + } + + for (pos, room) in to_set { + let Some(updated_room) = client.get_room(&room.room_id) else { + continue + }; + let space_room = SpaceRoom::new_from_known( + &updated_room, + room.children_count, + ).await; + let mut mutable_rooms = rooms.lock(); + mutable_rooms.set( + pos, + space_room, + ); + } } Err(err) => { error!("error when listening to room updates: {err}"); @@ -191,14 +199,14 @@ impl SpaceRoomList { while subscriber.next().await.is_some() { if let Some(room) = client.get_room(&space_id) { space_observable - .set(Some(SpaceRoom::new_from_known(&room, children_count))); + .set(Some(SpaceRoom::new_from_known(&room, children_count).await)); } } } }) .abort_on_drop(); - (Some(SpaceRoom::new_from_known(&parent, children_count)), Some(space_update_handle)) + (Some(SpaceRoom::new_from_known(&parent, children_count).await), Some(space_update_handle)) } else { (None, None) };