[fractal/fractal-next] session: Pass Session to obj that need access to it



commit a4d7f87bac3f72734f35e037cedb3cc14d124118
Author: Julian Sparber <julian sparber net>
Date:   Tue Jun 1 20:34:59 2021 +0200

    session: Pass Session to obj that need access to it
    
    Since we will have multiple Sessions at some point we need to tell
    objects the Session they belong to. This gives us direct access to the
    user of the session and the matrix client.

 src/session/mod.rs       |  57 +++++++++++--------
 src/session/room/room.rs | 145 ++++++++++++++++++-----------------------------
 src/session/room_list.rs | 124 ++++++++++++++++++----------------------
 src/session/user.rs      |  21 ++++++-
 4 files changed, 164 insertions(+), 183 deletions(-)
---
diff --git a/src/session/mod.rs b/src/session/mod.rs
index 4a183df4..e1906d14 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -55,7 +55,7 @@ mod imp {
         /// Contains the error if something went wrong
         pub error: RefCell<Option<matrix_sdk::Error>>,
         pub client: OnceCell<Client>,
-        pub room_list: RoomList,
+        pub room_list: OnceCell<RoomList>,
         pub categories: Categories,
         pub user: OnceCell<User>,
         pub selected_room: RefCell<Option<Room>>,
@@ -99,6 +99,13 @@ mod imp {
                         Room::static_type(),
                         glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
                     ),
+                    glib::ParamSpec::new_object(
+                        "user",
+                        "User",
+                        "The user of this session",
+                        User::static_type(),
+                        glib::ParamFlags::READABLE,
+                    ),
                 ]
             });
 
@@ -125,6 +132,7 @@ mod imp {
             match pspec.name() {
                 "categories" => self.categories.to_value(),
                 "selected-room" => obj.selected_room().to_value(),
+                "user" => obj.user().to_value(),
                 _ => unimplemented!(),
             }
         }
@@ -135,18 +143,6 @@ mod imp {
             });
             SIGNALS.as_ref()
         }
-
-        fn constructed(&self, obj: &Self::Type) {
-            self.parent_constructed(obj);
-
-            self.categories.set_room_list(&self.room_list);
-
-            self.room_list
-                .connect_error(clone!(@weak obj => move |_, error| {
-                        let priv_ = imp::Session::from_instance(&obj);
-                        priv_.error_list.append(&error);
-                }));
-        }
     }
     impl WidgetImpl for Session {}
     impl BinImpl for Session {}
