matrix_sdk_base/room/
tags.rs1use bitflags::bitflags;
16use ruma::events::{AnyRoomAccountDataEvent, RoomAccountDataEventType, tag::Tags};
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.info.read().base_info.notable_tags.contains(RoomNotableTags::FAVOURITE)
42 }
43
44 pub fn is_low_priority(&self) -> bool {
49 self.info.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 BaseClient, RoomState, SessionMeta,
86 client::ThreadingSupport,
87 response_processors as processors,
88 store::{RoomLoadSettings, StoreConfig},
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_unchecked();
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
142 processors::changes::save_and_apply(
143 context.clone(),
144 &client.state_store,
145 &client.ignore_user_list_changes,
146 None,
147 )
148 .await
149 .unwrap();
150
151 assert_ready!(room_info_subscriber);
153 assert_pending!(room_info_subscriber);
154
155 assert!(room.is_favourite());
157
158 let tag_raw = Raw::new(&json!({
160 "content": {
161 "tags": {},
162 },
163 "type": "m.tag"
164 }))
165 .unwrap()
166 .cast_unchecked();
167
168 processors::account_data::for_room(&mut context, room_id, &[tag_raw], &client.state_store);
169
170 processors::changes::save_and_apply(
171 context,
172 &client.state_store,
173 &client.ignore_user_list_changes,
174 None,
175 )
176 .await
177 .unwrap();
178
179 assert_ready!(room_info_subscriber);
181 assert_pending!(room_info_subscriber);
182
183 assert!(room.is_favourite().not());
185 }
186
187 #[async_test]
188 async fn test_is_low_priority() {
189 let client = BaseClient::new(
191 StoreConfig::new("cross-process-store-locks-holder-name".to_owned()),
192 ThreadingSupport::Disabled,
193 );
194
195 client
196 .activate(
197 SessionMeta {
198 user_id: user_id!("@alice:example.org").into(),
199 device_id: ruma::device_id!("AYEAYEAYE").into(),
200 },
201 RoomLoadSettings::default(),
202 #[cfg(feature = "e2e-encryption")]
203 None,
204 )
205 .await
206 .unwrap();
207
208 let room_id = room_id!("!test:localhost");
209 let room = client.get_or_create_room(room_id, RoomState::Joined);
210
211 assert!(!room.is_low_priority());
213
214 let mut room_info_subscriber = room.subscribe_info();
216
217 assert_pending!(room_info_subscriber);
218
219 let tag_raw = Raw::new(&json!({
221 "content": {
222 "tags": {
223 "m.lowpriority": {
224 "order": 0.0
225 },
226 }
227 },
228 "type": "m.tag"
229 }))
230 .unwrap()
231 .cast_unchecked();
232
233 let mut context = processors::Context::default();
235
236 processors::account_data::for_room(&mut context, room_id, &[tag_raw], &client.state_store);
237
238 processors::changes::save_and_apply(
239 context.clone(),
240 &client.state_store,
241 &client.ignore_user_list_changes,
242 None,
243 )
244 .await
245 .unwrap();
246
247 assert_ready!(room_info_subscriber);
249 assert_pending!(room_info_subscriber);
250
251 assert!(room.is_low_priority());
253
254 let tag_raw = Raw::new(&json!({
256 "content": {
257 "tags": {},
258 },
259 "type": "m.tag"
260 }))
261 .unwrap()
262 .cast_unchecked();
263
264 processors::account_data::for_room(&mut context, room_id, &[tag_raw], &client.state_store);
265
266 processors::changes::save_and_apply(
267 context,
268 &client.state_store,
269 &client.ignore_user_list_changes,
270 None,
271 )
272 .await
273 .unwrap();
274
275 assert_ready!(room_info_subscriber);
277 assert_pending!(room_info_subscriber);
278
279 assert!(room.is_low_priority().not());
281 }
282
283 #[test]
284 fn test_handle_notable_tags_favourite() {
285 let mut base_room_info = BaseRoomInfo::default();
286
287 let mut tags = Tags::new();
288 tags.insert(TagName::Favorite, TagInfo::default());
289
290 assert!(base_room_info.notable_tags.contains(RoomNotableTags::FAVOURITE).not());
291 base_room_info.handle_notable_tags(&tags);
292 assert!(base_room_info.notable_tags.contains(RoomNotableTags::FAVOURITE));
293 tags.clear();
294 base_room_info.handle_notable_tags(&tags);
295 assert!(base_room_info.notable_tags.contains(RoomNotableTags::FAVOURITE).not());
296 }
297
298 #[test]
299 fn test_handle_notable_tags_low_priority() {
300 let mut base_room_info = BaseRoomInfo::default();
301
302 let mut tags = Tags::new();
303 tags.insert(TagName::LowPriority, TagInfo::default());
304
305 assert!(base_room_info.notable_tags.contains(RoomNotableTags::LOW_PRIORITY).not());
306 base_room_info.handle_notable_tags(&tags);
307 assert!(base_room_info.notable_tags.contains(RoomNotableTags::LOW_PRIORITY));
308 tags.clear();
309 base_room_info.handle_notable_tags(&tags);
310 assert!(base_room_info.notable_tags.contains(RoomNotableTags::LOW_PRIORITY).not());
311 }
312}