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
65 }
66 } else {
67 RoomPinnedEventsChange::Added
70 }
71 }
72 StateEventContentChange::Redacted(_) => RoomPinnedEventsChange::Changed,
73 }
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use assert_matches::assert_matches;
80 use ruma::{
81 events::{
82 StateEventContentChange,
83 room::pinned_events::{
84 RedactedRoomPinnedEventsEventContent, RoomPinnedEventsEventContent,
85 },
86 },
87 owned_event_id,
88 };
89
90 use crate::timeline::event_item::content::pinned_events::RoomPinnedEventsChange;
91
92 #[test]
93 fn redacted_pinned_events_content_has_generic_changes() {
94 let content =
95 StateEventContentChange::Redacted(RedactedRoomPinnedEventsEventContent::new());
96 let ret: RoomPinnedEventsChange = (&content).into();
97 assert_matches!(ret, RoomPinnedEventsChange::Changed);
98 }
99
100 #[test]
101 fn pinned_events_content_with_no_prev_content_returns_added() {
102 let content = StateEventContentChange::Original {
103 content: RoomPinnedEventsEventContent::new(vec![owned_event_id!("$1")]),
104 prev_content: None,
105 };
106 let ret: RoomPinnedEventsChange = (&content).into();
107 assert_matches!(ret, RoomPinnedEventsChange::Added);
108 }
109
110 #[test]
111 fn pinned_events_content_with_added_ids_returns_added() {
112 let content = StateEventContentChange::Original {
113 content: RoomPinnedEventsEventContent::new(vec![owned_event_id!("$1")]),
114 prev_content: Some(RoomPinnedEventsEventContent::new(Vec::new()).into()),
115 };
116 let ret: RoomPinnedEventsChange = (&content).into();
117 assert_matches!(ret, RoomPinnedEventsChange::Added);
118 }
119
120 #[test]
121 fn pinned_events_content_with_removed_ids_returns_removed() {
122 let content = StateEventContentChange::Original {
123 content: RoomPinnedEventsEventContent::new(Vec::new()),
124 prev_content: Some(
125 RoomPinnedEventsEventContent::new(vec![owned_event_id!("$1")]).into(),
126 ),
127 };
128 let ret: RoomPinnedEventsChange = (&content).into();
129 assert_matches!(ret, RoomPinnedEventsChange::Removed);
130 }
131
132 #[test]
133 fn pinned_events_content_with_added_and_removed_ids_returns_changed() {
134 let content = StateEventContentChange::Original {
135 content: RoomPinnedEventsEventContent::new(vec![owned_event_id!("$2")]),
136 prev_content: Some(
137 RoomPinnedEventsEventContent::new(vec![owned_event_id!("$1")]).into(),
138 ),
139 };
140 let ret: RoomPinnedEventsChange = (&content).into();
141 assert_matches!(ret, RoomPinnedEventsChange::Changed);
142 }
143
144 #[test]
145 fn pinned_events_content_with_changed_order_returns_changed() {
146 let content = StateEventContentChange::Original {
147 content: RoomPinnedEventsEventContent::new(vec![
148 owned_event_id!("$2"),
149 owned_event_id!("$1"),
150 ]),
151 prev_content: Some(
152 RoomPinnedEventsEventContent::new(vec![
153 owned_event_id!("$1"),
154 owned_event_id!("$2"),
155 ])
156 .into(),
157 ),
158 };
159 let ret: RoomPinnedEventsChange = (&content).into();
160 assert_matches!(ret, RoomPinnedEventsChange::Changed);
161 }
162
163 #[test]
164 fn pinned_events_content_with_no_changes_returns_changed() {
165 let content = StateEventContentChange::Original {
170 content: RoomPinnedEventsEventContent::new(vec![
171 owned_event_id!("$1"),
172 owned_event_id!("$2"),
173 ]),
174 prev_content: Some(
175 RoomPinnedEventsEventContent::new(vec![
176 owned_event_id!("$1"),
177 owned_event_id!("$2"),
178 ])
179 .into(),
180 ),
181 };
182 let ret: RoomPinnedEventsChange = (&content).into();
183 assert_matches!(ret, RoomPinnedEventsChange::Changed);
184 }
185}