feat(ui): Add the RoomList Input API.

This patch lands the first design of the `Input` API. An `Input` is
something external that can be understood by the `RoomList` state
machine. The first inpuput is `Viewport` to change the “viewport” of the
`RoomList`, which translates to the change of the ranges of one specific
Sliding Sync list.
This commit is contained in:
Ivan Enderlin
2023-06-01 16:52:43 +02:00
parent 13d38993f8
commit 2f68c86796
2 changed files with 106 additions and 2 deletions

View File

@@ -10,7 +10,8 @@ use futures_util::{pin_mut, Stream, StreamExt};
use imbl::Vector;
pub use matrix_sdk::RoomListEntry;
use matrix_sdk::{
Client, Error as SlidingSyncError, SlidingSync, SlidingSyncList, SlidingSyncMode,
sliding_sync::Ranges, Client, Error as SlidingSyncError, SlidingSync, SlidingSyncList,
SlidingSyncMode,
};
use once_cell::sync::Lazy;
use thiserror::Error;
@@ -115,6 +116,25 @@ impl RoomList {
.ok_or_else(|| Error::UnknownList(ALL_ROOMS_LIST_NAME.to_string()))
}
pub async fn apply_input(&self, input: Input) -> Result<(), Error> {
use Input::*;
match input {
Viewport(ranges) => {
self.sliding_sync
.on_list(VISIBLE_ROOMS_LIST_NAME, |list| {
ready(list.set_sync_mode(
SlidingSyncMode::new_selective().add_ranges(ranges.clone()),
))
})
.await
.ok_or_else(|| Error::InputHasNotBeenApplied(Viewport(ranges)))?;
}
}
Ok(())
}
#[cfg(any(test, feature = "testing"))]
pub fn sliding_sync(&self) -> &SlidingSync {
&self.sliding_sync
@@ -136,6 +156,9 @@ pub enum Error {
#[error("Failed to acquire a lock to update the entries filter")]
CannotUpdateEntriesFilter,
#[error("The input has been not applied")]
InputHasNotBeenApplied(Input),
}
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -257,6 +280,11 @@ impl Actions {
}
}
#[derive(Debug)]
pub enum Input {
Viewport(Ranges),
}
#[cfg(test)]
mod tests {
use matrix_sdk::{config::RequestConfig, Session};

View File

@@ -5,7 +5,7 @@ use imbl::vector;
use matrix_sdk_test::async_test;
use matrix_sdk_ui::{
room_list::{
Error, RoomListEntry, State, ALL_ROOMS_LIST_NAME as ALL_ROOMS,
Error, Input, RoomListEntry, State, ALL_ROOMS_LIST_NAME as ALL_ROOMS,
VISIBLE_ROOMS_LIST_NAME as VISIBLE_ROOMS,
},
RoomList,
@@ -724,3 +724,79 @@ async fn test_entries_stream_with_updated_filter() -> Result<(), Error> {
Ok(())
}
#[async_test]
async fn test_input_viewport() -> Result<(), Error> {
let (server, room_list) = new_room_list().await?;
let sync = room_list.sync();
pin_mut!(sync);
// The input cannot be applied because the `VISIBLE_ROOMS_LIST_NAME` list isn't
// present.
assert_matches!(
room_list.apply_input(Input::Viewport(vec![10..=15])).await,
Err(Error::InputHasNotBeenApplied(_))
);
sync_then_assert_request_and_fake_response! {
[server, room_list, sync]
states = Init -> FirstRooms,
assert request = {
"lists": {
ALL_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
"pos": "0",
"lists": {},
"rooms": {},
},
};
sync_then_assert_request_and_fake_response! {
[server, room_list, sync]
states = FirstRooms -> AllRooms,
assert request = {
"lists": {
ALL_ROOMS: {
"ranges": [[0, 49]],
},
VISIBLE_ROOMS: {
"ranges": [],
}
}
},
respond with = {
"pos": "1",
"lists": {},
"rooms": {},
},
};
assert!(room_list.apply_input(Input::Viewport(vec![10..=15, 20..=25])).await.is_ok());
sync_then_assert_request_and_fake_response! {
[server, room_list, sync]
states = AllRooms -> Enjoy,
assert request = {
"lists": {
ALL_ROOMS: {
"ranges": [[0, 49]],
},
VISIBLE_ROOMS: {
"ranges": [[10, 15], [20, 25]],
}
}
},
respond with = {
"pos": "1",
"lists": {},
"rooms": {},
},
};
Ok(())
}