Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bindings/matrix-sdk-ffi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ All notable changes to this project will be documented in this file.

## [Unreleased] - ReleaseDate

## Refactor

- [**breaking**] `SpaceRoomList::rooms` and `SpaceRoomList::subscribe_to_room_updates` are now asynchronous.
([#6561](https://github.com/matrix-org/matrix-rust-sdk/pull/6561))

## [0.17.0] - 2026-05-08

### Bug Fixes
Expand Down
8 changes: 4 additions & 4 deletions bindings/matrix-sdk-ffi/src/spaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,16 +252,16 @@ impl SpaceRoomList {
}

/// Return the current list of rooms.
pub fn rooms(&self) -> Vec<SpaceRoom> {
self.inner.rooms().into_iter().map(Into::into).collect()
pub async fn rooms(&self) -> Vec<SpaceRoom> {
self.inner.rooms().await.into_iter().map(Into::into).collect()
}

/// Subscribes to room list updates.
pub fn subscribe_to_room_update(
pub async fn subscribe_to_room_update(
&self,
listener: Box<dyn SpaceRoomListEntriesListener>,
) -> Arc<TaskHandle> {
let (initial_values, mut stream) = self.inner.subscribe_to_room_updates();
let (initial_values, mut stream) = self.inner.subscribe_to_room_updates().await;

listener.on_update(vec![SpaceListUpdate::Reset {
values: initial_values.into_iter().map(Into::into).collect(),
Expand Down
6 changes: 6 additions & 0 deletions crates/matrix-sdk-base/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ All notable changes to this project will be documented in this file.

## [Unreleased] - ReleaseDate

### Features

- Add `Room::compute_joined_service_members` to compute the number of joined service members in a room.
This is needed for calculating display names of `SpaceRoom`s with service members.
([#6561](https://github.com/matrix-org/matrix-rust-sdk/pull/6561))

## [0.17.0] - 2026-05-08

### Bug Fixes
Expand Down
33 changes: 33 additions & 0 deletions crates/matrix-sdk-base/src/room/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,39 @@ impl Room {
}
}

/// Computes the joined service members in this room.
///
/// This result is useful for computing a room's display name, i.e.
#[instrument(skip_all, fields(room_id = ?self.room_id))]
pub async fn compute_joined_service_members(&self) -> StoreResult<Option<Vec<RoomMember>>> {
if !self.are_members_synced() {
trace!("Tried to compute joined service members in a room that is not synced");
return Ok(None);
}
if let Some(service_member_ids) = self.service_members() {
let mut ret = vec![];
for user_id in service_member_ids.iter() {
if let Some(member) = self.get_member(user_id).await.unwrap()
&& matches!(member.membership(), MembershipState::Join)
{
trace!("Found a joined service member ({})", user_id);
ret.push(member);
} else {
trace!("Did not find a joined service member ({})", user_id);
}
}
trace!(
"Computed joined service members ({}) for service member count {}",
ret.len(),
service_member_ids.len()
);
Ok(Some(ret))
} else {
trace!("Tried to compute joined service members in a room that has no service members",);
Ok(None)
}
}

/// Returns a cached value containing the active (joined/invited) service
/// member count, if known.
pub fn active_service_members_count(&self) -> Option<u64> {
Expand Down
6 changes: 6 additions & 0 deletions crates/matrix-sdk-ui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ All notable changes to this project will be documented in this file.

## [Unreleased] - ReleaseDate

### Refactor

- [**breaking**] `SpaceRoom::new_from_known` and `SpaceRoom::new_from_summary` are now asynchronous so we can
properly check if they are DMs on demand instead of trusting the pre-computed value. Some other related functions
are now `async` too. ([#6561](https://github.com/matrix-org/matrix-rust-sdk/pull/6561))

## [0.17.0] - 2026-05-08

### Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion crates/matrix-sdk-ui/src/spaces/leave.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
Expand Down
115 changes: 68 additions & 47 deletions crates/matrix-sdk-ui/src/spaces/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
use std::{cmp::Ordering, collections::HashMap, sync::Arc};

use eyeball_im::{ObservableVector, VectorSubscriberBatchedStream};
use futures_util::pin_mut;
use futures_util::{future::join_all, pin_mut};
use imbl::Vector;
use itertools::Itertools;
use matrix_sdk::{
Expand Down Expand Up @@ -134,7 +134,7 @@ struct SpaceState {
/// .await;
///
/// // Which can be used to retrieve information about the children rooms
/// let children = room_list.rooms();
/// let children = room_list.rooms().await;
/// # anyhow::Ok(()) };
/// ```
pub struct SpaceService {
Expand Down Expand Up @@ -317,8 +317,9 @@ impl SpaceService {
&& power_levels.user_can_send_state(user_id, StateEventType::SpaceChild)
{
let room_id = room.room_id();
editable_spaces
.push(SpaceRoom::new_from_known(room, graph.children_of(room_id).len() as u64));
editable_spaces.push(
SpaceRoom::new_from_known(room, graph.children_of(room_id).len() as u64).await,
);
}
}

Expand All @@ -334,14 +335,15 @@ impl SpaceService {
pub async fn joined_parents_of_child(&self, child_id: &RoomId) -> Vec<SpaceRoom> {
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));

join_all(rooms.map(|room| async move {
SpaceRoom::new_from_known(&room, graph.children_of(room.room_id()).len() as u64).await
}))
.await
}

/// Returns the corresponding `SpaceRoom` for the given room ID, or `None`
Expand All @@ -352,7 +354,10 @@ 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
}
Expand Down Expand Up @@ -583,15 +588,18 @@ impl SpaceService {
})
.collect::<Vec<_>>();

let top_level_spaces = top_level_space_rooms
.iter()
.map(|room| {
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)
})
.collect();
.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)
}
Expand All @@ -604,7 +612,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>,
Expand All @@ -619,22 +627,28 @@ impl SpaceService {
.collect::<Vec<_>>();

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
let children_rooms = join_all(
children
.iter()
.filter_map(|id| client.get_room(id))
.filter_map(|child| client.get_room(child))
.filter(|room| room.is_space())
.map(|room| {
.map(|room| async move {
SpaceRoom::new_from_known(
&room,
graph.children_of(room.room_id()).len() as u64,
)
})
.await
}),
)
.await;
filters.append(
&mut children_rooms
.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();
Expand Down Expand Up @@ -843,12 +857,13 @@ mod tests {

assert_eq!(
initial_values,
vec![SpaceRoom::new_from_known(&client.get_room(first_space_id).unwrap(), 0)].into()
vec![SpaceRoom::new_from_known(&client.get_room(first_space_id).unwrap(), 0).await]
.into()
);

assert_eq!(
space_service.top_level_joined_spaces().await,
vec![SpaceRoom::new_from_known(&client.get_room(first_space_id).unwrap(), 0)]
vec![SpaceRoom::new_from_known(&client.get_room(first_space_id).unwrap(), 0).await]
);

// And the stream is still pending as the initial values were
Expand Down Expand Up @@ -877,8 +892,8 @@ mod tests {
assert_eq!(
space_service.top_level_joined_spaces().await,
vec![
SpaceRoom::new_from_known(&client.get_room(first_space_id).unwrap(), 0),
SpaceRoom::new_from_known(&client.get_room(second_space_id).unwrap(), 1)
SpaceRoom::new_from_known(&client.get_room(first_space_id).unwrap(), 0).await,
SpaceRoom::new_from_known(&client.get_room(second_space_id).unwrap(), 1).await
]
);

Expand All @@ -888,8 +903,10 @@ mod tests {
VectorDiff::Clear,
VectorDiff::Append {
values: vec![
SpaceRoom::new_from_known(&client.get_room(first_space_id).unwrap(), 0),
SpaceRoom::new_from_known(&client.get_room(first_space_id).unwrap(), 0)
.await,
SpaceRoom::new_from_known(&client.get_room(second_space_id).unwrap(), 1)
.await
]
.into()
},
Expand All @@ -904,10 +921,10 @@ mod tests {
vec![
VectorDiff::Clear,
VectorDiff::Append {
values: vec![SpaceRoom::new_from_known(
&client.get_room(first_space_id).unwrap(),
0
)]
values: vec![
SpaceRoom::new_from_known(&client.get_room(first_space_id).unwrap(), 0)
.await
]
.into()
},
]
Expand All @@ -926,7 +943,7 @@ mod tests {
assert_pending!(joined_spaces_subscriber);
assert_eq!(
space_service.top_level_joined_spaces().await,
vec![SpaceRoom::new_from_known(&client.get_room(first_space_id).unwrap(), 0)]
vec![SpaceRoom::new_from_known(&client.get_room(first_space_id).unwrap(), 0).await]
);
}

Expand Down Expand Up @@ -1067,10 +1084,10 @@ mod tests {
assert_eq!(
space_service.top_level_joined_spaces().await,
vec![
SpaceRoom::new_from_known(&client.get_room(room_id!("!1:a.b")).unwrap(), 0),
SpaceRoom::new_from_known(&client.get_room(room_id!("!2:a.b")).unwrap(), 0),
SpaceRoom::new_from_known(&client.get_room(room_id!("!3:a.b")).unwrap(), 0),
SpaceRoom::new_from_known(&client.get_room(room_id!("!4:a.b")).unwrap(), 0),
SpaceRoom::new_from_known(&client.get_room(room_id!("!1:a.b")).unwrap(), 0).await,
SpaceRoom::new_from_known(&client.get_room(room_id!("!2:a.b")).unwrap(), 0).await,
SpaceRoom::new_from_known(&client.get_room(room_id!("!3:a.b")).unwrap(), 0).await,
SpaceRoom::new_from_known(&client.get_room(room_id!("!4:a.b")).unwrap(), 0).await,
]
);
}
Expand Down Expand Up @@ -1229,7 +1246,7 @@ mod tests {
let found = space_service.get_space_room(space_id).await;
assert!(found.is_some());

let expected = SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 0);
let expected = SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 0).await;
assert_eq!(found.unwrap(), expected);
}

Expand Down Expand Up @@ -1629,12 +1646,12 @@ mod tests {

assert_eq!(
initial_values,
vec![SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 0)].into()
vec![SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 0).await].into()
);

assert_eq!(
space_service.top_level_joined_spaces().await,
vec![SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 0)]
vec![SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 0).await]
);

// Two children are added.
Expand All @@ -1658,15 +1675,17 @@ mod tests {
// And expect the list to update.
assert_eq!(
space_service.top_level_joined_spaces().await,
vec![SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 2)]
vec![SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 2).await]
);
assert_next_eq!(
joined_spaces_subscriber,
vec![
VectorDiff::Clear,
VectorDiff::Append {
values: vec![SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 2)]
.into()
values: vec![
SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 2).await
]
.into()
},
]
);
Expand All @@ -1691,15 +1710,17 @@ mod tests {
// And expect the list to update.
assert_eq!(
space_service.top_level_joined_spaces().await,
vec![SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 1)]
vec![SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 1).await]
);
assert_next_eq!(
joined_spaces_subscriber,
vec![
VectorDiff::Clear,
VectorDiff::Append {
values: vec![SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 1)]
.into()
values: vec![
SpaceRoom::new_from_known(&client.get_room(space_id).unwrap(), 1).await
]
.into()
},
]
);
Expand Down
Loading
Loading