From 045dd8369f9dc69bee0423659dd78efaf04f3046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Tue, 19 Dec 2023 22:21:54 +0100 Subject: [PATCH] content: Finish porting to glib::Properties macro --- src/session/view/content/invite.rs | 193 ++++++++++++------------- src/session/view/content/mod.rs | 217 ++++++++++++----------------- 2 files changed, 172 insertions(+), 238 deletions(-) diff --git a/src/session/view/content/invite.rs b/src/session/view/content/invite.rs index 8661d814..4f76e4bb 100644 --- a/src/session/view/content/invite.rs +++ b/src/session/view/content/invite.rs @@ -13,18 +13,21 @@ use crate::{ mod imp { use std::{cell::RefCell, collections::HashSet}; - use glib::{signal::SignalHandlerId, subclass::InitializingObject}; + use glib::subclass::InitializingObject; use super::*; - #[derive(Debug, Default, CompositeTemplate)] + #[derive(Debug, Default, CompositeTemplate, glib::Properties)] #[template(resource = "/org/gnome/Fractal/ui/session/view/content/invite.ui")] + #[properties(wrapper_type = super::Invite)] pub struct Invite { + /// The room currently displayed. + #[property(get, set = Self::set_room, explicit_notify, nullable)] pub room: RefCell>, pub room_members: RefCell>, pub accept_requests: RefCell>, pub decline_requests: RefCell>, - pub category_handler: RefCell>, + pub category_handler: RefCell>, #[template_child] pub room_topic: TemplateChild, #[template_child] @@ -60,36 +63,8 @@ mod imp { } } + #[glib::derived_properties] impl ObjectImpl for Invite { - fn properties() -> &'static [glib::ParamSpec] { - use once_cell::sync::Lazy; - static PROPERTIES: Lazy> = Lazy::new(|| { - vec![glib::ParamSpecObject::builder::("room") - .explicit_notify() - .build()] - }); - - PROPERTIES.as_ref() - } - - fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { - let obj = self.obj(); - - match pspec.name() { - "room" => obj.set_room(value.get().unwrap()), - _ => unimplemented!(), - } - } - - fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { - let obj = self.obj(); - - match pspec.name() { - "room" => obj.room().to_value(), - _ => unimplemented!(), - } - } - fn constructed(&self) { self.parent_constructed(); @@ -108,13 +83,92 @@ mod imp { &[("user", "")], ))); } + + fn dispose(&self) { + if let Some(room) = self.room.take() { + if let Some(handler) = self.category_handler.take() { + room.disconnect(handler); + } + } + } } impl WidgetImpl for Invite {} impl BinImpl for Invite {} + + impl Invite { + /// Set the room currently displayed. + fn set_room(&self, room: Option) { + if *self.room.borrow() == room { + return; + } + let obj = self.obj(); + + match &room { + Some(room) if self.accept_requests.borrow().contains(room) => { + obj.action_set_enabled("invite.accept", false); + obj.action_set_enabled("invite.decline", false); + self.accept_button.set_loading(true); + } + Some(room) if self.decline_requests.borrow().contains(room) => { + obj.action_set_enabled("invite.accept", false); + obj.action_set_enabled("invite.decline", false); + self.decline_button.set_loading(true); + } + _ => obj.reset(), + } + + if let Some(room) = self.room.take() { + if let Some(handler) = self.category_handler.take() { + room.disconnect(handler); + } + } + + if let Some(room) = &room { + let category_handler = room.connect_category_notify( + clone!(@weak obj => move |room| { + let category = room.category(); + + if category == RoomType::Left { + // We declined the invite or the invite was retracted, we should close the room + // if it is opened. + let Some(session) = room.session() else { + return; + }; + let selection = session.sidebar_list_model().selection_model(); + if let Some(selected_room) = selection.selected_item().and_downcast::() { + if selected_room == *room { + selection.set_selected_item(Option::::None); + } + } + } + + if category != RoomType::Invited { + let imp = obj.imp(); + imp.decline_requests.borrow_mut().remove(room); + imp.accept_requests.borrow_mut().remove(room); + obj.reset(); + if let Some(category_handler) = imp.category_handler.take() { + room.disconnect(category_handler); + } + } + }), + ); + self.category_handler.replace(Some(category_handler)); + } + + // Keep a strong reference to the members list. + self.room_members + .replace(room.as_ref().map(|r| r.get_or_create_members())); + self.room.replace(room); + + obj.notify_room(); + } + } } glib::wrapper! { + /// A view presenting an invitation to a room. pub struct Invite(ObjectSubclass) @extends gtk::Widget, adw::Bin, @implements gtk::Accessible; } @@ -124,81 +178,6 @@ impl Invite { glib::Object::new() } - /// Set the room currently displayed. - pub fn set_room(&self, room: Option) { - let imp = self.imp(); - - if self.room() == room { - return; - } - - match room { - Some(ref room) if imp.accept_requests.borrow().contains(room) => { - self.action_set_enabled("invite.accept", false); - self.action_set_enabled("invite.decline", false); - imp.accept_button.set_loading(true); - } - Some(ref room) if imp.decline_requests.borrow().contains(room) => { - self.action_set_enabled("invite.accept", false); - self.action_set_enabled("invite.decline", false); - imp.decline_button.set_loading(true); - } - _ => self.reset(), - } - - if let Some(category_handler) = imp.category_handler.take() { - if let Some(room) = self.room() { - room.disconnect(category_handler); - } - } - - if let Some(ref room) = room { - let handler_id = room.connect_notify_local( - Some("category"), - clone!(@weak self as obj => move |room, _| { - let category = room.category(); - - if category == RoomType::Left { - // We declined the invite or the invite was retracted, we should close the room - // if it is opened. - let Some(session) = room.session() else { - return; - }; - let selection = session.sidebar_list_model().selection_model(); - if let Some(selected_room) = selection.selected_item().and_downcast::() { - if selected_room == *room { - selection.set_selected_item(Option::::None); - } - } - } - - if category != RoomType::Invited { - let imp = obj.imp(); - imp.decline_requests.borrow_mut().remove(room); - imp.accept_requests.borrow_mut().remove(room); - obj.reset(); - if let Some(category_handler) = imp.category_handler.take() { - room.disconnect(category_handler); - } - } - }), - ); - imp.category_handler.replace(Some(handler_id)); - } - - // Keep a strong reference to the members list. - imp.room_members - .replace(room.as_ref().map(|r| r.get_or_create_members())); - imp.room.replace(room); - - self.notify("room"); - } - - /// The room currently displayed. - pub fn room(&self) -> Option { - self.imp().room.borrow().clone() - } - fn reset(&self) { let imp = self.imp(); imp.accept_button.set_loading(false); diff --git a/src/session/view/content/mod.rs b/src/session/view/content/mod.rs index 88bae650..18f0abef 100644 --- a/src/session/view/content/mod.rs +++ b/src/session/view/content/mod.rs @@ -18,20 +18,25 @@ use crate::session::model::{ mod imp { use std::cell::{Cell, RefCell}; - use glib::{object::WeakRef, signal::SignalHandlerId, subclass::InitializingObject}; - use once_cell::sync::Lazy; + use glib::subclass::InitializingObject; use super::*; - #[derive(Debug, Default, CompositeTemplate)] + #[derive(Debug, Default, CompositeTemplate, glib::Properties)] #[template(resource = "/org/gnome/Fractal/ui/session/view/content/mod.ui")] + #[properties(wrapper_type = super::Content)] pub struct Content { - pub session: WeakRef, + /// The current session. + #[property(get, set = Self::set_session, explicit_notify, nullable)] + pub session: glib::WeakRef, /// Whether this is the only visible view, i.e. there is no sidebar. + #[property(get, set)] pub only_view: Cell, pub item_binding: RefCell>, + /// The item currently displayed. + #[property(get, set = Self::set_item, explicit_notify, nullable)] pub item: RefCell>, - pub signal_handler: RefCell>, + pub signal_handler: RefCell>, #[template_child] pub stack: TemplateChild, #[template_child] @@ -64,43 +69,8 @@ mod imp { } } + #[glib::derived_properties] impl ObjectImpl for Content { - fn properties() -> &'static [glib::ParamSpec] { - static PROPERTIES: Lazy> = Lazy::new(|| { - vec![ - glib::ParamSpecObject::builder::("session").build(), - glib::ParamSpecBoolean::builder("only-view").build(), - glib::ParamSpecObject::builder::("item") - .explicit_notify() - .build(), - ] - }); - - PROPERTIES.as_ref() - } - - fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { - let obj = self.obj(); - - match pspec.name() { - "session" => obj.set_session(value.get().unwrap()), - "only-view" => self.only_view.set(value.get().unwrap()), - "item" => obj.set_item(value.get().unwrap()), - _ => unimplemented!(), - } - } - - fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { - let obj = self.obj(); - - match pspec.name() { - "session" => obj.session().to_value(), - "only-view" => self.only_view.get().to_value(), - "item" => obj.item().to_value(), - _ => unimplemented!(), - } - } - fn constructed(&self) { self.parent_constructed(); @@ -121,12 +91,80 @@ mod imp { impl NavigationPageImpl for Content { fn hidden(&self) { - self.obj().set_item(None); + self.obj().set_item(None::); + } + } + + impl Content { + /// Set the current session. + fn set_session(&self, session: Option) { + if session == self.session.upgrade() { + return; + } + let obj = self.obj(); + + if let Some(binding) = self.item_binding.take() { + binding.unbind(); + } + + if let Some(session) = &session { + let item_binding = session + .sidebar_list_model() + .selection_model() + .bind_property("selected-item", &*obj, "item") + .sync_create() + .bidirectional() + .build(); + + self.item_binding.replace(Some(item_binding)); + } + + self.session.set(session.as_ref()); + obj.notify_session(); + } + + /// Set the item currently displayed. + fn set_item(&self, item: Option) { + if *self.item.borrow() == item { + return; + } + let obj = self.obj(); + + if let Some(item) = self.item.take() { + if let Some(signal_handler) = self.signal_handler.take() { + item.disconnect(signal_handler); + } + } + + if let Some(item) = &item { + if let Some(room) = item.downcast_ref::() { + let handler_id = room.connect_category_notify(clone!(@weak obj => move |_| { + obj.update_visible_child(); + })); + + self.signal_handler.replace(Some(handler_id)); + } else if let Some(verification) = item.downcast_ref::() { + let handler_id = verification.connect_notify_local( + Some("state"), + clone!(@weak obj => move |verification, _| { + if verification.is_finished() { + obj.set_item(None::); + } + }), + ); + self.signal_handler.replace(Some(handler_id)); + } + } + + self.item.replace(item); + obj.update_visible_child(); + obj.notify_item(); } } } glib::wrapper! { + /// A view displaying the selected content in the sidebar. pub struct Content(ObjectSubclass) @extends gtk::Widget, adw::NavigationPage, @implements gtk::Accessible; } @@ -149,89 +187,6 @@ impl Content { } } - /// The current session. - pub fn session(&self) -> Option { - self.imp().session.upgrade() - } - - /// Set the current session. - pub fn set_session(&self, session: Option) { - if session == self.session() { - return; - } - - let imp = self.imp(); - - if let Some(binding) = imp.item_binding.take() { - binding.unbind(); - } - - if let Some(session) = &session { - let item_binding = session - .sidebar_list_model() - .selection_model() - .bind_property("selected-item", self, "item") - .sync_create() - .bidirectional() - .build(); - - imp.item_binding.replace(Some(item_binding)); - } - - imp.session.set(session.as_ref()); - self.notify("session"); - } - - /// Set the item currently displayed. - pub fn set_item(&self, item: Option) { - let imp = self.imp(); - - if self.item() == item { - return; - } - - if let Some(signal_handler) = imp.signal_handler.take() { - if let Some(item) = self.item() { - item.disconnect(signal_handler); - } - } - - if let Some(ref item) = item { - if item.is::() { - let handler_id = item.connect_notify_local( - Some("category"), - clone!(@weak self as obj => move |_, _| { - obj.update_visible_child(); - }), - ); - - imp.signal_handler.replace(Some(handler_id)); - } - - if item.is::() { - let handler_id = item.connect_notify_local( - Some("state"), - clone!(@weak self as obj => move |request, _| { - let request = request.downcast_ref::().unwrap(); - if request.is_finished() { - obj.set_item(None); - } - }), - ); - imp.signal_handler.replace(Some(handler_id)); - } - } - - imp.item.replace(item); - self.update_visible_child(); - self.notify("item"); - } - - /// The item currently displayed. - pub fn item(&self) -> Option { - self.imp().item.borrow().clone() - } - /// Update the visible child according to the current item. fn update_visible_child(&self) { let imp = self.imp(); @@ -241,12 +196,12 @@ impl Content { imp.stack.set_visible_child(&*imp.empty_page); } Some(o) if o.is::() => { - if let Some(room) = imp.item.borrow().and_downcast_ref::() { + if let Ok(room) = o.downcast::() { if room.category() == RoomType::Invited { - imp.invite.set_room(Some(room.clone())); + imp.invite.set_room(Some(room)); imp.stack.set_visible_child(&*imp.invite); } else { - imp.room_history.set_room(Some(room.clone())); + imp.room_history.set_room(Some(room)); imp.stack.set_visible_child(&*imp.room_history); } } @@ -259,10 +214,10 @@ impl Content { imp.stack.set_visible_child(&*imp.explore); } Some(o) if o.is::() => { - if let Some(item) = imp.item.borrow().and_downcast_ref::() { - if item.mode() != VerificationMode::CurrentSession { + if let Ok(verification) = o.downcast::() { + if verification.mode() != VerificationMode::CurrentSession { imp.identity_verification_widget - .set_request(Some(item.clone())); + .set_request(Some(verification)); imp.stack.set_visible_child(&*imp.verification_page); } }