mirror of
https://gitlab.gnome.org/World/fractal.git
synced 2025-06-06 00:01:12 -04:00
Merge branch 'kcommaille/safety-pills' into 'main'
room-history: Make sure that mentions respect safety settings See merge request World/fractal!2024
This commit is contained in:
commit
6bf856ef0d
@ -16,9 +16,33 @@ pub use self::{
|
||||
};
|
||||
use crate::{
|
||||
components::AnimatedImagePaintable,
|
||||
session::model::Room,
|
||||
utils::{BoundObject, BoundObjectWeakRef, CountedRef},
|
||||
};
|
||||
|
||||
/// The safety setting to watch to decide whether the image of the avatar should
|
||||
/// be displayed.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, glib::Enum, Default)]
|
||||
#[enum_type(name = "AvatarImageSafetySetting")]
|
||||
pub enum AvatarImageSafetySetting {
|
||||
/// No setting needs to be watched, the image is always shown when
|
||||
/// available.
|
||||
#[default]
|
||||
None,
|
||||
|
||||
/// The media previews safety setting should be watched, with the image only
|
||||
/// shown when allowed.
|
||||
///
|
||||
/// This setting also requires the [`Room`] where the avatar is presented.
|
||||
MediaPreviews,
|
||||
|
||||
/// The invite avatars safety setting should be watched, with the image only
|
||||
/// shown when allowed.
|
||||
///
|
||||
/// This setting also requires the [`Room`] where the avatar is presented.
|
||||
InviteAvatars,
|
||||
}
|
||||
|
||||
mod imp {
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
@ -44,13 +68,19 @@ mod imp {
|
||||
/// The size of the Avatar.
|
||||
#[property(get = Self::size, set = Self::set_size, explicit_notify, builder().default_value(-1).minimum(-1))]
|
||||
size: PhantomData<i32>,
|
||||
/// Whether to inhibit the image of the avatar.
|
||||
/// The safety setting to watch to decide whether the image of the
|
||||
/// avatar should be displayed.
|
||||
#[property(get, set = Self::set_watched_safety_setting, explicit_notify, builder(AvatarImageSafetySetting::default()))]
|
||||
watched_safety_setting: Cell<AvatarImageSafetySetting>,
|
||||
/// The room to watch to apply the current safety settings.
|
||||
///
|
||||
/// If the image is inhibited, it will not be loaded.
|
||||
#[property(get, set = Self::set_inhibit_image, explicit_notify)]
|
||||
inhibit_image: Cell<bool>,
|
||||
/// This is required if `watched_safety_setting` is not `None`.
|
||||
#[property(get, set = Self::set_watched_room, explicit_notify, nullable)]
|
||||
watched_room: RefCell<Option<Room>>,
|
||||
paintable_ref: RefCell<Option<CountedRef>>,
|
||||
paintable_animation_ref: RefCell<Option<CountedRef>>,
|
||||
watched_room_handler: RefCell<Option<glib::SignalHandlerId>>,
|
||||
watched_session_settings_handler: RefCell<Option<glib::SignalHandlerId>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
@ -74,7 +104,11 @@ mod imp {
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for Avatar {}
|
||||
impl ObjectImpl for Avatar {
|
||||
fn dispose(&self) {
|
||||
self.disconnect_safety_setting_signals();
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for Avatar {
|
||||
fn map(&self) {
|
||||
@ -116,16 +150,134 @@ mod imp {
|
||||
self.obj().notify_size();
|
||||
}
|
||||
|
||||
/// Set whether to inhibit the image of the avatar.
|
||||
fn set_inhibit_image(&self, inhibit: bool) {
|
||||
if self.inhibit_image.get() == inhibit {
|
||||
/// Set the safety setting to watch to decide whether the image of the
|
||||
/// avatar should be displayed.
|
||||
fn set_watched_safety_setting(&self, setting: AvatarImageSafetySetting) {
|
||||
if self.watched_safety_setting.get() == setting {
|
||||
return;
|
||||
}
|
||||
|
||||
self.inhibit_image.set(inhibit);
|
||||
self.disconnect_safety_setting_signals();
|
||||
|
||||
self.watched_safety_setting.set(setting);
|
||||
|
||||
self.connect_safety_setting_signals();
|
||||
self.obj().notify_watched_safety_setting();
|
||||
}
|
||||
|
||||
/// Set the room to watch to apply the current safety settings.
|
||||
fn set_watched_room(&self, room: Option<Room>) {
|
||||
if *self.watched_room.borrow() == room {
|
||||
return;
|
||||
}
|
||||
|
||||
self.disconnect_safety_setting_signals();
|
||||
|
||||
self.watched_room.replace(room);
|
||||
|
||||
self.connect_safety_setting_signals();
|
||||
self.obj().notify_watched_room();
|
||||
}
|
||||
|
||||
/// Connect to the proper signals for the current safety setting.
|
||||
fn connect_safety_setting_signals(&self) {
|
||||
let Some(room) = self.watched_room.borrow().clone() else {
|
||||
return;
|
||||
};
|
||||
let Some(session) = room.session() else {
|
||||
return;
|
||||
};
|
||||
|
||||
match self.watched_safety_setting.get() {
|
||||
AvatarImageSafetySetting::None => {}
|
||||
AvatarImageSafetySetting::MediaPreviews => {
|
||||
let room_handler = room.connect_join_rule_notify(clone!(
|
||||
#[weak(rename_to = imp)]
|
||||
self,
|
||||
move |_| {
|
||||
imp.update_paintable();
|
||||
}
|
||||
));
|
||||
self.watched_room_handler.replace(Some(room_handler));
|
||||
|
||||
let session_settings_handler = session
|
||||
.settings()
|
||||
.connect_media_previews_enabled_changed(clone!(
|
||||
#[weak(rename_to = imp)]
|
||||
self,
|
||||
move |_| {
|
||||
imp.update_paintable();
|
||||
}
|
||||
));
|
||||
self.watched_session_settings_handler
|
||||
.replace(Some(session_settings_handler));
|
||||
}
|
||||
AvatarImageSafetySetting::InviteAvatars => {
|
||||
let room_handler = room.connect_is_invite_notify(clone!(
|
||||
#[weak(rename_to = imp)]
|
||||
self,
|
||||
move |_| {
|
||||
imp.update_paintable();
|
||||
}
|
||||
));
|
||||
self.watched_room_handler.replace(Some(room_handler));
|
||||
|
||||
let session_settings_handler = session
|
||||
.settings()
|
||||
.connect_invite_avatars_enabled_notify(clone!(
|
||||
#[weak(rename_to = imp)]
|
||||
self,
|
||||
move |_| {
|
||||
imp.update_paintable();
|
||||
}
|
||||
));
|
||||
self.watched_session_settings_handler
|
||||
.replace(Some(session_settings_handler));
|
||||
}
|
||||
}
|
||||
|
||||
self.update_paintable();
|
||||
self.obj().notify_inhibit_image();
|
||||
}
|
||||
|
||||
/// Disconnect the handlers for the signals of the safety setting.
|
||||
fn disconnect_safety_setting_signals(&self) {
|
||||
if let Some(room) = self.watched_room.borrow().as_ref() {
|
||||
if let Some(handler) = self.watched_room_handler.take() {
|
||||
room.disconnect(handler);
|
||||
}
|
||||
|
||||
if let Some(handler) = self.watched_session_settings_handler.take() {
|
||||
room.session()
|
||||
.inspect(|session| session.settings().disconnect(handler));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether we can display the image of the avatar with the current
|
||||
/// state.
|
||||
fn can_show_image(&self) -> bool {
|
||||
let watched_safety_setting = self.watched_safety_setting.get();
|
||||
|
||||
if watched_safety_setting == AvatarImageSafetySetting::None {
|
||||
return true;
|
||||
}
|
||||
|
||||
let Some(room) = self.watched_room.borrow().clone() else {
|
||||
return false;
|
||||
};
|
||||
let Some(session) = room.session() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
match watched_safety_setting {
|
||||
AvatarImageSafetySetting::None => unreachable!(),
|
||||
AvatarImageSafetySetting::MediaPreviews => {
|
||||
session.settings().should_room_show_media_previews(&room)
|
||||
}
|
||||
AvatarImageSafetySetting::InviteAvatars => {
|
||||
!room.is_invite() || session.settings().invite_avatars_enabled()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the [`AvatarData`] displayed by this widget.
|
||||
@ -208,7 +360,7 @@ mod imp {
|
||||
fn update_paintable(&self) {
|
||||
let _old_paintable_ref = self.paintable_ref.take();
|
||||
|
||||
if self.inhibit_image.get() {
|
||||
if !self.can_show_image() {
|
||||
// We need to unset the paintable.
|
||||
self.avatar.set_custom_image(None::<&gdk::Paintable>);
|
||||
self.update_animated_paintable_state();
|
||||
@ -245,7 +397,7 @@ mod imp {
|
||||
fn update_animated_paintable_state(&self) {
|
||||
let _old_paintable_animation_ref = self.paintable_animation_ref.take();
|
||||
|
||||
if self.inhibit_image.get() || !self.obj().is_mapped() {
|
||||
if !self.can_show_image() || !self.obj().is_mapped() {
|
||||
// We do not need to animate the paintable.
|
||||
return;
|
||||
}
|
||||
|
@ -1,18 +1,20 @@
|
||||
use gettextrs::gettext;
|
||||
use gtk::{glib, subclass::prelude::*};
|
||||
use ruma::OwnedRoomId;
|
||||
use gtk::{glib, prelude::*, subclass::prelude::*};
|
||||
use ruma::RoomId;
|
||||
|
||||
use crate::{components::PillSource, prelude::*};
|
||||
use crate::{components::PillSource, prelude::*, session::model::Room};
|
||||
|
||||
mod imp {
|
||||
use std::cell::OnceCell;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug, Default, glib::Properties)]
|
||||
#[properties(wrapper_type = super::AtRoom)]
|
||||
pub struct AtRoom {
|
||||
/// The ID of the room currently represented.
|
||||
room_id: OnceCell<OwnedRoomId>,
|
||||
/// The room represented by this mention.
|
||||
#[property(get, set = Self::set_room, construct_only)]
|
||||
room: OnceCell<Room>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
@ -22,6 +24,7 @@ mod imp {
|
||||
type ParentType = PillSource;
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for AtRoom {}
|
||||
|
||||
impl PillSourceImpl for AtRoom {
|
||||
@ -31,14 +34,23 @@ mod imp {
|
||||
}
|
||||
|
||||
impl AtRoom {
|
||||
/// Set the ID of the room currently represented.
|
||||
pub(super) fn set_room_id(&self, room_id: OwnedRoomId) {
|
||||
self.room_id.set(room_id).expect("room ID is uninitialized");
|
||||
/// Set the room represented by this mention.
|
||||
fn set_room(&self, room: Room) {
|
||||
let room = self.room.get_or_init(|| room);
|
||||
|
||||
// Bind the avatar image so it always looks the same.
|
||||
room.avatar_data()
|
||||
.bind_property("image", &self.obj().avatar_data(), "image")
|
||||
.sync_create()
|
||||
.build();
|
||||
}
|
||||
|
||||
/// The ID of the room currently represented.
|
||||
pub(super) fn room_id(&self) -> &OwnedRoomId {
|
||||
self.room_id.get().expect("room ID is initialized")
|
||||
/// The ID of the room represented by this mention.
|
||||
pub(super) fn room_id(&self) -> &RoomId {
|
||||
self.room
|
||||
.get()
|
||||
.expect("room should be initialized")
|
||||
.room_id()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -49,19 +61,16 @@ glib::wrapper! {
|
||||
}
|
||||
|
||||
impl AtRoom {
|
||||
/// Constructs an empty `@room` mention.
|
||||
pub fn new(room_id: OwnedRoomId) -> Self {
|
||||
let obj = glib::Object::builder::<Self>()
|
||||
/// Constructs an `@room` mention for the given room.
|
||||
pub fn new(room: &Room) -> Self {
|
||||
glib::Object::builder()
|
||||
.property("display-name", "@room")
|
||||
.build();
|
||||
|
||||
obj.imp().set_room_id(room_id);
|
||||
|
||||
obj
|
||||
.property("room", room)
|
||||
.build()
|
||||
}
|
||||
|
||||
/// The ID of the room currently represented.
|
||||
pub fn room_id(&self) -> &OwnedRoomId {
|
||||
/// The ID of the room represented by this mention.
|
||||
pub fn room_id(&self) -> &RoomId {
|
||||
self.imp().room_id()
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ pub use self::{
|
||||
source::{PillSource, PillSourceExt, PillSourceImpl},
|
||||
source_row::PillSourceRow,
|
||||
};
|
||||
use super::{Avatar, RoomPreviewDialog, UserProfileDialog};
|
||||
use super::{Avatar, AvatarImageSafetySetting, RoomPreviewDialog, UserProfileDialog};
|
||||
use crate::{
|
||||
prelude::*,
|
||||
session::{
|
||||
@ -48,11 +48,15 @@ mod imp {
|
||||
/// Whether the pill can be activated.
|
||||
#[property(get, set = Self::set_activatable, explicit_notify)]
|
||||
activatable: Cell<bool>,
|
||||
/// Whether to inhibit the image of the avatar.
|
||||
/// The safety setting to watch to decide whether the image of the
|
||||
/// avatar should be displayed.
|
||||
#[property(get = Self::watched_safety_setting, set = Self::set_watched_safety_setting, builder(AvatarImageSafetySetting::default()))]
|
||||
watched_safety_setting: PhantomData<AvatarImageSafetySetting>,
|
||||
/// The room to watch to apply the current safety settings.
|
||||
///
|
||||
/// If the image is inhibited, it will not be loaded.
|
||||
#[property(get = Self::inhibit_image, set = Self::set_inhibit_image)]
|
||||
inhibit_image: PhantomData<bool>,
|
||||
/// This is required if `watched_safety_setting` is not `None`.
|
||||
#[property(get = Self::watched_room, set = Self::set_watched_room, nullable)]
|
||||
watched_room: PhantomData<Option<Room>>,
|
||||
gesture_click: RefCell<Option<gtk::GestureClick>>,
|
||||
}
|
||||
|
||||
@ -173,14 +177,26 @@ mod imp {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether to inhibit the image of the avatar.
|
||||
fn inhibit_image(&self) -> bool {
|
||||
self.avatar.inhibit_image()
|
||||
/// The safety setting to watch to decide whether the image of the
|
||||
/// avatar should be displayed.
|
||||
fn watched_safety_setting(&self) -> AvatarImageSafetySetting {
|
||||
self.avatar.watched_safety_setting()
|
||||
}
|
||||
|
||||
/// Set whether to inhibit the image of the avatar.
|
||||
fn set_inhibit_image(&self, inhibit: bool) {
|
||||
self.avatar.set_inhibit_image(inhibit);
|
||||
/// Set the safety setting to watch to decide whether the image of the
|
||||
/// avatar should be displayed.
|
||||
fn set_watched_safety_setting(&self, setting: AvatarImageSafetySetting) {
|
||||
self.avatar.set_watched_safety_setting(setting);
|
||||
}
|
||||
|
||||
/// The room to watch to apply the current safety settings.
|
||||
fn watched_room(&self) -> Option<Room> {
|
||||
self.avatar.watched_room()
|
||||
}
|
||||
|
||||
/// Set the room to watch to apply the current safety settings.
|
||||
fn set_watched_room(&self, room: Option<Room>) {
|
||||
self.avatar.set_watched_room(room);
|
||||
}
|
||||
|
||||
/// Set the display name of this pill.
|
||||
@ -240,8 +256,30 @@ glib::wrapper! {
|
||||
}
|
||||
|
||||
impl Pill {
|
||||
/// Create a pill with the given source.
|
||||
pub fn new(source: &impl IsA<PillSource>) -> Self {
|
||||
glib::Object::builder().property("source", source).build()
|
||||
/// Create a pill with the given source and watching the given safety
|
||||
/// setting.
|
||||
pub fn new(
|
||||
source: &impl IsA<PillSource>,
|
||||
watched_safety_setting: AvatarImageSafetySetting,
|
||||
watched_room: Option<Room>,
|
||||
) -> Self {
|
||||
let source = source.upcast_ref();
|
||||
|
||||
let (watched_safety_setting, watched_room) = if let Some(room) = source
|
||||
.downcast_ref::<Room>()
|
||||
.cloned()
|
||||
.or_else(|| source.downcast_ref::<AtRoom>().map(AtRoom::room))
|
||||
{
|
||||
// We must always watch the invite avatars setting for local rooms.
|
||||
(AvatarImageSafetySetting::InviteAvatars, Some(room))
|
||||
} else {
|
||||
(watched_safety_setting, watched_room)
|
||||
};
|
||||
|
||||
glib::Object::builder()
|
||||
.property("source", source)
|
||||
.property("watched-safety-setting", watched_safety_setting)
|
||||
.property("watched-room", watched_room)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use gtk::{
|
||||
CompositeTemplate,
|
||||
};
|
||||
|
||||
use crate::components::{Pill, PillSource};
|
||||
use crate::components::{AvatarImageSafetySetting, Pill, PillSource};
|
||||
|
||||
mod imp {
|
||||
use std::{cell::RefCell, collections::HashMap, marker::PhantomData, sync::LazyLock};
|
||||
@ -175,7 +175,9 @@ mod imp {
|
||||
return;
|
||||
}
|
||||
|
||||
let pill = Pill::new(source);
|
||||
// We do not need to watch the safety setting as this entry should only be used
|
||||
// with search results.
|
||||
let pill = Pill::new(source, AvatarImageSafetySetting::None, None);
|
||||
pill.set_margin_start(3);
|
||||
pill.set_margin_end(3);
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
use gtk::{glib, prelude::*, subclass::prelude::*};
|
||||
|
||||
use super::Pill;
|
||||
use crate::components::AvatarData;
|
||||
use crate::{
|
||||
components::{AvatarData, AvatarImageSafetySetting},
|
||||
session::model::Room,
|
||||
};
|
||||
|
||||
mod imp {
|
||||
use std::{cell::Cell, marker::PhantomData};
|
||||
@ -153,8 +156,13 @@ pub trait PillSourceExt: 'static {
|
||||
f: F,
|
||||
) -> glib::SignalHandlerId;
|
||||
|
||||
/// Get a `Pill` representing this source.
|
||||
fn to_pill(&self) -> Pill;
|
||||
/// Get a `Pill` representing this source, watching the given safety
|
||||
/// setting.
|
||||
fn to_pill(
|
||||
&self,
|
||||
watched_safety_setting: AvatarImageSafetySetting,
|
||||
watched_room: Option<Room>,
|
||||
) -> Pill;
|
||||
}
|
||||
|
||||
impl<O: IsA<PillSource>> PillSourceExt for O {
|
||||
@ -209,8 +217,12 @@ impl<O: IsA<PillSource>> PillSourceExt for O {
|
||||
}
|
||||
|
||||
/// Get a `Pill` representing this source.
|
||||
fn to_pill(&self) -> Pill {
|
||||
Pill::new(self)
|
||||
fn to_pill(
|
||||
&self,
|
||||
watched_safety_setting: AvatarImageSafetySetting,
|
||||
watched_room: Option<Room>,
|
||||
) -> Pill {
|
||||
Pill::new(self, watched_safety_setting, watched_room)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
|
||||
use super::{Avatar, PillSource};
|
||||
use super::{AtRoom, Avatar, AvatarImageSafetySetting, PillSource};
|
||||
use crate::session::model::Room;
|
||||
|
||||
mod imp {
|
||||
use std::cell::RefCell;
|
||||
@ -52,6 +53,20 @@ mod imp {
|
||||
return;
|
||||
}
|
||||
|
||||
let (watched_safety_setting, watched_room) = if let Some(room) = source
|
||||
.and_downcast_ref::<Room>()
|
||||
.cloned()
|
||||
.or_else(|| source.and_downcast_ref::<AtRoom>().map(AtRoom::room))
|
||||
{
|
||||
// We must always watch the invite avatars setting for local rooms.
|
||||
(AvatarImageSafetySetting::InviteAvatars, Some(room))
|
||||
} else {
|
||||
(AvatarImageSafetySetting::None, None)
|
||||
};
|
||||
self.avatar
|
||||
.set_watched_safety_setting(watched_safety_setting);
|
||||
self.avatar.set_watched_room(watched_room);
|
||||
|
||||
self.source.replace(source);
|
||||
self.obj().notify_source();
|
||||
}
|
||||
|
@ -1660,15 +1660,7 @@ impl Room {
|
||||
|
||||
/// Constructs an `AtRoom` for this room.
|
||||
pub(crate) fn at_room(&self) -> AtRoom {
|
||||
let at_room = AtRoom::new(self.room_id().to_owned());
|
||||
|
||||
// Bind the avatar image so it always looks the same.
|
||||
self.avatar_data()
|
||||
.bind_property("image", &at_room.avatar_data(), "image")
|
||||
.sync_create()
|
||||
.build();
|
||||
|
||||
at_room
|
||||
AtRoom::new(self)
|
||||
}
|
||||
|
||||
/// Get or create the list of members of this room.
|
||||
|
@ -3,7 +3,10 @@ use gettextrs::gettext;
|
||||
use gtk::{glib, glib::clone, prelude::*, CompositeTemplate};
|
||||
|
||||
use crate::{
|
||||
components::{confirm_leave_room_dialog, Avatar, LabelWithWidgets, LoadingButton, Pill},
|
||||
components::{
|
||||
confirm_leave_room_dialog, Avatar, AvatarImageSafetySetting, LabelWithWidgets,
|
||||
LoadingButton, Pill,
|
||||
},
|
||||
gettext_f,
|
||||
prelude::*,
|
||||
session::model::{MemberList, Room, RoomCategory, TargetRoomCategory, User},
|
||||
@ -22,29 +25,30 @@ mod imp {
|
||||
#[template(resource = "/org/gnome/Fractal/ui/session/view/content/invite.ui")]
|
||||
#[properties(wrapper_type = super::Invite)]
|
||||
pub struct Invite {
|
||||
/// The room currently displayed.
|
||||
#[property(get, set = Self::set_room, explicit_notify, nullable)]
|
||||
pub room: RefCell<Option<Room>>,
|
||||
pub room_members: RefCell<Option<MemberList>>,
|
||||
pub accept_requests: RefCell<HashSet<Room>>,
|
||||
pub decline_requests: RefCell<HashSet<Room>>,
|
||||
category_handler: RefCell<Option<glib::SignalHandlerId>>,
|
||||
invite_avatars_handler: RefCell<Option<glib::SignalHandlerId>>,
|
||||
inviter_pill: RefCell<Option<Pill>>,
|
||||
#[template_child]
|
||||
pub header_bar: TemplateChild<adw::HeaderBar>,
|
||||
pub(super) header_bar: TemplateChild<adw::HeaderBar>,
|
||||
#[template_child]
|
||||
avatar: TemplateChild<Avatar>,
|
||||
#[template_child]
|
||||
pub room_alias: TemplateChild<gtk::Label>,
|
||||
room_alias: TemplateChild<gtk::Label>,
|
||||
#[template_child]
|
||||
pub room_topic: TemplateChild<gtk::Label>,
|
||||
room_topic: TemplateChild<gtk::Label>,
|
||||
#[template_child]
|
||||
pub inviter: TemplateChild<LabelWithWidgets>,
|
||||
inviter: TemplateChild<LabelWithWidgets>,
|
||||
#[template_child]
|
||||
pub accept_button: TemplateChild<LoadingButton>,
|
||||
accept_button: TemplateChild<LoadingButton>,
|
||||
#[template_child]
|
||||
pub decline_button: TemplateChild<LoadingButton>,
|
||||
decline_button: TemplateChild<LoadingButton>,
|
||||
/// The room currently displayed.
|
||||
#[property(get, set = Self::set_room, explicit_notify, nullable)]
|
||||
room: RefCell<Option<Room>>,
|
||||
/// The list of members in the room.
|
||||
room_members: RefCell<Option<MemberList>>,
|
||||
/// The rooms that are currently being accepted.
|
||||
accept_requests: RefCell<HashSet<Room>>,
|
||||
/// The rooms that are currently being declined.
|
||||
decline_requests: RefCell<HashSet<Room>>,
|
||||
category_handler: RefCell<Option<glib::SignalHandlerId>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
@ -55,15 +59,9 @@ mod imp {
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
Self::bind_template(klass);
|
||||
Self::bind_template_callbacks(klass);
|
||||
|
||||
klass.set_accessible_role(gtk::AccessibleRole::Group);
|
||||
|
||||
klass.install_action_async("invite.decline", None, move |widget, _, _| async move {
|
||||
widget.decline().await;
|
||||
});
|
||||
klass.install_action_async("invite.accept", None, move |widget, _, _| async move {
|
||||
widget.accept().await;
|
||||
});
|
||||
}
|
||||
|
||||
fn instance_init(obj: &InitializingObject<Self>) {
|
||||
@ -118,6 +116,7 @@ mod imp {
|
||||
|
||||
impl BinImpl for Invite {}
|
||||
|
||||
#[gtk::template_callbacks]
|
||||
impl Invite {
|
||||
/// Set the room currently displayed.
|
||||
fn set_room(&self, room: Option<Room>) {
|
||||
@ -126,28 +125,25 @@ mod imp {
|
||||
}
|
||||
|
||||
self.disconnect_signals();
|
||||
self.inviter_pill.take();
|
||||
|
||||
let obj = self.obj();
|
||||
|
||||
match &room {
|
||||
Some(room) if self.accept_requests.borrow().contains(room) => {
|
||||
obj.action_set_enabled("invite.accept", false);
|
||||
obj.action_set_enabled("invite.decline", false);
|
||||
self.decline_button.set_is_loading(false);
|
||||
self.decline_button.set_sensitive(false);
|
||||
self.accept_button.set_is_loading(true);
|
||||
}
|
||||
Some(room) if self.decline_requests.borrow().contains(room) => {
|
||||
obj.action_set_enabled("invite.accept", false);
|
||||
obj.action_set_enabled("invite.decline", false);
|
||||
self.accept_button.set_is_loading(false);
|
||||
self.accept_button.set_sensitive(false);
|
||||
self.decline_button.set_is_loading(true);
|
||||
}
|
||||
_ => obj.reset(),
|
||||
_ => self.reset(),
|
||||
}
|
||||
|
||||
if let Some(room) = &room {
|
||||
let category_handler = room.connect_category_notify(clone!(
|
||||
#[weak]
|
||||
obj,
|
||||
#[weak(rename_to = imp)]
|
||||
self,
|
||||
move |room| {
|
||||
let category = room.category();
|
||||
|
||||
@ -168,10 +164,10 @@ mod imp {
|
||||
}
|
||||
|
||||
if category != RoomCategory::Invited {
|
||||
let imp = obj.imp();
|
||||
imp.decline_requests.borrow_mut().remove(room);
|
||||
imp.accept_requests.borrow_mut().remove(room);
|
||||
obj.reset();
|
||||
imp.reset();
|
||||
|
||||
if let Some(category_handler) = imp.category_handler.take() {
|
||||
room.disconnect(category_handler);
|
||||
}
|
||||
@ -180,31 +176,12 @@ mod imp {
|
||||
));
|
||||
self.category_handler.replace(Some(category_handler));
|
||||
|
||||
if let Some(session) = room.session() {
|
||||
let settings = session.settings();
|
||||
|
||||
let invite_avatars_handler =
|
||||
settings.connect_invite_avatars_enabled_notify(clone!(
|
||||
#[weak(rename_to = imp)]
|
||||
self,
|
||||
move |settings| {
|
||||
let inhibit_images = !settings.invite_avatars_enabled();
|
||||
imp.avatar.set_inhibit_image(inhibit_images);
|
||||
|
||||
if let Some(pill) = &*imp.inviter_pill.borrow() {
|
||||
pill.set_inhibit_image(inhibit_images);
|
||||
};
|
||||
}
|
||||
));
|
||||
self.invite_avatars_handler
|
||||
.replace(Some(invite_avatars_handler));
|
||||
|
||||
let inhibit_images = !settings.invite_avatars_enabled();
|
||||
self.avatar.set_inhibit_image(inhibit_images);
|
||||
|
||||
if let Some(inviter) = room.inviter() {
|
||||
let pill = inviter.to_pill();
|
||||
pill.set_inhibit_image(inhibit_images);
|
||||
let pill = Pill::new(
|
||||
&inviter,
|
||||
AvatarImageSafetySetting::InviteAvatars,
|
||||
Some(room.clone()),
|
||||
);
|
||||
|
||||
let label = gettext_f(
|
||||
// Translators: Do NOT translate the content between '{' and '}', these
|
||||
@ -218,8 +195,6 @@ mod imp {
|
||||
|
||||
self.inviter
|
||||
.set_label_and_widgets(label, vec![pill.clone()]);
|
||||
self.inviter_pill.replace(Some(pill));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +203,96 @@ mod imp {
|
||||
.replace(room.as_ref().map(Room::get_or_create_members));
|
||||
self.room.replace(room);
|
||||
|
||||
obj.notify_room();
|
||||
self.obj().notify_room();
|
||||
}
|
||||
|
||||
/// Reset the state of the view.
|
||||
fn reset(&self) {
|
||||
self.accept_button.set_is_loading(false);
|
||||
self.accept_button.set_sensitive(true);
|
||||
|
||||
self.decline_button.set_is_loading(false);
|
||||
self.decline_button.set_sensitive(true);
|
||||
}
|
||||
|
||||
/// Accept the invite.
|
||||
#[template_callback]
|
||||
async fn accept(&self) {
|
||||
let Some(room) = self.room.borrow().clone() else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.decline_button.set_sensitive(false);
|
||||
self.accept_button.set_is_loading(true);
|
||||
self.accept_requests.borrow_mut().insert(room.clone());
|
||||
|
||||
if room
|
||||
.change_category(TargetRoomCategory::Normal)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
toast!(
|
||||
self.obj(),
|
||||
gettext(
|
||||
// Translators: Do NOT translate the content between '{' and '}', this
|
||||
// is a variable name.
|
||||
"Could not accept invitation for {room}",
|
||||
),
|
||||
@room,
|
||||
);
|
||||
|
||||
self.accept_requests.borrow_mut().remove(&room);
|
||||
self.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// Decline the invite.
|
||||
#[template_callback]
|
||||
async fn decline(&self) {
|
||||
let Some(room) = self.room.borrow().clone() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let obj = self.obj();
|
||||
|
||||
let Some(response) = confirm_leave_room_dialog(&room, &*obj).await else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.accept_button.set_sensitive(false);
|
||||
self.decline_button.set_is_loading(true);
|
||||
self.decline_requests.borrow_mut().insert(room.clone());
|
||||
|
||||
let ignored_inviter = response.ignore_inviter.then(|| room.inviter()).flatten();
|
||||
|
||||
let closed = if room.change_category(TargetRoomCategory::Left).await.is_ok() {
|
||||
// A room where we were invited is usually empty so just close it.
|
||||
let _ = obj.activate_action("session.close-room", None);
|
||||
true
|
||||
} else {
|
||||
toast!(
|
||||
obj,
|
||||
gettext(
|
||||
// Translators: Do NOT translate the content between '{' and '}', this
|
||||
// is a variable name.
|
||||
"Could not decline invitation for {room}",
|
||||
),
|
||||
@room,
|
||||
);
|
||||
|
||||
self.decline_requests.borrow_mut().remove(&room);
|
||||
self.reset();
|
||||
false
|
||||
};
|
||||
|
||||
if let Some(inviter) = ignored_inviter {
|
||||
if inviter.upcast::<User>().ignore().await.is_err() {
|
||||
toast!(obj, gettext("Could not ignore user"));
|
||||
} else if !closed {
|
||||
// Ignoring the user should remove the room from the sidebar so close it.
|
||||
let _ = obj.activate_action("session.close-room", None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Disconnect the signal handlers of this view.
|
||||
@ -237,12 +301,6 @@ mod imp {
|
||||
if let Some(handler) = self.category_handler.take() {
|
||||
room.disconnect(handler);
|
||||
}
|
||||
|
||||
if let Some(session) = room.session() {
|
||||
if let Some(handler) = self.invite_avatars_handler.take() {
|
||||
session.settings().disconnect(handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -263,92 +321,4 @@ impl Invite {
|
||||
pub fn header_bar(&self) -> &adw::HeaderBar {
|
||||
&self.imp().header_bar
|
||||
}
|
||||
|
||||
fn reset(&self) {
|
||||
let imp = self.imp();
|
||||
imp.accept_button.set_is_loading(false);
|
||||
imp.decline_button.set_is_loading(false);
|
||||
self.action_set_enabled("invite.accept", true);
|
||||
self.action_set_enabled("invite.decline", true);
|
||||
}
|
||||
|
||||
/// Accept the invite.
|
||||
async fn accept(&self) {
|
||||
let Some(room) = self.room() else {
|
||||
return;
|
||||
};
|
||||
let imp = self.imp();
|
||||
|
||||
self.action_set_enabled("invite.accept", false);
|
||||
self.action_set_enabled("invite.decline", false);
|
||||
imp.accept_button.set_is_loading(true);
|
||||
imp.accept_requests.borrow_mut().insert(room.clone());
|
||||
|
||||
if room
|
||||
.change_category(TargetRoomCategory::Normal)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
toast!(
|
||||
self,
|
||||
gettext(
|
||||
// Translators: Do NOT translate the content between '{' and '}', this
|
||||
// is a variable name.
|
||||
"Could not accept invitation for {room}",
|
||||
),
|
||||
@room,
|
||||
);
|
||||
|
||||
imp.accept_requests.borrow_mut().remove(&room);
|
||||
self.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// Decline the invite.
|
||||
async fn decline(&self) {
|
||||
let Some(room) = self.room() else {
|
||||
return;
|
||||
};
|
||||
let imp = self.imp();
|
||||
|
||||
let Some(response) = confirm_leave_room_dialog(&room, self).await else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.action_set_enabled("invite.accept", false);
|
||||
self.action_set_enabled("invite.decline", false);
|
||||
imp.decline_button.set_is_loading(true);
|
||||
imp.decline_requests.borrow_mut().insert(room.clone());
|
||||
|
||||
let ignored_inviter = response.ignore_inviter.then(|| room.inviter()).flatten();
|
||||
|
||||
let closed = if room.change_category(TargetRoomCategory::Left).await.is_ok() {
|
||||
// A room where we were invited is usually empty so just close it.
|
||||
let _ = self.activate_action("session.close-room", None);
|
||||
true
|
||||
} else {
|
||||
toast!(
|
||||
self,
|
||||
gettext(
|
||||
// Translators: Do NOT translate the content between '{' and '}', this
|
||||
// is a variable name.
|
||||
"Could not decline invitation for {room}",
|
||||
),
|
||||
@room,
|
||||
);
|
||||
|
||||
imp.decline_requests.borrow_mut().remove(&room);
|
||||
self.reset();
|
||||
false
|
||||
};
|
||||
|
||||
if let Some(inviter) = ignored_inviter {
|
||||
if inviter.upcast::<User>().ignore().await.is_err() {
|
||||
toast!(self, gettext("Could not ignore user"));
|
||||
} else if !closed {
|
||||
// Ignoring the user should remove the room from the sidebar so close it.
|
||||
let _ = self.activate_action("session.close-room", None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,10 @@
|
||||
<lookup name="room">ContentInvite</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<binding name="watched-room">
|
||||
<lookup name="room">ContentInvite</lookup>
|
||||
</binding>
|
||||
<property name="watched-safety-setting">invite-avatars</property>
|
||||
<property name="accessible-role">presentation</property>
|
||||
</object>
|
||||
</child>
|
||||
@ -114,7 +118,7 @@
|
||||
<child>
|
||||
<object class="LoadingButton" id="decline_button">
|
||||
<property name="content-label" translatable="yes">_Decline</property>
|
||||
<property name="action-name">invite.decline</property>
|
||||
<signal name="clicked" handler="decline" swapped="yes"/>
|
||||
<style>
|
||||
<class name="pill"/>
|
||||
<class name="large"/>
|
||||
@ -124,7 +128,7 @@
|
||||
<child>
|
||||
<object class="LoadingButton" id="accept_button">
|
||||
<property name="content-label" translatable="yes">_Accept</property>
|
||||
<property name="action-name">invite.accept</property>
|
||||
<signal name="clicked" handler="accept" swapped="yes"/>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
<class name="pill"/>
|
||||
|
@ -118,7 +118,6 @@ mod imp {
|
||||
#[property(get)]
|
||||
is_published: Cell<bool>,
|
||||
expr_watch: RefCell<Option<gtk::ExpressionWatch>>,
|
||||
invite_avatars_handler: RefCell<Option<glib::SignalHandlerId>>,
|
||||
notifications_settings_handlers: RefCell<Vec<glib::SignalHandlerId>>,
|
||||
membership_handler: RefCell<Option<glib::SignalHandlerId>>,
|
||||
permissions_handler: RefCell<Option<glib::SignalHandlerId>>,
|
||||
@ -313,31 +312,12 @@ mod imp {
|
||||
imp.update_encryption();
|
||||
}
|
||||
)),
|
||||
room.connect_is_invite_notify(clone!(
|
||||
#[weak(rename_to = imp)]
|
||||
self,
|
||||
move |_| {
|
||||
imp.update_image();
|
||||
}
|
||||
)),
|
||||
];
|
||||
|
||||
self.room.set(room, room_handler_ids);
|
||||
obj.notify_room();
|
||||
|
||||
if let Some(session) = room.session() {
|
||||
let invite_avatars_handler = session
|
||||
.settings()
|
||||
.connect_invite_avatars_enabled_notify(clone!(
|
||||
#[weak(rename_to = imp)]
|
||||
self,
|
||||
move |_| {
|
||||
imp.update_image();
|
||||
}
|
||||
));
|
||||
self.invite_avatars_handler
|
||||
.replace(Some(invite_avatars_handler));
|
||||
|
||||
let notifications_settings = session.notifications().settings();
|
||||
let notifications_settings_handlers = vec![
|
||||
notifications_settings.connect_account_enabled_notify(clone!(
|
||||
@ -360,7 +340,6 @@ mod imp {
|
||||
.replace(notifications_settings_handlers);
|
||||
}
|
||||
|
||||
self.update_image();
|
||||
self.init_edit_details();
|
||||
self.update_members();
|
||||
self.update_notifications();
|
||||
@ -436,20 +415,6 @@ mod imp {
|
||||
);
|
||||
}
|
||||
|
||||
/// Update the image of the avatar of the room according to the current
|
||||
/// state.
|
||||
fn update_image(&self) {
|
||||
let Some(room) = self.room.obj() else {
|
||||
return;
|
||||
};
|
||||
let Some(session) = room.session() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let inhibit_image = room.is_invite() && !session.settings().invite_avatars_enabled();
|
||||
self.avatar.set_inhibit_image(inhibit_image);
|
||||
}
|
||||
|
||||
/// Initialize the button to edit details.
|
||||
fn init_edit_details(&self) {
|
||||
let Some(room) = self.room.obj() else {
|
||||
@ -560,10 +525,6 @@ mod imp {
|
||||
fn disconnect_all(&self) {
|
||||
if let Some(room) = self.room.obj() {
|
||||
if let Some(session) = room.session() {
|
||||
if let Some(handler) = self.invite_avatars_handler.take() {
|
||||
session.settings().disconnect(handler);
|
||||
}
|
||||
|
||||
for handler in self.notifications_settings_handlers.take() {
|
||||
session.notifications().settings().disconnect(handler);
|
||||
}
|
||||
|
@ -17,6 +17,10 @@
|
||||
<lookup name="room">RoomDetailsGeneralPage</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<binding name="watched-room">
|
||||
<lookup name="room">RoomDetailsGeneralPage</lookup>
|
||||
</binding>
|
||||
<property name="watched-safety-setting">invite-avatars</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -5,7 +5,7 @@ use secular::normalized_lower_lay_string;
|
||||
|
||||
use super::{CompletionMemberList, CompletionRoomList};
|
||||
use crate::{
|
||||
components::{Pill, PillSource, PillSourceRow},
|
||||
components::{AvatarImageSafetySetting, Pill, PillSource, PillSourceRow},
|
||||
session::{model::Room, view::content::room_history::message_toolbar::MessageToolbar},
|
||||
utils::BoundObject,
|
||||
};
|
||||
@ -651,7 +651,9 @@ mod imp {
|
||||
|
||||
buffer.delete(&mut start, &mut end);
|
||||
|
||||
let pill = Pill::new(&source);
|
||||
// We do not need to watch safety settings for mentions, rooms will be watched
|
||||
// automatically.
|
||||
let pill = Pill::new(&source, AvatarImageSafetySetting::None, None);
|
||||
self.message_toolbar()
|
||||
.current_composer_state()
|
||||
.add_widget(pill, &mut start);
|
||||
|
@ -18,8 +18,7 @@ use tracing::{error, warn};
|
||||
|
||||
use super::ComposerParser;
|
||||
use crate::{
|
||||
components::{Pill, PillSource},
|
||||
prelude::*,
|
||||
components::{AvatarImageSafetySetting, Pill, PillSource},
|
||||
session::model::{Event, Member, Room, Timeline},
|
||||
spawn, spawn_tokio,
|
||||
utils::matrix::{find_at_room, find_html_mentions, AT_ROOM},
|
||||
@ -312,7 +311,10 @@ mod imp {
|
||||
|
||||
match DraftMention::new(&room, &text[content_start..content_end]) {
|
||||
DraftMention::Source(source) => {
|
||||
self.add_widget(source.to_pill().upcast(), &mut end_iter);
|
||||
// We do not need to watch safety settings for mentions, rooms will be
|
||||
// watched automatically.
|
||||
let pill = Pill::new(&source, AvatarImageSafetySetting::None, None);
|
||||
self.add_widget(pill.upcast(), &mut end_iter);
|
||||
}
|
||||
DraftMention::Text(s) => {
|
||||
self.buffer.insert(&mut end_iter, s);
|
||||
@ -387,7 +389,9 @@ mod imp {
|
||||
let can_contain_at_room = message.mentions().is_none_or(|m| m.room);
|
||||
if room.permissions().can_notify_room() && can_contain_at_room {
|
||||
if let Some(start) = find_at_room(&text) {
|
||||
let pill = room.at_room().to_pill();
|
||||
// We do not need to watch safety settings for at-room mentions, our own member
|
||||
// is in the room.
|
||||
let pill = Pill::new(&room.at_room(), AvatarImageSafetySetting::None, None);
|
||||
let end = start + AT_ROOM.len();
|
||||
mentions.push(DetectedMention { pill, start, end });
|
||||
|
||||
|
@ -37,7 +37,7 @@ use self::{
|
||||
};
|
||||
use super::message_row::MessageContent;
|
||||
use crate::{
|
||||
components::{CustomEntry, LabelWithWidgets, LoadingButton},
|
||||
components::{AvatarImageSafetySetting, CustomEntry, LabelWithWidgets, LoadingButton},
|
||||
gettext_f,
|
||||
prelude::*,
|
||||
session::model::{Event, Member, Room, RoomListRoomInfo, Timeline},
|
||||
@ -516,7 +516,9 @@ mod imp {
|
||||
"Reply to {user}",
|
||||
&[("user", LabelWithWidgets::PLACEHOLDER)],
|
||||
);
|
||||
let pill = sender.to_pill();
|
||||
// We do not need to watch safety settings for mentions, rooms will be watched
|
||||
// automatically.
|
||||
let pill = sender.to_pill(AvatarImageSafetySetting::None, None);
|
||||
|
||||
self.related_event_header
|
||||
.set_label_and_widgets(label, vec![pill]);
|
||||
@ -551,7 +553,8 @@ mod imp {
|
||||
let buffer = self.message_entry.buffer();
|
||||
let mut insert = buffer.iter_at_mark(&buffer.get_insert());
|
||||
|
||||
let pill = member.to_pill();
|
||||
// We do not need to watch safety settings for users.
|
||||
let pill = member.to_pill(AvatarImageSafetySetting::None, None);
|
||||
self.current_composer_state().add_widget(pill, &mut insert);
|
||||
|
||||
self.message_entry.grab_focus();
|
||||
|
@ -33,7 +33,6 @@ mod imp {
|
||||
#[template_child]
|
||||
notification_count: TemplateChild<gtk::Label>,
|
||||
direct_icon: RefCell<Option<gtk::Image>>,
|
||||
invite_avatars_handler: RefCell<Option<glib::SignalHandlerId>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
@ -86,10 +85,6 @@ mod imp {
|
||||
));
|
||||
self.obj().add_controller(drag);
|
||||
}
|
||||
|
||||
fn dispose(&self) {
|
||||
self.disconnect_signals();
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for SidebarRoomRow {}
|
||||
@ -102,23 +97,9 @@ mod imp {
|
||||
return;
|
||||
}
|
||||
|
||||
self.disconnect_signals();
|
||||
self.room.disconnect_signals();
|
||||
|
||||
if let Some(room) = room {
|
||||
if let Some(session) = room.session() {
|
||||
let invite_avatars_handler = session
|
||||
.settings()
|
||||
.connect_invite_avatars_enabled_notify(clone!(
|
||||
#[weak(rename_to = imp)]
|
||||
self,
|
||||
move |_| {
|
||||
imp.update_image();
|
||||
}
|
||||
));
|
||||
self.invite_avatars_handler
|
||||
.replace(Some(invite_avatars_handler));
|
||||
}
|
||||
|
||||
let highlight_handler = room.connect_highlight_notify(clone!(
|
||||
#[weak(rename_to = imp)]
|
||||
self,
|
||||
@ -154,13 +135,6 @@ mod imp {
|
||||
imp.update_display_name();
|
||||
}
|
||||
));
|
||||
let is_invite_handler = room.connect_is_invite_notify(clone!(
|
||||
#[weak(rename_to = imp)]
|
||||
self,
|
||||
move |_| {
|
||||
imp.update_image();
|
||||
}
|
||||
));
|
||||
|
||||
self.room.set(
|
||||
room,
|
||||
@ -170,34 +144,18 @@ mod imp {
|
||||
name_handler,
|
||||
notifications_count_handler,
|
||||
category_handler,
|
||||
is_invite_handler,
|
||||
],
|
||||
);
|
||||
|
||||
self.update_accessibility_label();
|
||||
}
|
||||
|
||||
self.update_image();
|
||||
self.update_display_name();
|
||||
self.update_highlight();
|
||||
self.update_direct_icon();
|
||||
self.obj().notify_room();
|
||||
}
|
||||
|
||||
/// Update the image of the avatar of the room according to the current
|
||||
/// state.
|
||||
fn update_image(&self) {
|
||||
let Some(room) = self.room.obj() else {
|
||||
return;
|
||||
};
|
||||
let Some(session) = room.session() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let inhibit_image = room.is_invite() && !session.settings().invite_avatars_enabled();
|
||||
self.avatar.set_inhibit_image(inhibit_image);
|
||||
}
|
||||
|
||||
/// Update the display name of the room according to the current state.
|
||||
fn update_display_name(&self) {
|
||||
let Some(room) = self.room.obj() else {
|
||||
@ -346,17 +304,6 @@ mod imp {
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
/// Disconnect the signal handlers of this row.
|
||||
fn disconnect_signals(&self) {
|
||||
if let Some(session) = self.room.obj().and_then(|room| room.session()) {
|
||||
if let Some(handler) = self.invite_avatars_handler.take() {
|
||||
session.settings().disconnect(handler);
|
||||
}
|
||||
}
|
||||
|
||||
self.room.disconnect_signals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,10 @@
|
||||
<lookup name="room">SidebarRoomRow</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<binding name="watched-room">
|
||||
<lookup name="room">SidebarRoomRow</lookup>
|
||||
</binding>
|
||||
<property name="watched-safety-setting">invite-avatars</property>
|
||||
<property name="accessible-role">presentation</property>
|
||||
</object>
|
||||
</child>
|
||||
|
@ -33,7 +33,12 @@ pub(crate) mod ext_traits;
|
||||
mod media_message;
|
||||
|
||||
pub(crate) use self::media_message::*;
|
||||
use crate::{components::Pill, prelude::*, secret::StoredSession, session::model::Room};
|
||||
use crate::{
|
||||
components::{AvatarImageSafetySetting, Pill},
|
||||
prelude::*,
|
||||
secret::StoredSession,
|
||||
session::model::Room,
|
||||
};
|
||||
|
||||
/// The result of a password validation.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
@ -382,18 +387,29 @@ impl MatrixIdUri {
|
||||
match self {
|
||||
Self::Room(room_uri) => {
|
||||
let session = room.session()?;
|
||||
session
|
||||
.room_list()
|
||||
.get_by_identifier(&room_uri.id)
|
||||
.as_ref()
|
||||
.map(Pill::new)
|
||||
.or_else(|| Some(Pill::new(&session.remote_cache().room(room_uri))))
|
||||
|
||||
let pill =
|
||||
if let Some(uri_room) = session.room_list().get_by_identifier(&room_uri.id) {
|
||||
// We do not need to watch safety settings for local rooms, they will be
|
||||
// watched automatically.
|
||||
Pill::new(&uri_room, AvatarImageSafetySetting::None, None)
|
||||
} else {
|
||||
Pill::new(
|
||||
&session.remote_cache().room(room_uri),
|
||||
AvatarImageSafetySetting::MediaPreviews,
|
||||
Some(room.clone()),
|
||||
)
|
||||
};
|
||||
|
||||
Some(pill)
|
||||
}
|
||||
Self::User(user_id) => {
|
||||
// We should have a strong reference to the list wherever we show a user pill,
|
||||
// so we can use `get_or_create_members()`.
|
||||
let user = room.get_or_create_members().get_or_create(user_id);
|
||||
Some(Pill::new(&user))
|
||||
|
||||
// We do not need to watch safety settings for users.
|
||||
Some(Pill::new(&user, AvatarImageSafetySetting::None, None))
|
||||
}
|
||||
Self::Event(_) => None,
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ mod tests;
|
||||
|
||||
use super::matrix::{find_at_room, MatrixIdUri, AT_ROOM};
|
||||
use crate::{
|
||||
components::{LabelWithWidgets, Pill},
|
||||
components::{AvatarImageSafetySetting, LabelWithWidgets, Pill},
|
||||
prelude::*,
|
||||
session::model::Room,
|
||||
};
|
||||
@ -182,7 +182,9 @@ impl PangoStrMutExt for String {
|
||||
self.push_str(LabelWithWidgets::PLACEHOLDER);
|
||||
self.push_str(&(&s[pos + AT_ROOM.len()..]).escape_markup());
|
||||
|
||||
Some(room.at_room().to_pill())
|
||||
// We do not need to watch safety settings for mentions, rooms will be watched
|
||||
// automatically.
|
||||
Some(room.at_room().to_pill(AvatarImageSafetySetting::None, None))
|
||||
} else {
|
||||
self.push_str(&s.escape_markup());
|
||||
None
|
||||
|
@ -128,7 +128,9 @@ macro_rules! _toast_accum {
|
||||
([$($string_vars:tt)*], [$($pill_vars:tt)*], @$var:ident = $val:expr, $($tail:tt)*) => {
|
||||
{
|
||||
use $crate::components::PillSourceExt;
|
||||
let pill: $crate::components::Pill = $val.to_pill();
|
||||
// We do not need to watch safety settings for pills, rooms will be watched
|
||||
// automatically.
|
||||
let pill: $crate::components::Pill = $val.to_pill($crate::components::AvatarImageSafetySetting::None, None);
|
||||
$crate::_toast_accum!([$($string_vars)*], [$($pill_vars)* (stringify!($var), pill),], $($tail)*)
|
||||
}
|
||||
};
|
||||
@ -136,7 +138,9 @@ macro_rules! _toast_accum {
|
||||
([$($string_vars:tt)*], [$($pill_vars:tt)*], @$var:ident $($tail:tt)*) => {
|
||||
{
|
||||
use $crate::components::PillSourceExt;
|
||||
let pill: $crate::components::Pill = $var.to_pill();
|
||||
// We do not need to watch safety settings for pills, rooms will be watched
|
||||
// automatically.
|
||||
let pill: $crate::components::Pill = $var.to_pill($crate::components::AvatarImageSafetySetting::None, None);
|
||||
$crate::_toast_accum!([$($string_vars)*], [$($pill_vars)* (stringify!($var), pill),] $($tail)*)
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user