chore(spaces): converge on single naming scheme for all spaces related components on both the UI and the FFI crates

This commit is contained in:
Stefan Ceriu
2025-08-12 14:25:30 +03:00
committed by Stefan Ceriu
parent 990fe86fdc
commit 87fdd3c3bf
6 changed files with 85 additions and 113 deletions

View File

@@ -1259,7 +1259,7 @@ impl Client {
SyncServiceBuilder::new((*self.inner).clone(), self.utd_hook_manager.get().cloned())
}
pub fn spaces_service(&self) -> Arc<SpaceService> {
pub fn space_service(&self) -> Arc<SpaceService> {
let inner = UISpaceService::new((*self.inner).clone());
Arc::new(SpaceService::new(inner))
}

View File

@@ -17,9 +17,8 @@ use std::{fmt::Debug, sync::Arc};
use futures_util::{pin_mut, StreamExt};
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_ui::spaces::{
room_list::SpaceServiceRoomListPaginationState as UISpaceServiceRoomListPaginationState,
SpaceService as UISpaceService, SpaceServiceRoom as UISpaceServiceRoom,
SpaceServiceRoomList as UISpaceServiceRoomList,
room_list::SpaceRoomListPaginationState, SpaceRoom as UISpaceRoom,
SpaceRoomList as UISpaceRoomList, SpaceService as UISpaceService,
};
use ruma::RoomId;
@@ -38,14 +37,14 @@ pub struct SpaceService {
}
impl SpaceService {
pub fn new(inner: UISpaceService) -> Self {
pub(crate) fn new(inner: UISpaceService) -> Self {
Self { inner }
}
}
#[matrix_sdk_ffi_macros::export]
impl SpaceService {
pub async fn joined_spaces(&self) -> Vec<SpaceServiceRoom> {
pub async fn joined_spaces(&self) -> Vec<SpaceRoom> {
self.inner.joined_spaces().await.into_iter().map(Into::into).collect()
}
@@ -77,32 +76,32 @@ impl SpaceService {
pub async fn space_room_list(
&self,
space_id: String,
) -> Result<Arc<SpaceServiceRoomList>, ClientError> {
) -> Result<Arc<SpaceRoomList>, ClientError> {
let space_id = RoomId::parse(space_id)?;
Ok(Arc::new(SpaceServiceRoomList::new(self.inner.space_room_list(space_id))))
Ok(Arc::new(SpaceRoomList::new(self.inner.space_room_list(space_id))))
}
}
#[derive(uniffi::Object)]
pub struct SpaceServiceRoomList {
inner: UISpaceServiceRoomList,
pub struct SpaceRoomList {
inner: UISpaceRoomList,
}
impl SpaceServiceRoomList {
pub fn new(inner: UISpaceServiceRoomList) -> Self {
impl SpaceRoomList {
fn new(inner: UISpaceRoomList) -> Self {
Self { inner }
}
}
#[matrix_sdk_ffi_macros::export]
impl SpaceServiceRoomList {
pub fn pagination_state(&self) -> SpaceServiceRoomListPaginationState {
self.inner.pagination_state().into()
impl SpaceRoomList {
pub fn pagination_state(&self) -> SpaceRoomListPaginationState {
self.inner.pagination_state()
}
pub fn subscribe_to_pagination_state_updates(
&self,
listener: Box<dyn SpaceServiceRoomListPaginationStateListener>,
listener: Box<dyn SpaceRoomListPaginationStateListener>,
) -> Arc<TaskHandle> {
let pagination_state = self.inner.subscribe_to_pagination_state_updates();
@@ -110,18 +109,18 @@ impl SpaceServiceRoomList {
pin_mut!(pagination_state);
while let Some(state) = pagination_state.next().await {
listener.on_update(state.into());
listener.on_update(state);
}
})))
}
pub fn rooms(&self) -> Vec<SpaceServiceRoom> {
pub fn rooms(&self) -> Vec<SpaceRoom> {
self.inner.rooms().into_iter().map(Into::into).collect()
}
pub fn subscribe_to_room_update(
&self,
listener: Box<dyn SpaceServiceRoomListEntriesListener>,
listener: Box<dyn SpaceRoomListEntriesListener>,
) -> Arc<TaskHandle> {
let entries_stream = self.inner.subscribe_to_room_updates();
@@ -139,44 +138,23 @@ impl SpaceServiceRoomList {
}
}
#[derive(uniffi::Enum)]
pub enum SpaceServiceRoomListPaginationState {
Idle { end_reached: bool },
Loading,
}
impl From<UISpaceServiceRoomListPaginationState> for SpaceServiceRoomListPaginationState {
fn from(state: UISpaceServiceRoomListPaginationState) -> Self {
match state {
UISpaceServiceRoomListPaginationState::Idle { end_reached } => {
SpaceServiceRoomListPaginationState::Idle { end_reached }
}
UISpaceServiceRoomListPaginationState::Loading => {
SpaceServiceRoomListPaginationState::Loading
}
}
}
#[matrix_sdk_ffi_macros::export(callback_interface)]
pub trait SpaceRoomListPaginationStateListener: SendOutsideWasm + SyncOutsideWasm + Debug {
fn on_update(&self, pagination_state: SpaceRoomListPaginationState);
}
#[matrix_sdk_ffi_macros::export(callback_interface)]
pub trait SpaceServiceRoomListPaginationStateListener:
SendOutsideWasm + SyncOutsideWasm + Debug
{
fn on_update(&self, pagination_state: SpaceServiceRoomListPaginationState);
}
#[matrix_sdk_ffi_macros::export(callback_interface)]
pub trait SpaceServiceRoomListEntriesListener: SendOutsideWasm + SyncOutsideWasm + Debug {
fn on_update(&self, rooms: Vec<SpaceServiceRoom>);
pub trait SpaceRoomListEntriesListener: SendOutsideWasm + SyncOutsideWasm + Debug {
fn on_update(&self, rooms: Vec<SpaceRoom>);
}
#[matrix_sdk_ffi_macros::export(callback_interface)]
pub trait SpaceServiceJoinedSpacesListener: SendOutsideWasm + SyncOutsideWasm + Debug {
fn on_update(&self, rooms: Vec<SpaceServiceRoom>);
fn on_update(&self, rooms: Vec<SpaceRoom>);
}
#[derive(uniffi::Record)]
pub struct SpaceServiceRoom {
pub struct SpaceRoom {
pub room_id: String,
pub canonical_alias: Option<String>,
pub name: Option<String>,
@@ -193,8 +171,8 @@ pub struct SpaceServiceRoom {
pub heroes: Option<Vec<RoomHero>>,
}
impl From<UISpaceServiceRoom> for SpaceServiceRoom {
fn from(room: UISpaceServiceRoom) -> Self {
impl From<UISpaceRoom> for SpaceRoom {
fn from(room: UISpaceRoom) -> Self {
Self {
room_id: room.room_id.into(),
canonical_alias: room.canonical_alias.map(|alias| alias.into()),

View File

@@ -17,30 +17,30 @@ use std::collections::{BTreeMap, BTreeSet};
use ruma::OwnedRoomId;
#[derive(Debug)]
struct SpaceServiceGraphNode {
struct SpaceGraphNode {
id: OwnedRoomId,
parents: BTreeSet<OwnedRoomId>,
children: BTreeSet<OwnedRoomId>,
}
impl SpaceServiceGraphNode {
impl SpaceGraphNode {
fn new(id: OwnedRoomId) -> Self {
Self { id, parents: BTreeSet::new(), children: BTreeSet::new() }
}
}
#[derive(Debug)]
pub struct SpaceServiceGraph {
nodes: BTreeMap<OwnedRoomId, SpaceServiceGraphNode>,
pub struct SpaceGraph {
nodes: BTreeMap<OwnedRoomId, SpaceGraphNode>,
}
impl Default for SpaceServiceGraph {
impl Default for SpaceGraph {
fn default() -> Self {
Self::new()
}
}
impl SpaceServiceGraph {
impl SpaceGraph {
pub fn new() -> Self {
Self { nodes: BTreeMap::new() }
}
@@ -54,15 +54,13 @@ impl SpaceServiceGraph {
}
pub fn add_node(&mut self, node_id: OwnedRoomId) {
self.nodes.entry(node_id.clone()).or_insert(SpaceServiceGraphNode::new(node_id));
self.nodes.entry(node_id.clone()).or_insert(SpaceGraphNode::new(node_id));
}
pub fn add_edge(&mut self, parent_id: OwnedRoomId, child_id: OwnedRoomId) {
self.nodes
.entry(parent_id.clone())
.or_insert(SpaceServiceGraphNode::new(parent_id.clone()));
self.nodes.entry(parent_id.clone()).or_insert(SpaceGraphNode::new(parent_id.clone()));
self.nodes.entry(child_id.clone()).or_insert(SpaceServiceGraphNode::new(child_id.clone()));
self.nodes.entry(child_id.clone()).or_insert(SpaceGraphNode::new(child_id.clone()));
self.nodes.get_mut(&parent_id).unwrap().children.insert(child_id.clone());
self.nodes.get_mut(&child_id).unwrap().parents.insert(parent_id);
@@ -124,7 +122,7 @@ mod tests {
#[test]
fn test_add_edge_and_root_nodes() {
let mut graph = SpaceServiceGraph::new();
let mut graph = SpaceGraph::new();
let a = room_id!("!a:example.org").to_owned();
let b = room_id!("!b:example.org").to_owned();
@@ -143,7 +141,7 @@ mod tests {
#[test]
fn test_remove_cycles() {
let mut graph = SpaceServiceGraph::new();
let mut graph = SpaceGraph::new();
let a = room_id!("!a:example.org").to_owned();
let b = room_id!("!b:example.org").to_owned();
@@ -163,7 +161,7 @@ mod tests {
#[test]
fn test_disconnected_graph_roots() {
let mut graph = SpaceServiceGraph::new();
let mut graph = SpaceGraph::new();
let a = room_id!("!a:example.org").to_owned();
let b = room_id!("!b:example.org").to_owned();
@@ -182,7 +180,7 @@ mod tests {
#[test]
fn test_multiple_parents() {
let mut graph = SpaceServiceGraph::new();
let mut graph = SpaceGraph::new();
let a = room_id!("!a:example.org").to_owned();
let b = room_id!("!b:example.org").to_owned();

View File

@@ -29,8 +29,8 @@ use ruma::{
};
use tracing::error;
use crate::spaces::graph::SpaceServiceGraph;
pub use crate::spaces::{room::SpaceServiceRoom, room_list::SpaceServiceRoomList};
use crate::spaces::graph::SpaceGraph;
pub use crate::spaces::{room::SpaceRoom, room_list::SpaceRoomList};
pub mod graph;
pub mod room;
@@ -39,7 +39,7 @@ pub mod room_list;
pub struct SpaceService {
client: Client,
joined_spaces: SharedObservable<Vec<SpaceServiceRoom>>,
joined_spaces: SharedObservable<Vec<SpaceRoom>>,
room_update_handle: Mutex<Option<JoinHandle<()>>>,
}
@@ -61,7 +61,7 @@ impl SpaceService {
}
}
pub fn subscribe_to_joined_spaces(&self) -> Subscriber<Vec<SpaceServiceRoom>> {
pub fn subscribe_to_joined_spaces(&self) -> Subscriber<Vec<SpaceRoom>> {
if self.room_update_handle.lock().is_none() {
let client_clone = self.client.clone();
let joined_spaces_clone = self.joined_spaces.clone();
@@ -89,7 +89,7 @@ impl SpaceService {
self.joined_spaces.subscribe()
}
pub async fn joined_spaces(&self) -> Vec<SpaceServiceRoom> {
pub async fn joined_spaces(&self) -> Vec<SpaceRoom> {
let spaces = Self::joined_spaces_for(&self.client).await;
if spaces != self.joined_spaces.get() {
@@ -99,18 +99,18 @@ impl SpaceService {
spaces
}
pub fn space_room_list(&self, space_id: OwnedRoomId) -> SpaceServiceRoomList {
SpaceServiceRoomList::new(self.client.clone(), space_id)
pub fn space_room_list(&self, space_id: OwnedRoomId) -> SpaceRoomList {
SpaceRoomList::new(self.client.clone(), space_id)
}
async fn joined_spaces_for(client: &Client) -> Vec<SpaceServiceRoom> {
async fn joined_spaces_for(client: &Client) -> Vec<SpaceRoom> {
let joined_spaces = client
.joined_rooms()
.into_iter()
.filter_map(|room| room.is_space().then_some(room))
.collect::<Vec<_>>();
let mut graph = SpaceServiceGraph::new();
let mut graph = SpaceGraph::new();
for space in joined_spaces.iter() {
graph.add_node(space.room_id().to_owned());
@@ -160,7 +160,7 @@ impl SpaceService {
let room_id = room.room_id().to_owned();
if root_notes.contains(&&room_id) {
Some(SpaceServiceRoom::new_from_known(
Some(SpaceRoom::new_from_known(
room.clone(),
graph.children_of(&room_id).len() as u64,
))
@@ -330,7 +330,7 @@ mod tests {
assert_eq!(
space_service.joined_spaces().await,
vec![SpaceServiceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0)]
vec![SpaceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0)]
);
// Join the second space
@@ -355,8 +355,8 @@ mod tests {
assert_eq!(
space_service.joined_spaces().await,
vec![
SpaceServiceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0),
SpaceServiceRoom::new_from_known(client.get_room(second_space_id).unwrap(), 1)
SpaceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0),
SpaceRoom::new_from_known(client.get_room(second_space_id).unwrap(), 1)
]
);
@@ -364,8 +364,8 @@ mod tests {
assert_next_eq!(
joined_spaces_subscriber,
vec![
SpaceServiceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0),
SpaceServiceRoom::new_from_known(client.get_room(second_space_id).unwrap(), 1)
SpaceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0),
SpaceRoom::new_from_known(client.get_room(second_space_id).unwrap(), 1)
]
);
@@ -374,7 +374,7 @@ mod tests {
// and when one is left
assert_next_eq!(
joined_spaces_subscriber,
vec![SpaceServiceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0)]
vec![SpaceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0)]
);
// but it doesn't when a non-space room gets joined
@@ -390,7 +390,7 @@ mod tests {
assert_pending!(joined_spaces_subscriber);
assert_eq!(
space_service.joined_spaces().await,
vec![SpaceServiceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0)]
vec![SpaceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0)]
);
}
}

View File

@@ -20,7 +20,7 @@ use ruma::{
};
#[derive(Debug, Clone, PartialEq)]
pub struct SpaceServiceRoom {
pub struct SpaceRoom {
pub room_id: OwnedRoomId,
pub canonical_alias: Option<OwnedRoomAliasId>,
pub name: Option<String>,
@@ -37,7 +37,7 @@ pub struct SpaceServiceRoom {
pub heroes: Option<Vec<RoomHero>>,
}
impl SpaceServiceRoom {
impl SpaceRoom {
pub fn new_from_summary(
summary: &RoomSummary,
known_room: Option<Room>,

View File

@@ -21,36 +21,37 @@ use matrix_sdk_common::executor::{JoinHandle, spawn};
use ruma::{OwnedRoomId, api::client::space::get_hierarchy, uint};
use tracing::error;
use crate::spaces::SpaceServiceRoom;
use crate::spaces::SpaceRoom;
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SpaceServiceRoomListPaginationState {
pub enum SpaceRoomListPaginationState {
Idle { end_reached: bool },
Loading,
}
pub struct SpaceServiceRoomList {
pub struct SpaceRoomList {
client: Client,
parent_space_id: OwnedRoomId,
token: Mutex<PaginationToken>,
pagination_state: SharedObservable<SpaceServiceRoomListPaginationState>,
pagination_state: SharedObservable<SpaceRoomListPaginationState>,
rooms: SharedObservable<Vec<SpaceServiceRoom>>,
rooms: SharedObservable<Vec<SpaceRoom>>,
room_update_handle: JoinHandle<()>,
}
impl Drop for SpaceServiceRoomList {
impl Drop for SpaceRoomList {
fn drop(&mut self) {
self.room_update_handle.abort();
}
}
impl SpaceServiceRoomList {
impl SpaceRoomList {
pub fn new(client: Client, parent_space_id: OwnedRoomId) -> Self {
let rooms = SharedObservable::new(Vec::<SpaceServiceRoom>::new());
let rooms = SharedObservable::new(Vec::<SpaceRoom>::new());
let client_clone = client.clone();
let rooms_clone = rooms.clone();
@@ -69,10 +70,7 @@ impl SpaceServiceRoomList {
new_rooms.iter_mut().find(|room| &room.room_id == updated_room_id)
&& let Some(update_room) = client_clone.get_room(updated_room_id)
{
*room = SpaceServiceRoom::new_from_known(
update_room,
room.children_count,
);
*room = SpaceRoom::new_from_known(update_room, room.children_count);
}
});
@@ -91,7 +89,7 @@ impl SpaceServiceRoomList {
client,
parent_space_id,
token: Mutex::new(None.into()),
pagination_state: SharedObservable::new(SpaceServiceRoomListPaginationState::Idle {
pagination_state: SharedObservable::new(SpaceRoomListPaginationState::Idle {
end_reached: false,
}),
rooms,
@@ -99,36 +97,36 @@ impl SpaceServiceRoomList {
}
}
pub fn pagination_state(&self) -> SpaceServiceRoomListPaginationState {
pub fn pagination_state(&self) -> SpaceRoomListPaginationState {
self.pagination_state.get()
}
pub fn subscribe_to_pagination_state_updates(
&self,
) -> Subscriber<SpaceServiceRoomListPaginationState> {
) -> Subscriber<SpaceRoomListPaginationState> {
self.pagination_state.subscribe()
}
pub fn rooms(&self) -> Vec<SpaceServiceRoom> {
pub fn rooms(&self) -> Vec<SpaceRoom> {
self.rooms.get()
}
pub fn subscribe_to_room_updates(&self) -> Subscriber<Vec<SpaceServiceRoom>> {
pub fn subscribe_to_room_updates(&self) -> Subscriber<Vec<SpaceRoom>> {
self.rooms.subscribe()
}
pub async fn paginate(&self) -> Result<(), Error> {
match *self.pagination_state.read() {
SpaceServiceRoomListPaginationState::Idle { end_reached } if end_reached => {
SpaceRoomListPaginationState::Idle { end_reached } if end_reached => {
return Ok(());
}
SpaceServiceRoomListPaginationState::Loading => {
SpaceRoomListPaginationState::Loading => {
return Ok(());
}
_ => {}
}
self.pagination_state.set(SpaceServiceRoomListPaginationState::Loading);
self.pagination_state.set(SpaceRoomListPaginationState::Loading);
let mut request = get_hierarchy::v1::Request::new(self.parent_space_id.clone());
request.max_depth = Some(uint!(1)); // We only want the immediate children of the space
@@ -159,7 +157,7 @@ impl SpaceServiceRoomList {
if room.summary.room_id == self.parent_space_id {
None
} else {
Some(SpaceServiceRoom::new_from_summary(
Some(SpaceRoom::new_from_summary(
&room.summary,
self.client.get_room(&room.summary.room_id),
room.children_state.len() as u64,
@@ -171,7 +169,7 @@ impl SpaceServiceRoomList {
self.rooms.set(current_rooms.clone());
self.pagination_state.set(SpaceServiceRoomListPaginationState::Idle {
self.pagination_state.set(SpaceRoomListPaginationState::Idle {
end_reached: result.next_batch.is_none(),
});
@@ -179,7 +177,7 @@ impl SpaceServiceRoomList {
}
Err(err) => {
self.pagination_state
.set(SpaceServiceRoomListPaginationState::Idle { end_reached: false });
.set(SpaceRoomListPaginationState::Idle { end_reached: false });
Err(err.into())
}
}
@@ -198,9 +196,7 @@ mod tests {
};
use stream_assert::{assert_next_eq, assert_next_matches, assert_pending, assert_ready};
use crate::spaces::{
SpaceService, SpaceServiceRoom, room_list::SpaceServiceRoomListPaginationState,
};
use crate::spaces::{SpaceRoom, SpaceService, room_list::SpaceRoomListPaginationState};
#[async_test]
async fn test_room_list_pagination() {
@@ -217,7 +213,7 @@ mod tests {
// Start off idle
assert_matches!(
room_list.pagination_state(),
SpaceServiceRoomListPaginationState::Idle { end_reached: false }
SpaceRoomListPaginationState::Idle { end_reached: false }
);
// without any rooms
@@ -251,14 +247,14 @@ mod tests {
// informs that the pagination reached the end
assert_next_matches!(
pagination_state_subscriber,
SpaceServiceRoomListPaginationState::Idle { end_reached: true }
SpaceRoomListPaginationState::Idle { end_reached: true }
);
// yields results
assert_next_eq!(
rooms_subscriber,
vec![
SpaceServiceRoom::new_from_summary(
SpaceRoom::new_from_summary(
&RoomSummary::new(
child_space_id_1.to_owned(),
JoinRuleSummary::Public,
@@ -269,7 +265,7 @@ mod tests {
None,
1
),
SpaceServiceRoom::new_from_summary(
SpaceRoom::new_from_summary(
&RoomSummary::new(
child_space_id_2.to_owned(),
JoinRuleSummary::Public,