Browse Source

room-history: Refactor and fix visibility

pipelines/786320
Kévin Commaille 1 year ago
parent
commit
573e15d8a7
No known key found for this signature in database
GPG Key ID: C971D9DBC9D678D
  1. 93
      src/session/view/content/room_history/divider_row.rs
  2. 189
      src/session/view/content/room_history/mod.rs
  3. 12
      src/session/view/content/room_history/verification_info_bar.rs

93
src/session/view/content/room_history/divider_row.rs

@ -13,7 +13,7 @@ mod imp {
#[template(resource = "/org/gnome/Fractal/ui/session/view/content/room_history/divider_row.ui")]
pub struct DividerRow {
#[template_child]
pub(super) inner_label: TemplateChild<gtk::Label>,
inner_label: TemplateChild<gtk::Label>,
}
#[glib::object_subclass]
@ -37,6 +37,56 @@ mod imp {
impl WidgetImpl for DividerRow {}
impl BinImpl for DividerRow {}
impl DividerRow {
/// Set the kind of this divider.
///
/// Panics if the kind is not `TimelineStart`, `DayDivider` or
/// `NewMessages`.
pub(super) fn set_kind(&self, kind: &VirtualItemKind) {
let label = match kind {
VirtualItemKind::TimelineStart => {
gettext("This is the start of the visible history")
}
VirtualItemKind::DayDivider(utc_date) => {
let date = utc_date.to_local().unwrap_or(utc_date.clone());
let fmt = if date.year()
== glib::DateTime::now_local()
.expect("we should be able to get the local datetime")
.year()
{
// Translators: This is a date format in the day divider without the
// year. For example, "Friday, May 5".
// Please use `-` before specifiers that add spaces on single
// digits. See `man strftime` or the documentation of g_date_time_format for the available specifiers: <https://docs.gtk.org/glib/method.DateTime.format.html>
gettext("%A, %B %-e")
} else {
// Translators: This is a date format in the day divider with the
// year. For ex. "Friday, May 5, 2023".
// Please use `-` before specifiers that add spaces on single
// digits. See `man strftime` or the documentation of g_date_time_format for the available specifiers: <https://docs.gtk.org/glib/method.DateTime.format.html>
gettext("%A, %B %-e, %Y")
};
date.format(&fmt)
.expect("we should be able to format the datetime")
.into()
}
VirtualItemKind::NewMessages => gettext("New Messages"),
_ => unimplemented!(),
};
let obj = self.obj();
if matches!(kind, VirtualItemKind::NewMessages) {
obj.add_css_class("new-messages");
} else {
obj.remove_css_class("new-messages");
}
self.inner_label.set_label(&label);
}
}
}
glib::wrapper! {
@ -54,44 +104,7 @@ impl DividerRow {
///
/// Panics if the kind is not `TimelineStart`, `DayDivider` or
/// `NewMessages`.
pub fn set_kind(&self, kind: &VirtualItemKind) {
let label = match kind {
VirtualItemKind::TimelineStart => gettext("This is the start of the visible history"),
VirtualItemKind::DayDivider(utc_date) => {
let date = utc_date.to_local().unwrap_or(utc_date.clone());
let fmt = if date.year()
== glib::DateTime::now_local()
.expect("we should be able to get the local datetime")
.year()
{
// Translators: This is a date format in the day divider without the
// year. For example, "Friday, May 5".
// Please use `-` before specifiers that add spaces on single
// digits. See `man strftime` or the documentation of g_date_time_format for the available specifiers: <https://docs.gtk.org/glib/method.DateTime.format.html>
gettext("%A, %B %-e")
} else {
// Translators: This is a date format in the day divider with the
// year. For ex. "Friday, May 5, 2023".
// Please use `-` before specifiers that add spaces on single
// digits. See `man strftime` or the documentation of g_date_time_format for the available specifiers: <https://docs.gtk.org/glib/method.DateTime.format.html>
gettext("%A, %B %-e, %Y")
};
date.format(&fmt)
.expect("we should be able to format the datetime")
.into()
}
VirtualItemKind::NewMessages => gettext("New Messages"),
_ => unimplemented!(),
};
if matches!(kind, VirtualItemKind::NewMessages) {
self.add_css_class("new-messages");
} else {
self.remove_css_class("new-messages");
}
self.imp().inner_label.set_label(&label);
pub(crate) fn set_kind(&self, kind: &VirtualItemKind) {
self.imp().set_kind(kind);
}
}

189
src/session/view/content/room_history/mod.rs

@ -59,7 +59,7 @@ mod imp {
#[properties(wrapper_type = super::RoomHistory)]
pub struct RoomHistory {
#[template_child]
pub(super) sender_menu_model: TemplateChild<gio::Menu>,
sender_menu_model: TemplateChild<gio::Menu>,
#[template_child]
pub(super) header_bar: TemplateChild<adw::HeaderBar>,
#[template_child]
@ -86,9 +86,9 @@ mod imp {
tombstoned_banner: TemplateChild<adw::Banner>,
#[template_child]
drag_overlay: TemplateChild<DragOverlay>,
pub(super) item_context_menu: OnceCell<gtk::PopoverMenu>,
pub(super) item_quick_reaction_chooser: QuickReactionChooser,
pub(super) sender_context_menu: OnceCell<gtk::PopoverMenu>,
item_context_menu: OnceCell<gtk::PopoverMenu>,
item_quick_reaction_chooser: QuickReactionChooser,
sender_context_menu: OnceCell<gtk::PopoverMenu>,
/// The room currently displayed.
#[property(get, set = Self::set_room, explicit_notify, nullable)]
room: BoundObject<Room>,
@ -103,7 +103,7 @@ mod imp {
///
/// We hold a strong reference here to keep the list in memory as long
/// as the room is opened.
pub(super) room_members: RefCell<Option<MemberList>>,
room_members: RefCell<Option<MemberList>>,
timeline_handlers: RefCell<Vec<glib::SignalHandlerId>>,
/// Whether the current room history scrolling is automatic.
is_auto_scrolling: Cell<bool>,
@ -133,7 +133,7 @@ mod imp {
Timeline::ensure_type();
Self::bind_template(klass);
Self::Type::bind_template_callbacks(klass);
Self::bind_template_callbacks(klass);
TemplateCallbacks::bind_template_callbacks(klass);
klass.set_accessible_role(gtk::AccessibleRole::Group);
@ -188,7 +188,7 @@ mod imp {
return;
};
obj.message_toolbar().set_reply_to(&event);
obj.imp().message_toolbar.set_reply_to(&event);
},
);
@ -212,7 +212,7 @@ mod imp {
return;
};
obj.message_toolbar().set_edit(&event);
obj.imp().message_toolbar.set_edit(&event);
},
);
}
@ -248,6 +248,7 @@ mod imp {
impl WidgetImpl for RoomHistory {}
impl BinImpl for RoomHistory {}
#[gtk::template_callbacks]
impl RoomHistory {
/// Initialize the list view.
fn init_listview(&self) {
@ -575,7 +576,8 @@ mod imp {
}
/// Scroll to the bottom of the timeline.
pub(super) fn scroll_down(&self) {
#[template_callback]
fn scroll_down(&self) {
tracing::trace!("scroll_down");
self.set_is_auto_scrolling(true);
@ -658,7 +660,8 @@ mod imp {
}
/// Load more events at the beginning of the history.
pub(super) fn load_more_events(&self) {
#[template_callback]
fn load_more_events(&self) {
let Some(room) = self.room.obj() else {
return;
};
@ -934,6 +937,77 @@ mod imp {
self.obj()
.action_set_enabled("room-history.invite-members", can_invite);
}
/// Join or view the successor of the room, if possible.
#[template_callback]
async fn join_or_view_successor(&self) {
let Some(room) = self.room.obj() else {
return;
};
let Some(session) = room.session() else {
return;
};
if !room.is_joined() || !room.is_tombstoned() {
return;
}
let obj = self.obj();
if let Some(successor) = room.successor() {
let Some(window) = obj.root().and_downcast::<Window>() else {
return;
};
window.show_room(session.session_id(), successor.room_id());
} else if let Some(successor_id) = room.successor_id().map(ToOwned::to_owned) {
let via = successor_id
.server_name()
.map(ToOwned::to_owned)
.into_iter()
.collect();
if let Err(error) = session
.room_list()
.join_by_id_or_alias(successor_id.into(), via)
.await
{
toast!(obj, error);
}
}
}
/// The context menu for the item rows.
pub(super) fn item_context_menu(&self) -> &gtk::PopoverMenu {
self.item_context_menu.get_or_init(|| {
let popover = gtk::PopoverMenu::builder()
.has_arrow(false)
.halign(gtk::Align::Start)
.build();
popover
.update_property(&[gtk::accessible::Property::Label(&gettext("Context Menu"))]);
popover
})
}
/// The reaction chooser for the item rows.
pub(super) fn item_quick_reaction_chooser(&self) -> &QuickReactionChooser {
&self.item_quick_reaction_chooser
}
/// The context menu for the sender avatars.
pub(super) fn sender_context_menu(&self) -> &gtk::PopoverMenu {
self.sender_context_menu.get_or_init(|| {
let popover = gtk::PopoverMenu::builder()
.has_arrow(false)
.halign(gtk::Align::Start)
.menu_model(&*self.sender_menu_model)
.build();
popover.update_property(&[gtk::accessible::Property::Label(&gettext(
"Sender Context Menu",
))]);
popover
})
}
}
}
@ -943,14 +1017,13 @@ glib::wrapper! {
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
}
#[gtk::template_callbacks]
impl RoomHistory {
pub fn new() -> Self {
glib::Object::new()
}
/// The header bar of the room history.
pub fn header_bar(&self) -> &adw::HeaderBar {
pub(crate) fn header_bar(&self) -> &adw::HeaderBar {
&self.imp().header_bar
}
@ -959,16 +1032,11 @@ impl RoomHistory {
&self.imp().message_toolbar
}
/// The members of the room currently displayed.
pub fn room_members(&self) -> Option<MemberList> {
self.imp().room_members.borrow().clone()
}
/// Opens the room details.
///
/// If `subpage_name` is set, the room details will be opened on the given
/// subpage.
pub fn open_room_details(&self, subpage_name: Option<room_details::SubpageName>) {
pub(crate) fn open_room_details(&self, subpage_name: Option<room_details::SubpageName>) {
let Some(room) = self.room() else {
return;
};
@ -980,21 +1048,9 @@ impl RoomHistory {
window.present();
}
/// Load more events at the beginning of the history.
#[template_callback]
fn load_more_events(&self) {
self.imp().load_more_events();
}
/// Scroll to the bottom of the timeline.
#[template_callback]
fn scroll_down(&self) {
self.imp().scroll_down();
}
/// Enable or disable the mode allowing the room history to stick to the
/// bottom based on scrollbar position.
pub fn enable_sticky_mode(&self, enable: bool) {
pub(crate) fn enable_sticky_mode(&self, enable: bool) {
let imp = self.imp();
if enable {
imp.set_sticky(imp.is_at_bottom());
@ -1004,77 +1060,22 @@ impl RoomHistory {
}
/// Handle a paste action.
pub fn handle_paste_action(&self) {
self.message_toolbar().handle_paste_action();
pub(crate) fn handle_paste_action(&self) {
self.imp().message_toolbar.handle_paste_action();
}
/// The context menu for the item rows.
pub fn item_context_menu(&self) -> &gtk::PopoverMenu {
self.imp().item_context_menu.get_or_init(|| {
let popover = gtk::PopoverMenu::builder()
.has_arrow(false)
.halign(gtk::Align::Start)
.build();
popover.update_property(&[gtk::accessible::Property::Label(&gettext("Context Menu"))]);
popover
})
pub(crate) fn item_context_menu(&self) -> &gtk::PopoverMenu {
self.imp().item_context_menu()
}
/// The reaction chooser for the item rows.
pub fn item_quick_reaction_chooser(&self) -> &QuickReactionChooser {
&self.imp().item_quick_reaction_chooser
pub(crate) fn item_quick_reaction_chooser(&self) -> &QuickReactionChooser {
self.imp().item_quick_reaction_chooser()
}
/// The context menu for the sender avatars.
pub fn sender_context_menu(&self) -> &gtk::PopoverMenu {
let imp = self.imp();
imp.sender_context_menu.get_or_init(|| {
let popover = gtk::PopoverMenu::builder()
.has_arrow(false)
.halign(gtk::Align::Start)
.menu_model(&*imp.sender_menu_model)
.build();
popover.update_property(&[gtk::accessible::Property::Label(&gettext(
"Sender Context Menu",
))]);
popover
})
}
/// Join or view the room's successor, if possible.
#[template_callback]
async fn join_or_view_successor(&self) {
let Some(room) = self.room() else {
return;
};
let Some(session) = room.session() else {
return;
};
if !room.is_joined() || !room.is_tombstoned() {
return;
}
if let Some(successor) = room.successor() {
let Some(window) = self.root().and_downcast::<Window>() else {
return;
};
window.show_room(session.session_id(), successor.room_id());
} else if let Some(successor_id) = room.successor_id().map(ToOwned::to_owned) {
let via = successor_id
.server_name()
.map(ToOwned::to_owned)
.into_iter()
.collect();
if let Err(error) = session
.room_list()
.join_by_id_or_alias(successor_id.into(), via)
.await
{
toast!(self, error);
}
}
pub(crate) fn sender_context_menu(&self) -> &gtk::PopoverMenu {
self.imp().sender_context_menu()
}
}

12
src/session/view/content/room_history/verification_info_bar.rs

@ -26,17 +26,17 @@ mod imp {
#[properties(wrapper_type = super::VerificationInfoBar)]
pub struct VerificationInfoBar {
#[template_child]
pub revealer: TemplateChild<gtk::Revealer>,
revealer: TemplateChild<gtk::Revealer>,
#[template_child]
pub label: TemplateChild<gtk::Label>,
label: TemplateChild<gtk::Label>,
#[template_child]
pub accept_btn: TemplateChild<LoadingButton>,
accept_btn: TemplateChild<LoadingButton>,
#[template_child]
pub cancel_btn: TemplateChild<LoadingButton>,
cancel_btn: TemplateChild<LoadingButton>,
/// The identity verification presented by this info bar.
#[property(get, set = Self::set_verification, explicit_notify)]
pub verification: BoundObjectWeakRef<IdentityVerification>,
pub user_handler: RefCell<Option<glib::SignalHandlerId>>,
verification: BoundObjectWeakRef<IdentityVerification>,
user_handler: RefCell<Option<glib::SignalHandlerId>>,
}
#[glib::object_subclass]

Loading…
Cancel
Save