[fractal/notification-setting: 13/13] Room notification setting




commit eebfc9fdd502cc7e2b54a11253f1ae0f1b455c84
Author: Daniel GarcĂ­a Moreno <dani danigm net>
Date:   Tue Aug 11 17:26:59 2020 +0200

    Room notification setting
    
    This patch adds a switch button to the room settings where you can
    enable or disable notifications.
    
    When the switch is disabled only mentions are enabled for this room.
    When the switch is enabled the setting is set to always notify.
    
    Because this is an on/off button there's no way to fine tuning
    notifications, so it's not possible to set never-notify or something
    different.
    
    Fix https://gitlab.gnome.org/GNOME/fractal/-/issues/199

 fractal-gtk/res/ui/room_settings.ui                |  4 +-
 fractal-gtk/src/appop/room_settings.rs             |  6 ++
 fractal-gtk/src/backend/room.rs                    | 92 ++++++++++++++++++++++
 fractal-gtk/src/widgets/room_settings.rs           | 84 ++++++++++++++++++--
 fractal-matrix-api/src/r0.rs                       |  1 +
 fractal-matrix-api/src/r0/pushrules.rs             |  3 +
 .../src/r0/pushrules/delete_room_rules.rs          | 23 ++++++
 .../src/r0/pushrules/get_room_rules.rs             | 23 ++++++
 .../src/r0/pushrules/set_room_rules.rs             | 29 +++++++
 9 files changed, 257 insertions(+), 8 deletions(-)
---
diff --git a/fractal-gtk/res/ui/room_settings.ui b/fractal-gtk/res/ui/room_settings.ui
index 6dc58b6f..17b9e635 100644
--- a/fractal-gtk/res/ui/room_settings.ui
+++ b/fractal-gtk/res/ui/room_settings.ui
@@ -212,7 +212,7 @@
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkFrame" id="room_settings_notification_switch">
+                          <object class="GtkFrame">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
                             <property name="margin_bottom">24</property>
@@ -245,7 +245,7 @@
                                           </packing>
                                         </child>
                                         <child>
-                                          <object class="GtkSwitch">
+                                          <object class="GtkSwitch" id="room_settings_notification_switch">
                                             <property name="visible">True</property>
                                             <property name="can_focus">False</property>
                                           </object>
diff --git a/fractal-gtk/src/appop/room_settings.rs b/fractal-gtk/src/appop/room_settings.rs
index 01524706..841e109d 100644
--- a/fractal-gtk/src/appop/room_settings.rs
+++ b/fractal-gtk/src/appop/room_settings.rs
@@ -71,4 +71,10 @@ impl AppOp {
         panel.show_new_room_topic();
         None
     }
+
+    pub fn set_notifications_switch(&self, active: bool, sensitive: bool) -> Option<()> {
+        let panel = self.room_settings.clone()?;
+        panel.set_notifications_switch(active, sensitive);
+        None
+    }
 }
diff --git a/fractal-gtk/src/backend/room.rs b/fractal-gtk/src/backend/room.rs
index c1ae07e5..b26fa827 100644
--- a/fractal-gtk/src/backend/room.rs
+++ b/fractal-gtk/src/backend/room.rs
@@ -48,6 +48,12 @@ use fractal_api::r0::message::get_message_events::request as get_messages_events
 use fractal_api::r0::message::get_message_events::Direction as GetMessagesEventsDirection;
 use fractal_api::r0::message::get_message_events::Parameters as GetMessagesEventsParams;
 use fractal_api::r0::message::get_message_events::Response as GetMessagesEventsResponse;
+use fractal_api::r0::pushrules::delete_room_rules::request as delete_room_rules;
+use fractal_api::r0::pushrules::delete_room_rules::Parameters as DelRoomRulesParams;
+use fractal_api::r0::pushrules::get_room_rules::request as get_room_rules;
+use fractal_api::r0::pushrules::get_room_rules::Parameters as GetRoomRulesParams;
+use fractal_api::r0::pushrules::set_room_rules::request as set_room_rules;
+use fractal_api::r0::pushrules::set_room_rules::Parameters as SetRoomRulesParams;
 use fractal_api::r0::read_marker::set_read_marker::request as set_read_marker;
 use fractal_api::r0::read_marker::set_read_marker::Body as SetReadMarkerBody;
 use fractal_api::r0::read_marker::set_read_marker::Parameters as SetReadMarkerParameters;
