matrix_sdk_base/room/
tags.rs1use bitflags::bitflags;
16use ruma::events::{tag::Tags, AnyRoomAccountDataEvent, RoomAccountDataEventType};
17use serde::{Deserialize, Serialize};
18
19use super::Room;
20use crate::store::Result as StoreResult;
21
22impl Room {
23 pub async fn tags(&self) -> StoreResult<Option<Tags>> {
25 if let Some(AnyRoomAccountDataEvent::Tag(event)) = self
26 .store
27 .get_room_account_data_event(self.room_id(), RoomAccountDataEventType::Tag)
28 .await?
29 .and_then(|raw| raw.deserialize().ok())
30 {
31 Ok(Some(event.content.tags))
32 } else {
33 Ok(None)
34 }
35 }
36
37 pub fn is_favourite(&self) -> bool {
41 self.inner.read().base_info.notable_tags.contains(RoomNotableTags::FAVOURITE)
42 }
43
44 pub fn is_low_priority(&self) -> bool {
49 self.inner.read().base_info.notable_tags.contains(RoomNotableTags::LOW_PRIORITY)
50 }
51}
52
53bitflags! {
54 #[repr(transparent)]
59 #[derive(Debug, Default, Clone, Copy, Deserialize, Serialize)]
60 pub(crate) struct RoomNotableTags: u8 {
61 const FAVOURITE = 0b0000_0001;
63
64 const LOW_PRIORITY = 0b0000_0010;
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use std::ops::Not;
72
73 use matrix_sdk_test::async_test;
74 use ruma::{
75 events::tag::{TagInfo, TagName, Tags},
76 room_id,
77 serde::Raw,
78 user_id,
79 };
80 use serde_json::json;
81 use stream_assert::{assert_pending, assert_ready};
82
83 use super::{super::BaseRoomInfo, RoomNotableTags};
84 use crate::{
85 client::ThreadingSupport,
86 response_processors as processors,
87 store::{RoomLoadSettings, StoreConfig},
88 BaseClient, RoomState, SessionMeta,
89 };
90
91 #[async_test]
92 async fn test_is_favourite() {
93 let client = BaseClient::new(
95 StoreConfig::new("cross-process-store-locks-holder-name".to_owned()),
96 ThreadingSupport::Disabled,
97 );
98
99 client
100 .activate(
101 SessionMeta {
102 user_id: user_id!("@alice:example.org").into(),
103 device_id: ruma::device_id!("AYEAYEAYE").into(),
104 },
105 RoomLoadSettings::default(),
106 #[cfg(feature = "e2e-encryption")]
107 None,
108 )
109 .await
110 .unwrap();
111
112 let room_id = room_id!("!test:localhost");
113 let room = client.get_or_create_room(room_id, RoomState::Joined);
114
115 assert!(room.is_favourite().not());
117
118 let mut room_info_subscriber = room.subscribe_info();
120
121 assert_pending!(room_info_subscriber);
122
123 let tag_raw = Raw::new(&json!({
125 "content": {
126 "tags": {
127 "m.favourite": {
128 "order": 0.0
129 },
130 },
131 },
132 "type": "m.tag",
133 }))
134 .unwrap()
135 .cast();
136
137 let mut context = processors::Context::default();
139
140 processors::account_data::for_room(&mut context, room_id, &[tag_raw], &client.state_store)
141 .await;
142
143 processors::changes::save_and_apply(
144 context.clone(),
145 &client.state_store,
146 &client.ignore_user_list_changes,
147 None,
148 )
149 .await
150 .unwrap();
151
152 assert_ready!(room_info_subscriber);
154 assert_pending!(room_info_subscriber);
155
156 assert!(room.is_favourite());
158
159 let tag_raw = Raw::new(&json!({
161 "content": {
162 "tags": {},
163 },
164 "type": "m.tag"
165 }))
166 .unwrap()
167 .cast();
168
169 processors::account_data::for_room(&mut context, room_id, &[tag_raw], &client.state_store)
170 .await;
171
172 processors::changes::save_and_apply(
173 context,
174 &client.state_store,
175 &client.ignore_user_list_changes,
176 None,
177 )
178 .await
179 .unwrap();
180
181 assert_ready!(room_info_subscriber);
183 assert_pending!(room_info_subscriber);
184
185 assert!(room.is_favourite().not());
187 }
188
189 #[async_test]
190 async fn test_is_low_priority() {
191 let client = BaseClient::new(
193 StoreConfig::new("cross-process-store-locks-holder-name".to_owned()),
194 ThreadingSupport::Disabled,
195 );
196
197 client
198 .activate(
199 SessionMeta {
200 user_id: user_id!("@alice:example.org").into(),
201 device_id: ruma::device_id!("AYEAYEAYE").into(),
202 },
203 RoomLoadSettings::default(),
204 #[cfg(feature = "e2e-encryption")]
205 None,
206 )
207 .await
208 .unwrap();
209
210 let room_id = room_id!("!test:localhost");
211 let room = client.get_or_create_room(room_id, RoomState::Joined);
212
213 assert!(!room.is_low_priority());
215
216 let mut room_info_subscriber = room.subscribe_info();
218
219 assert_pending!(room_info_subscriber);
220
221 let tag_raw = Raw::new(&json!({
223 "content": {
224 "tags": {
225 "m.lowpriority": {
226 "order": 0.0
227 },
228 }
229 },
230 "type": "m.tag"
231 }))
232 .unwrap()
233 .cast();
234
235 let mut context = processors::Context::default();
237
238 processors::account_data::for_room(&mut context, room_id, &[tag_raw], &client.state_store)
239 .await;
240
241 processors::changes::save_and_apply(
242 context.clone(),
243 &client.state_store,
244 &client.ignore_user_list_changes,
245 None,
246 )
247 .await
248 .unwrap();
249
250 assert_ready!(room_info_subscriber);
252 assert_pending!(room_info_subscriber);
253
254 assert!(room.is_low_priority());
256
257 let tag_raw = Raw::new(&json!({
259 "content": {
260 "tags": {},
261 },
262 "type": "m.tag"
263 }))
264 .unwrap()
265 .cast();
266
267 processors::account_data::for_room(&mut context, room_id, &[tag_raw], &client.state_store)
268 .await;
269
270 processors::changes::save_and_apply(
271 context,
272 &client.state_store,
273 &client.ignore_user_list_changes,
274 None,
275 )
276 .await
277 .unwrap();
278
279 assert_ready!(room_info_subscriber);
281 assert_pending!(room_info_subscriber);
282
283 assert!(room.is_low_priority().not());
285 }
286
287 #[test]
288 fn test_handle_notable_tags_favourite() {
289 let mut base_room_info = BaseRoomInfo::default();
290
291 let mut tags = Tags::new();
292 tags.insert(TagName::Favorite, TagInfo::default());
293
294 assert!(base_room_info.notable_tags.contains(RoomNotableTags::FAVOURITE).not());
295 base_room_info.handle_notable_tags(&tags);
296 assert!(base_room_info.notable_tags.contains(RoomNotableTags::FAVOURITE));
297 tags.clear();
298 base_room_info.handle_notable_tags(&tags);
299 assert!(base_room_info.notable_tags.contains(RoomNotableTags::FAVOURITE).not());
300 }
301
302 #[test]
303 fn test_handle_notable_tags_low_priority() {
304 let mut base_room_info = BaseRoomInfo::default();
305
306 let mut tags = Tags::new();
307 tags.insert(TagName::LowPriority, TagInfo::default());
308
309 assert!(base_room_info.notable_tags.contains(RoomNotableTags::LOW_PRIORITY).not());
310 base_room_info.handle_notable_tags(&tags);
311 assert!(base_room_info.notable_tags.contains(RoomNotableTags::LOW_PRIORITY));
312 tags.clear();
313 base_room_info.handle_notable_tags(&tags);
314 assert!(base_room_info.notable_tags.contains(RoomNotableTags::LOW_PRIORITY).not());
315 }
316}