From 2f68c86796b9211ad9d950f09a448a8ef6b726ec Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 1 Jun 2023 16:52:43 +0200 Subject: [PATCH] feat(ui): Add the `RoomList` `Input` API. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- crates/matrix-sdk-ui/src/room_list/mod.rs | 30 ++++++- .../tests/integration/room_list.rs | 78 ++++++++++++++++++- 2 files changed, 106 insertions(+), 2 deletions(-) diff --git a/crates/matrix-sdk-ui/src/room_list/mod.rs b/crates/matrix-sdk-ui/src/room_list/mod.rs index 48fd38b6a..1d03f4285 100644 --- a/crates/matrix-sdk-ui/src/room_list/mod.rs +++ b/crates/matrix-sdk-ui/src/room_list/mod.rs @@ -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}; diff --git a/crates/matrix-sdk-ui/tests/integration/room_list.rs b/crates/matrix-sdk-ui/tests/integration/room_list.rs index 4e0e6753a..6a4ef442d 100644 --- a/crates/matrix-sdk-ui/tests/integration/room_list.rs +++ b/crates/matrix-sdk-ui/tests/integration/room_list.rs @@ -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(()) +}