@@ -271,19 +267,19 @@ impl Session {
         let priv_ = imp::Session::from_instance(self);
         match result {
             Ok((client, session)) => {
-                priv_.client.set(client.clone()).unwrap();
-
-                let user = User::new(&session.user_id);
-                self.set_user(user.clone());
+                priv_.client.set(client).unwrap();
+                let user = User::new(self, &session.user_id);
+                priv_.user.set(user).unwrap();
 
                 if store_session {
                     // TODO: report secret service errors
                     secret::store_session(session).unwrap();
                 }
 
-                priv_.room_list.set_client(client).unwrap();
-                priv_.room_list.set_user(user).unwrap();
-                priv_.room_list.load();
+                let room_list = RoomList::new(self);
+                priv_.categories.set_room_list(&room_list);
+                room_list.load();
+                priv_.room_list.set(room_list).unwrap();
 
                 self.sync();
             }
@@ -339,9 +335,14 @@ impl Session {
         priv_.is_ready.get().copied().unwrap_or_default()
     }
 
-    fn set_user(&self, user: User) {
+    pub fn user(&self) -> &User {
+        let priv_ = &imp::Session::from_instance(self);
+        priv_.user.get().unwrap()
+    }
+
+    pub fn client(&self) -> &Client {
         let priv_ = &imp::Session::from_instance(self);
-        priv_.user.set(user).unwrap();
+        priv_.client.get().unwrap()
     }
 
     /// Sets up the required channel to receive new room events
@@ -363,6 +364,12 @@ impl Session {
         sender
     }
 
+    /// This appends a new error to the list of errors
+    pub fn append_error(&self, error: &Error) {
+        let priv_ = imp::Session::from_instance(self);
+        priv_.error_list.append(error);
+    }
+
     /// Returns and consumes the `error` that was generated when the session failed to login,
     /// on a successful login this will be `None`.
     /// Unfortunatly it's not possible to connect the Error direclty to the `prepared` signals.
@@ -385,6 +392,10 @@ impl Session {
     fn handle_sync_response(&self, response: SyncResponse) {
         let priv_ = imp::Session::from_instance(self);
 
-        priv_.room_list.handle_response_rooms(response.rooms);
+        priv_
+            .room_list
+            .get()
+            .unwrap()
+            .handle_response_rooms(response.rooms);
     }
 }
diff --git a/src/session/room/room.rs b/src/session/room/room.rs
index e8eaa2d3..c99b38b5 100644
--- a/src/session/room/room.rs
+++ b/src/session/room/room.rs
@@ -22,13 +22,14 @@ use matrix_sdk::{
     MilliSecondsSinceUnixEpoch, Raw, RoomMember,
 };
 use std::cell::RefCell;
+use std::convert::TryFrom;
 
 use crate::components::{LabelWithWidgets, Pill};
 use crate::event_from_sync_event;
 use crate::session::{
     categories::CategoryType,
     room::{HighlightFlags, Timeline},
-    User,
+    Session, User,
 };
 use crate::utils::do_async;
 use crate::Error;
@@ -36,22 +37,20 @@ use crate::RUNTIME;
 
 mod imp {
     use super::*;
-    use glib::subclass::Signal;
     use once_cell::sync::{Lazy, OnceCell};
     use std::cell::Cell;
     use std::collections::HashMap;
 
     #[derive(Debug, Default)]
     pub struct Room {
+        pub room_id: OnceCell<RoomId>,
         pub matrix_room: RefCell<Option<MatrixRoom>>,
-        pub user: OnceCell<User>,
+        pub session: OnceCell<Session>,
         pub name: RefCell<Option<String>>,
         pub avatar: RefCell<Option<gio::LoadableIcon>>,
         pub category: Cell<CategoryType>,
         pub timeline: OnceCell<Timeline>,
         pub room_members: RefCell<HashMap<UserId, User>>,
-        /// The user of this room
-        pub user_id: OnceCell<UserId>,
         /// The user who send the invite to this room. This is only set when this room is an invitiation.
         pub inviter: RefCell<Option<User>>,
     }
@@ -67,12 +66,19 @@ mod imp {
         fn properties() -> &'static [glib::ParamSpec] {
             static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
                 vec![
-                    glib::ParamSpec::new_boxed(
-                        "matrix-room",
-                        "Matrix room",
-                        "The underlaying matrix room.",
-                        BoxedMatrixRoom::static_type(),
-                        glib::ParamFlags::WRITABLE | glib::ParamFlags::CONSTRUCT,
+                    glib::ParamSpec::new_string(
+                        "room-id",
+                        "Room id",
+                        "The room id of this Room",
+                        None,
+                        glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+                    ),
+                    glib::ParamSpec::new_object(
+                        "session",
+                        "Session",
+                        "The session",
+                        Session::static_type(),
+                        glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
                     ),
                     glib::ParamSpec::new_string(
                         "display-name",
@@ -81,13 +87,6 @@ mod imp {
                         None,
                         glib::ParamFlags::READABLE,
                     ),
-                    glib::ParamSpec::new_object(
-                        "user",
-                        "User",
-                        "The user of the session that owns this room",
-                        User::static_type(),
-                        glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
-                    ),
                     glib::ParamSpec::new_object(
                         "inviter",
                         "Inviter",
@@ -155,18 +154,15 @@ mod imp {
             pspec: &glib::ParamSpec,
         ) {
             match pspec.name() {
-                "matrix-room" => {
-                    let matrix_room = value.get::<BoxedMatrixRoom>().unwrap();
-                    obj.set_matrix_room(matrix_room.0);
-                }
-                "user" => {
-                    let user = value.get().unwrap();
-                    self.user.set(user).unwrap();
-                }
+                "session" => self.session.set(value.get().unwrap()).unwrap(),
                 "category" => {
                     let category = value.get().unwrap();
                     obj.set_category(category);
                 }
+                "room-id" => self
+                    .room_id
+                    .set(RoomId::try_from(value.get::<String>().unwrap()).unwrap())
+                    .unwrap(),
                 _ => unimplemented!(),
             }
         }
@@ -175,7 +171,8 @@ mod imp {
             let matrix_room = self.matrix_room.borrow();
             let matrix_room = matrix_room.as_ref().unwrap();
             match pspec.name() {
-                "user" => obj.user().to_value(),
+                "room-id" => obj.room_id().as_str().to_value(),
+                "session" => obj.session().to_value(),
                 "inviter" => obj.inviter().to_value(),
                 "display-name" => obj.display_name().to_value(),
                 "avatar" => self.avatar.borrow().to_value(),
@@ -198,16 +195,11 @@ mod imp {
             }
         }
 
-        fn signals() -> &'static [Signal] {
-            static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
-                vec![Signal::builder(
-                    "error",
-                    &[Error::static_type().into()],
-                    <()>::static_type().into(),
-                )
-                .build()]
-            });
-            SIGNALS.as_ref()
+        fn constructed(&self, obj: &Self::Type) {
+            self.parent_constructed(obj);
+
+            obj.set_matrix_room(obj.session().client().get_room(obj.room_id()).unwrap());
+            self.timeline.set(Timeline::new(obj)).unwrap();
         }
     }
 }
@@ -216,25 +208,20 @@ glib::wrapper! {
     pub struct Room(ObjectSubclass<imp::Room>);
 }
 
-#[derive(Clone, Debug, glib::GBoxed)]
-#[gboxed(type_name = "BoxedMatrixRoom")]
-struct BoxedMatrixRoom(MatrixRoom);
-
 impl Room {
-    pub fn new(room: MatrixRoom, user: &User) -> Self {
-        glib::Object::new(&[("matrix-room", &BoxedMatrixRoom(room)), ("user", user)])
+    pub fn new(session: &Session, room_id: &RoomId) -> Self {
+        glib::Object::new(&[("session", session), ("room-id", &room_id.to_string())])
             .expect("Failed to create Room")
     }
 
-    pub fn matrix_room_id(&self) -> RoomId {
+    pub fn session(&self) -> &Session {
+        let priv_ = imp::Room::from_instance(&self);
+        priv_.session.get().unwrap()
+    }
+
+    pub fn room_id(&self) -> &RoomId {
         let priv_ = imp::Room::from_instance(self);
-        priv_
-            .matrix_room
-            .borrow()
-            .as_ref()
-            .unwrap()
-            .room_id()
-            .clone()
+        priv_.room_id.get().unwrap().into()
     }
 
     fn matrix_room(&self) -> MatrixRoom {
@@ -243,7 +230,7 @@ impl Room {
     }
 
     /// Set the new sdk room struct represented by this `Room`
-    pub fn set_matrix_room(&self, matrix_room: MatrixRoom) {
+    fn set_matrix_room(&self, matrix_room: MatrixRoom) {
         let priv_ = imp::Room::from_instance(self);
 
         // Check if the previous type was different
@@ -261,19 +248,12 @@ impl Room {
         }
 
         priv_.matrix_room.replace(Some(matrix_room));
-        // We create the timeline once
-        priv_.timeline.get_or_init(|| Timeline::new(self));
 
         self.load_members();
         self.load_display_name();
         self.load_category();
     }
 
-    pub fn user(&self) -> &User {
-        let priv_ = imp::Room::from_instance(self);
-        priv_.user.get().unwrap()
-    }
-
     pub fn category(&self) -> CategoryType {
         let priv_ = imp::Room::from_instance(self);
         priv_.category.get()
@@ -381,7 +361,7 @@ impl Room {
                                         }),
                                 );
 
-                                obj.emit_by_name("error", &[&error]).unwrap();
+                                obj.session().append_error(&error);
 
                                 // Load the previous category
                                 obj.load_category();
@@ -501,7 +481,7 @@ impl Room {
 
         room_members
             .entry(user_id.clone())
-            .or_insert(User::new(&user_id))
+            .or_insert(User::new(self.session(), &user_id))
             .clone()
     }
 
@@ -515,7 +495,7 @@ impl Room {
             .find(|event| {
                 if let AnyStrippedStateEvent::RoomMember(event) = event {
                     event.content.membership == MembershipState::Invite
-                        && event.state_key == self.user().user_id().as_str()
+                        && event.state_key == self.session().user().user_id().as_str()
                 } else {
                     false
                 }
@@ -532,7 +512,7 @@ impl Room {
             }
         });
 
-        let inviter = User::new(inviter_id);
+        let inviter = User::new(self.session(), inviter_id);
         if let Some(AnyStrippedStateEvent::RoomMember(event)) = inviter_event {
             inviter.update_from_stripped_member_event(event);
         }
@@ -577,7 +557,7 @@ impl Room {
             let user_id = member.user_id();
             let user = room_members
                 .entry(user_id.clone())
-                .or_insert(User::new(user_id));
+                .or_insert(User::new(self.session(), user_id));
             user.update_from_room_member(&member);
         }
     }
@@ -589,7 +569,7 @@ impl Room {
         let user_id = &event.sender;
         let user = room_members
             .entry(user_id.clone())
-            .or_insert(User::new(user_id));
+            .or_insert(User::new(self.session(), user_id));
         user.update_from_member_event(event);
     }
 
@@ -626,7 +606,6 @@ impl Room {
     }
 
     pub fn send_text_message(&self, body: &str, markdown_enabled: bool) {
-        use std::convert::TryFrom;
         if let MatrixRoom::Joined(matrix_room) = self.matrix_room() {
             let content = if let Some(body) = body.strip_prefix("/me ") {
                 let emote = if markdown_enabled {
@@ -649,7 +628,7 @@ impl Room {
             let pending_event = AnyMessageEvent::RoomMessage(MessageEvent {
                 content,
                 event_id: EventId::try_from(format!("${}:fractal.gnome.org", txn_id)).unwrap(),
-                sender: self.user().user_id().clone(),
+                sender: self.session().user().user_id().clone(),
                 origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
                 room_id: matrix_room.room_id().clone(),
                 unsigned: Unsigned::default(),
@@ -708,7 +687,7 @@ impl Room {
                                 Some(error_label.upcast())
                         }),
                     );
-                    self.emit_by_name("error", &[&error]).unwrap();
+                    self.session().append_error(&error);
                     Err(error)
                 }
             }
@@ -738,7 +717,7 @@ impl Room {
                                 Some(error_label.upcast())
                         }),
                     );
-                    self.emit_by_name("error", &[&error]).unwrap();
+                    self.session().append_error(&error);
                     Err(error)
                 }
             }
@@ -748,10 +727,10 @@ impl Room {
         }
     }
 
-    pub fn handle_left_response(&self, response_room: LeftRoom, matrix_room: MatrixRoom) {
-        self.set_matrix_room(matrix_room);
+    pub fn handle_left_response(&self, response_room: LeftRoom) {
+        self.set_matrix_room(self.session().client().get_room(self.room_id()).unwrap());
 
-        let room_id = self.matrix_room_id();
+        let room_id = self.room_id();
 
         self.append_events(
             response_room
@@ -771,8 +750,8 @@ impl Room {
         );
     }
 
-    pub fn handle_joined_response(&self, response_room: JoinedRoom, matrix_room: MatrixRoom) {
-        self.set_matrix_room(matrix_room);
+    pub fn handle_joined_response(&self, response_room: JoinedRoom) {
+        self.set_matrix_room(self.session().client().get_room(self.room_id()).unwrap());
 
         if response_room
             .account_data
@@ -783,7 +762,7 @@ impl Room {
             self.load_category();
         }
 
-        let room_id = self.matrix_room_id();
+        let room_id = self.room_id();
 
         self.append_events(
             response_room
@@ -803,8 +782,8 @@ impl Room {
         );
     }
 
-    pub fn handle_invited_response(&self, response_room: InvitedRoom, matrix_room: MatrixRoom) {
-        self.set_matrix_room(matrix_room);
+    pub fn handle_invited_response(&self, response_room: InvitedRoom) {
+        self.set_matrix_room(self.session().client().get_room(self.room_id()).unwrap());
 
         self.handle_invite_events(
             response_room
@@ -822,16 +801,4 @@ impl Room {
                 .collect(),
         )
     }
-
-    pub fn connect_error<F: Fn(&Self, Error) + 'static>(&self, f: F) -> glib::SignalHandlerId {
-        self.connect_local("error", true, move |values| {
-            let obj = values[0].get::<Self>().unwrap();
-            let error = values[1].get::<Error>().unwrap();
-
-            f(&obj, error);
-
-            None
-        })
-        .unwrap()
-    }
 }
diff --git a/src/session/room_list.rs b/src/session/room_list.rs
index 9171176a..51228741 100644
--- a/src/session/room_list.rs
+++ b/src/session/room_list.rs
@@ -1,14 +1,10 @@
 use gtk::{gio, glib, glib::clone, prelude::*, subclass::prelude::*};
 use indexmap::map::IndexMap;
-use matrix_sdk::{deserialized_responses::Rooms as ResponseRooms, identifiers::RoomId, Client};
+use matrix_sdk::{deserialized_responses::Rooms as ResponseRooms, identifiers::RoomId};
 
-use crate::{
-    session::{room::Room, user::User},
-    Error,
-};
+use crate::session::{room::Room, Session};
 
 mod imp {
-    use glib::subclass::Signal;
     use once_cell::sync::{Lazy, OnceCell};
     use std::cell::RefCell;
 
@@ -17,8 +13,7 @@ mod imp {
     #[derive(Debug, Default)]
     pub struct RoomList {
         pub list: RefCell<IndexMap<RoomId, Room>>,
-        pub client: OnceCell<Client>,
-        pub user: OnceCell<User>,
+        pub session: OnceCell<Session>,
     }
 
     #[glib::object_subclass]
@@ -30,16 +25,38 @@ mod imp {
     }
 
     impl ObjectImpl for RoomList {
-        fn signals() -> &'static [Signal] {
-            static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
-                vec![Signal::builder(
-                    "error",
-                    &[Error::static_type().into()],
-                    <()>::static_type().into(),
-                )
-                .build()]
+        fn properties() -> &'static [glib::ParamSpec] {
+            static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+                vec![glib::ParamSpec::new_object(
+                    "session",
+                    "Session",
+                    "The session",
+                    Session::static_type(),
+                    glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+                )]
             });
-            SIGNALS.as_ref()
+
+            PROPERTIES.as_ref()
+        }
+
+        fn set_property(
+            &self,
+            _obj: &Self::Type,
+            _id: usize,
+            value: &glib::Value,
+            pspec: &glib::ParamSpec,
+        ) {
+            match pspec.name() {
+                "session" => self.session.set(value.get().unwrap()).unwrap(),
+                _ => unimplemented!(),
+            }
+        }
+
+        fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+            match pspec.name() {
+                "session" => obj.session().to_value(),
+                _ => unimplemented!(),
+            }
         }
     }
 
@@ -66,25 +83,14 @@ glib::wrapper! {
         @implements gio::ListModel;
 }
 
-impl Default for RoomList {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
 impl RoomList {
-    pub fn new() -> Self {
-        glib::Object::new(&[]).expect("Failed to create RoomList")
+    pub fn new(session: &Session) -> Self {
+        glib::Object::new(&[("session", session)]).expect("Failed to create RoomList")
     }
 
-    pub fn set_client(&self, client: Client) -> Result<(), Client> {
+    pub fn session(&self) -> &Session {
         let priv_ = imp::RoomList::from_instance(&self);
-        priv_.client.set(client)
-    }
-
-    pub fn set_user(&self, user: User) -> Result<(), User> {
-        let priv_ = imp::RoomList::from_instance(&self);
-        priv_.user.set(user)
+        priv_.session.get().unwrap()
     }
 
     pub fn get(&self, room_id: &RoomId) -> Option<Room> {
@@ -131,15 +137,11 @@ impl RoomList {
             room.connect_notify_local(
                 Some("category"),
                 clone!(@weak self as obj => move |r, _| {
-                    if let Some((position, _, _)) = obj.get_full(&r.matrix_room_id()) {
+                    if let Some((position, _, _)) = obj.get_full(&r.room_id()) {
                         obj.items_changed(position as u32, 1, 1);
                     }
                 }),
             );
-
-            room.connect_error(clone!(@weak self as obj => move |_, error| {
-                obj.emit_by_name("error", &[&error]).unwrap();
-            }));
         }
 
         self.items_changed(position as u32, 0, added as u32);
@@ -151,17 +153,18 @@ impl RoomList {
     /// loading much via this function.
     pub fn load(&self) {
         let priv_ = imp::RoomList::from_instance(&self);
-
-        let matrix_rooms = priv_.client.get().unwrap().rooms();
+        let session = self.session();
+        let client = session.client();
+        let matrix_rooms = client.rooms();
         let added = matrix_rooms.len();
 
         if added > 0 {
             {
                 let mut list = priv_.list.borrow_mut();
                 for matrix_room in matrix_rooms {
-                    let room = Room::new(matrix_room, priv_.user.get().unwrap());
-
-                    list.insert(room.matrix_room_id(), room);
+                    let room_id = matrix_room.room_id().to_owned();
+                    let room = Room::new(session, &room_id);
+                    list.insert(room_id, room);
                 }
             }
 
@@ -171,71 +174,54 @@ impl RoomList {
 
     pub fn handle_response_rooms(&self, rooms: ResponseRooms) {
         let priv_ = imp::RoomList::from_instance(&self);
+        let session = self.session();
 
         let mut added = 0;
 
         for (room_id, left_room) in rooms.leave {
-            let matrix_room = priv_.client.get().unwrap().get_room(&room_id).unwrap();
-
             let room = priv_
                 .list
                 .borrow_mut()
-                .entry(room_id)
+                .entry(room_id.clone())
                 .or_insert_with(|| {
                     added += 1;
-                    Room::new(matrix_room.clone(), priv_.user.get().unwrap())
+                    Room::new(session, &room_id)
                 })
                 .clone();
 
-            room.handle_left_response(left_room, matrix_room);
+            room.handle_left_response(left_room);
         }
 
         for (room_id, joined_room) in rooms.join {
-            let matrix_room = priv_.client.get().unwrap().get_room(&room_id).unwrap();
-
             let room = priv_
                 .list
                 .borrow_mut()
-                .entry(room_id)
+                .entry(room_id.clone())
                 .or_insert_with(|| {
                     added += 1;
-                    Room::new(matrix_room.clone(), priv_.user.get().unwrap())
+                    Room::new(session, &room_id)
                 })
                 .clone();
 
-            room.handle_joined_response(joined_room, matrix_room);
+            room.handle_joined_response(joined_room);
         }
 
         for (room_id, invited_room) in rooms.invite {
-            let matrix_room = priv_.client.get().unwrap().get_room(&room_id).unwrap();
-
             let room = priv_
                 .list
                 .borrow_mut()
-                .entry(room_id)
+                .entry(room_id.clone())
                 .or_insert_with(|| {
                     added += 1;
-                    Room::new(matrix_room.clone(), priv_.user.get().unwrap())
+                    Room::new(session, &room_id)
                 })
                 .clone();
 
-            room.handle_invited_response(invited_room, matrix_room);
+            room.handle_invited_response(invited_room);
         }
 
         if added > 0 {
             self.items_added(added);
         }
     }
-
-    pub fn connect_error<F: Fn(&Self, Error) + 'static>(&self, f: F) -> glib::SignalHandlerId {
-        self.connect_local("error", true, move |values| {
-            let obj = values[0].get::<Self>().unwrap();
-            let error = values[1].get::<Error>().unwrap();
-
-            f(&obj, error);
-
-            None
-        })
-        .unwrap()
-    }
 }
diff --git a/src/session/user.rs b/src/session/user.rs
index d31b8592..2cc4af30 100644
--- a/src/session/user.rs
+++ b/src/session/user.rs
@@ -1,5 +1,6 @@
 use gtk::{gio, glib, prelude::*, subclass::prelude::*};
 
+use crate::session::Session;
 use matrix_sdk::{
     events::{room::member::MemberEventContent, StateEvent, StrippedStateEvent},
     identifiers::UserId,
@@ -16,6 +17,7 @@ mod imp {
         pub user_id: OnceCell<String>,
         pub display_name: RefCell<Option<String>>,
         pub avatar: RefCell<Option<gio::LoadableIcon>>,
+        pub session: OnceCell<Session>,
     }
 
     #[glib::object_subclass]
@@ -50,6 +52,13 @@ mod imp {
                         gio::LoadableIcon::static_type(),
                         glib::ParamFlags::READABLE,
                     ),
+                    glib::ParamSpec::new_object(
+                        "session",
+                        "Session",
+                        "The session",
+                        Session::static_type(),
+                        glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+                    ),
                 ]
             });
 
@@ -68,6 +77,7 @@ mod imp {
                     let user_id = value.get().unwrap();
                     self.user_id.set(user_id).unwrap();
                 }
+                "session" => self.session.set(value.get().unwrap()).unwrap(),
                 _ => unimplemented!(),
             }
         }
@@ -77,6 +87,7 @@ mod imp {
                 "display-name" => obj.display_name().to_value(),
                 "user-id" => self.user_id.get().to_value(),
                 "avatar" => self.avatar.borrow().to_value(),
+                "session" => obj.session().to_value(),
                 _ => unimplemented!(),
             }
         }
@@ -89,8 +100,14 @@ glib::wrapper! {
 
 /// This is a `glib::Object` rapresentation of matrix users.
 impl User {
-    pub fn new(user_id: &UserId) -> Self {
-        glib::Object::new(&[("user-id", &user_id.to_string())]).expect("Failed to create User")
+    pub fn new(session: &Session, user_id: &UserId) -> Self {
+        glib::Object::new(&[("session", session), ("user-id", &user_id.to_string())])
+            .expect("Failed to create User")
+    }
+
+    pub fn session(&self) -> &Session {
+        let priv_ = imp::User::from_instance(&self);
+        priv_.session.get().unwrap()
     }
 
     pub fn user_id(&self) -> UserId {


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