[fractal/fractal-next] room_details: Add editing of room name and topic



commit 7ce448ba625d61fce8576416b17e946630ad81a0
Author: Kai A. Hiller <V02460 gmail com>
Date:   Sat Jul 10 14:33:56 2021 +0200

    room_details: Add editing of room name and topic

 data/resources/ui/content-room-details.ui        |  1 -
 src/session/content/room_details/room_details.rs | 56 ++++++++++++++-
 src/session/room/room.rs                         | 89 ++++++++++++++++++++++--
 3 files changed, 138 insertions(+), 8 deletions(-)
---
diff --git a/data/resources/ui/content-room-details.ui b/data/resources/ui/content-room-details.ui
index 913f4f44..20cda5d0 100644
--- a/data/resources/ui/content-room-details.ui
+++ b/data/resources/ui/content-room-details.ui
@@ -69,7 +69,6 @@
             <child>
               <object class="GtkToggleButton" id="edit_toggle">
                 <property name="halign">center</property>
-                <property name="label" translatable="yes">Edit Details</property>
               </object>
             </child>
           </object>
diff --git a/src/session/content/room_details/room_details.rs 
b/src/session/content/room_details/room_details.rs
index 4da4a807..10b3b313 100644
--- a/src/session/content/room_details/room_details.rs
+++ b/src/session/content/room_details/room_details.rs
@@ -1,5 +1,11 @@
 use adw::subclass::prelude::*;
-use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
+use gettextrs::gettext;
+use gtk::{
+    glib::{self, clone},
+    prelude::*,
+    subclass::prelude::*,
+    CompositeTemplate,
+};
 
 use crate::components::CustomEntry;
 use crate::session::Room;
@@ -13,6 +19,12 @@ mod imp {
     #[template(resource = "/org/gnome/FractalNext/content-room-details.ui")]
     pub struct RoomDetails {
         pub room: OnceCell<Room>,
+        #[template_child]
+        pub edit_toggle: TemplateChild<gtk::ToggleButton>,
+        #[template_child]
+        pub room_name_entry: TemplateChild<gtk::Entry>,
+        #[template_child]
+        pub room_topic_text_view: TemplateChild<gtk::TextView>,
     }
 
     #[glib::object_subclass]
@@ -66,6 +78,12 @@ mod imp {
                 _ => unimplemented!(),
             }
         }
+
+        fn constructed(&self, obj: &Self::Type) {
+            self.parent_constructed(obj);
+
+            obj.init_edit_toggle();
+        }
     }
 
     impl WidgetImpl for RoomDetails {}
@@ -96,4 +114,40 @@ impl RoomDetails {
         let priv_ = imp::RoomDetails::from_instance(self);
         priv_.room.set(room).expect("Room already initialized");
     }
+
+    fn init_edit_toggle(&self) {
+        let priv_ = imp::RoomDetails::from_instance(self);
+        let edit_toggle = &priv_.edit_toggle;
+        let label_enabled = gettext("Save Details");
+        let label_disabled = gettext("Edit Details");
+
+        edit_toggle.set_active(false);
+        edit_toggle.set_label(&label_disabled);
+
+        // Save changes of name and topic on toggle button release.
+        edit_toggle.connect_toggled(clone!(@weak self as this => move |button| {
+            if button.is_active() {
+                button.set_label(&label_enabled);
+                return;
+            }
+            button.set_label(&label_disabled);
+
+            let priv_ = imp::RoomDetails::from_instance(&this);
+            let room = this.room();
+
+            let room_name = priv_.room_name_entry.buffer().text();
+            let topic_buffer = priv_.room_topic_text_view.buffer();
+            let topic = topic_buffer.text(&topic_buffer.start_iter(), &topic_buffer.end_iter(), true);
+            room.store_room_name(room_name);
+            room.store_topic(topic.to_string());
+        }));
+
+        // End editing on enter.
+        priv_
+            .room_name_entry
+            .connect_activate(clone!(@weak self as this => move |_entry| {
+                let priv_ = imp::RoomDetails::from_instance(&this);
+                priv_.edit_toggle.set_active(false);
+            }));
+    }
 }
diff --git a/src/session/room/room.rs b/src/session/room/room.rs
index ab32b8b1..dda7f3c7 100644
--- a/src/session/room/room.rs
+++ b/src/session/room/room.rs
@@ -1,6 +1,6 @@
 use gettextrs::gettext;
 use gtk::{glib, glib::clone, prelude::*, subclass::prelude::*};
-use log::{debug, error, warn};
+use log::{debug, error, info, warn};
 use matrix_sdk::{
     deserialized_responses::{JoinedRoom, LeftRoom},
     room::Room as MatrixRoom,
@@ -13,10 +13,13 @@ use matrix_sdk::{
                     EmoteMessageEventContent, MessageEventContent, MessageType,
                     TextMessageEventContent,
                 },
+                name::NameEventContent,
+                topic::TopicEventContent,
             },
             tag::TagName,
