Browse Source

state-row: Refactor and fix visibility

pipelines/786320
Kévin Commaille 1 year ago
parent
commit
b4efcb049a
No known key found for this signature in database
GPG Key ID: C971D9DBC9D678D
  1. 53
      src/session/view/content/room_history/state_row/creation.rs
  2. 547
      src/session/view/content/room_history/state_row/mod.rs
  3. 109
      src/session/view/content/room_history/state_row/tombstone.rs

53
src/session/view/content/room_history/state_row/creation.rs

@ -15,9 +15,9 @@ mod imp {
)]
pub struct StateCreation {
#[template_child]
pub previous_room_btn: TemplateChild<gtk::Button>,
previous_room_btn: TemplateChild<gtk::Button>,
#[template_child]
pub description: TemplateChild<gtk::Label>,
description: TemplateChild<gtk::Label>,
}
#[glib::object_subclass]
@ -38,6 +38,31 @@ mod imp {
impl ObjectImpl for StateCreation {}
impl WidgetImpl for StateCreation {}
impl BinImpl for StateCreation {}
impl StateCreation {
/// Set the room create state event to display.
pub(super) fn set_event(&self, event: &FullStateEventContent<RoomCreateEventContent>) {
let predecessor = match event {
FullStateEventContent::Original { content, .. } => content.predecessor.as_ref(),
FullStateEventContent::Redacted(_) => None,
};
if let Some(predecessor) = &predecessor {
self.previous_room_btn.set_detailed_action_name(&format!(
"session.show-room::{}",
predecessor.room_id
));
self.previous_room_btn.set_visible(true);
self.description
.set_label(&gettext("This is the continuation of an upgraded room."));
} else {
self.previous_room_btn.set_visible(false);
self.previous_room_btn.set_action_name(None);
self.description
.set_label(&gettext("This is the beginning of this room."));
}
}
}
}
glib::wrapper! {
@ -49,29 +74,7 @@ glib::wrapper! {
impl StateCreation {
pub fn new(event: &FullStateEventContent<RoomCreateEventContent>) -> Self {
let obj: Self = glib::Object::new();
obj.set_event(event);
obj.imp().set_event(event);
obj
}
fn set_event(&self, event: &FullStateEventContent<RoomCreateEventContent>) {
let imp = self.imp();
let predecessor = match event {
FullStateEventContent::Original { content, .. } => content.predecessor.as_ref(),
FullStateEventContent::Redacted(_) => None,
};
if let Some(predecessor) = &predecessor {
imp.previous_room_btn
.set_detailed_action_name(&format!("session.show-room::{}", predecessor.room_id));
imp.previous_room_btn.set_visible(true);
imp.description
.set_label(&gettext("This is the continuation of an upgraded room."));
} else {
imp.previous_room_btn.set_visible(false);
imp.previous_room_btn.set_action_name(None);
imp.description
.set_label(&gettext("This is the beginning of this room."));
}
}
}

547
src/session/view/content/room_history/state_row/mod.rs

@ -33,12 +33,12 @@ mod imp {
#[properties(wrapper_type = super::StateRow)]
pub struct StateRow {
#[template_child]
pub content: TemplateChild<adw::Bin>,
content: TemplateChild<adw::Bin>,
#[template_child]
pub read_receipts: TemplateChild<ReadReceiptsList>,
read_receipts: TemplateChild<ReadReceiptsList>,
/// The state event displayed by this widget.
#[property(get, set = Self::set_event)]
pub event: RefCell<Option<Event>>,
event: RefCell<Option<Event>>,
}
#[glib::object_subclass]
@ -66,19 +66,17 @@ mod imp {
impl StateRow {
/// Set the event presented by this row.
fn set_event(&self, event: Event) {
let obj = self.obj();
match event.content() {
TimelineItemContent::MembershipChange(membership_change) => {
obj.update_with_membership_change(&membership_change, &event.sender_id());
self.update_with_membership_change(&membership_change, &event.sender_id());
}
TimelineItemContent::ProfileChange(profile_change) => obj
TimelineItemContent::ProfileChange(profile_change) => self
.update_with_profile_change(
&profile_change,
&event.sender().disambiguated_name(),
),
TimelineItemContent::OtherState(other_state) => {
obj.update_with_other_state(&event, &other_state);
self.update_with_other_state(&event, &other_state);
}
_ => unreachable!(),
}
@ -86,309 +84,308 @@ mod imp {
self.read_receipts.set_source(event.read_receipts());
self.event.replace(Some(event));
}
}
}
glib::wrapper! {
/// A row presenting a state event.
pub struct StateRow(ObjectSubclass<imp::StateRow>)
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
}
impl StateRow {
pub fn new() -> Self {
glib::Object::new()
}
pub fn content(&self) -> &adw::Bin {
&self.imp().content
}
fn update_with_other_state(&self, event: &Event, other_state: &OtherState) {
let widget = match other_state.content() {
AnyOtherFullStateEventContent::RoomCreate(content) => {
WidgetType::Creation(StateCreation::new(content))
}
AnyOtherFullStateEventContent::RoomEncryption(_) => {
WidgetType::Text(gettext("This room is encrypted from this point on."))
}
AnyOtherFullStateEventContent::RoomThirdPartyInvite(content) => {
let display_name = match content {
FullStateEventContent::Original { content, .. } => {
match &content.display_name {
s if s.is_empty() => other_state.state_key(),
s => s,
/// Update this row with the given [`OtherState`].
fn update_with_other_state(&self, event: &Event, other_state: &OtherState) {
let widget = match other_state.content() {
AnyOtherFullStateEventContent::RoomCreate(content) => {
WidgetType::Creation(StateCreation::new(content))
}
AnyOtherFullStateEventContent::RoomEncryption(_) => {
WidgetType::Text(gettext("This room is encrypted from this point on."))
}
AnyOtherFullStateEventContent::RoomThirdPartyInvite(content) => {
let display_name = match content {
FullStateEventContent::Original { content, .. } => {
match &content.display_name {
s if s.is_empty() => other_state.state_key(),
s => s,
}
}
}
FullStateEventContent::Redacted(_) => other_state.state_key(),
};
WidgetType::Text(gettext_f(
// Translators: Do NOT translate the content between '{' and '}', this is a
// variable name.
"{user} was invited to this room.",
&[("user", display_name)],
))
}
AnyOtherFullStateEventContent::RoomTombstone(_) => {
WidgetType::Tombstone(StateTombstone::new(&event.room()))
}
_ => {
warn!(
"Unsupported state event: {}",
other_state.content().event_type()
);
WidgetType::Text(gettext("An unsupported state event was received."))
}
};
FullStateEventContent::Redacted(_) => other_state.state_key(),
};
WidgetType::Text(gettext_f(
// Translators: Do NOT translate the content between '{' and '}', this is a
// variable name.
"{user} was invited to this room.",
&[("user", display_name)],
))
}
AnyOtherFullStateEventContent::RoomTombstone(_) => {
WidgetType::Tombstone(StateTombstone::new(&event.room()))
}
_ => {
warn!(
"Unsupported state event: {}",
other_state.content().event_type()
);
WidgetType::Text(gettext("An unsupported state event was received."))
}
};
let content = self.content();
match widget {
WidgetType::Text(message) => {
if let Some(child) = content.child().and_downcast::<gtk::Label>() {
child.set_text(&message);
} else {
content.set_child(Some(&text(&message)));
};
match widget {
WidgetType::Text(message) => {
if let Some(child) = self.content.child().and_downcast::<gtk::Label>() {
child.set_text(&message);
} else {
self.content.set_child(Some(&text(&message)));
};
}
WidgetType::Creation(widget) => self.content.set_child(Some(&widget)),
WidgetType::Tombstone(widget) => self.content.set_child(Some(&widget)),
}
WidgetType::Creation(widget) => content.set_child(Some(&widget)),
WidgetType::Tombstone(widget) => content.set_child(Some(&widget)),
}
}
/// Update this row for the given membership change.
fn update_with_membership_change(
&self,
membership_change: &RoomMembershipChange,
sender: &UserId,
) {
let display_name = match membership_change.content() {
FullStateEventContent::Original { content, .. } => content
.displayname
.clone()
.unwrap_or_else(|| membership_change.user_id().to_string()),
FullStateEventContent::Redacted(_) => membership_change.user_id().to_string(),
};
/// Update this row for the given membership change.
fn update_with_membership_change(
&self,
membership_change: &RoomMembershipChange,
sender: &UserId,
) {
let display_name = match membership_change.content() {
FullStateEventContent::Original { content, .. } => content
.displayname
.clone()
.unwrap_or_else(|| membership_change.user_id().to_string()),
FullStateEventContent::Redacted(_) => membership_change.user_id().to_string(),
};
let supported_membership_change =
Self::to_supported_membership_change(membership_change, sender);
let supported_membership_change =
Self::to_supported_membership_change(membership_change, sender);
let message = match supported_membership_change {
MembershipChange::Joined => {
// Translators: Do NOT translate the content between '{' and '}', this
// is a variable name.
gettext_f("{user} joined this room.", &[("user", &display_name)])
}
MembershipChange::Left => {
// Translators: Do NOT translate the content between '{' and '}',
// this is a variable name.
gettext_f("{user} left the room.", &[("user", &display_name)])
}
MembershipChange::Banned => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} was banned.",
&[("user", &display_name)],
),
MembershipChange::Unbanned => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} was unbanned.",
&[("user", &display_name)],
),
MembershipChange::Kicked => gettext_f(
// Translators: Do NOT translate the content between '{' and
// '}', this is a variable name.
"{user} was kicked out of the room.",
&[("user", &display_name)],
),
MembershipChange::Invited | MembershipChange::KnockAccepted => gettext_f(
// Translators: Do NOT translate the content between '{' and '}', this is
// a variable name.
"{user} was invited to this room.",
&[("user", &display_name)],
),
MembershipChange::KickedAndBanned => gettext_f(
// Translators: Do NOT translate the content between '{' and '}', this is
// a variable name.
"{user} was kicked out of the room and banned.",
&[("user", &display_name)],
),
MembershipChange::InvitationAccepted => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} accepted the invite.",
&[("user", &display_name)],
),
MembershipChange::InvitationRejected => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} rejected the invite.",
&[("user", &display_name)],
),
MembershipChange::InvitationRevoked => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"The invitation for {user} has been revoked.",
&[("user", &display_name)],
),
MembershipChange::Knocked =>
// TODO: Add button to invite the user.
{
gettext_f(
let message = match supported_membership_change {
MembershipChange::Joined => {
// Translators: Do NOT translate the content between '{' and '}', this
// is a variable name.
"{user} requested to be invited to this room.",
gettext_f("{user} joined this room.", &[("user", &display_name)])
}
MembershipChange::Left => {
// Translators: Do NOT translate the content between '{' and '}',
// this is a variable name.
gettext_f("{user} left the room.", &[("user", &display_name)])
}
MembershipChange::Banned => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} was banned.",
&[("user", &display_name)],
)
}
MembershipChange::KnockRetracted => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} retracted their request to be invited to this room.",
&[("user", &display_name)],
),
MembershipChange::KnockDenied => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user}’s request to be invited to this room was denied.",
&[("user", &display_name)],
),
_ => {
warn!(
"Unsupported membership change event: {:?}",
membership_change.content()
);
gettext("An unsupported room member event was received.")
}
};
),
MembershipChange::Unbanned => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} was unbanned.",
&[("user", &display_name)],
),
MembershipChange::Kicked => gettext_f(
// Translators: Do NOT translate the content between '{' and
// '}', this is a variable name.
"{user} was kicked out of the room.",
&[("user", &display_name)],
),
MembershipChange::Invited | MembershipChange::KnockAccepted => gettext_f(
// Translators: Do NOT translate the content between '{' and '}', this is
// a variable name.
"{user} was invited to this room.",
&[("user", &display_name)],
),
MembershipChange::KickedAndBanned => gettext_f(
// Translators: Do NOT translate the content between '{' and '}', this is
// a variable name.
"{user} was kicked out of the room and banned.",
&[("user", &display_name)],
),
MembershipChange::InvitationAccepted => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} accepted the invite.",
&[("user", &display_name)],
),
MembershipChange::InvitationRejected => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} rejected the invite.",
&[("user", &display_name)],
),
MembershipChange::InvitationRevoked => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"The invitation for {user} has been revoked.",
&[("user", &display_name)],
),
MembershipChange::Knocked =>
// TODO: Add button to invite the user.
{
gettext_f(
// Translators: Do NOT translate the content between '{' and '}', this
// is a variable name.
"{user} requested to be invited to this room.",
&[("user", &display_name)],
)
}
MembershipChange::KnockRetracted => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} retracted their request to be invited to this room.",
&[("user", &display_name)],
),
MembershipChange::KnockDenied => gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user}’s request to be invited to this room was denied.",
&[("user", &display_name)],
),
_ => {
warn!(
"Unsupported membership change event: {:?}",
membership_change.content()
);
gettext("An unsupported room member event was received.")
}
};
let content = self.content();
if let Some(child) = content.child().and_downcast::<gtk::Label>() {
child.set_text(&message);
} else {
content.set_child(Some(&text(&message)));
};
}
if let Some(child) = self.content.child().and_downcast::<gtk::Label>() {
child.set_text(&message);
} else {
self.content.set_child(Some(&text(&message)));
};
}
/// Convert a received membership change to a supported membership change.
///
/// This is used to fallback to showing the membership when we do not know
/// or do not want to show the change.
fn to_supported_membership_change(
membership_change: &RoomMembershipChange,
sender: &UserId,
) -> MembershipChange {
match membership_change.change().unwrap_or(MembershipChange::None) {
MembershipChange::Joined => MembershipChange::Joined,
MembershipChange::Left => MembershipChange::Left,
MembershipChange::Banned => MembershipChange::Banned,
MembershipChange::Unbanned => MembershipChange::Unbanned,
MembershipChange::Kicked => MembershipChange::Kicked,
MembershipChange::Invited => MembershipChange::Invited,
MembershipChange::KickedAndBanned => MembershipChange::KickedAndBanned,
MembershipChange::InvitationAccepted => MembershipChange::InvitationAccepted,
MembershipChange::InvitationRejected => MembershipChange::InvitationRejected,
MembershipChange::InvitationRevoked => MembershipChange::InvitationRevoked,
MembershipChange::Knocked => MembershipChange::Knocked,
MembershipChange::KnockAccepted => MembershipChange::KnockAccepted,
MembershipChange::KnockRetracted => MembershipChange::KnockRetracted,
MembershipChange::KnockDenied => MembershipChange::KnockDenied,
_ => {
let membership = match membership_change.content() {
FullStateEventContent::Original { content, .. } => &content.membership,
FullStateEventContent::Redacted(content) => &content.membership,
};
/// Convert a received membership change to a supported membership
/// change.
///
/// This is used to fallback to showing the membership when we do not
/// know or do not want to show the change.
fn to_supported_membership_change(
membership_change: &RoomMembershipChange,
sender: &UserId,
) -> MembershipChange {
match membership_change.change().unwrap_or(MembershipChange::None) {
MembershipChange::Joined => MembershipChange::Joined,
MembershipChange::Left => MembershipChange::Left,
MembershipChange::Banned => MembershipChange::Banned,
MembershipChange::Unbanned => MembershipChange::Unbanned,
MembershipChange::Kicked => MembershipChange::Kicked,
MembershipChange::Invited => MembershipChange::Invited,
MembershipChange::KickedAndBanned => MembershipChange::KickedAndBanned,
MembershipChange::InvitationAccepted => MembershipChange::InvitationAccepted,
MembershipChange::InvitationRejected => MembershipChange::InvitationRejected,
MembershipChange::InvitationRevoked => MembershipChange::InvitationRevoked,
MembershipChange::Knocked => MembershipChange::Knocked,
MembershipChange::KnockAccepted => MembershipChange::KnockAccepted,
MembershipChange::KnockRetracted => MembershipChange::KnockRetracted,
MembershipChange::KnockDenied => MembershipChange::KnockDenied,
_ => {
let membership = match membership_change.content() {
FullStateEventContent::Original { content, .. } => &content.membership,
FullStateEventContent::Redacted(content) => &content.membership,
};
match membership {
MembershipState::Ban => MembershipChange::Banned,
MembershipState::Invite => MembershipChange::Invited,
MembershipState::Join => MembershipChange::Joined,
MembershipState::Knock => MembershipChange::Knocked,
MembershipState::Leave => {
if membership_change.user_id() == sender {
MembershipChange::Left
} else {
MembershipChange::Kicked
match membership {
MembershipState::Ban => MembershipChange::Banned,
MembershipState::Invite => MembershipChange::Invited,
MembershipState::Join => MembershipChange::Joined,
MembershipState::Knock => MembershipChange::Knocked,
MembershipState::Leave => {
if membership_change.user_id() == sender {
MembershipChange::Left
} else {
MembershipChange::Kicked
}
}
_ => MembershipChange::NotImplemented,
}
_ => MembershipChange::NotImplemented,
}
}
}
}
fn update_with_profile_change(&self, profile_change: &MemberProfileChange, display_name: &str) {
let message = if let Some(displayname) = profile_change.displayname_change() {
if let Some(prev_name) = &displayname.old {
if let Some(new_name) = &displayname.new {
fn update_with_profile_change(
&self,
profile_change: &MemberProfileChange,
display_name: &str,
) {
let message = if let Some(displayname) = profile_change.displayname_change() {
if let Some(prev_name) = &displayname.old {
if let Some(new_name) = &displayname.new {
gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{previous_user_name} changed their display name to {new_user_name}.",
&[
("previous_user_name", prev_name),
("new_user_name", new_name),
],
)
} else {
gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{previous_user_name} removed their display name.",
&[("previous_user_name", prev_name)],
)
}
} else {
let new_name = displayname
.new
.as_ref()
.expect("At least one displayname is set in a display name change");
gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{previous_user_name} changed their display name to {new_user_name}.",
"{user_id} set their display name to {new_user_name}.",
&[
("previous_user_name", prev_name),
("user_id", profile_change.user_id().as_ref()),
("new_user_name", new_name),
],
)
}
} else if let Some(avatar_url) = profile_change.avatar_url_change() {
if avatar_url.old.is_none() {
gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} set their avatar.",
&[("user", display_name)],
)
} else if avatar_url.new.is_none() {
gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} removed their avatar.",
&[("user", display_name)],
)
} else {
gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{previous_user_name} removed their display name.",
&[("previous_user_name", prev_name)],
"{user} changed their avatar.",
&[("user", display_name)],
)
}
} else {
let new_name = displayname
.new
.as_ref()
.expect("At least one displayname is set in a display name change");
gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user_id} set their display name to {new_user_name}.",
&[
("user_id", profile_change.user_id().as_ref()),
("new_user_name", new_name),
],
)
}
} else if let Some(avatar_url) = profile_change.avatar_url_change() {
if avatar_url.old.is_none() {
gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} set their avatar.",
&[("user", display_name)],
)
} else if avatar_url.new.is_none() {
gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} removed their avatar.",
&[("user", display_name)],
)
// We don't know what changed so fall back to the membership.
// Translators: Do NOT translate the content between '{' and '}', this
// is a variable name.
gettext_f("{user} joined this room.", &[("user", display_name)])
};
if let Some(child) = self.content.child().and_downcast::<gtk::Label>() {
child.set_text(&message);
} else {
gettext_f(
// Translators: Do NOT translate the content between
// '{' and '}', this is a variable name.
"{user} changed their avatar.",
&[("user", display_name)],
)
}
} else {
// We don't know what changed so fall back to the membership.
// Translators: Do NOT translate the content between '{' and '}', this
// is a variable name.
gettext_f("{user} joined this room.", &[("user", display_name)])
};
self.content.set_child(Some(&text(&message)));
};
}
}
}
let content = self.content();
if let Some(child) = content.child().and_downcast::<gtk::Label>() {
child.set_text(&message);
} else {
content.set_child(Some(&text(&message)));
};
glib::wrapper! {
/// A row presenting a state event.
pub struct StateRow(ObjectSubclass<imp::StateRow>)
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
}
impl StateRow {
pub fn new() -> Self {
glib::Object::new()
}
}

