use gtk::{glib, prelude::*, subclass::prelude::*};
use ruma::{OwnedDeviceId, OwnedUserId};
use url::Url;
use crate::{components::AvatarData, secret::StoredSession};
mod imp {
use std::{cell::OnceCell, marker::PhantomData};
use super::*;
#[repr(C)]
pub struct SessionInfoClass {
pub parent_class: glib::object::ObjectClass,
pub avatar_data: fn(&super::SessionInfo) -> AvatarData,
}
unsafe impl ClassStruct for SessionInfoClass {
type Type = SessionInfo;
}
pub(super) fn session_info_avatar_data(this: &super::SessionInfo) -> AvatarData {
let klass = this.class();
(klass.as_ref().avatar_data)(this)
}
#[derive(Debug, Default, glib::Properties)]
#[properties(wrapper_type = super::SessionInfo)]
pub struct SessionInfo {
#[property(get, construct_only)]
pub info: OnceCell<StoredSession>,
#[property(get = Self::user_id_string)]
pub user_id_string: PhantomData<String>,
#[property(get = Self::homeserver_string)]
pub homeserver_string: PhantomData<String>,
#[property(get = Self::device_id_string)]
pub device_id_string: PhantomData<String>,
#[property(get = Self::session_id)]
pub session_id: PhantomData<String>,
#[property(get = Self::avatar_data)]
pub avatar_data: PhantomData<AvatarData>,
}
#[glib::object_subclass]
impl ObjectSubclass for SessionInfo {
const NAME: &'static str = "SessionInfo";
const ABSTRACT: bool = true;
type Type = super::SessionInfo;
type Class = SessionInfoClass;
}
#[glib::derived_properties]
impl ObjectImpl for SessionInfo {}
impl SessionInfo {
pub fn info(&self) -> &StoredSession {
self.info.get().unwrap()
}
fn user_id_string(&self) -> String {
self.info().user_id.to_string()
}
fn homeserver_string(&self) -> String {
self.info().homeserver.to_string()
}
fn device_id_string(&self) -> String {
self.info().device_id.to_string()
}
fn session_id(&self) -> String {
self.info().id.clone()
}
fn avatar_data(&self) -> AvatarData {
session_info_avatar_data(&self.obj())
}
}
}
glib::wrapper! {
pub struct SessionInfo(ObjectSubclass<imp::SessionInfo>);
}
pub trait SessionInfoExt: 'static {
fn info(&self) -> &StoredSession;
fn user_id(&self) -> &OwnedUserId {
&self.info().user_id
}
fn homeserver(&self) -> &Url {
&self.info().homeserver
}
fn device_id(&self) -> &OwnedDeviceId {
&self.info().device_id
}
fn session_id(&self) -> &str {
&self.info().id
}
#[allow(dead_code)]
fn avatar_data(&self) -> AvatarData;
}
impl<O: IsA<SessionInfo>> SessionInfoExt for O {
fn info(&self) -> &StoredSession {
self.upcast_ref().imp().info()
}
fn avatar_data(&self) -> AvatarData {
imp::session_info_avatar_data(self.upcast_ref())
}
}
pub trait SessionInfoImpl: ObjectImpl {
fn avatar_data(&self) -> AvatarData;
}
unsafe impl<T> IsSubclassable<T> for SessionInfo
where
T: SessionInfoImpl,
T::Type: IsA<SessionInfo>,
{
fn class_init(class: &mut glib::Class<Self>) {
Self::parent_class_init::<T>(class.upcast_ref_mut());
let klass = class.as_mut();
klass.avatar_data = avatar_data_trampoline::<T>;
}
}
fn avatar_data_trampoline<T>(this: &SessionInfo) -> AvatarData
where
T: ObjectSubclass + SessionInfoImpl,
T::Type: IsA<SessionInfo>,
{
let this = this.downcast_ref::<T::Type>().unwrap();
this.imp().avatar_data()
}