diff --git a/bindings/matrix-sdk-ffi/src/room.rs b/bindings/matrix-sdk-ffi/src/room.rs index 82d1aca5f04..01d8715489b 100644 --- a/bindings/matrix-sdk-ffi/src/room.rs +++ b/bindings/matrix-sdk-ffi/src/room.rs @@ -228,6 +228,25 @@ impl Room { Ok(Timeline::new(timeline)) } + pub async fn pinned_events_timeline( + &self, + internal_id_prefix: Option, + max_events_to_load: u16, + ) -> Result, ClientError> { + let room = &self.inner; + + let mut builder = matrix_sdk_ui::timeline::Timeline::builder(room); + + if let Some(internal_id_prefix) = internal_id_prefix { + builder = builder.with_internal_id_prefix(internal_id_prefix); + } + + let timeline = + builder.with_focus(TimelineFocus::PinnedEvents { max_events_to_load }).build().await?; + + Ok(Timeline::new(timeline)) + } + pub fn is_encrypted(&self) -> Result { Ok(RUNTIME.block_on(self.inner.is_encrypted())?) } diff --git a/bindings/matrix-sdk-ffi/src/room_info.rs b/bindings/matrix-sdk-ffi/src/room_info.rs index 1dad22af707..b8fb47b7c32 100644 --- a/bindings/matrix-sdk-ffi/src/room_info.rs +++ b/bindings/matrix-sdk-ffi/src/room_info.rs @@ -66,7 +66,7 @@ impl RoomInfo { for (id, level) in power_levels_map.iter() { user_power_levels.insert(id.to_string(), *level); } - let pinned_event_ids = room.pinned_events().iter().map(|id| id.to_string()).collect(); + let pinned_event_ids = room.pinned_event_ids().iter().map(|id| id.to_string()).collect(); Ok(Self { id: room.room_id().to_string(), diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index ca8c59a2142..581d8dacae9 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -949,11 +949,6 @@ impl Room { self.inner.read().recency_stamp } - /// Get the list of event ids for pinned events in this room. - pub fn pinned_event_ids(&self) -> Vec { - self.inner.get().base_info.pinned_events.map(|content| content.pinned).unwrap_or_default() - } - /// Get a `Stream` of loaded pinned events for this room. /// If no pinned events are found a single empty `Vec` will be returned. pub fn pinned_event_ids_stream(&self) -> impl Stream> { @@ -962,19 +957,9 @@ impl Room { .map(|i| i.base_info.pinned_events.map(|c| c.pinned).unwrap_or_default()) } - /// Checks if an `EventId` is currently pinned. - /// It avoids having to clone the whole list of event ids to check a single - /// value. - /// - /// Returns `true` if the provided `event_id` is pinned, `false` otherwise. - pub fn is_pinned_event(&self, event_id: &EventId) -> bool { - self.inner - .read() - .base_info - .pinned_events - .as_ref() - .map(|p| p.pinned.contains(&event_id.to_owned())) - .unwrap_or_default() + /// Returns the current pinned event ids for this room. + pub fn pinned_event_ids(&self) -> Vec { + self.inner.read().pinned_event_ids() } } @@ -1495,6 +1480,24 @@ impl RoomInfo { pub(crate) fn update_recency_stamp(&mut self, stamp: u64) { self.recency_stamp = Some(stamp); } + + /// Returns the current pinned event ids for this room. + pub fn pinned_event_ids(&self) -> Vec { + self.base_info.pinned_events.clone().map(|c| c.pinned).unwrap_or_default() + } + + /// Checks if an `EventId` is currently pinned. + /// It avoids having to clone the whole list of event ids to check a single + /// value. + /// + /// Returns `true` if the provided `event_id` is pinned, `false` otherwise. + pub fn is_pinned_event(&self, event_id: &EventId) -> bool { + self.base_info + .pinned_events + .as_ref() + .map(|p| p.pinned.contains(&event_id.to_owned())) + .unwrap_or_default() + } } #[cfg(feature = "experimental-sliding-sync")] diff --git a/crates/matrix-sdk-ui/src/timeline/builder.rs b/crates/matrix-sdk-ui/src/timeline/builder.rs index 21e358cb906..6ef391450f2 100644 --- a/crates/matrix-sdk-ui/src/timeline/builder.rs +++ b/crates/matrix-sdk-ui/src/timeline/builder.rs @@ -176,12 +176,12 @@ impl TimelineBuilder { let room = inner.room(); let client = room.client(); - let mut pinned_event_ids_stream = room.pinned_event_ids_stream(); let pinned_events_join_handle = if is_pinned_events { + let mut pinned_event_ids_stream = room.pinned_event_ids_stream(); Some(spawn({ let inner = inner.clone(); async move { - while let Some(_) = pinned_event_ids_stream.next().await { + while pinned_event_ids_stream.next().await.is_some() { if let Ok(events) = inner.pinned_events_load_events().await { inner .replace_with_initial_remote_events( @@ -263,24 +263,21 @@ impl TimelineBuilder { RoomEventCacheUpdate::AddTimelineEvents { events, origin } => { trace!("Received new timeline events."); - // Special case for pinned events: when we receive new events what we'll do is - // updated the cache for those events that are pinned and reload the - // list. - match &*focus.clone() { - TimelineFocus::PinnedEvents { .. } => { - if let Ok(events) = inner.pinned_events_load_events().await { - inner.replace_with_initial_remote_events(events, RemoteEventOrigin::Sync).await; - } - } - _ => { - inner.add_events_at( - events, - TimelineEnd::Back, - match origin { - EventsOrigin::Sync => RemoteEventOrigin::Sync, - } - ).await; + // Special case for pinned events: when we receive new events what we'll do is, instead of adding the + // events, update the pinned events cache with them, reload the list of pinned event ids and reload + // the list of pinned events with this info. + if let TimelineFocus::PinnedEvents { .. } = &*focus.clone() { + if let Ok(events) = inner.pinned_events_load_events().await { + inner.replace_with_initial_remote_events(events, RemoteEventOrigin::Sync).await; } + } else { + inner.add_events_at( + events, + TimelineEnd::Back, + match origin { + EventsOrigin::Sync => RemoteEventOrigin::Sync, + } + ).await; } } diff --git a/crates/matrix-sdk-ui/src/timeline/event_handler.rs b/crates/matrix-sdk-ui/src/timeline/event_handler.rs index 1be9f1d912a..9a03b1a02ff 100644 --- a/crates/matrix-sdk-ui/src/timeline/event_handler.rs +++ b/crates/matrix-sdk-ui/src/timeline/event_handler.rs @@ -348,7 +348,7 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> { // events in an event-focused timeline. let can_add_to_live = match self.live_timeline_updates_type { LiveTimelineUpdatesAllowed::PinnedEvents => { - room_data_provider.room_is_pinned_event_id(event_id) + room_data_provider.is_pinned_event(event_id) } LiveTimelineUpdatesAllowed::All => true, LiveTimelineUpdatesAllowed::None => false, diff --git a/crates/matrix-sdk-ui/src/timeline/mod.rs b/crates/matrix-sdk-ui/src/timeline/mod.rs index f88fac04c54..e26f8308272 100644 --- a/crates/matrix-sdk-ui/src/timeline/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/mod.rs @@ -63,6 +63,8 @@ use ruma::{ use thiserror::Error; use tracing::{error, instrument, trace, warn}; +use crate::timeline::pinned_events_loader::PinnedEventsRoom; + mod builder; mod day_dividers; mod error; diff --git a/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs b/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs index 03726a67465..2d9156d4a04 100644 --- a/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs +++ b/crates/matrix-sdk-ui/src/timeline/pinned_events_loader.rs @@ -39,7 +39,7 @@ impl PinnedEventsLoader { pub async fn load_events(&self) -> Result, PinnedEventsLoaderError> { let pinned_event_ids: Vec = self .room - .room_pinned_event_ids() + .pinned_event_ids() .into_iter() .rev() .take(self.max_events_to_load) @@ -71,7 +71,7 @@ impl PinnedEventsLoader { .await .map_err(|_| PinnedEventsLoaderError::SemaphoreNotAcquired)?; let ret = provider - .room_event(&id) + .event(&id) .await .map_err(|_| PinnedEventsLoaderError::EventNotFound(id.to_owned())); drop(permit); @@ -118,7 +118,7 @@ impl PinnedEventsLoader { for ev in events { let ev = ev.into(); if let Some(ev_id) = ev.event_id() { - if self.room.room_is_pinned_event_id(&ev_id) { + if self.room.is_pinned_event(&ev_id) { to_update.push(ev); } } @@ -137,31 +137,34 @@ impl PinnedEventsLoader { #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] pub trait PinnedEventsRoom: SendOutsideWasm + SyncOutsideWasm { /// Load a single room event. - async fn room_event(&self, event_id: &EventId) -> Result; + async fn event(&self, event_id: &EventId) -> Result; /// Get the pinned event ids for a room. - fn room_pinned_event_ids(&self) -> Vec; + fn pinned_event_ids(&self) -> Vec; /// Checks whether an event id is pinned in this room. - fn room_is_pinned_event_id(&self, event_id: &EventId) -> bool; + /// + /// It avoids having to clone the whole list of event ids to check a single + /// value. + fn is_pinned_event(&self, event_id: &EventId) -> bool; } #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl PinnedEventsRoom for Room { - async fn room_event(&self, event_id: &EventId) -> Result { + async fn event(&self, event_id: &EventId) -> Result { self.event(event_id) .await .map(|e| e.into()) .map_err(|err| PaginatorError::SdkError(Box::new(err))) } - fn room_pinned_event_ids(&self) -> Vec { - self.pinned_event_ids() + fn pinned_event_ids(&self) -> Vec { + self.clone_info().pinned_event_ids() } - fn room_is_pinned_event_id(&self, event_id: &EventId) -> bool { - self.is_pinned_event(event_id) + fn is_pinned_event(&self, event_id: &EventId) -> bool { + self.subscribe_info().read().is_pinned_event(event_id) } } diff --git a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs index 30e9f9a1857..1df4040e0aa 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs @@ -321,15 +321,15 @@ impl PaginableRoom for TestRoomDataProvider { #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl PinnedEventsRoom for TestRoomDataProvider { - async fn room_event(&self, _event_id: &EventId) -> Result { + async fn event(&self, _event_id: &EventId) -> Result { unimplemented!(); } - fn room_pinned_event_ids(&self) -> Vec { + fn pinned_event_ids(&self) -> Vec { unimplemented!(); } - fn room_is_pinned_event_id(&self, _event_id: &EventId) -> bool { + fn is_pinned_event(&self, _event_id: &EventId) -> bool { unimplemented!(); } } diff --git a/crates/matrix-sdk-ui/tests/integration/timeline/pinned_event.rs b/crates/matrix-sdk-ui/tests/integration/timeline/pinned_event.rs index 95d9b3b3687..90f7a98ffda 100644 --- a/crates/matrix-sdk-ui/tests/integration/timeline/pinned_event.rs +++ b/crates/matrix-sdk-ui/tests/integration/timeline/pinned_event.rs @@ -75,7 +75,6 @@ async fn test_new_pinned_events_are_added_on_sync() { assert_matches!(timeline_stream.next().await.unwrap(), VectorDiff::PushFront { value } => { assert!(value.is_day_divider()); }); - assert_pending!(timeline_stream); test_helper.server.reset().await; }