|
|
|
|
@ -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() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|