You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

201 lines
6.4 KiB

use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext;
use gtk::{glib, glib::clone};
use crate::{
components::{Avatar, LoadingButton},
session::model::{Room, RoomCategory, TargetRoomCategory},
toast,
utils::matrix::MatrixIdUri,
};
mod imp {
use std::cell::RefCell;
use glib::subclass::InitializingObject;
use super::*;
#[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
#[template(resource = "/org/gnome/Fractal/ui/session_view/content/invite_request.ui")]
#[properties(wrapper_type = super::InviteRequest)]
pub struct InviteRequest {
#[template_child]
pub(super) header_bar: TemplateChild<adw::HeaderBar>,
#[template_child]
avatar: TemplateChild<Avatar>,
#[template_child]
room_alias: TemplateChild<gtk::Label>,
#[template_child]
room_topic: TemplateChild<gtk::Label>,
#[template_child]
retract_button: TemplateChild<LoadingButton>,
/// The room currently displayed.
#[property(get, set = Self::set_room, explicit_notify, nullable)]
room: RefCell<Option<Room>>,
category_handler: RefCell<Option<glib::SignalHandlerId>>,
}
#[glib::object_subclass]
impl ObjectSubclass for InviteRequest {
const NAME: &'static str = "ContentInviteRequest";
type Type = super::InviteRequest;
type ParentType = adw::Bin;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
Self::bind_template_callbacks(klass);
klass.set_accessible_role(gtk::AccessibleRole::Group);
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
#[glib::derived_properties]
impl ObjectImpl for InviteRequest {
fn constructed(&self) {
self.parent_constructed();
let obj = self.obj();
self.room_alias.connect_label_notify(|room_alias| {
room_alias.set_visible(!room_alias.label().is_empty());
});
self.room_alias
.set_visible(!self.room_alias.label().is_empty());
self.room_topic.connect_label_notify(|room_topic| {
room_topic.set_visible(!room_topic.label().is_empty());
});
self.room_topic
.set_visible(!self.room_topic.label().is_empty());
self.room_topic.connect_activate_link(clone!(
#[weak]
obj,
#[upgrade_or]
glib::Propagation::Proceed,
move |_, uri| {
if MatrixIdUri::parse(uri).is_ok() {
let _ =
obj.activate_action("session.show-matrix-uri", Some(&uri.to_variant()));
glib::Propagation::Stop
} else {
glib::Propagation::Proceed
}
}
));
}
fn dispose(&self) {
self.disconnect_signals();
}
}
impl WidgetImpl for InviteRequest {
fn grab_focus(&self) -> bool {
self.retract_button.grab_focus()
}
}
impl BinImpl for InviteRequest {}
#[gtk::template_callbacks]
impl InviteRequest {
/// Set the room currently displayed.
fn set_room(&self, room: Option<Room>) {
if *self.room.borrow() == room {
return;
}
self.disconnect_signals();
if let Some(room) = &room {
let category_handler = room.connect_category_notify(clone!(
#[weak(rename_to = imp)]
self,
move |room| {
let category = room.category();
if category == RoomCategory::Left {
// We retracted the request or the request was denied, 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 selection
.selected_item()
.and_downcast::<Room>()
.is_some_and(|selected_room| selected_room == *room)
{
selection.set_selected_item(None::<glib::Object>);
}
}
if category != RoomCategory::Knocked {
imp.retract_button.set_is_loading(false);
if let Some(category_handler) = imp.category_handler.take() {
room.disconnect(category_handler);
}
}
}
));
self.category_handler.replace(Some(category_handler));
}
self.room.replace(room);
self.obj().notify_room();
}
/// Retract the request.
#[template_callback]
async fn retract(&self) {
let Some(room) = self.room.borrow().clone() else {
return;
};
self.retract_button.set_is_loading(true);
if room
.change_category(TargetRoomCategory::Left)
.await
.is_err()
{
toast!(self.obj(), gettext("Could not retract invite request",),);
self.retract_button.set_is_loading(false);
}
}
/// Disconnect the signal handlers of this view.
fn disconnect_signals(&self) {
if let Some(room) = self.room.take()
&& let Some(handler) = self.category_handler.take()
{
room.disconnect(handler);
}
}
}
}
glib::wrapper! {
/// A view presenting an invitate request to a room.
pub struct InviteRequest(ObjectSubclass<imp::InviteRequest>)
@extends gtk::Widget, adw::Bin,
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
}
impl InviteRequest {
pub fn new() -> Self {
glib::Object::new()
}
/// The header bar of the invite request.
pub fn header_bar(&self) -> &adw::HeaderBar {
&self.imp().header_bar
}
}