1use std::sync::{Arc, RwLock};
2
3use matrix_sdk::{
4 event_handler::EventHandlerHandle,
5 notification_settings::{
6 NotificationSettings as SdkNotificationSettings,
7 RoomNotificationMode as SdkRoomNotificationMode,
8 },
9 ruma::events::push_rules::PushRulesEvent,
10 Client as MatrixClient,
11};
12use ruma::{
13 push::{PredefinedOverrideRuleId, PredefinedUnderrideRuleId, RuleKind},
14 RoomId,
15};
16use tokio::sync::RwLock as AsyncRwLock;
17
18use crate::error::NotificationSettingsError;
19
20#[derive(Clone, uniffi::Enum)]
22pub enum RoomNotificationMode {
23 AllMessages,
25 MentionsAndKeywordsOnly,
27 Mute,
29}
30
31impl From<SdkRoomNotificationMode> for RoomNotificationMode {
32 fn from(value: SdkRoomNotificationMode) -> Self {
33 match value {
34 SdkRoomNotificationMode::AllMessages => Self::AllMessages,
35 SdkRoomNotificationMode::MentionsAndKeywordsOnly => Self::MentionsAndKeywordsOnly,
36 SdkRoomNotificationMode::Mute => Self::Mute,
37 }
38 }
39}
40
41impl From<RoomNotificationMode> for SdkRoomNotificationMode {
42 fn from(value: RoomNotificationMode) -> Self {
43 match value {
44 RoomNotificationMode::AllMessages => Self::AllMessages,
45 RoomNotificationMode::MentionsAndKeywordsOnly => Self::MentionsAndKeywordsOnly,
46 RoomNotificationMode::Mute => Self::Mute,
47 }
48 }
49}
50
51#[matrix_sdk_ffi_macros::export(callback_interface)]
53pub trait NotificationSettingsDelegate: Sync + Send {
54 fn settings_did_change(&self);
55}
56
57#[derive(Clone, uniffi::Record)]
59pub struct RoomNotificationSettings {
60 mode: RoomNotificationMode,
62 is_default: bool,
64}
65
66impl RoomNotificationSettings {
67 fn new(mode: RoomNotificationMode, is_default: bool) -> Self {
68 RoomNotificationSettings { mode, is_default }
69 }
70}
71
72#[derive(Clone, uniffi::Object)]
73pub struct NotificationSettings {
74 sdk_client: MatrixClient,
75 sdk_notification_settings: Arc<AsyncRwLock<SdkNotificationSettings>>,
76 pushrules_event_handler: Arc<RwLock<Option<EventHandlerHandle>>>,
77}
78
79impl NotificationSettings {
80 pub(crate) fn new(
81 sdk_client: MatrixClient,
82 sdk_notification_settings: SdkNotificationSettings,
83 ) -> Self {
84 Self {
85 sdk_client,
86 sdk_notification_settings: Arc::new(AsyncRwLock::new(sdk_notification_settings)),
87 pushrules_event_handler: Arc::new(RwLock::new(None)),
88 }
89 }
90}
91
92impl Drop for NotificationSettings {
93 fn drop(&mut self) {
94 if let Some(event_handler) = self.pushrules_event_handler.read().unwrap().as_ref() {
96 self.sdk_client.remove_event_handler(event_handler.clone());
97 }
98 }
99}
100
101#[matrix_sdk_ffi_macros::export]
102impl NotificationSettings {
103 pub fn set_delegate(&self, delegate: Option<Box<dyn NotificationSettingsDelegate>>) {
104 if let Some(delegate) = delegate {
105 let delegate: Arc<dyn NotificationSettingsDelegate> = Arc::from(delegate);
106
107 let event_handler =
109 self.sdk_client.add_event_handler(move |_: PushRulesEvent| async move {
110 delegate.settings_did_change();
111 });
112
113 *self.pushrules_event_handler.write().unwrap() = Some(event_handler);
114 } else {
115 let event_handler = &mut *self.pushrules_event_handler.write().unwrap();
117 if let Some(event_handler) = event_handler {
118 self.sdk_client.remove_event_handler(event_handler.clone());
119 }
120 *event_handler = None;
121 }
122 }
123
124 pub async fn get_room_notification_settings(
133 &self,
134 room_id: String,
135 is_encrypted: bool,
136 is_one_to_one: bool,
137 ) -> Result<RoomNotificationSettings, NotificationSettingsError> {
138 let parsed_room_id = RoomId::parse(&room_id)
139 .map_err(|_e| NotificationSettingsError::InvalidRoomId { room_id })?;
140
141 let notification_settings = self.sdk_notification_settings.read().await;
142
143 if let Some(mode) =
145 notification_settings.get_user_defined_room_notification_mode(&parsed_room_id).await
146 {
147 return Ok(RoomNotificationSettings::new(mode.into(), false));
148 }
149
150 let mode = notification_settings
153 .get_default_room_notification_mode(is_encrypted.into(), is_one_to_one.into())
154 .await;
155
156 Ok(RoomNotificationSettings::new(mode.into(), true))
157 }
158
159 pub async fn set_room_notification_mode(
161 &self,
162 room_id: String,
163 mode: RoomNotificationMode,
164 ) -> Result<(), NotificationSettingsError> {
165 let parsed_room_id = RoomId::parse(&room_id)
166 .map_err(|_e| NotificationSettingsError::InvalidRoomId { room_id })?;
167
168 self.sdk_notification_settings
169 .read()
170 .await
171 .set_room_notification_mode(&parsed_room_id, mode.into())
172 .await?;
173
174 Ok(())
175 }
176
177 pub async fn get_user_defined_room_notification_mode(
179 &self,
180 room_id: String,
181 ) -> Result<Option<RoomNotificationMode>, NotificationSettingsError> {
182 let notification_settings = self.sdk_notification_settings.read().await;
183 let parsed_room_id = RoomId::parse(&room_id)
184 .map_err(|_e| NotificationSettingsError::InvalidRoomId { room_id })?;
185 if let Some(mode) =
187 notification_settings.get_user_defined_room_notification_mode(&parsed_room_id).await
188 {
189 Ok(Some(mode.into()))
190 } else {
191 Ok(None)
192 }
193 }
194
195 pub async fn get_default_room_notification_mode(
206 &self,
207 is_encrypted: bool,
208 is_one_to_one: bool,
209 ) -> RoomNotificationMode {
210 let notification_settings = self.sdk_notification_settings.read().await;
211 let mode = notification_settings
212 .get_default_room_notification_mode(is_encrypted.into(), is_one_to_one.into())
213 .await;
214 mode.into()
215 }
216
217 pub async fn set_default_room_notification_mode(
226 &self,
227 is_encrypted: bool,
228 is_one_to_one: bool,
229 mode: RoomNotificationMode,
230 ) -> Result<(), NotificationSettingsError> {
231 let notification_settings = self.sdk_notification_settings.read().await;
232 notification_settings
233 .set_default_room_notification_mode(
234 is_encrypted.into(),
235 is_one_to_one.into(),
236 mode.into(),
237 )
238 .await?;
239 Ok(())
240 }
241
242 pub async fn restore_default_room_notification_mode(
244 &self,
245 room_id: String,
246 ) -> Result<(), NotificationSettingsError> {
247 let notification_settings = self.sdk_notification_settings.read().await;
248 let parsed_room_id = RoomId::parse(&room_id)
249 .map_err(|_e| NotificationSettingsError::InvalidRoomId { room_id })?;
250 notification_settings.delete_user_defined_room_rules(&parsed_room_id).await?;
251 Ok(())
252 }
253
254 pub async fn get_rooms_with_user_defined_rules(&self, enabled: Option<bool>) -> Vec<String> {
256 let notification_settings = self.sdk_notification_settings.read().await;
257 notification_settings.get_rooms_with_user_defined_rules(enabled).await
258 }
259
260 pub async fn contains_keywords_rules(&self) -> bool {
262 let notification_settings = self.sdk_notification_settings.read().await;
263 notification_settings.contains_keyword_rules().await
264 }
265
266 pub async fn is_room_mention_enabled(&self) -> Result<bool, NotificationSettingsError> {
268 let notification_settings = self.sdk_notification_settings.read().await;
269 let enabled = notification_settings
270 .is_push_rule_enabled(RuleKind::Override, PredefinedOverrideRuleId::IsRoomMention)
271 .await?;
272 Ok(enabled)
273 }
274
275 pub async fn set_room_mention_enabled(
277 &self,
278 enabled: bool,
279 ) -> Result<(), NotificationSettingsError> {
280 let notification_settings = self.sdk_notification_settings.read().await;
281 notification_settings
282 .set_push_rule_enabled(
283 RuleKind::Override,
284 PredefinedOverrideRuleId::IsRoomMention,
285 enabled,
286 )
287 .await?;
288 Ok(())
289 }
290
291 pub async fn is_user_mention_enabled(&self) -> Result<bool, NotificationSettingsError> {
293 let notification_settings = self.sdk_notification_settings.read().await;
294 let enabled = notification_settings
295 .is_push_rule_enabled(RuleKind::Override, PredefinedOverrideRuleId::IsUserMention)
296 .await?;
297 Ok(enabled)
298 }
299
300 pub async fn can_push_encrypted_event_to_device(&self) -> bool {
304 let notification_settings = self.sdk_notification_settings.read().await;
305 if let Ok(enabled) = notification_settings
307 .is_push_rule_enabled(RuleKind::Override, ".m.rule.encrypted_event")
308 .await
309 {
310 enabled
311 } else {
312 notification_settings
314 .is_push_rule_enabled(RuleKind::Override, ".org.matrix.msc4028.encrypted_event")
315 .await
316 .unwrap_or(false)
317 }
318 }
319
320 pub async fn can_homeserver_push_encrypted_event_to_device(&self) -> bool {
324 self.sdk_client.can_homeserver_push_encrypted_event_to_device().await.unwrap()
325 }
326
327 pub async fn set_user_mention_enabled(
329 &self,
330 enabled: bool,
331 ) -> Result<(), NotificationSettingsError> {
332 let notification_settings = self.sdk_notification_settings.read().await;
333 notification_settings
334 .set_push_rule_enabled(
335 RuleKind::Override,
336 PredefinedOverrideRuleId::IsUserMention,
337 enabled,
338 )
339 .await?;
340 Ok(())
341 }
342
343 pub async fn is_call_enabled(&self) -> Result<bool, NotificationSettingsError> {
345 let notification_settings = self.sdk_notification_settings.read().await;
346 let enabled = notification_settings
347 .is_push_rule_enabled(RuleKind::Underride, PredefinedUnderrideRuleId::Call)
348 .await?;
349 Ok(enabled)
350 }
351
352 pub async fn set_call_enabled(&self, enabled: bool) -> Result<(), NotificationSettingsError> {
354 let notification_settings = self.sdk_notification_settings.read().await;
355 notification_settings
356 .set_push_rule_enabled(RuleKind::Underride, PredefinedUnderrideRuleId::Call, enabled)
357 .await?;
358 Ok(())
359 }
360
361 pub async fn is_invite_for_me_enabled(&self) -> Result<bool, NotificationSettingsError> {
363 let notification_settings = self.sdk_notification_settings.read().await;
364 let enabled = notification_settings
365 .is_push_rule_enabled(
366 RuleKind::Override,
367 PredefinedOverrideRuleId::InviteForMe.as_str(),
368 )
369 .await?;
370 Ok(enabled)
371 }
372
373 pub async fn set_invite_for_me_enabled(
375 &self,
376 enabled: bool,
377 ) -> Result<(), NotificationSettingsError> {
378 let notification_settings = self.sdk_notification_settings.read().await;
379 notification_settings
380 .set_push_rule_enabled(
381 RuleKind::Override,
382 PredefinedOverrideRuleId::InviteForMe.as_str(),
383 enabled,
384 )
385 .await?;
386 Ok(())
387 }
388
389 pub async fn unmute_room(
398 &self,
399 room_id: String,
400 is_encrypted: bool,
401 is_one_to_one: bool,
402 ) -> Result<(), NotificationSettingsError> {
403 let notification_settings = self.sdk_notification_settings.read().await;
404 let parsed_room_id = RoomId::parse(&room_id)
405 .map_err(|_e| NotificationSettingsError::InvalidRoomId { room_id })?;
406 notification_settings
407 .unmute_room(&parsed_room_id, is_encrypted.into(), is_one_to_one.into())
408 .await?;
409 Ok(())
410 }
411}