Browse Source

Use SyncRoomEvent instead of other types

merge-requests/1327/merge
Julian Sparber 5 years ago
parent
commit
5a3c22a403
  1. 116
      src/session/content/item_row.rs
  2. 42
      src/session/content/message_row.rs
  3. 4
      src/session/content/state_row.rs
  4. 348
      src/session/room/event.rs
  5. 8
      src/session/room/item.rs
  6. 133
      src/session/room/room.rs
  7. 65
      src/session/room/timeline.rs
  8. 4
      src/session/user.rs

116
src/session/content/item_row.rs

@ -1,21 +1,23 @@
use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext;
use gtk::{gio, glib, prelude::*, subclass::prelude::*};
use gtk::{gio, glib, glib::clone, prelude::*, subclass::prelude::*};
use crate::components::{ContextMenuBin, ContextMenuBinExt, ContextMenuBinImpl};
use crate::session::content::{DividerRow, MessageRow, StateRow};
use crate::session::event_source_dialog::EventSourceDialog;
use crate::session::room::{Item, ItemType};
use matrix_sdk::ruma::events::AnyRoomEvent;
use crate::session::room::{Event, Item, ItemType};
use matrix_sdk::ruma::events::AnySyncRoomEvent;
mod imp {
use super::*;
use glib::signal::SignalHandlerId;
use std::cell::RefCell;
#[derive(Debug, Default)]
pub struct ItemRow {
pub item: RefCell<Option<Item>>,
pub menu_model: RefCell<Option<gio::MenuModel>>,
pub event_notify_handler: RefCell<Option<SignalHandlerId>>,
}
#[glib::object_subclass]
@ -73,6 +75,16 @@ mod imp {
_ => unimplemented!(),
}
}
fn dispose(&self, _obj: &Self::Type) {
if let Some(ItemType::Event(event)) =
self.item.borrow().as_ref().map(|item| item.type_())
{
if let Some(handler) = self.event_notify_handler.borrow_mut().take() {
event.disconnect(handler);
}
}
}
}
impl WidgetImpl for ItemRow {}
@ -113,6 +125,13 @@ impl ItemRow {
fn set_item(&self, item: Option<Item>) {
let priv_ = imp::ItemRow::from_instance(&self);
if let Some(ItemType::Event(event)) = priv_.item.borrow().as_ref().map(|item| item.type_())
{
if let Some(handler) = priv_.event_notify_handler.borrow_mut().take() {
event.disconnect(handler);
}
}
if let Some(ref item) = item {
match item.type_() {
ItemType::Event(event) => {
@ -126,57 +145,19 @@ impl ItemRow {
self.enable_gactions();
}
match event.matrix_event() {
AnyRoomEvent::Message(_message) => {
let child = if let Some(Ok(child)) =
self.child().map(|w| w.downcast::<MessageRow>())
{
child
} else {
let child = MessageRow::new();
self.set_child(Some(&child));
child
};
child.set_event(event.clone());
}
AnyRoomEvent::State(state) => {
let child = if let Some(Ok(child)) =
self.child().map(|w| w.downcast::<StateRow>())
{
child
} else {
let child = StateRow::new();
self.set_child(Some(&child));
child
};
child.update(&state);
}
AnyRoomEvent::RedactedMessage(_) => {
let child = if let Some(Ok(child)) =
self.child().map(|w| w.downcast::<MessageRow>())
{
child
} else {
let child = MessageRow::new();
self.set_child(Some(&child));
child
};
child.set_event(event.clone());
}
AnyRoomEvent::RedactedState(_) => {
let child = if let Some(Ok(child)) =
self.child().map(|w| w.downcast::<MessageRow>())
{
child
} else {
let child = MessageRow::new();
self.set_child(Some(&child));
child
};
child.set_event(event.clone());
}
}
let event_notify_handler = event.connect_notify_local(
Some("event"),
clone!(@weak self as obj => move |event, _| {
obj.set_event_widget(event);
}),
);
priv_
.event_notify_handler
.borrow_mut()
.replace(event_notify_handler);
self.set_event_widget(event);
}
ItemType::DayDivider(date) => {
if self.context_menu().is_some() {
@ -219,4 +200,31 @@ impl ItemRow {
}
priv_.item.replace(item);
}
fn set_event_widget(&self, event: &Event) {
match event.matrix_event() {
Some(AnySyncRoomEvent::State(state)) => {
let child = if let Some(Ok(child)) = self.child().map(|w| w.downcast::<StateRow>())
{
child
} else {
let child = StateRow::new();
self.set_child(Some(&child));
child
};
child.update(&state);
}
_ => {
let child =
if let Some(Ok(child)) = self.child().map(|w| w.downcast::<MessageRow>()) {
child
} else {
let child = MessageRow::new();
self.set_child(Some(&child));
child
};
child.set_event(event.clone());
}
}
}
}

42
src/session/content/message_row.rs

@ -1,5 +1,6 @@
use crate::components::Avatar;
use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext;
use gtk::{
gio, glib, glib::clone, glib::signal::SignalHandlerId, prelude::*, subclass::prelude::*,
CompositeTemplate,
@ -12,7 +13,7 @@ use log::warn;
use matrix_sdk::ruma::events::{
room::message::{FormattedBody, MessageFormat, MessageType, Relation},
room::redaction::RedactionEventContent,
AnyMessageEvent, AnyMessageEventContent, AnyRoomEvent,
AnyMessageEventContent, AnySyncMessageEvent, AnySyncRoomEvent,
};
use sourceview::prelude::*;
@ -190,10 +191,10 @@ impl MessageRow {
if let Some(replacement_event) = event.relates_to().iter().rev().find(|event| {
let matrix_event = event.matrix_event();
match matrix_event {
AnyRoomEvent::Message(AnyMessageEvent::RoomMessage(message)) => {
Some(AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(message))) => {
message.content.relates_to.is_some()
}
AnyRoomEvent::Message(AnyMessageEvent::RoomRedaction(_)) => true,
Some(AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomRedaction(_))) => true,
_ => false,
}
}) {
@ -207,24 +208,32 @@ impl MessageRow {
}
}
/// Find the content we need to display
fn find_content(&self, event: &Event) -> AnyMessageEventContent {
fn find_content(&self, event: &Event) -> Option<AnyMessageEventContent> {
match self.find_last_event(event).matrix_event() {
AnyRoomEvent::Message(message) => message.content(),
AnyRoomEvent::RedactedMessage(message) => {
Some(AnySyncRoomEvent::Message(message)) => Some(message.content()),
Some(AnySyncRoomEvent::RedactedMessage(message)) => {
if let Some(ref redaction_event) = message.unsigned().redacted_because {
AnyMessageEventContent::RoomRedaction(redaction_event.content.clone())
Some(AnyMessageEventContent::RoomRedaction(
redaction_event.content.clone(),
))
} else {
AnyMessageEventContent::RoomRedaction(RedactionEventContent::new())
Some(AnyMessageEventContent::RoomRedaction(
RedactionEventContent::new(),
))
}
}
AnyRoomEvent::RedactedState(state) => {
Some(AnySyncRoomEvent::RedactedState(state)) => {
if let Some(ref redaction_event) = state.unsigned().redacted_because {
AnyMessageEventContent::RoomRedaction(redaction_event.content.clone())
Some(AnyMessageEventContent::RoomRedaction(
redaction_event.content.clone(),
))
} else {
AnyMessageEventContent::RoomRedaction(RedactionEventContent::new())
Some(AnyMessageEventContent::RoomRedaction(
RedactionEventContent::new(),
))
}
}
_ => panic!("This event isn’t a room message event or redacted event"),
_ => None,
}
}
@ -234,8 +243,9 @@ impl MessageRow {
// TODO: create widgets for all event types
// TODO: display reaction events from event.relates_to()
match content {
AnyMessageEventContent::RoomMessage(message) => {
Some(AnyMessageEventContent::RoomMessage(message)) => {
let msgtype = if let Some(Relation::Replacement(replacement)) = message.relates_to {
replacement.new_content.msgtype
} else {
@ -300,10 +310,10 @@ impl MessageRow {
}
}
}
AnyMessageEventContent::RoomRedaction(_) => {
self.show_label_with_text("This message was removed.");
Some(AnyMessageEventContent::RoomRedaction(_)) => {
self.show_label_with_text(&gettext("This message was removed."))
}
_ => warn!("Event not supported: {:?}", content),
_ => self.show_label_with_text(&gettext("Unsupported event")),
}
}

4
src/session/content/state_row.rs

@ -3,7 +3,7 @@ use gettextrs::gettext;
use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
use log::warn;
use matrix_sdk::ruma::events::{
room::member::MembershipState, AnyStateEvent, AnyStateEventContent,
room::member::MembershipState, AnyStateEventContent, AnySyncStateEvent,
};
mod imp {
@ -51,7 +51,7 @@ impl StateRow {
glib::Object::new(&[]).expect("Failed to create StateRow")
}
pub fn update(&self, state: &AnyStateEvent) {
pub fn update(&self, state: &AnySyncStateEvent) {
let _priv_ = imp::StateRow::from_instance(self);
// We may want to show more state events in the future
// For a full list of state events see:

348
src/session/room/event.rs

@ -1,20 +1,23 @@
use gtk::{glib, glib::DateTime, prelude::*, subclass::prelude::*};
use matrix_sdk::ruma::{
events::{
room::message::MessageType, room::message::Relation, AnyMessageEvent,
AnyMessageEventContent, AnyRedactedMessageEvent, AnyRedactedStateEvent, AnyRoomEvent,
AnyStateEvent,
use matrix_sdk::{
deserialized_responses::SyncRoomEvent,
ruma::{
events::{
room::message::MessageType, room::message::Relation, AnyMessageEventContent,
AnyRedactedSyncMessageEvent, AnyRedactedSyncStateEvent, AnySyncMessageEvent,
AnySyncRoomEvent, AnySyncStateEvent,
},
identifiers::{EventId, UserId},
MilliSecondsSinceUnixEpoch,
},
identifiers::{EventId, UserId},
};
use crate::fn_event;
use crate::session::User;
use std::cell::RefCell;
use crate::session::{Room, User};
use log::warn;
#[derive(Clone, Debug, glib::GBoxed)]
#[gboxed(type_name = "BoxedAnyRoomEvent")]
pub struct BoxedAnyRoomEvent(AnyRoomEvent);
#[gboxed(type_name = "BoxedSyncRoomEvent")]
pub struct BoxedSyncRoomEvent(SyncRoomEvent);
mod imp {
use super::*;
@ -24,11 +27,13 @@ mod imp {
#[derive(Debug, Default)]
pub struct Event {
pub event: OnceCell<RefCell<AnyRoomEvent>>,
pub source: RefCell<Option<String>>,
/// The deserialized matrix event
pub event: RefCell<Option<AnySyncRoomEvent>>,
/// The SDK event containing encryption information and the serialized event as `Raw`
pub pure_event: RefCell<Option<SyncRoomEvent>>,
pub relates_to: RefCell<Vec<super::Event>>,
pub show_header: Cell<bool>,
pub sender: OnceCell<User>,
pub room: OnceCell<Room>,
}
#[glib::object_subclass]
@ -53,15 +58,15 @@ mod imp {
"event",
"event",
"The matrix event of this Event",
BoxedAnyRoomEvent::static_type(),
glib::ParamFlags::WRITABLE | glib::ParamFlags::CONSTRUCT,
BoxedSyncRoomEvent::static_type(),
glib::ParamFlags::WRITABLE,
),
glib::ParamSpec::new_string(
"source",
"Source",
"The source (JSON) of this Event",
None,
glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT | glib::ParamFlags::EXPLICIT_NOTIFY,
glib::ParamFlags::READABLE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
glib::ParamSpec::new_boolean(
"show-header",
@ -82,6 +87,13 @@ mod imp {
"Sender",
"The sender of this matrix event",
User::static_type(),
glib::ParamFlags::READABLE,
),
glib::ParamSpec::new_object(
"room",
"Room",
"The room containing this event",
Room::static_type(),
glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
),
glib::ParamSpec::new_string(
@ -106,22 +118,15 @@ mod imp {
) {
match pspec.name() {
"event" => {
let event = value.get::<BoxedAnyRoomEvent>().unwrap();
obj.set_matrix_event(event.0);
}
"source" => {
let source = value.get().unwrap();
obj.set_source(source);
let event = value.get::<BoxedSyncRoomEvent>().unwrap();
obj.set_matrix_pure_event(event.0);
}
"show-header" => {
let show_header = value.get().unwrap();
let _ = obj.set_show_header(show_header);
}
"sender" => {
let sender = value.get().unwrap();
if let Some(sender) = sender {
let _ = self.sender.set(sender).unwrap();
}
"room" => {
let _ = self.room.set(value.get().unwrap());
}
_ => unimplemented!(),
}
@ -130,7 +135,8 @@ mod imp {
fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"source" => obj.source().to_value(),
"sender" => self.sender.get().to_value(),
"sender" => obj.sender().to_value(),
"room" => self.room.get().unwrap().to_value(),
"show-header" => obj.show_header().to_value(),
"can-hide-header" => obj.can_hide_header().to_value(),
"time" => obj.time().to_value(),
@ -149,68 +155,108 @@ glib::wrapper! {
/// This is the GObject representation of a matrix room event
impl Event {
pub fn new(event: &AnyRoomEvent, source: &String, sender: &User) -> Self {
let event = BoxedAnyRoomEvent(event.to_owned());
glib::Object::new(&[("event", &event), ("source", source), ("sender", sender)])
.expect("Failed to create Event")
pub fn new(event: SyncRoomEvent, room: &Room) -> Self {
let event = BoxedSyncRoomEvent(event);
glib::Object::new(&[("event", &event), ("room", room)]).expect("Failed to create Event")
}
pub fn sender(&self) -> &User {
pub fn sender(&self) -> User {
let priv_ = imp::Event::from_instance(&self);
priv_.sender.get().unwrap()
priv_
.room
.get()
.unwrap()
.member_by_id(&self.matrix_sender())
}
pub fn matrix_event(&self) -> AnyRoomEvent {
/// Get the matrix event
///
/// If the `SyncRoomEvent` couldn't be deserialized this is `None`
pub fn matrix_event(&self) -> Option<AnySyncRoomEvent> {
let priv_ = imp::Event::from_instance(&self);
priv_.event.get().unwrap().borrow().clone()
priv_.event.borrow().clone()
}
pub fn set_matrix_event(&self, event: AnyRoomEvent) {
pub fn matrix_pure_event(&self) -> SyncRoomEvent {
let priv_ = imp::Event::from_instance(&self);
if let Some(value) = priv_.event.get() {
value.replace(event);
priv_.pure_event.borrow().clone().unwrap()
}
pub fn set_matrix_pure_event(&self, event: SyncRoomEvent) {
let priv_ = imp::Event::from_instance(&self);
if let Ok(deserialized) = event.event.deserialize() {
priv_.event.replace(Some(deserialized));
} else {
priv_.event.set(RefCell::new(event)).unwrap();
warn!("Failed to deserialize event: {:?}", event);
}
priv_.pure_event.replace(Some(event));
self.notify("event");
}
pub fn matrix_sender(&self) -> UserId {
let priv_ = imp::Event::from_instance(&self);
let event = &*priv_.event.get().unwrap().borrow();
fn_event!(event, sender).clone()
if let Some(event) = priv_.event.borrow().as_ref() {
event.sender().to_owned()
} else {
priv_
.pure_event
.borrow()
.as_ref()
.unwrap()
.event
.get_field::<UserId>("sender")
.unwrap()
.unwrap()
}
}
pub fn matrix_event_id(&self) -> EventId {
let priv_ = imp::Event::from_instance(&self);
let event = &*priv_.event.get().unwrap().borrow();
fn_event!(event, event_id).clone()
}
pub fn source(&self) -> String {
let priv_ = imp::Event::from_instance(&self);
priv_.source.borrow().clone().unwrap_or("".into())
if let Some(event) = priv_.event.borrow().as_ref() {
event.event_id().to_owned()
} else {
priv_
.pure_event
.borrow()
.as_ref()
.unwrap()
.event
.get_field::<EventId>("event_id")
.unwrap()
.unwrap()
}
}
pub fn set_source(&self, source: Option<String>) {
pub fn source(&self) -> String {
let priv_ = imp::Event::from_instance(&self);
if Some(self.source()) == source {
return;
}
priv_.source.replace(source);
self.notify("source");
serde_json::to_string_pretty(priv_.pure_event.borrow().as_ref().unwrap().event.json())
.unwrap()
}
pub fn timestamp(&self) -> DateTime {
let priv_ = imp::Event::from_instance(&self);
let event = &*priv_.event.get().unwrap().borrow();
let ts = fn_event!(event, origin_server_ts).clone();
// FIXME: we need to add `as_secs()` to `MilliSecondsSinceUnixEpoch`
DateTime::from_unix_utc(i64::from(ts.0) / 1000)
let ts = if let Some(event) = priv_.event.borrow().as_ref() {
event.origin_server_ts().as_secs()
} else {
priv_
.pure_event
.borrow()
.as_ref()
.unwrap()
.event
.get_field::<MilliSecondsSinceUnixEpoch>("origin_server_ts")
.unwrap()
.unwrap()
.as_secs()
};
DateTime::from_unix_utc(ts.into())
.and_then(|t| t.to_local())
.unwrap()
}
@ -234,9 +280,9 @@ impl Event {
pub fn related_matrix_event(&self) -> Option<EventId> {
let priv_ = imp::Event::from_instance(&self);
match *priv_.event.get().unwrap().borrow() {
AnyRoomEvent::Message(ref message) => match message {
AnyMessageEvent::RoomRedaction(event) => Some(event.redacts.clone()),
match priv_.event.borrow().as_ref()? {
AnySyncRoomEvent::Message(ref message) => match message {
AnySyncMessageEvent::RoomRedaction(event) => Some(event.redacts.clone()),
_ => match message.content() {
AnyMessageEventContent::Reaction(event) => Some(event.relates_to.event_id),
AnyMessageEventContent::RoomMessage(event) => match event.relates_to {
@ -265,75 +311,79 @@ impl Event {
return true;
}
match &*priv_.event.get().unwrap().borrow() {
AnyRoomEvent::Message(message) => match message {
AnyMessageEvent::CallAnswer(_) => true,
AnyMessageEvent::CallInvite(_) => true,
AnyMessageEvent::CallHangup(_) => true,
AnyMessageEvent::CallCandidates(_) => true,
AnyMessageEvent::KeyVerificationReady(_) => true,
AnyMessageEvent::KeyVerificationStart(_) => true,
AnyMessageEvent::KeyVerificationCancel(_) => true,
AnyMessageEvent::KeyVerificationAccept(_) => true,
AnyMessageEvent::KeyVerificationKey(_) => true,
AnyMessageEvent::KeyVerificationMac(_) => true,
AnyMessageEvent::KeyVerificationDone(_) => true,
AnyMessageEvent::RoomEncrypted(_) => true,
AnyMessageEvent::RoomMessageFeedback(_) => true,
AnyMessageEvent::RoomRedaction(_) => true,
AnyMessageEvent::Sticker(_) => true,
_ => false,
},
AnyRoomEvent::State(state) => match state {
AnyStateEvent::PolicyRuleRoom(_) => true,
AnyStateEvent::PolicyRuleServer(_) => true,
AnyStateEvent::PolicyRuleUser(_) => true,
AnyStateEvent::RoomAliases(_) => true,
AnyStateEvent::RoomAvatar(_) => true,
AnyStateEvent::RoomCanonicalAlias(_) => true,
AnyStateEvent::RoomEncryption(_) => true,
AnyStateEvent::RoomJoinRules(_) => true,
AnyStateEvent::RoomName(_) => true,
AnyStateEvent::RoomPinnedEvents(_) => true,
AnyStateEvent::RoomPowerLevels(_) => true,
AnyStateEvent::RoomServerAcl(_) => true,
AnyStateEvent::RoomTopic(_) => true,
_ => false,
},
AnyRoomEvent::RedactedMessage(message) => match message {
AnyRedactedMessageEvent::CallAnswer(_) => true,
AnyRedactedMessageEvent::CallInvite(_) => true,
AnyRedactedMessageEvent::CallHangup(_) => true,
AnyRedactedMessageEvent::CallCandidates(_) => true,
AnyRedactedMessageEvent::KeyVerificationReady(_) => true,
AnyRedactedMessageEvent::KeyVerificationStart(_) => true,
AnyRedactedMessageEvent::KeyVerificationCancel(_) => true,
AnyRedactedMessageEvent::KeyVerificationAccept(_) => true,
AnyRedactedMessageEvent::KeyVerificationKey(_) => true,
AnyRedactedMessageEvent::KeyVerificationMac(_) => true,
AnyRedactedMessageEvent::KeyVerificationDone(_) => true,
AnyRedactedMessageEvent::RoomEncrypted(_) => true,
AnyRedactedMessageEvent::RoomMessageFeedback(_) => true,
AnyRedactedMessageEvent::RoomRedaction(_) => true,
AnyRedactedMessageEvent::Sticker(_) => true,
_ => false,
},
AnyRoomEvent::RedactedState(state) => match state {
AnyRedactedStateEvent::PolicyRuleRoom(_) => true,
AnyRedactedStateEvent::PolicyRuleServer(_) => true,
AnyRedactedStateEvent::PolicyRuleUser(_) => true,
AnyRedactedStateEvent::RoomAliases(_) => true,
AnyRedactedStateEvent::RoomAvatar(_) => true,
AnyRedactedStateEvent::RoomCanonicalAlias(_) => true,
AnyRedactedStateEvent::RoomEncryption(_) => true,
AnyRedactedStateEvent::RoomJoinRules(_) => true,
AnyRedactedStateEvent::RoomName(_) => true,
AnyRedactedStateEvent::RoomPinnedEvents(_) => true,
AnyRedactedStateEvent::RoomPowerLevels(_) => true,
AnyRedactedStateEvent::RoomServerAcl(_) => true,
AnyRedactedStateEvent::RoomTopic(_) => true,
_ => false,
},
if let Some(event) = priv_.event.borrow().as_ref() {
match event {
AnySyncRoomEvent::Message(message) => match message {
AnySyncMessageEvent::CallAnswer(_) => true,
AnySyncMessageEvent::CallInvite(_) => true,
AnySyncMessageEvent::CallHangup(_) => true,
AnySyncMessageEvent::CallCandidates(_) => true,
AnySyncMessageEvent::KeyVerificationReady(_) => true,
AnySyncMessageEvent::KeyVerificationStart(_) => true,
AnySyncMessageEvent::KeyVerificationCancel(_) => true,
AnySyncMessageEvent::KeyVerificationAccept(_) => true,
AnySyncMessageEvent::KeyVerificationKey(_) => true,
AnySyncMessageEvent::KeyVerificationMac(_) => true,
AnySyncMessageEvent::KeyVerificationDone(_) => true,
AnySyncMessageEvent::RoomEncrypted(_) => true,
AnySyncMessageEvent::RoomMessageFeedback(_) => true,
AnySyncMessageEvent::RoomRedaction(_) => true,
AnySyncMessageEvent::Sticker(_) => true,
_ => false,
},
AnySyncRoomEvent::State(state) => match state {
AnySyncStateEvent::PolicyRuleRoom(_) => true,
AnySyncStateEvent::PolicyRuleServer(_) => true,
AnySyncStateEvent::PolicyRuleUser(_) => true,
AnySyncStateEvent::RoomAliases(_) => true,
AnySyncStateEvent::RoomAvatar(_) => true,
AnySyncStateEvent::RoomCanonicalAlias(_) => true,
AnySyncStateEvent::RoomEncryption(_) => true,
AnySyncStateEvent::RoomJoinRules(_) => true,
AnySyncStateEvent::RoomName(_) => true,
AnySyncStateEvent::RoomPinnedEvents(_) => true,
AnySyncStateEvent::RoomPowerLevels(_) => true,
AnySyncStateEvent::RoomServerAcl(_) => true,
AnySyncStateEvent::RoomTopic(_) => true,
_ => false,
},
AnySyncRoomEvent::RedactedMessage(message) => match message {
AnyRedactedSyncMessageEvent::CallAnswer(_) => true,
AnyRedactedSyncMessageEvent::CallInvite(_) => true,
AnyRedactedSyncMessageEvent::CallHangup(_) => true,
AnyRedactedSyncMessageEvent::CallCandidates(_) => true,
AnyRedactedSyncMessageEvent::KeyVerificationReady(_) => true,
AnyRedactedSyncMessageEvent::KeyVerificationStart(_) => true,
AnyRedactedSyncMessageEvent::KeyVerificationCancel(_) => true,
AnyRedactedSyncMessageEvent::KeyVerificationAccept(_) => true,
AnyRedactedSyncMessageEvent::KeyVerificationKey(_) => true,
AnyRedactedSyncMessageEvent::KeyVerificationMac(_) => true,
AnyRedactedSyncMessageEvent::KeyVerificationDone(_) => true,
AnyRedactedSyncMessageEvent::RoomEncrypted(_) => true,
AnyRedactedSyncMessageEvent::RoomMessageFeedback(_) => true,
AnyRedactedSyncMessageEvent::RoomRedaction(_) => true,
AnyRedactedSyncMessageEvent::Sticker(_) => true,
_ => false,
},
AnySyncRoomEvent::RedactedState(state) => match state {
AnyRedactedSyncStateEvent::PolicyRuleRoom(_) => true,
AnyRedactedSyncStateEvent::PolicyRuleServer(_) => true,
AnyRedactedSyncStateEvent::PolicyRuleUser(_) => true,
AnyRedactedSyncStateEvent::RoomAliases(_) => true,
AnyRedactedSyncStateEvent::RoomAvatar(_) => true,
AnyRedactedSyncStateEvent::RoomCanonicalAlias(_) => true,
AnyRedactedSyncStateEvent::RoomEncryption(_) => true,
AnyRedactedSyncStateEvent::RoomJoinRules(_) => true,
AnyRedactedSyncStateEvent::RoomName(_) => true,
AnyRedactedSyncStateEvent::RoomPinnedEvents(_) => true,
AnyRedactedSyncStateEvent::RoomPowerLevels(_) => true,
AnyRedactedSyncStateEvent::RoomServerAcl(_) => true,
AnyRedactedSyncStateEvent::RoomTopic(_) => true,
_ => false,
},
}
} else {
false
}
}
@ -353,23 +403,25 @@ impl Event {
}
pub fn can_hide_header(&self) -> bool {
let priv_ = imp::Event::from_instance(&self);
match &*priv_.event.get().unwrap().borrow() {
AnyRoomEvent::Message(ref message) => match message.content() {
AnyMessageEventContent::RoomMessage(message) => match message.msgtype {
MessageType::Audio(_) => true,
MessageType::File(_) => true,
MessageType::Image(_) => true,
MessageType::Location(_) => true,
MessageType::Notice(_) => true,
MessageType::Text(_) => true,
MessageType::Video(_) => true,
if let Some(event) = self.matrix_event() {
match event {
AnySyncRoomEvent::Message(ref message) => match message.content() {
AnyMessageEventContent::RoomMessage(message) => match message.msgtype {
MessageType::Audio(_) => true,
MessageType::File(_) => true,
MessageType::Image(_) => true,
MessageType::Location(_) => true,
MessageType::Notice(_) => true,
MessageType::Text(_) => true,
MessageType::Video(_) => true,
_ => false,
},
_ => false,
},
_ => false,
},
_ => false,
}
} else {
false
}
}

8
src/session/room/item.rs

@ -1,6 +1,6 @@
use gtk::{glib, glib::DateTime, prelude::*, subclass::prelude::*};
use matrix_sdk::ruma::{
events::AnyRoomEvent,
events::AnySyncRoomEvent,
identifiers::{EventId, UserId},
};
@ -115,7 +115,7 @@ glib::wrapper! {
}
/// This represents any row inside the room history.
/// This can be AnyRoomEvent, a day divider or new message divider.
/// This can be AnySyncRoomEvent, a day divider or new message divider.
impl Item {
pub fn for_event(event: Event) -> Self {
let type_ = BoxedItemType(ItemType::Event(event));
@ -141,10 +141,10 @@ impl Item {
}
}
pub fn matrix_event(&self) -> Option<AnyRoomEvent> {
pub fn matrix_event(&self) -> Option<AnySyncRoomEvent> {
let priv_ = imp::Item::from_instance(&self);
if let ItemType::Event(event) = priv_.type_.get().unwrap() {
Some(event.matrix_event())
event.matrix_event()
} else {
None
}

133
src/session/room/room.rs

@ -7,7 +7,6 @@ use matrix_sdk::{
ruma::{
api::client::r0::sync::sync_events::InvitedRoom,
events::{
exports::serde::de::DeserializeOwned,
room::{
member::{MemberEventContent, MembershipState},
message::{
@ -16,8 +15,8 @@ use matrix_sdk::{
},
},
tag::TagName,
AnyMessageEvent, AnyRoomAccountDataEvent, AnyRoomEvent, AnyStateEvent,
AnyStrippedStateEvent, AnySyncRoomEvent, MessageEvent, StateEvent, Unsigned,
AnyRoomAccountDataEvent, AnyStrippedStateEvent, AnySyncMessageEvent, AnySyncRoomEvent,
AnySyncStateEvent, SyncMessageEvent, SyncStateEvent, Unsigned,
},
identifiers::{EventId, RoomId, UserId},
serde::Raw,
@ -26,13 +25,13 @@ use matrix_sdk::{
uuid::Uuid,
RoomMember,
};
use serde_json::value::RawValue;
use std::cell::RefCell;
use std::convert::TryFrom;
use crate::components::{LabelWithWidgets, Pill};
use crate::event_from_sync_event;
use crate::session::{
room::{HighlightFlags, RoomType, Timeline},
room::{Event, HighlightFlags, RoomType, Timeline},
Avatar, Session, User,
};
use crate::utils::do_async;
@ -539,28 +538,30 @@ impl Room {
}
/// Add new events to the timeline
pub fn append_events<T: DeserializeOwned>(&self, batch: Vec<(AnyRoomEvent, Raw<T>)>) {
pub fn append_events(&self, batch: Vec<Event>) {
let priv_ = imp::Room::from_instance(self);
//FIXME: notify only when the count has changed
self.notify_notification_count();
for (event, _) in batch.iter() {
match event {
AnyRoomEvent::State(AnyStateEvent::RoomMember(ref event)) => {
self.update_member_for_member_event(event)
}
AnyRoomEvent::State(AnyStateEvent::RoomAvatar(event)) => {
self.avatar().set_url(event.content.url.to_owned());
}
AnyRoomEvent::State(AnyStateEvent::RoomName(_)) => {
// FIXME: this doesn't take into account changes in the calculated name
self.load_display_name()
}
AnyRoomEvent::State(AnyStateEvent::RoomTopic(_)) => {
self.notify("topic");
for event in &batch {
if let Some(event) = event.matrix_event() {
match event {
AnySyncRoomEvent::State(AnySyncStateEvent::RoomMember(ref event)) => {
self.update_member_for_member_event(event)
}
AnySyncRoomEvent::State(AnySyncStateEvent::RoomAvatar(event)) => {
self.avatar().set_url(event.content.url.to_owned());
}
AnySyncRoomEvent::State(AnySyncStateEvent::RoomName(_)) => {
// FIXME: this doesn't take into account changes in the calculated name
self.load_display_name()
}
AnySyncRoomEvent::State(AnySyncStateEvent::RoomTopic(_)) => {
self.notify("topic");
}
_ => {}
}
_ => {}
}
}
@ -583,7 +584,7 @@ impl Room {
}
/// Updates a room member based on the room member state event
fn update_member_for_member_event(&self, event: &StateEvent<MemberEventContent>) {
fn update_member_for_member_event(&self, event: &SyncStateEvent<MemberEventContent>) {
let priv_ = imp::Room::from_instance(self);
let mut room_members = priv_.room_members.borrow_mut();
let user_id = &event.sender;
@ -636,49 +637,46 @@ impl Room {
}
pub fn send_text_message(&self, body: &str, markdown_enabled: bool) {
if let MatrixRoom::Joined(matrix_room) = self.matrix_room() {
let content = if let Some(body) = body.strip_prefix("/me ") {
let emote = if markdown_enabled {
EmoteMessageEventContent::markdown(body)
} else {
EmoteMessageEventContent::plain(body)
};
MessageEventContent::new(MessageType::Emote(emote))
let content = if let Some(body) = body.strip_prefix("/me ") {
let emote = if markdown_enabled {
EmoteMessageEventContent::markdown(body)
} else {
let text = if markdown_enabled {
TextMessageEventContent::markdown(body)
} else {
TextMessageEventContent::plain(body)
};
MessageEventContent::new(MessageType::Text(text))
EmoteMessageEventContent::plain(body)
};
MessageEventContent::new(MessageType::Emote(emote))
} else {
let text = if markdown_enabled {
TextMessageEventContent::markdown(body)
} else {
TextMessageEventContent::plain(body)
};
MessageEventContent::new(MessageType::Text(text))
};
let txn_id = Uuid::new_v4();
let txn_id = Uuid::new_v4();
let pending_event = AnyMessageEvent::RoomMessage(MessageEvent {
content,
event_id: EventId::try_from(format!("${}:fractal.gnome.org", txn_id)).unwrap(),
sender: self.session().user().user_id().clone(),
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
room_id: matrix_room.room_id().clone(),
unsigned: Unsigned::default(),
});
let pending_event = AnySyncMessageEvent::RoomMessage(SyncMessageEvent {
content,
event_id: EventId::try_from(format!("${}:fractal.gnome.org", txn_id)).unwrap(),
sender: self.session().user().user_id().clone(),
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
unsigned: Unsigned::default(),
});
self.send_message(txn_id, pending_event);
}
self.send_message(txn_id, pending_event);
}
pub fn send_message(&self, txn_id: Uuid, event: AnyMessageEvent) {
pub fn send_message(&self, txn_id: Uuid, event: AnySyncMessageEvent) {
let priv_ = imp::Room::from_instance(self);
let content = event.content();
if let MatrixRoom::Joined(matrix_room) = self.matrix_room() {
let pending_id = event.event_id().clone();
priv_
.timeline
.get()
.unwrap()
.append_pending(AnyRoomEvent::Message(event));
let json = serde_json::to_string(&AnySyncRoomEvent::Message(event)).unwrap();
let raw_event: Raw<AnySyncRoomEvent> =
Raw::from_json(RawValue::from_string(json).unwrap());
let event = Event::new(raw_event.into(), self);
priv_.timeline.get().unwrap().append_pending(event);
do_async(
glib::PRIORITY_DEFAULT_IDLE,
@ -686,10 +684,7 @@ impl Room {
clone!(@weak self as obj => move |result| async move {
// FIXME: We should retry the request if it fails
match result {
Ok(result) => {
let priv_ = imp::Room::from_instance(&obj);
priv_.timeline.get().unwrap().set_event_id_for_pending(pending_id, result.event_id)
},
Ok(result) => obj.timeline().set_event_id_for_pending(pending_id, result.event_id),
Err(error) => error!("Couldn’t send message: {}", error),
};
}),
@ -760,22 +755,12 @@ impl Room {
pub fn handle_left_response(&self, response_room: LeftRoom) {
self.set_matrix_room(self.session().client().get_room(self.room_id()).unwrap());
let room_id = self.room_id();
self.append_events(
response_room
.timeline
.events
.into_iter()
.filter_map(|raw_event| {
if let Ok(event) = raw_event.event.deserialize() {
Some((event, raw_event.event))
} else {
error!("Couldn’t deserialize event: {:?}", raw_event);
None
}
})
.map(|(event, source)| (event_from_sync_event!(event, room_id), source))
.map(|event| Event::new(event, self))
.collect(),
);
}
@ -792,22 +777,12 @@ impl Room {
self.load_category();
}
let room_id = self.room_id();
self.append_events(
response_room
.timeline
.events
.into_iter()
.filter_map(|raw_event| {
if let Ok(event) = raw_event.event.deserialize() {
Some((event, raw_event.event))
} else {
error!("Couldn’t deserialize event: {:?}", raw_event);
None
}
})
.map(|(event, source)| (event_from_sync_event!(event, room_id), source))
.map(|event| Event::new(event, self))
.collect(),
);
}

65
src/session/room/timeline.rs

@ -1,12 +1,6 @@
use gtk::{gio, glib, prelude::*, subclass::prelude::*};
use matrix_sdk::ruma::{
events::{exports::serde::de::DeserializeOwned, AnyRoomEvent},
identifiers::EventId,
serde::Raw,
};
use serde_json::{to_string_pretty as to_json_string_pretty, to_value as to_json_value};
use crate::fn_event;
use matrix_sdk::ruma::identifiers::EventId;
use crate::session::room::{Event, Item, Room};
mod imp {
@ -268,7 +262,7 @@ impl Timeline {
/// Append the new events
// TODO: This should be lazy, for inspiration see: https://blogs.gnome.org/ebassi/documentation/lazy-loading/
pub fn append<T: DeserializeOwned>(&self, batch: Vec<(AnyRoomEvent, Raw<T>)>) {
pub fn append(&self, batch: Vec<Event>) {
let priv_ = imp::Timeline::from_instance(self);
if batch.is_empty() {
@ -286,24 +280,22 @@ impl Timeline {
let mut pending_events = priv_.pending_events.borrow_mut();
for (event, raw) in batch.into_iter() {
let event_id = fn_event!(event, event_id).clone();
let user = self.room().member_by_id(fn_event!(event, sender));
let source = to_json_value(raw.into_json())
.and_then(|v| to_json_string_pretty(&v))
.unwrap();
for event in batch.into_iter() {
let event_id = event.matrix_event_id();
if let Some(pending_id) = pending_events.remove(&event_id) {
if let Some(event_obj) = priv_.event_map.borrow_mut().remove(&pending_id) {
event_obj.set_matrix_event(event);
event_obj.set_source(Some(source));
priv_.event_map.borrow_mut().insert(event_id, event_obj);
}
let mut event_map = priv_.event_map.borrow_mut();
if let Some(pending_event) = event_map.remove(&pending_id) {
pending_event.set_matrix_pure_event(event.matrix_pure_event());
event_map.insert(event_id, pending_event);
};
added -= 1;
} else {
let event = Event::new(&event, &source, &user);
priv_.event_map.borrow_mut().insert(event_id, event.clone());
priv_
.event_map
.borrow_mut()
.insert(event_id.to_owned(), event.clone());
if event.is_hidden_event() {
self.add_hidden_event(event);
added -= 1;
@ -320,17 +312,18 @@ impl Timeline {
}
/// Append an event that wasn't yet fully sent and received via a sync
pub fn append_pending(&self, event: AnyRoomEvent) {
pub fn append_pending(&self, event: Event) {
let priv_ = imp::Timeline::from_instance(self);
priv_
.event_map
.borrow_mut()
.insert(event.matrix_event_id(), event.clone());
let index = {
let mut list = priv_.list.borrow_mut();
let index = list.len();
let user = self.room().member_by_id(fn_event!(event, sender));
let source = to_json_string_pretty(&event).unwrap();
let event = Event::new(&event, &source, &user);
if event.is_hidden_event() {
self.add_hidden_event(event);
None
@ -363,7 +356,7 @@ impl Timeline {
/// Prepends a batch of events
// TODO: This should be lazy, see: https://blogs.gnome.org/ebassi/documentation/lazy-loading/
pub fn prepend<T: DeserializeOwned>(&self, batch: Vec<(AnyRoomEvent, Raw<T>)>) {
pub fn prepend(&self, batch: Vec<Event>) {
let priv_ = imp::Timeline::from_instance(self);
let mut added = batch.len();
@ -371,15 +364,11 @@ impl Timeline {
// Extend the size of the list so that rust doesn't need to reallocate memory multiple times
priv_.list.borrow_mut().reserve(added);
for (event, raw) in batch {
let user = self.room().member_by_id(fn_event!(event, sender));
let event_id = fn_event!(event, event_id).clone();
let source = to_json_value(raw.into_json())
.and_then(|v| to_json_string_pretty(&v))
.unwrap();
let event = Event::new(&event, &source, &user);
priv_.event_map.borrow_mut().insert(event_id, event.clone());
for event in batch {
priv_
.event_map
.borrow_mut()
.insert(event.matrix_event_id(), event.clone());
if event.is_hidden_event() {
self.add_hidden_event(event);

4
src/session/user.rs

@ -3,7 +3,7 @@ use gtk::{glib, prelude::*, subclass::prelude::*};
use crate::session::Session;
use matrix_sdk::{
ruma::{
events::{room::member::MemberEventContent, StateEvent, StrippedStateEvent},
events::{room::member::MemberEventContent, StrippedStateEvent, SyncStateEvent},
identifiers::UserId,
},
RoomMember,
@ -181,7 +181,7 @@ impl User {
}
/// Update the user based on the the room member state event
pub fn update_from_member_event(&self, event: &StateEvent<MemberEventContent>) {
pub fn update_from_member_event(&self, event: &SyncStateEvent<MemberEventContent>) {
let changed = {
let priv_ = imp::User::from_instance(&self);
let user_id = priv_.user_id.get().unwrap();

Loading…
Cancel
Save