fractal/session/view/content/room_details/permissions/
member_row.rsuse gtk::{glib, glib::clone, prelude::*, subclass::prelude::*, CompositeTemplate};
use super::MemberPowerLevel;
use crate::{
components::{Avatar, PowerLevelSelectionPopover, RoleBadge},
session::model::Permissions,
utils::{key_bindings, BoundObject},
};
mod imp {
use std::cell::OnceCell;
use glib::subclass::InitializingObject;
use super::*;
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
#[template(
resource = "/org/gnome/Fractal/ui/session/view/content/room_details/permissions/member_row.ui"
)]
#[properties(wrapper_type = super::PermissionsMemberRow)]
pub struct PermissionsMemberRow {
#[template_child]
selected_level_label: TemplateChild<gtk::Label>,
#[template_child]
arrow_box: TemplateChild<gtk::Box>,
#[template_child]
popover: TemplateChild<PowerLevelSelectionPopover>,
#[property(get, set = Self::set_permissions, construct_only)]
permissions: OnceCell<Permissions>,
#[property(get, set = Self::set_member, explicit_notify, nullable)]
member: BoundObject<MemberPowerLevel>,
}
#[glib::object_subclass]
impl ObjectSubclass for PermissionsMemberRow {
const NAME: &'static str = "RoomDetailsPermissionsMemberRow";
type Type = super::PermissionsMemberRow;
type ParentType = gtk::Box;
fn class_init(klass: &mut Self::Class) {
Avatar::ensure_type();
RoleBadge::ensure_type();
Self::bind_template(klass);
Self::bind_template_callbacks(klass);
klass.set_css_name("permissions-member-row");
klass.install_action("permissions-member.activate", None, |obj, _, _| {
obj.imp().activate_row();
});
key_bindings::add_activate_bindings(klass, "permissions-member.activate");
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
#[glib::derived_properties]
impl ObjectImpl for PermissionsMemberRow {}
impl WidgetImpl for PermissionsMemberRow {
fn focus(&self, _direction_type: gtk::DirectionType) -> bool {
let obj = self.obj();
if obj.is_focus() {
false
} else {
obj.grab_focus()
}
}
}
impl BoxImpl for PermissionsMemberRow {}
#[gtk::template_callbacks]
impl PermissionsMemberRow {
fn set_permissions(&self, permissions: Permissions) {
self.permissions.set(permissions.clone()).unwrap();
self.popover.set_permissions(Some(permissions));
}
fn set_member(&self, member: Option<MemberPowerLevel>) {
if self.member.obj() == member {
return;
}
self.member.disconnect_signals();
if let Some(member) = member {
let power_level_handler = member.connect_power_level_notify(clone!(
#[weak(rename_to = imp)]
self,
move |_| {
imp.update_power_level();
}
));
let editable_handler = member.connect_editable_notify(clone!(
#[weak(rename_to = imp)]
self,
move |_| {
imp.update_accessible_role();
}
));
self.member
.set(member, vec![power_level_handler, editable_handler]);
self.update_power_level();
self.update_accessible_role();
}
self.obj().notify_member();
}
fn update_power_level(&self) {
let Some(member) = self.member.obj() else {
return;
};
self.selected_level_label
.set_label(&member.power_level().to_string());
}
fn update_accessible_role(&self) {
let Some(member) = self.member.obj() else {
return;
};
let editable = member.editable();
let role = if editable {
gtk::AccessibleRole::ComboBox
} else {
gtk::AccessibleRole::ListItem
};
self.obj().set_accessible_role(role);
self.arrow_box.set_opacity(editable.into());
}
#[template_callback]
fn activate_row(&self) {
let Some(member) = self.member.obj() else {
return;
};
if member.editable() {
self.popover.popup();
}
}
#[template_callback]
fn popover_visible(&self) {
let obj = self.obj();
let is_visible = self.popover.is_visible();
if is_visible {
obj.add_css_class("has-open-popup");
} else {
obj.remove_css_class("has-open-popup");
}
}
#[template_callback]
fn power_level_changed(&self) {
let Some(member) = self.member.obj() else {
return;
};
let pl = self.popover.selected_power_level();
member.set_power_level(pl);
}
}
}
glib::wrapper! {
pub struct PermissionsMemberRow(ObjectSubclass<imp::PermissionsMemberRow>)
@extends gtk::Widget, gtk::Box, @implements gtk::Accessible;
}
impl PermissionsMemberRow {
pub fn new(permissions: &Permissions) -> Self {
glib::Object::builder()
.property("permissions", permissions)
.build()
}
}