diff --git a/crates/matrix-sdk-base/src/rooms/mod.rs b/crates/matrix-sdk-base/src/rooms/mod.rs index 4d530b73f51..86728c331af 100644 --- a/crates/matrix-sdk-base/src/rooms/mod.rs +++ b/crates/matrix-sdk-base/src/rooms/mod.rs @@ -30,6 +30,7 @@ use ruma::{ join_rules::RoomJoinRulesEventContent, member::MembershipState, name::RoomNameEventContent, + pinned_events::RoomPinnedEventsEventContent, tombstone::RoomTombstoneEventContent, topic::RoomTopicEventContent, }, @@ -117,6 +118,8 @@ pub struct BaseRoomInfo { /// others, and this field collects them. #[serde(skip_serializing_if = "RoomNotableTags::is_empty", default)] pub(crate) notable_tags: RoomNotableTags, + /// The `m.room.pinned_events` of this room. + pub(crate) pinned_events: Option, } impl BaseRoomInfo { @@ -194,6 +197,9 @@ impl BaseRoomInfo { ev.as_original().is_some_and(|o| !o.content.active_memberships(None).is_empty()) }); } + AnySyncStateEvent::RoomPinnedEvents(p) => { + self.pinned_events = p.as_original().map(|p| p.content.clone()); + } _ => return false, } @@ -253,6 +259,11 @@ impl BaseRoomInfo { // wont have call information. return false; } + AnyStrippedStateEvent::RoomPinnedEvents(p) => { + if let Some(pinned) = p.content.pinned.clone() { + self.pinned_events = Some(RoomPinnedEventsEventContent::new(pinned)); + } + } _ => return false, } @@ -349,6 +360,7 @@ impl Default for BaseRoomInfo { rtc_member: BTreeMap::new(), is_marked_unread: false, notable_tags: RoomNotableTags::empty(), + pinned_events: None, } } } diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index 777be9ad83b..35b377aa3a3 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -947,6 +947,11 @@ impl Room { pub fn recency_stamp(&self) -> Option { self.inner.read().recency_stamp } + + /// Get the list of event ids for pinned events in this room. + pub fn pinned_events(&self) -> Vec { + self.inner.get().base_info.pinned_events.map(|content| content.pinned).unwrap_or_default() + } } /// The underlying pure data structure for joined and left rooms. @@ -1615,10 +1620,11 @@ mod tests { SyncRoomMemberEvent, }, name::RoomNameEventContent, + pinned_events::RoomPinnedEventsEventContent, }, AnySyncStateEvent, EmptyStateKey, StateEventType, StateUnsigned, SyncStateEvent, }, - room_alias_id, room_id, + owned_event_id, room_alias_id, room_id, serde::Raw, user_id, EventEncryptionAlgorithm, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId, UserId, @@ -1671,7 +1677,9 @@ mod tests { latest_event: Some(Box::new(LatestEvent::new( Raw::from_json_string(json!({"sender": "@u:i.uk"}).to_string()).unwrap().into(), ))), - base_info: Box::new(BaseRoomInfo::new()), + base_info: Box::new( + assign!(BaseRoomInfo::new(), { pinned_events: Some(RoomPinnedEventsEventContent::new(vec![owned_event_id!("$a")])) }), + ), read_receipts: Default::default(), warned_about_unknown_room_version: Arc::new(false.into()), cached_display_name: None, @@ -1720,6 +1728,9 @@ mod tests { "name": null, "tombstone": null, "topic": null, + "pinned_events": { + "pinned": ["$a"] + }, }, "read_receipts": { "num_unread": 0, diff --git a/crates/matrix-sdk-base/src/sliding_sync/mod.rs b/crates/matrix-sdk-base/src/sliding_sync/mod.rs index 5e327700474..05a9e9a3521 100644 --- a/crates/matrix-sdk-base/src/sliding_sync/mod.rs +++ b/crates/matrix-sdk-base/src/sliding_sync/mod.rs @@ -860,11 +860,12 @@ mod tests { member::{MembershipState, RoomMemberEventContent}, message::SyncRoomMessageEvent, name::RoomNameEventContent, + pinned_events::RoomPinnedEventsEventContent, }, AnySyncMessageLikeEvent, AnySyncTimelineEvent, GlobalAccountDataEventContent, StateEventContent, }, - mxc_uri, owned_mxc_uri, owned_user_id, room_alias_id, room_id, + mxc_uri, owned_event_id, owned_mxc_uri, owned_user_id, room_alias_id, room_id, serde::Raw, uint, user_id, JsOption, MxcUri, OwnedRoomId, OwnedUserId, RoomAliasId, RoomId, UserId, }; @@ -2178,6 +2179,53 @@ mod tests { ); } + #[async_test] + async fn test_pinned_events_are_updated_on_sync() { + let user_a_id = user_id!("@a:e.uk"); + let client = logged_in_base_client(Some(user_a_id)).await; + let room_id = room_id!("!r:e.uk"); + let pinned_event_id = owned_event_id!("$an-id:e.uk"); + + // Create room + let mut room_response = http::response::Room::new(); + set_room_joined(&mut room_response, user_a_id); + let response = response_with_room(room_id, room_response); + client.process_sliding_sync(&response, &(), true).await.expect("Failed to process sync"); + + // The newly created room has no pinned event ids + let room = client.get_room(room_id).unwrap(); + let pinned_event_ids = room.pinned_events(); + assert!(pinned_event_ids.is_empty()); + + // Load new pinned event id + let mut room_response = http::response::Room::new(); + room_response.required_state.push(make_state_event( + user_a_id, + "", + RoomPinnedEventsEventContent::new(vec![pinned_event_id.clone()]), + None, + )); + let response = response_with_room(room_id, room_response); + client.process_sliding_sync(&response, &(), true).await.expect("Failed to process sync"); + + let pinned_event_ids = room.pinned_events(); + assert_eq!(pinned_event_ids.len(), 1); + assert_eq!(pinned_event_ids[0], pinned_event_id); + + // Pinned event ids are now empty + let mut room_response = http::response::Room::new(); + room_response.required_state.push(make_state_event( + user_a_id, + "", + RoomPinnedEventsEventContent::new(Vec::new()), + None, + )); + let response = response_with_room(room_id, room_response); + client.process_sliding_sync(&response, &(), true).await.expect("Failed to process sync"); + let pinned_event_ids = room.pinned_events(); + assert!(pinned_event_ids.is_empty()); + } + async fn choose_event_to_cache(events: &[SyncTimelineEvent]) -> Option { let room = make_room(); let mut room_info = room.clone_info(); diff --git a/crates/matrix-sdk-base/src/store/migration_helpers.rs b/crates/matrix-sdk-base/src/store/migration_helpers.rs index fc2332fd7ca..c621a40763c 100644 --- a/crates/matrix-sdk-base/src/store/migration_helpers.rs +++ b/crates/matrix-sdk-base/src/store/migration_helpers.rs @@ -213,6 +213,7 @@ impl BaseRoomInfoV1 { rtc_member: BTreeMap::new(), is_marked_unread: false, notable_tags: RoomNotableTags::empty(), + pinned_events: None, }) } }