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 response_processors as processors,
86 store::{RoomLoadSettings, StoreConfig},
87 BaseClient, RoomState, SessionMeta,
88 };
89
90 #[async_test]
91 async fn test_is_favourite() {
92 let client =
94 BaseClient::new(StoreConfig::new("cross-process-store-locks-holder-name".to_owned()));
95
96 client
97 .activate(
98 SessionMeta {
99 user_id: user_id!("@alice:example.org").into(),
100 device_id: ruma::device_id!("AYEAYEAYE").into(),
101 },
102 RoomLoadSettings::default(),
103 #[cfg(feature = "e2e-encryption")]
104 None,
105 )
106 .await
107 .unwrap();
108
109 let room_id = room_id!("!test:localhost");
110 let room = client.get_or_create_room(room_id, RoomState::Joined);
111
112 assert!(room.is_favourite().not());
114
115 let mut room_info_subscriber = room.subscribe_info();
117
118 assert_pending!(room_info_subscriber);
119
120 let tag_raw = Raw::new(&json!({
122 "content": {
123 "tags": {
124 "m.favourite": {
125 "order": 0.0
126 },
127 },
128 },
129 "type": "m.tag",
130 }))
131 .unwrap()
132 .cast();
133
134 let mut context = processors::Context::default();
136
137 processors::account_data::for_room(&mut context, room_id, &[tag_raw], &client.state_store)
138 .await;
139
140 processors::changes::save_and_apply(
141 context.clone(),
142 &client.state_store,
143 &client.ignore_user_list_changes,
144 None,
145 )
146 .await
147 .unwrap();
148
149 assert_ready!(room_info_subscriber);
151 assert_pending!(room_info_subscriber);
152
153 assert!(room.is_favourite());
155
156 let tag_raw = Raw::new(&json!({
158 "content": {
159 "tags": {},
160 },
161 "type": "m.tag"
162 }))
163 .unwrap()
164 .cast();
165
166 processors::account_data::for_room(&mut context, room_id, &[tag_raw], &client.state_store)
167 .await;
168
169 processors::changes::save_and_apply(
170 context,
171 &client.state_store,
172 &client.ignore_user_list_changes,
173 None,
174 )
175 .await
176 .unwrap();
177
178 assert_ready!(room_info_subscriber);
180 assert_pending!(room_info_subscriber);
181
182 assert!(room.is_favourite().not());
184 }
185
186 #[async_test]
187 async fn test_is_low_priority() {
188 let client =
190 BaseClient::new(StoreConfig::new("cross-process-store-locks-holder-name".to_owned()));
191
192 client
193 .activate(
194 SessionMeta {
195 user_id: user_id!("@alice:example.org").into(),
196 device_id: ruma::device_id!("AYEAYEAYE").into(),
197 },
198 RoomLoadSettings::default(),
199 #[cfg(feature = "e2e-encryption")]
200 None,
201 )
202 .await
203 .unwrap();
204
205 let room_id = room_id!("!test:localhost");
206 let room = client.get_or_create_room(room_id, RoomState::Joined);
207
208 assert!(!room.is_low_priority());
210
211 let mut room_info_subscriber = room.subscribe_info();
213
214 assert_pending!(room_info_subscriber);
215
216 let tag_raw = Raw::new(&json!({
218 "content": {
219 "tags": {
220 "m.lowpriority": {
221 "order": 0.0
222 },
223 }
224 },
225 "type": "m.tag"
226 }))
227 .unwrap()
228 .cast();
229
230 let mut context = processors::Context::default();
232
233 processors::account_data::for_room(&mut context, room_id, &[tag_raw], &client.state_store)
234 .await;
235
236 processors::changes::save_and_apply(
237 context.clone(),
238 &client.state_store,
239 &client.ignore_user_list_changes,
240 None,
241 )
242 .await
243 .unwrap();
244
245 assert_ready!(room_info_subscriber);
247 assert_pending!(room_info_subscriber);
248
249 assert!(room.is_low_priority());
251
252 let tag_raw = Raw::new(&json!({
254 "content": {
255 "tags": {},
256 },
257 "type": "m.tag"
258 }))
259 .unwrap()
260 .cast();
261
262 processors::account_data::for_room(&mut context, room_id, &[tag_raw], &client.state_store)
263 .await;
264
265 processors::changes::save_and_apply(
266 context,
267 &client.state_store,
268 &client.ignore_user_list_changes,
269 None,
270 )
271 .await
272 .unwrap();
273
274 assert_ready!(room_info_subscriber);
276 assert_pending!(room_info_subscriber);
277
278 assert!(room.is_low_priority().not());
280 }
281
282 #[test]
283 fn test_handle_notable_tags_favourite() {
284 let mut base_room_info = BaseRoomInfo::default();
285
286 let mut tags = Tags::new();
287 tags.insert(TagName::Favorite, TagInfo::default());
288
289 assert!(base_room_info.notable_tags.contains(RoomNotableTags::FAVOURITE).not());
290 base_room_info.handle_notable_tags(&tags);
291 assert!(base_room_info.notable_tags.contains(RoomNotableTags::FAVOURITE));
292 tags.clear();
293 base_room_info.handle_notable_tags(&tags);
294 assert!(base_room_info.notable_tags.contains(RoomNotableTags::FAVOURITE).not());
295 }
296
297 #[test]
298 fn test_handle_notable_tags_low_priority() {
299 let mut base_room_info = BaseRoomInfo::default();
300
301 let mut tags = Tags::new();
302 tags.insert(TagName::LowPriority, TagInfo::default());
303
304 assert!(base_room_info.notable_tags.contains(RoomNotableTags::LOW_PRIORITY).not());
305 base_room_info.handle_notable_tags(&tags);
306 assert!(base_room_info.notable_tags.contains(RoomNotableTags::LOW_PRIORITY));
307 tags.clear();
308 base_room_info.handle_notable_tags(&tags);
309 assert!(base_room_info.notable_tags.contains(RoomNotableTags::LOW_PRIORITY).not());
310 }
311}