read-receipts-list: Implement as a toggle button instead of using a child
Improves the location where the popover points to. Improves the a11y by removing children from the tree.
This commit is contained in:
parent
d70e8d3f4e
commit
971e1c2c33
3 changed files with 101 additions and 34 deletions
|
@ -505,6 +505,25 @@ message-reactions .reaction-count {
|
|||
padding: 2px;
|
||||
}
|
||||
|
||||
read-receipts-list {
|
||||
min-height: 24px;
|
||||
min-width: 16px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
read-receipts-list:hover {
|
||||
background-color: alpha(currentColor, .07);
|
||||
}
|
||||
|
||||
read-receipts-list:active {
|
||||
background-color: alpha(currentColor, .16);
|
||||
}
|
||||
|
||||
read-receipts-list:checked {
|
||||
background-color: alpha(currentColor, .1);
|
||||
}
|
||||
|
||||
read-receipts-list .cutout {
|
||||
background-color: @view_bg_color;
|
||||
border-radius: 999px;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use adw::subclass::prelude::*;
|
||||
use gtk::{gio, glib, glib::clone, prelude::*, CompositeTemplate};
|
||||
use gtk::{gdk, gio, glib, glib::clone, prelude::*, CompositeTemplate};
|
||||
|
||||
mod read_receipts_popover;
|
||||
|
||||
|
@ -18,7 +18,7 @@ use crate::{
|
|||
const MAX_RECEIPTS_SHOWN: u32 = 10;
|
||||
|
||||
mod imp {
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use glib::subclass::InitializingObject;
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -30,12 +30,14 @@ mod imp {
|
|||
resource = "/org/gnome/Fractal/ui/session/view/content/room_history/read_receipts_list/mod.ui"
|
||||
)]
|
||||
pub struct ReadReceiptsList {
|
||||
#[template_child]
|
||||
pub toggle_button: TemplateChild<gtk::ToggleButton>,
|
||||
#[template_child]
|
||||
pub label: TemplateChild<gtk::Label>,
|
||||
#[template_child]
|
||||
pub avatar_list: TemplateChild<OverlappingAvatars>,
|
||||
/// Whether this list is active.
|
||||
///
|
||||
/// This list is active when the popover is displayed.
|
||||
pub active: Cell<bool>,
|
||||
/// The list of room members.
|
||||
pub members: RefCell<Option<MemberList>>,
|
||||
/// The list of read receipts.
|
||||
|
@ -49,9 +51,9 @@ mod imp {
|
|||
impl Default for ReadReceiptsList {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
toggle_button: Default::default(),
|
||||
label: Default::default(),
|
||||
avatar_list: Default::default(),
|
||||
active: Default::default(),
|
||||
members: Default::default(),
|
||||
list: gio::ListStore::new::<MemberTimestamp>(),
|
||||
source: Default::default(),
|
||||
|
@ -71,6 +73,7 @@ mod imp {
|
|||
Self::Type::bind_template_callbacks(klass);
|
||||
|
||||
klass.set_css_name("read-receipts-list");
|
||||
klass.set_accessible_role(gtk::AccessibleRole::ToggleButton);
|
||||
}
|
||||
|
||||
fn instance_init(obj: &InitializingObject<Self>) {
|
||||
|
@ -82,6 +85,9 @@ mod imp {
|
|||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![
|
||||
glib::ParamSpecBoolean::builder("active")
|
||||
.read_only()
|
||||
.build(),
|
||||
glib::ParamSpecObject::builder::<MemberList>("members").build(),
|
||||
glib::ParamSpecObject::builder::<gio::ListStore>("list")
|
||||
.read_only()
|
||||
|
@ -96,6 +102,7 @@ mod imp {
|
|||
let obj = self.obj();
|
||||
|
||||
match pspec.name() {
|
||||
"active" => obj.active().to_value(),
|
||||
"members" => obj.members().to_value(),
|
||||
"list" => obj.list().to_value(),
|
||||
_ => unimplemented!(),
|
||||
|
@ -128,6 +135,8 @@ mod imp {
|
|||
obj.update_tooltip();
|
||||
obj.update_label();
|
||||
}));
|
||||
|
||||
obj.set_pressed_state(false);
|
||||
}
|
||||
|
||||
fn dispose(&self) {
|
||||
|
@ -137,6 +146,13 @@ mod imp {
|
|||
|
||||
impl WidgetImpl for ReadReceiptsList {}
|
||||
impl BinImpl for ReadReceiptsList {}
|
||||
|
||||
impl AccessibleImpl for ReadReceiptsList {
|
||||
fn first_accessible_child(&self) -> Option<gtk::Accessible> {
|
||||
// Hide the children in the a11y tree.
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
|
@ -151,6 +167,40 @@ impl ReadReceiptsList {
|
|||
glib::Object::builder().property("members", members).build()
|
||||
}
|
||||
|
||||
/// Whether this list is active.
|
||||
///
|
||||
/// This list is active when the popover is displayed.
|
||||
pub fn active(&self) -> bool {
|
||||
self.imp().active.get()
|
||||
}
|
||||
|
||||
/// Set whether this list is active.
|
||||
fn set_active(&self, active: bool) {
|
||||
if self.active() == active {
|
||||
return;
|
||||
}
|
||||
|
||||
self.imp().active.set(active);
|
||||
self.notify("active");
|
||||
self.set_pressed_state(active);
|
||||
}
|
||||
|
||||
/// Set the CSS and a11 states.
|
||||
fn set_pressed_state(&self, pressed: bool) {
|
||||
if pressed {
|
||||
self.set_state_flags(gtk::StateFlags::CHECKED, false);
|
||||
} else {
|
||||
self.unset_state_flags(gtk::StateFlags::CHECKED);
|
||||
}
|
||||
|
||||
let tristate = if pressed {
|
||||
gtk::AccessibleTristate::True
|
||||
} else {
|
||||
gtk::AccessibleTristate::False
|
||||
};
|
||||
self.update_state(&[gtk::accessible::State::Pressed(tristate)]);
|
||||
}
|
||||
|
||||
/// The list of room members.
|
||||
pub fn members(&self) -> Option<MemberList> {
|
||||
self.imp().members.borrow().clone()
|
||||
|
@ -253,7 +303,7 @@ impl ReadReceiptsList {
|
|||
)
|
||||
});
|
||||
|
||||
self.imp().toggle_button.set_tooltip_text(text.as_deref())
|
||||
self.set_tooltip_text(text.as_deref())
|
||||
}
|
||||
|
||||
fn update_member_tooltip(&self, member: &Member) {
|
||||
|
@ -261,7 +311,7 @@ impl ReadReceiptsList {
|
|||
// variable name.
|
||||
let text = gettext_f("Seen by {name}", &[("name", &member.display_name())]);
|
||||
|
||||
self.imp().toggle_button.set_tooltip_text(Some(&text));
|
||||
self.set_tooltip_text(Some(&text));
|
||||
}
|
||||
|
||||
fn update_label(&self) {
|
||||
|
@ -280,18 +330,19 @@ impl ReadReceiptsList {
|
|||
///
|
||||
/// Shows a popover with the list of receipts if there are any.
|
||||
#[template_callback]
|
||||
fn show_popover(&self) {
|
||||
fn show_popover(&self, _n_press: i32, x: f64, y: f64) {
|
||||
if self.list().n_items() == 0 {
|
||||
// No popover.
|
||||
return;
|
||||
}
|
||||
self.set_active(true);
|
||||
|
||||
let toggle_button = &*self.imp().toggle_button;
|
||||
let popover = ReadReceiptsPopover::new(self.list());
|
||||
popover.set_parent(toggle_button);
|
||||
popover.connect_closed(clone!(@weak toggle_button => move |popover| {
|
||||
popover.set_parent(self);
|
||||
popover.set_pointing_to(Some(&gdk::Rectangle::new(x as i32, y as i32, 0, 0)));
|
||||
popover.connect_closed(clone!(@weak self as obj => move |popover| {
|
||||
popover.unparent();
|
||||
toggle_button.set_active(false);
|
||||
obj.set_active(false);
|
||||
}));
|
||||
|
||||
popover.popup();
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="ContentReadReceiptsList" parent="AdwBin">
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="toggle_button">
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
<property name="halign">end</property>
|
||||
<signal name="clicked" handler="show_popover" swapped="true"/>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">6</property>
|
||||
|
@ -27,6 +21,9 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGestureClick">
|
||||
<signal name="released" handler="show_popover" swapped="true"/>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
|
|
Loading…
Reference in a new issue