matrix_sdk_ui/timeline/event_item/content/
pinned_events.rs1use std::collections::HashSet;
16
17use ruma::{
18 OwnedEventId,
19 events::{StateEventContentChange, room::pinned_events::RoomPinnedEventsEventContent},
20};
21
22#[derive(Clone, Debug)]
23#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
24pub enum RoomPinnedEventsChange {
26 Added,
28 Removed,
30 Changed,
32}
33
34impl From<&StateEventContentChange<RoomPinnedEventsEventContent>> for RoomPinnedEventsChange {
35 fn from(value: &StateEventContentChange<RoomPinnedEventsEventContent>) -> Self {
36 match value {
37 StateEventContentChange::Original { content, prev_content } => {
38 if let Some(prev_content) = prev_content {
39 let mut new_pinned: HashSet<&OwnedEventId> =
40 HashSet::from_iter(&content.pinned);
41 if let Some(old_pinned) = &prev_content.pinned {
42 let mut still_pinned: HashSet<&OwnedEventId> =
43 HashSet::from_iter(old_pinned);
44
45 still_pinned.retain(|item| new_pinned.remove(item));
48
49 let added = !new_pinned.is_empty();
50 let removed = still_pinned.len() < old_pinned.len();
51 if added && removed {
52 RoomPinnedEventsChange::Changed
53 } else if added {
54 RoomPinnedEventsChange::Added
55 } else if removed {
56 RoomPinnedEventsChange::Removed
57 } else {
58 RoomPinnedEventsChange::Changed
60 }
61 } else {
62 RoomPinnedEventsChange::Changed
64 }
65 } else {
66 RoomPinnedEventsChange::Added
69 }
70 }
71 StateEventContentChange::Redacted(_) => RoomPinnedEventsChange::Changed,
72 }
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use assert_matches::assert_matches;
79 use ruma::{
80 events::{
81 StateEventContentChange,
82 room::pinned_events::{
83 RedactedRoomPinnedEventsEventContent, RoomPinnedEventsEventContent,
84 },
85 },
86 owned_event_id,
87 };
88
89 use crate::timeline::event_item::content::pinned_events::RoomPinnedEventsChange;
90
91 #[test]
92 fn redacted_pinned_events_content_has_generic_changes() {
93 let content =
94 StateEventContentChange::Redacted(RedactedRoomPinnedEventsEventContent::new());
95 let ret: RoomPinnedEventsChange = (&content).into();
96 assert_matches!(ret, RoomPinnedEventsChange::Changed);
97 }
98
99 #[test]
100 fn pinned_events_content_with_no_prev_content_returns_added() {
101 let content = StateEventContentChange::Original {
102 content: RoomPinnedEventsEventContent::new(vec![owned_event_id!("$1")]),
103 prev_content: None,
104 };
105 let ret: RoomPinnedEventsChange = (&content).into();
106 assert_matches!(ret, RoomPinnedEventsChange::Added);
107 }
108
109 #[test]
110 fn pinned_events_content_with_added_ids_returns_added() {
111 let content = StateEventContentChange::Original {
112 content: RoomPinnedEventsEventContent::new(vec![owned_event_id!("$1")]),
113 prev_content: Some(RoomPinnedEventsEventContent::new(Vec::new()).into()),
114 };
115 let ret: RoomPinnedEventsChange = (&content).into();
116 assert_matches!(ret, RoomPinnedEventsChange::Added);
117 }
118
119 #[test]
120 fn pinned_events_content_with_removed_ids_returns_removed() {
121 let content = StateEventContentChange::Original {
122 content: RoomPinnedEventsEventContent::new(Vec::new()),
123 prev_content: Some(
124 RoomPinnedEventsEventContent::new(vec![owned_event_id!("$1")]).into(),
125 ),
126 };
127 let ret: RoomPinnedEventsChange = (&content).into();
128 assert_matches!(ret, RoomPinnedEventsChange::Removed);
129 }
130
131 #[test]
132 fn pinned_events_content_with_added_and_removed_ids_returns_changed() {
133 let content = StateEventContentChange::Original {
134 content: RoomPinnedEventsEventContent::new(vec![owned_event_id!("$2")]),
135 prev_content: Some(
136 RoomPinnedEventsEventContent::new(vec![owned_event_id!("$1")]).into(),
137 ),
138 };
139 let ret: RoomPinnedEventsChange = (&content).into();
140 assert_matches!(ret, RoomPinnedEventsChange::Changed);
141 }
142
143 #[test]
144 fn pinned_events_content_with_changed_order_returns_changed() {
145 let content = StateEventContentChange::Original {
146 content: RoomPinnedEventsEventContent::new(vec![
147 owned_event_id!("$2"),
148 owned_event_id!("$1"),
149 ]),
150 prev_content: Some(
151 RoomPinnedEventsEventContent::new(vec![
152 owned_event_id!("$1"),
153 owned_event_id!("$2"),
154 ])
155 .into(),
156 ),
157 };
158 let ret: RoomPinnedEventsChange = (&content).into();
159 assert_matches!(ret, RoomPinnedEventsChange::Changed);
160 }
161
162 #[test]
163 fn pinned_events_content_with_no_changes_returns_changed() {
164 let content = StateEventContentChange::Original {
168 content: RoomPinnedEventsEventContent::new(vec![
169 owned_event_id!("$1"),
170 owned_event_id!("$2"),
171 ]),
172 prev_content: Some(
173 RoomPinnedEventsEventContent::new(vec![
174 owned_event_id!("$1"),
175 owned_event_id!("$2"),
176 ])
177 .into(),
178 ),
179 };
180 let ret: RoomPinnedEventsChange = (&content).into();
181 assert_matches!(ret, RoomPinnedEventsChange::Changed);
182 }
183}