-            AnyRoomAccountDataEvent, AnyStrippedStateEvent, AnySyncMessageEvent, AnySyncRoomEvent,
-            AnySyncStateEvent, SyncMessageEvent, SyncStateEvent, Unsigned,
+            AnyRoomAccountDataEvent, AnyStateEventContent, AnyStrippedStateEvent,
+            AnySyncMessageEvent, AnySyncRoomEvent, AnySyncStateEvent, SyncMessageEvent,
+            SyncStateEvent, Unsigned,
         },
         identifiers::{EventId, RoomId, UserId},
         serde::Raw,
@@ -27,7 +30,7 @@ use matrix_sdk::{
 };
 use serde_json::value::RawValue;
 use std::cell::RefCell;
-use std::convert::TryFrom;
+use std::convert::{TryFrom, TryInto};
 
 use crate::components::{LabelWithWidgets, Pill};
 use crate::prelude::*;
@@ -93,7 +96,7 @@ mod imp {
                         "Display Name",
                         "The display name of this room",
                         None,
-                        glib::ParamFlags::READABLE,
+                        glib::ParamFlags::READWRITE,
                     ),
                     glib::ParamSpec::new_object(
                         "inviter",
@@ -146,7 +149,7 @@ mod imp {
                         "Topic",
                         "The topic of this room",
                         None,
-                        glib::ParamFlags::READABLE,
+                        glib::ParamFlags::READWRITE,
                     ),
                     glib::ParamSpec::new_boxed(
                         "latest-change",
@@ -170,6 +173,10 @@ mod imp {
         ) {
             match pspec.name() {
                 "session" => self.session.set(value.get().unwrap()).unwrap(),
+                "display-name" => {
+                    let room_name = value.get().unwrap();
+                    obj.store_room_name(room_name)
+                }
                 "category" => {
                     let category = value.get().unwrap();
                     obj.set_category(category);
@@ -178,6 +185,10 @@ mod imp {
                     .room_id
                     .set(RoomId::try_from(value.get::<&str>().unwrap()).unwrap())
                     .unwrap(),
+                "topic" => {
+                    let topic = value.get().unwrap();
+                    obj.store_topic(topic);
+                }
                 _ => unimplemented!(),
             }
         }
@@ -500,6 +511,43 @@ impl Room {
         );
     }
 
+    /// Updates the Matrix room with the given name.
+    pub fn store_room_name(&self, room_name: String) {
+        if self.display_name() == room_name {
+            return;
+        }
+
+        let joined_room = match self.matrix_room() {
+            MatrixRoom::Joined(joined_room) => joined_room,
+            _ => {
+                error!("Room name can’t be changed when not a member.");
+                return;
+            }
+        };
+        let room_name = match room_name.try_into() {
+            Ok(room_name) => room_name,
+            Err(e) => {
+                error!("Invalid room name: {}", e);
+                return;
+            }
+        };
+        let name_content = NameEventContent::new(Some(room_name));
+
+        do_async(
+            glib::PRIORITY_DEFAULT_IDLE,
+            async move {
+                let content = AnyStateEventContent::RoomName(name_content);
+                joined_room.send_state_event(content, "").await
+            },
+            clone!(@weak self as obj => move |room_name| async move {
+                match room_name {
+                    Ok(_room_name) => info!("Successfully updated room name"),
+                    Err(error) => error!("Couldn’t update room name: {}", error),
+                };
+            }),
+        );
+    }
+
     pub fn avatar(&self) -> &Avatar {
         let priv_ = imp::Room::from_instance(self);
         priv_.avatar.get().unwrap()
@@ -511,6 +559,35 @@ impl Room {
             .filter(|topic| !topic.is_empty() && topic.find(|c: char| !c.is_whitespace()).is_some())
     }
 
+    /// Updates the Matrix room with the given topic.
+    pub fn store_topic(&self, topic: String) {
+        if self.topic().as_ref() == Some(&topic) {
+            return;
+        }
+
+        let joined_room = match self.matrix_room() {
+            MatrixRoom::Joined(joined_room) => joined_room,
+            _ => {
+                error!("Room topic can’t be changed when not a member.");
+                return;
+            }
+        };
+
+        do_async(
+            glib::PRIORITY_DEFAULT_IDLE,
+            async move {
+                let content = AnyStateEventContent::RoomTopic(TopicEventContent::new(topic));
+                joined_room.send_state_event(content, "").await
+            },
+            clone!(@weak self as obj => move |topic| async move {
+                match topic {
+                    Ok(_topic) => info!("Successfully updated room topic"),
+                    Err(error) => error!("Couldn’t update topic: {}", error),
+                };
+            }),
+        );
+    }
+
     pub fn power_levels(&self) -> PowerLevels {
         let priv_ = imp::Room::from_instance(self);
         priv_.power_levels.borrow().clone()


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