[fractal] Refactor message handling into MessageList
- From: Alejandro Domínguez <aledomu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal] Refactor message handling into MessageList
- Date: Fri, 12 Feb 2021 11:43:41 +0000 (UTC)
commit 9f686d1428a025d6afeb98faab935fee170ef0ff
Author: Kai A. Hiller <V02460 gmail com>
Date: Sat Jan 9 22:27:15 2021 +0100
Refactor message handling into MessageList
fractal-gtk/src/appop/message.rs | 36 ++++++++++--------
fractal-gtk/src/appop/sync.rs | 7 +++-
fractal-gtk/src/model/message_list.rs | 65 +++++++++++++++++++++++++++++++++
fractal-gtk/src/model/mod.rs | 1 +
fractal-gtk/src/model/room.rs | 39 +++++++++++---------
fractal-gtk/src/widgets/media_viewer.rs | 3 +-
fractal-gtk/src/widgets/roomlist.rs | 4 +-
7 files changed, 117 insertions(+), 38 deletions(-)
---
diff --git a/fractal-gtk/src/appop/message.rs b/fractal-gtk/src/appop/message.rs
index 3ae44e32..ebc3fbe5 100644
--- a/fractal-gtk/src/appop/message.rs
+++ b/fractal-gtk/src/appop/message.rs
@@ -136,17 +136,24 @@ impl AppOp {
let active_room_id = self.active_room.as_ref()?;
let room = self.rooms.get_mut(active_room_id)?;
let uid = login_data.uid.clone();
- room.messages.iter_mut().for_each(|msg| {
- if msg.receipt.contains_key(&uid) {
- msg.receipt.remove(&uid);
- }
- });
- let last_message = room.messages.last_mut()?;
+
+ let dirty_msgs: Vec<_> = room
+ .messages
+ .iter()
+ .filter(|m| m.receipt.contains_key(&uid))
+ .cloned()
+ .collect();
+ for mut msg in dirty_msgs {
+ msg.receipt.remove(&uid);
+ room.take_new_message(msg);
+ }
+ let mut last_message = room.messages.iter().last()?.clone();
+ let event_id = last_message.id.clone()?;
+ let room_id = last_message.room.clone();
last_message.receipt.insert(uid, 0);
+ room.take_new_message(last_message);
let session_client = login_data.session_client;
- let room_id = last_message.room.clone();
- let event_id = last_message.id.clone()?;
RUNTIME.spawn(async move {
match room::mark_as_read(session_client, room_id, event_id).await {
Ok((r, _)) => {
@@ -353,10 +360,10 @@ impl AppOp {
for msg in newmsgs.iter() {
if let Some(r) = self.rooms.get_mut(&msg.room) {
- if !r.messages.contains(msg) {
- r.messages.push(msg.clone());
+ if !r.messages.contains(msg.id.as_ref().unwrap()) {
msgs.push(msg.clone());
}
+ r.take_new_message(msg.clone());
}
}
@@ -421,7 +428,7 @@ impl AppOp {
}
if let Some(r) = self.rooms.get_mut(&item.room) {
- r.messages.insert(0, item.clone());
+ r.take_new_message(item.clone());
}
}
@@ -433,12 +440,11 @@ impl AppOp {
pub fn remove_message(&mut self, room_id: RoomId, id: EventId) -> Option<()> {
let message = self.get_message_by_id(&room_id, &id);
- if let Some(msg) = message {
+ if let Some(mut msg) = message {
self.remove_room_message(msg.clone());
if let Some(ref mut room) = self.rooms.get_mut(&msg.room) {
- if let Some(ref mut message) = room.messages.iter_mut().find(|e| e.id == msg.id) {
- message.redacted = true;
- }
+ msg.redacted = true;
+ room.take_new_message(msg);
}
}
None
diff --git a/fractal-gtk/src/appop/sync.rs b/fractal-gtk/src/appop/sync.rs
index 17f282aa..87ba0000 100644
--- a/fractal-gtk/src/appop/sync.rs
+++ b/fractal-gtk/src/appop/sync.rs
@@ -50,8 +50,11 @@ impl AppOp {
let clear_room_list = sync_ret.updates.is_none();
if let Some(updates) = sync_ret.updates {
let rooms = sync_ret.rooms;
- let msgs: Vec<_> =
- rooms.iter().flat_map(|r| &r.messages).cloned().collect();
+ let msgs: Vec<_> = rooms
+ .iter()
+ .flat_map(|r| r.messages.iter())
+ .cloned()
+ .collect();
APPOP!(set_rooms, (rooms, clear_room_list));
APPOP!(show_room_messages, (msgs));
let typing_events_as_rooms = updates.typing_events_as_rooms;
diff --git a/fractal-gtk/src/model/message_list.rs b/fractal-gtk/src/model/message_list.rs
new file mode 100644
index 00000000..ac476449
--- /dev/null
+++ b/fractal-gtk/src/model/message_list.rs
@@ -0,0 +1,65 @@
+use crate::model::message::Message;
+use matrix_sdk::identifiers::EventId;
+use std::iter::FromIterator;
+use std::slice::Iter;
+
+/// Contains an ordered list of messages and their relations.
+#[derive(Debug, Default, Clone)]
+pub struct MessageList {
+ messages: Vec<Message>,
+}
+
+impl MessageList {
+ pub fn new() -> Self {
+ Default::default()
+ }
+
+ /// Returns the message with the given event ID.
+ pub fn get(&self, event_id: &EventId) -> Option<&Message> {
+ self.messages
+ .iter()
+ .find(|m| m.id.as_ref() == Some(event_id))
+ }
+
+ /// Whether the message with the given id is in the room.
+ pub fn contains(&self, msg_id: &EventId) -> bool {
+ self.get(msg_id).is_some()
+ }
+
+ /// Returns an iterator over all messages.
+ pub fn iter(&self) -> Iter<Message> {
+ self.messages.iter()
+ }
+
+ /// Inserts the message at the correct position replacing its older version.
+ pub fn add(&mut self, msg: Message) {
+ assert!(msg.id.is_some());
+
+ // Deduplication only happens for messages with the same date, so we have
+ // to manually go through the message list and remove possible duplicates.
+ //
+ // This is necessary due to the special case of just-sent messages.
+ // They don't contain the “official” timestamp from the server, but the
+ // time they were sent from Fractal. Due to this circumstance, we might
+ // end up with two messages having the same id, but different dates. We
+ // brute-force-fix this by searching all messages for duplicates.
+ self.messages.retain(|m| m.id != msg.id);
+
+ match self.messages.binary_search(&msg) {
+ Ok(idx) => self.messages[idx] = msg,
+ Err(idx) => self.messages.insert(idx, msg),
+ }
+ // TODO: Use is_sorted (https://github.com/rust-lang/rust/issues/53485)
+ // debug_assert!(self.messages.is_sorted());
+ }
+}
+
+impl FromIterator<Message> for MessageList {
+ fn from_iter<I: IntoIterator<Item = Message>>(messages: I) -> Self {
+ let mut message_list = Self::new();
+ for m in messages {
+ message_list.add(m);
+ }
+ message_list
+ }
+}
diff --git a/fractal-gtk/src/model/mod.rs b/fractal-gtk/src/model/mod.rs
index 6d9eedcb..1781d7e4 100644
--- a/fractal-gtk/src/model/mod.rs
+++ b/fractal-gtk/src/model/mod.rs
@@ -1,4 +1,5 @@
pub mod fileinfo;
pub mod member;
pub mod message;
+pub mod message_list;
pub mod room;
diff --git a/fractal-gtk/src/model/room.rs b/fractal-gtk/src/model/room.rs
index b852b5bd..7a508541 100644
--- a/fractal-gtk/src/model/room.rs
+++ b/fractal-gtk/src/model/room.rs
@@ -1,6 +1,7 @@
use crate::model::member::Member;
use crate::model::member::MemberList;
use crate::model::message::Message;
+use crate::model::message_list::MessageList;
use anyhow::anyhow;
use chrono::DateTime;
use chrono::Utc;
@@ -123,7 +124,7 @@ pub struct Room {
pub members: MemberList,
pub notifications: u64,
pub highlight: u64,
- pub messages: Vec<Message>,
+ pub messages: MessageList,
pub membership: RoomMembership,
pub direct: bool,
pub prev_batch: Option<String>,
@@ -324,30 +325,27 @@ impl Room {
})
.collect();
- r.messages
- .iter_mut()
+ let changed_msgs: Vec<_> = r
+ .messages
+ .iter()
.filter_map(|msg| {
- let receipt = msg
- .id
- .as_ref()
- .and_then(|evid| receipts.get(evid))
- .cloned()?;
- Some((msg, receipt))
+ let receipt = msg.id.as_ref().and_then(|evid| receipts.get(evid))?;
+ Some((msg.clone(), receipt.clone()))
})
- .for_each(|(msg, receipt)| msg.set_receipt(receipt));
+ .collect();
+ for (mut msg, receipt) in changed_msgs {
+ msg.set_receipt(receipt);
+ r.take_new_message(msg);
+ }
if let Some(event_id) = room.ephemeral.events.iter().find_map(|event| match event {
AnySyncEphemeralRoomEvent::FullyRead(ev) => Some(ev.content.event_id.clone()),
_ => None,
}) {
- let event_id = Some(event_id);
-
- r.messages
- .iter_mut()
- .filter(|msg| msg.id == event_id)
- .for_each(|msg| {
- msg.receipt.insert(user_id.clone(), 0);
- });
+ if let Some(mut msg) = r.messages.get(&event_id).cloned() {
+ msg.receipt.insert(user_id.clone(), 0);
+ r.take_new_message(msg);
+ }
}
r
@@ -452,6 +450,11 @@ impl Room {
.chain(invited_rooms)
.collect()
}
+
+ /// Inserts the given message into the room.
+ pub fn take_new_message(&mut self, msg: Message) {
+ self.messages.add(msg);
+ }
}
impl TryFrom<PublicRoomsChunk> for Room {
diff --git a/fractal-gtk/src/widgets/media_viewer.rs b/fractal-gtk/src/widgets/media_viewer.rs
index 3f74ccaa..f697e93c 100644
--- a/fractal-gtk/src/widgets/media_viewer.rs
+++ b/fractal-gtk/src/widgets/media_viewer.rs
@@ -594,7 +594,8 @@ impl MediaViewer {
let media_list: Vec<Message> = room
.messages
- .clone()
+ .iter()
+ .cloned()
.into_iter()
.filter(|msg| msg.mtype == "m.image" || msg.mtype == "m.video")
.collect();
diff --git a/fractal-gtk/src/widgets/roomlist.rs b/fractal-gtk/src/widgets/roomlist.rs
index e1606703..42b5a4f0 100644
--- a/fractal-gtk/src/widgets/roomlist.rs
+++ b/fractal-gtk/src/widgets/roomlist.rs
@@ -23,7 +23,7 @@ pub struct RoomUpdated {
impl RoomUpdated {
pub fn new(room: Room) -> RoomUpdated {
- let updated = match room.messages.last() {
+ let updated = match room.messages.iter().last() {
Some(l) => l.date,
None => Local.ymd(1970, 1, 1).and_hms(0, 0, 0),
};
@@ -367,7 +367,7 @@ impl RoomListGroup {
}
pub fn add_rooms(&mut self, mut array: Vec<Room>) {
- array.sort_by_key(|ref x| match x.messages.last() {
+ array.sort_by_key(|ref x| match x.messages.iter().last() {
Some(l) => l.date,
None => Local.ymd(1970, 1, 1).and_hms(0, 0, 0),
});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]