@@ -932,3 +938,89 @@ pub fn set_language(
 
     Ok(())
 }
+
+#[derive(Debug)]
+pub enum RoomNotify {
+    All,
+    DontNotify,
+    NotSet,
+}
+
+#[derive(Debug)]
+pub struct PushRulesError(ReqwestError);
+
+impl From<ReqwestError> for PushRulesError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
+    }
+}
+
+impl HandleError for PushRulesError {
+    fn handle_error(&self) {
+        error!("PushRules: {}", self.0);
+    }
+}
+
+pub fn get_pushrules(
+    base: Url,
+    access_token: AccessToken,
+    room_id: RoomId,
+) -> Result<RoomNotify, PushRulesError> {
+    let params = GetRoomRulesParams { access_token };
+
+    let request = get_room_rules(base, &params, &room_id)?;
+
+    let mut value = RoomNotify::NotSet;
+
+    let response: Result<JsonValue, _> = HTTP_CLIENT.get_client().execute(request)?.json();
+
+    if let Ok(js) = response {
+        if let Some(array) = js["actions"].as_array() {
+            for v in array {
+                match v.as_str().unwrap_or_default() {
+                    "notify" => value = RoomNotify::All,
+                    "dont_notify" => value = RoomNotify::DontNotify,
+                    _ => {}
+                };
+            }
+        }
+    }
+
+    Ok(value)
+}
+
+pub fn set_pushrules(
+    base: Url,
+    access_token: AccessToken,
+    room_id: RoomId,
+    notify: RoomNotify,
+) -> Result<(), PushRulesError> {
+    if let RoomNotify::NotSet = notify {
+        return delete_pushrules(base, access_token, room_id);
+    }
+
+    let params = SetRoomRulesParams { access_token };
+    let js = match notify {
+        RoomNotify::DontNotify => json!({"actions": ["dont_notify"]}),
+        RoomNotify::All => json!({
+            "actions": ["notify", {"set_tweak": "sound", "value": "default"}]
+        }),
+        _ => json!({}),
+    };
+
+    let request = set_room_rules(base, &params, &room_id, &js)?;
+
+    HTTP_CLIENT.get_client().execute(request)?;
+    Ok(())
+}
+
+pub fn delete_pushrules(
+    base: Url,
+    access_token: AccessToken,
+    room_id: RoomId,
+) -> Result<(), PushRulesError> {
+    let params = DelRoomRulesParams { access_token };
+    let request = delete_room_rules(base, &params, &room_id)?;
+    HTTP_CLIENT.get_client().execute(request)?;
+    Ok(())
+}
diff --git a/fractal-gtk/src/widgets/room_settings.rs b/fractal-gtk/src/widgets/room_settings.rs
index fde79787..b6ce7b6e 100644
--- a/fractal-gtk/src/widgets/room_settings.rs
+++ b/fractal-gtk/src/widgets/room_settings.rs
@@ -30,6 +30,7 @@ pub struct RoomSettings {
     members_list: Option<MembersList>,
     server_url: Url,
     access_token: AccessToken,
+    switch_handler: Option<Rc<glib::SignalHandlerId>>,
 }
 
 impl RoomSettings {
@@ -61,6 +62,7 @@ impl RoomSettings {
             members_list: None,
             server_url,
             access_token,
+            switch_handler: None,
         }
     }
 
@@ -101,7 +103,7 @@ impl RoomSettings {
         None
     }
 
