use gtk::{glib, glib::clone, prelude::*, subclass::prelude::*};
use matrix_sdk::ruma::directory::PublicRoomsChunk;
use crate::{
components::{AvatarData, AvatarImage, AvatarUriSource},
session::model::{Room, RoomList},
};
mod imp {
use std::cell::{Cell, OnceCell, RefCell};
use glib::signal::SignalHandlerId;
use super::*;
#[derive(Debug, Default, glib::Properties)]
#[properties(wrapper_type = super::PublicRoom)]
pub struct PublicRoom {
#[property(get, construct_only)]
pub room_list: OnceCell<RoomList>,
#[property(get, construct_only)]
pub server: OnceCell<String>,
pub matrix_public_room: OnceCell<PublicRoomsChunk>,
#[property(get)]
pub avatar_data: OnceCell<AvatarData>,
#[property(get)]
pub room: RefCell<Option<Room>>,
#[property(get)]
pub pending: Cell<bool>,
pub room_handler: RefCell<Option<SignalHandlerId>>,
}
#[glib::object_subclass]
impl ObjectSubclass for PublicRoom {
const NAME: &'static str = "PublicRoom";
type Type = super::PublicRoom;
}
#[glib::derived_properties]
impl ObjectImpl for PublicRoom {
fn constructed(&self) {
self.parent_constructed();
let obj = self.obj();
let avatar_data = if let Some(session) = obj.room_list().session() {
AvatarData::with_image(AvatarImage::new(
&session,
AvatarUriSource::Room,
None,
None,
))
} else {
AvatarData::new()
};
self.avatar_data.set(avatar_data).unwrap();
obj.room_list().connect_pending_rooms_changed(clone!(
#[weak]
obj,
move |_| {
let Some(matrix_public_room) = obj.matrix_public_room() else {
return;
};
obj.set_pending(
obj.room_list()
.is_pending_room((*matrix_public_room.room_id).into()),
);
}
));
}
fn dispose(&self) {
if let Some(handler_id) = self.room_handler.take() {
self.obj().room_list().disconnect(handler_id);
}
}
}
}
glib::wrapper! {
pub struct PublicRoom(ObjectSubclass<imp::PublicRoom>);
}
impl PublicRoom {
pub fn new(room_list: &RoomList, server: &str) -> Self {
glib::Object::builder()
.property("room-list", room_list)
.property("server", server)
.build()
}
fn set_room(&self, room: Room) {
self.imp().room.replace(Some(room));
self.notify_room();
}
fn set_pending(&self, pending: bool) {
if self.pending() == pending {
return;
}
self.imp().pending.set(pending);
self.notify_pending();
}
pub fn set_matrix_public_room(&self, room: PublicRoomsChunk) {
let imp = self.imp();
if let Some(display_name) = room.name.clone() {
self.avatar_data().set_display_name(display_name);
}
self.avatar_data()
.image()
.unwrap()
.set_uri_and_info(room.avatar_url.clone(), None);
if let Some(room) = self.room_list().get(&room.room_id) {
self.set_room(room);
} else {
let room_id = room.room_id.clone();
let handler_id = self.room_list().connect_items_changed(clone!(
#[weak(rename_to = obj)]
self,
move |room_list, _, _, _| {
if let Some(room) = room_list.get(&room_id) {
if let Some(handler_id) = obj.imp().room_handler.take() {
obj.set_room(room);
room_list.disconnect(handler_id);
}
}
}
));
imp.room_handler.replace(Some(handler_id));
}
self.set_pending(self.room_list().is_pending_room((*room.room_id).into()));
imp.matrix_public_room.set(room).unwrap();
}
pub fn matrix_public_room(&self) -> Option<&PublicRoomsChunk> {
self.imp().matrix_public_room.get()
}
pub fn display_name(&self) -> String {
let Some(matrix_public_room) = self.matrix_public_room() else {
return String::new();
};
matrix_public_room
.name
.as_deref()
.or(matrix_public_room
.canonical_alias
.as_ref()
.map(|a| a.as_str()))
.unwrap_or_else(|| matrix_public_room.room_id.as_str())
.to_owned()
}
}