fractal/session_list/
session_info.rs1use gtk::{glib, prelude::*, subclass::prelude::*};
2use matrix_sdk::authentication::oauth::ClientId;
3use ruma::{OwnedDeviceId, OwnedUserId};
4use url::Url;
5
6use crate::{components::AvatarData, secret::StoredSession};
7
8mod imp {
9 use std::{cell::OnceCell, marker::PhantomData};
10
11 use super::*;
12
13 #[repr(C)]
14 pub struct SessionInfoClass {
15 parent_class: glib::object::ObjectClass,
16 pub(super) avatar_data: fn(&super::SessionInfo) -> AvatarData,
17 }
18
19 unsafe impl ClassStruct for SessionInfoClass {
20 type Type = SessionInfo;
21 }
22
23 pub(super) fn session_info_avatar_data(this: &super::SessionInfo) -> AvatarData {
24 let klass = this.class();
25 (klass.as_ref().avatar_data)(this)
26 }
27
28 #[derive(Debug, Default, glib::Properties)]
29 #[properties(wrapper_type = super::SessionInfo)]
30 pub struct SessionInfo {
31 #[property(get, construct_only)]
33 info: OnceCell<StoredSession>,
34 #[property(get = Self::user_id_string)]
36 user_id_string: PhantomData<String>,
37 #[property(get = Self::homeserver_string)]
39 homeserver_string: PhantomData<String>,
40 #[property(get = Self::device_id_string)]
42 device_id_string: PhantomData<String>,
43 #[property(get = Self::session_id)]
45 session_id: PhantomData<String>,
46 #[property(get = Self::avatar_data)]
48 avatar_data: PhantomData<AvatarData>,
49 }
50
51 #[glib::object_subclass]
52 impl ObjectSubclass for SessionInfo {
53 const NAME: &'static str = "SessionInfo";
54 const ABSTRACT: bool = true;
55 type Type = super::SessionInfo;
56 type Class = SessionInfoClass;
57 }
58
59 #[glib::derived_properties]
60 impl ObjectImpl for SessionInfo {}
61
62 impl SessionInfo {
63 pub(super) fn info(&self) -> &StoredSession {
65 self.info.get().expect("info is initialized")
66 }
67
68 fn user_id_string(&self) -> String {
70 self.info().user_id.to_string()
71 }
72
73 fn homeserver_string(&self) -> String {
75 self.info().homeserver.to_string()
76 }
77
78 fn device_id_string(&self) -> String {
80 self.info().device_id.to_string()
81 }
82
83 fn session_id(&self) -> String {
85 self.info().id.clone()
86 }
87
88 fn avatar_data(&self) -> AvatarData {
90 session_info_avatar_data(&self.obj())
91 }
92 }
93}
94
95glib::wrapper! {
96 pub struct SessionInfo(ObjectSubclass<imp::SessionInfo>);
100}
101
102pub trait SessionInfoExt: 'static {
108 fn info(&self) -> &StoredSession;
110
111 fn user_id(&self) -> &OwnedUserId {
113 &self.info().user_id
114 }
115
116 fn homeserver(&self) -> &Url {
118 &self.info().homeserver
119 }
120
121 fn client_id(&self) -> Option<&ClientId> {
123 self.info().client_id.as_ref()
124 }
125
126 fn uses_oauth_api(&self) -> bool {
128 self.client_id().is_some()
129 }
130
131 fn device_id(&self) -> &OwnedDeviceId {
133 &self.info().device_id
134 }
135
136 fn session_id(&self) -> &str {
138 &self.info().id
139 }
140
141 #[allow(dead_code)]
143 fn avatar_data(&self) -> AvatarData;
144}
145
146impl<O: IsA<SessionInfo>> SessionInfoExt for O {
147 fn info(&self) -> &StoredSession {
148 self.upcast_ref().imp().info()
149 }
150
151 fn avatar_data(&self) -> AvatarData {
152 imp::session_info_avatar_data(self.upcast_ref())
153 }
154}
155
156pub trait SessionInfoImpl: ObjectImpl {
162 fn avatar_data(&self) -> AvatarData;
163}
164
165unsafe impl<T> IsSubclassable<T> for SessionInfo
167where
168 T: SessionInfoImpl,
169 T::Type: IsA<SessionInfo>,
170{
171 fn class_init(class: &mut glib::Class<Self>) {
172 Self::parent_class_init::<T>(class.upcast_ref_mut());
173 let klass = class.as_mut();
174
175 klass.avatar_data = avatar_data_trampoline::<T>;
176 }
177}
178
179fn avatar_data_trampoline<T>(this: &SessionInfo) -> AvatarData
181where
182 T: ObjectSubclass + SessionInfoImpl,
183 T::Type: IsA<SessionInfo>,
184{
185 let this = this.downcast_ref::<T::Type>().unwrap();
186 this.imp().avatar_data()
187}