-    pub fn connect(&self) {
+    pub fn connect(&mut self) {
         let name_btn = self
             .builder
             .get_object::<gtk::Button>("room_settings_room_name_button")
@@ -122,6 +124,10 @@ impl RoomSettings {
             .builder
             .get_object::<gtk::Button>("room_settings_avatar_button")
             .expect("Can't find room_settings_avatar_button in ui file.");
+        let switch = self
+            .builder
+            .get_object::<gtk::Switch>("room_settings_notification_switch")
+            .expect("Can't find room_settings_notification_switch in ui file.");
 
         let this: Rc<RefCell<RoomSettings>> = Rc::new(RefCell::new(self.clone()));
 
@@ -183,6 +189,26 @@ impl RoomSettings {
                 }),
             );
         }
+
+        let switch_handler = switch.connect_property_active_notify(
+            clone!(@strong this => move |switch| {
+                let active = switch.get_active();
+                let notify = if active { room::RoomNotify::All } else { room::RoomNotify::DontNotify };
+                let server = this.borrow().server_url.clone();
+                let access_token = this.borrow().access_token.clone();
+                let room_id = this.borrow().room.id.clone();
+                switch.set_sensitive(false);
+
+                thread::spawn(move || {
+                    if let Err(err) = room::set_pushrules(server, access_token, room_id, notify) {
+                        err.handle_error();
+                    }
+                    let sensitive = true;
+                    APPOP!(set_notifications_switch, (active, sensitive));
+                });
+            }));
+
+        self.switch_handler = Some(Rc::new(switch_handler));
     }
 
     fn init_room_settings(&mut self) {
@@ -220,6 +246,7 @@ impl RoomSettings {
         self.room_settings_show_room_topic(topic, is_room, edit);
         self.room_settings_show_room_type(description);
         self.room_settings_show_members(members);
+        self.room_settings_show_notifications();
 
         /* admin parts */
         self.room_settings_show_group_room(is_room || is_group);
@@ -612,10 +639,6 @@ impl RoomSettings {
             .builder
             .get_object::<gtk::Frame>("room_settings_media")
             .expect("Can't find room_settings_media in ui file.");
-        let switch = self
-            .builder
-            .get_object::<gtk::Frame>("room_settings_notification_switch")
-            .expect("Can't find room_settings_notification_switch in ui file.");
         let history = self
             .builder
             .get_object::<gtk::Frame>("room_settings_history_visibility")
@@ -630,7 +653,6 @@ impl RoomSettings {
             .expect("Can't find room_settings_room_visibility in ui file.");
         notification.hide();
         media.hide();
-        switch.hide();
         history.hide();
         room.hide();
         join.hide();
@@ -669,4 +691,54 @@ impl RoomSettings {
         self.members_list = Some(list);
         None
     }
+
+    fn room_settings_show_notifications(&mut self) {
+        let switch = self
+            .builder
+            .get_object::<gtk::Switch>("room_settings_notification_switch")
+            .expect("Can't find room_settings_notification_switch in ui file.");
+
+        switch.set_sensitive(false);
+
+        let server = self.server_url.clone();
+        let access_token = self.access_token.clone();
+        let room_id = self.room.id.clone();
+
+        thread::spawn(move || {
+            let mut active = true;
+            let mut sensitive = true;
+            match room::get_pushrules(server, access_token, room_id) {
+                Ok(room::RoomNotify::DontNotify) => {
+                    active = false;
+                }
+                Err(err) => {
+                    err.handle_error();
+                    active = false;
+                    sensitive = false;
+                }
+                _ => {}
+            };
+            APPOP!(set_notifications_switch, (active, sensitive));
+        });
+    }
+
+    pub fn set_notifications_switch(&self, active: bool, sensitive: bool) {
+        let switch = self
+            .builder
+            .get_object::<gtk::Switch>("room_settings_notification_switch")
+            .expect("Can't find room_settings_notification_switch in ui file.");
+
+        if let Some(handler) = &self.switch_handler {
+            println!("handler block");
+            switch.block_signal(&handler);
+        }
+
+        switch.set_active(active);
+        switch.set_sensitive(sensitive);
+
+        if let Some(handler) = &self.switch_handler {
+            println!("handler unblock");
+            switch.unblock_signal(&handler);
+        }
+    }
 }
diff --git a/fractal-matrix-api/src/r0.rs b/fractal-matrix-api/src/r0.rs
index d83447fb..2bc9f0a2 100644
--- a/fractal-matrix-api/src/r0.rs
+++ b/fractal-matrix-api/src/r0.rs
@@ -8,6 +8,7 @@ pub mod media;
 pub mod membership;
 pub mod message;
 pub mod profile;
+pub mod pushrules;
 pub mod read_marker;
 pub mod redact;
 pub mod room;
diff --git a/fractal-matrix-api/src/r0/pushrules.rs b/fractal-matrix-api/src/r0/pushrules.rs
new file mode 100644
index 00000000..0ac4e160
--- /dev/null
+++ b/fractal-matrix-api/src/r0/pushrules.rs
@@ -0,0 +1,3 @@
+pub mod delete_room_rules;
+pub mod get_room_rules;
+pub mod set_room_rules;
diff --git a/fractal-matrix-api/src/r0/pushrules/delete_room_rules.rs 
b/fractal-matrix-api/src/r0/pushrules/delete_room_rules.rs
new file mode 100644
index 00000000..753bc457
--- /dev/null
+++ b/fractal-matrix-api/src/r0/pushrules/delete_room_rules.rs
@@ -0,0 +1,23 @@
+use crate::r0::AccessToken;
+use reqwest::blocking::Client;
+use reqwest::blocking::Request;
+use reqwest::Error;
+use ruma_identifiers::RoomId;
+use serde::Serialize;
+use url::Url;
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Parameters {
+    pub access_token: AccessToken,
+}
+
+pub fn request(base: Url, params: &Parameters, room_id: &RoomId) -> Result<Request, Error> {
+    let url = base
+        .join(&format!(
+            "_matrix/client/r0/pushrules/global/room/{}",
+            room_id
+        ))
+        .expect("Malformed URL in delete_room_rules");
+
+    Client::new().delete(url).query(params).build()
+}
diff --git a/fractal-matrix-api/src/r0/pushrules/get_room_rules.rs 
b/fractal-matrix-api/src/r0/pushrules/get_room_rules.rs
new file mode 100644
index 00000000..ea3c4491
--- /dev/null
+++ b/fractal-matrix-api/src/r0/pushrules/get_room_rules.rs
@@ -0,0 +1,23 @@
+use crate::r0::AccessToken;
+use reqwest::blocking::Client;
+use reqwest::blocking::Request;
+use reqwest::Error;
+use ruma_identifiers::RoomId;
+use serde::Serialize;
+use url::Url;
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Parameters {
+    pub access_token: AccessToken,
+}
+
+pub fn request(base: Url, params: &Parameters, room_id: &RoomId) -> Result<Request, Error> {
+    let url = base
+        .join(&format!(
+            "_matrix/client/r0/pushrules/global/room/{}",
+            room_id
+        ))
+        .expect("Malformed URL in get_room_rules");
+
+    Client::new().get(url).query(params).build()
+}
diff --git a/fractal-matrix-api/src/r0/pushrules/set_room_rules.rs 
b/fractal-matrix-api/src/r0/pushrules/set_room_rules.rs
new file mode 100644
index 00000000..cc1cac1b
--- /dev/null
+++ b/fractal-matrix-api/src/r0/pushrules/set_room_rules.rs
@@ -0,0 +1,29 @@
+use crate::r0::AccessToken;
+use reqwest::blocking::Client;
+use reqwest::blocking::Request;
+use reqwest::Error;
+use ruma_identifiers::RoomId;
+use serde::Serialize;
+use serde_json::Value as JsonValue;
+use url::Url;
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Parameters {
+    pub access_token: AccessToken,
+}
+
+pub fn request(
+    base: Url,
+    params: &Parameters,
+    room_id: &RoomId,
+    rule: &JsonValue,
+) -> Result<Request, Error> {
+    let url = base
+        .join(&format!(
+            "_matrix/client/r0/pushrules/global/room/{}",
+            room_id
+        ))
+        .expect("Malformed URL in set_room_rules");
+
+    Client::new().put(url).query(params).json(rule).build()
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]