feat(ui,ffi): Implement the all and any filters on FFI.

This patch implements the `all` and `any` filters in `matrix-sdk-ffi`.
The `not` filter cannot be implemented because recursive enum isn't
supported by UniFFI (see https://github.com/mozilla/uniffi-rs/issues/396).
This commit is contained in:
Ivan Enderlin
2024-02-05 14:14:24 +01:00
parent 61d3f8d1d9
commit d699b2fa70
3 changed files with 46 additions and 26 deletions

View File

@@ -13,9 +13,12 @@ use matrix_sdk::{
RoomListEntry as MatrixRoomListEntry,
};
use matrix_sdk_ui::{
room_list_service::filters::{
new_filter_fuzzy_match_room_name, new_filter_non_left, new_filter_none,
new_filter_normalized_match_room_name,
room_list_service::{
filters::{
new_filter_all, new_filter_any, new_filter_fuzzy_match_room_name, new_filter_non_left,
new_filter_none, new_filter_normalized_match_room_name,
},
BoxedFilterFn,
},
timeline::default_event_filter,
};
@@ -391,18 +394,8 @@ impl RoomListDynamicEntriesController {
#[uniffi::export]
impl RoomListDynamicEntriesController {
fn set_filter(&self, kind: RoomListEntriesDynamicFilterKind) -> bool {
use RoomListEntriesDynamicFilterKind as Kind;
match kind {
Kind::NonLeft => self.inner.set_filter(new_filter_non_left(&self.client)),
Kind::None => self.inner.set_filter(new_filter_none()),
Kind::NormalizedMatchRoomName { pattern } => {
self.inner.set_filter(new_filter_normalized_match_room_name(&self.client, &pattern))
}
Kind::FuzzyMatchRoomName { pattern } => {
self.inner.set_filter(new_filter_fuzzy_match_room_name(&self.client, &pattern))
}
}
let FilterWrapper(filter) = FilterWrapper::from(&self.client, kind);
self.inner.set_filter(filter)
}
fn add_one_page(&self) {
@@ -416,12 +409,41 @@ impl RoomListDynamicEntriesController {
#[derive(uniffi::Enum)]
pub enum RoomListEntriesDynamicFilterKind {
All { filters: Vec<RoomListEntriesDynamicFilterKind> },
Any { filters: Vec<RoomListEntriesDynamicFilterKind> },
NonLeft,
None,
NormalizedMatchRoomName { pattern: String },
FuzzyMatchRoomName { pattern: String },
}
/// Custom internal type to transform a `RoomListEntriesDynamicFilterKind` into
/// a `BoxedFilterFn`.
struct FilterWrapper(BoxedFilterFn);
impl FilterWrapper {
fn from(client: &matrix_sdk::Client, value: RoomListEntriesDynamicFilterKind) -> Self {
use RoomListEntriesDynamicFilterKind as Kind;
match value {
Kind::All { filters } => Self(Box::new(new_filter_all(
filters.into_iter().map(|filter| FilterWrapper::from(client, filter).0).collect(),
))),
Kind::Any { filters } => Self(Box::new(new_filter_any(
filters.into_iter().map(|filter| FilterWrapper::from(client, filter).0).collect(),
))),
Kind::NonLeft => Self(Box::new(new_filter_non_left(client))),
Kind::None => Self(Box::new(new_filter_none())),
Kind::NormalizedMatchRoomName { pattern } => {
Self(Box::new(new_filter_normalized_match_room_name(client, &pattern)))
}
Kind::FuzzyMatchRoomName { pattern } => {
Self(Box::new(new_filter_fuzzy_match_room_name(client, &pattern)))
}
}
}
}
#[derive(uniffi::Object)]
pub struct RoomListItem {
inner: Arc<matrix_sdk_ui::room_list_service::Room>,

View File

@@ -26,7 +26,7 @@ use matrix_sdk::{
RoomListEntry, SlidingSync, SlidingSyncList,
};
use super::{Error, State};
use super::{filters::Filter, Error, State};
/// A `RoomList` represents a list of rooms, from a
/// [`RoomListService`](super::RoomListService).
@@ -199,7 +199,8 @@ pub enum RoomListLoadingState {
},
}
type BoxedFilterFn = Box<dyn Fn(&RoomListEntry) -> bool + Send + Sync>;
/// Type alias for a boxed filter function.
pub type BoxedFilterFn = Box<dyn Filter + Send + Sync>;
/// Controller for the [`RoomList`] dynamic entries.
///
@@ -226,17 +227,14 @@ impl RoomListDynamicEntriesController {
///
/// If the associated stream has been dropped, returns `false` to indicate
/// the operation didn't have an effect.
pub fn set_filter(
&self,
filter: impl Fn(&RoomListEntry) -> bool + Send + Sync + 'static,
) -> bool {
pub fn set_filter(&self, filter: BoxedFilterFn) -> bool {
if Arc::strong_count(&self.filter) == 1 {
// there is no other reference to the boxed filter fn, setting it
// would be pointless (no new references can be created from self,
// either)
false
} else {
self.filter.set(Box::new(filter));
self.filter.set(filter);
true
}
}

View File

@@ -1643,7 +1643,7 @@ async fn test_dynamic_entries_stream() -> Result<(), Error> {
assert_pending!(dynamic_entries_stream);
// Now, let's define a filter.
dynamic_entries.set_filter(new_filter_fuzzy_match_room_name(&client, "mat ba"));
dynamic_entries.set_filter(Box::new(new_filter_fuzzy_match_room_name(&client, "mat ba")));
// Assert the dynamic entries.
assert_entries_batch! {
@@ -1799,7 +1799,7 @@ async fn test_dynamic_entries_stream() -> Result<(), Error> {
assert_pending!(dynamic_entries_stream);
// Now, let's change the dynamic entries!
dynamic_entries.set_filter(new_filter_fuzzy_match_room_name(&client, "hell"));
dynamic_entries.set_filter(Box::new(new_filter_fuzzy_match_room_name(&client, "hell")));
// Assert the dynamic entries.
assert_entries_batch! {
@@ -1811,7 +1811,7 @@ async fn test_dynamic_entries_stream() -> Result<(), Error> {
assert_pending!(dynamic_entries_stream);
// Now, let's change again the dynamic filter!
dynamic_entries.set_filter(new_filter_none());
dynamic_entries.set_filter(Box::new(new_filter_none()));
// Assert the dynamic entries.
assert_entries_batch! {
@@ -1822,7 +1822,7 @@ async fn test_dynamic_entries_stream() -> Result<(), Error> {
};
// Now, let's change again the dynamic filter!
dynamic_entries.set_filter(new_filter_non_left(&client));
dynamic_entries.set_filter(Box::new(new_filter_non_left(&client)));
// Assert the dynamic entries.
assert_entries_batch! {