109
src/session/view/content/room_history/state_row/tombstone.rs

@ -16,10 +16,10 @@ mod imp {
#[properties(wrapper_type = super::StateTombstone)]
pub struct StateTombstone {
#[template_child]
pub new_room_btn: TemplateChild<gtk::Button>,
new_room_btn: TemplateChild<gtk::Button>,
/// The [`Room`] this event belongs to.
#[property(get, set = Self::set_room, construct_only)]
pub room: BoundObjectWeakRef<Room>,
room: BoundObjectWeakRef<Room>,
}
#[glib::object_subclass]
@ -30,7 +30,7 @@ mod imp {
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
Self::Type::bind_template_callbacks(klass);
Self::bind_template_callbacks(klass);
}
fn instance_init(obj: &InitializingObject<Self>) {
@ -44,11 +44,10 @@ mod imp {
impl WidgetImpl for StateTombstone {}
impl BinImpl for StateTombstone {}
#[gtk::template_callbacks]
impl StateTombstone {
/// Set the room this event belongs to.
fn set_room(&self, room: &Room) {
let obj = self.obj();
let successor_handler = room.connect_successor_id_string_notify(clone!(
#[weak(rename_to = imp)]
self,
@ -59,17 +58,63 @@ mod imp {
self.new_room_btn.set_visible(room.successor_id().is_some());
let successor_room_handler = room.connect_successor_notify(clone!(
#[weak]
obj,
#[weak(rename_to = imp)]
self,
move |room| {
obj.update_button_label(room);
imp.update_button_label(room);
}
));
obj.update_button_label(room);
self.update_button_label(room);
self.room
.set(room, vec![successor_handler, successor_room_handler]);
}
/// Update the button of the label.
fn update_button_label(&self, room: &Room) {
let label = if room.successor().is_some() {
// Translators: This is a verb, as in 'View Room'.
gettext("View")
} else {
gettext("Join")
};
self.new_room_btn.set_label(&label);
}
/// Join or view the successor of this event's room.
#[template_callback]
async fn join_or_view_successor(&self) {
let Some(room) = self.room.obj() else {
return;
};
let Some(session) = room.session() else {
return;
};
let room_list = session.room_list();
let obj = self.obj();
// Join or view the room with the given identifier.
if let Some(successor) = room.successor() {
let Some(window) = obj.root().and_downcast::<Window>() else {
return;
};
window.session_view().select_room(Some(successor));
} 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) = room_list
.join_by_id_or_alias(successor_id.into(), via)
.await
{
toast!(obj, error);
}
}
}
}
}
@ -79,55 +124,9 @@ glib::wrapper! {
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
}
#[gtk::template_callbacks]
impl StateTombstone {
/// Construct a new `StateTombstone` with the given room.
pub fn new(room: &Room) -> Self {
glib::Object::builder().property("room", room).build()
}
/// Update the button of the label.
fn update_button_label(&self, room: &Room) {
let button = &self.imp().new_room_btn;
if room.successor().is_some() {
// Translators: This is a verb, as in 'View Room'.
button.set_label(&gettext("View"));
} else {
button.set_label(&gettext("Join"));
}
}
/// Join or view the successor of this event's room.
#[template_callback]
async fn join_or_view_successor(&self) {
let Some(room) = self.room() else {
return;
};
let Some(session) = room.session() else {
return;
};
let room_list = session.room_list();
// Join or view the room with the given identifier.
if let Some(successor) = room.successor() {
let Some(window) = self.root().and_downcast::<Window>() else {
return;
};
window.session_view().select_room(Some(successor));
} 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) = room_list
.join_by_id_or_alias(successor_id.into(), via)
.await
{
toast!(self, error);
}
}
}
}

Loading…
Cancel
Save