timeline: use the day divider adjuster when updating the send state of a message

This commit is contained in:
Benjamin Bouvier
2024-03-29 19:41:46 +01:00
parent ef5b12035d
commit 96a4b06ca6
2 changed files with 21 additions and 24 deletions

View File

@@ -62,7 +62,10 @@ use super::{
AnnotationKey, EventSendState, EventTimelineItem, InReplyToDetails, Message, Profile,
RepliedToEvent, TimelineDetails, TimelineItem, TimelineItemContent, TimelineItemKind,
};
use crate::{timeline::TimelineEventFilterFn, unable_to_decrypt_hook::UtdHookManager};
use crate::{
timeline::{day_dividers::DayDividerAdjuster, TimelineEventFilterFn},
unable_to_decrypt_hook::UtdHookManager,
};
mod state;
@@ -491,14 +494,14 @@ impl<P: RoomDataProvider> TimelineInner<P> {
send_state: EventSendState,
) {
let mut state = self.state.write().await;
let mut items_txn = state.items.transaction();
let mut txn = state.transaction();
let new_event_id: Option<&EventId> =
as_variant!(&send_state, EventSendState::Sent { event_id } => event_id);
// The local echoes are always at the end of the timeline, we must first make
// sure the remote echo hasn't showed up yet.
if rfind_event_item(&items_txn, |it| {
if rfind_event_item(&txn.items, |it| {
new_event_id.is_some() && it.event_id() == new_event_id && it.as_remote().is_some()
})
.is_some()
@@ -506,33 +509,26 @@ impl<P: RoomDataProvider> TimelineInner<P> {
// Remote echo already received. This is very unlikely.
trace!("Remote echo received before send-event response");
let local_echo = rfind_event_item(&items_txn, |it| it.transaction_id() == Some(txn_id));
let local_echo = rfind_event_item(&txn.items, |it| it.transaction_id() == Some(txn_id));
// If there's both the remote echo and a local echo, that means the
// remote echo was received before the response *and* contained no
// transaction ID (and thus duplicated the local echo).
if let Some((idx, _)) = local_echo {
warn!("Message echo got duplicated, removing the local one");
items_txn.remove(idx);
txn.items.remove(idx);
if idx == 0 {
error!("Inconsistent state: Local echo was not preceded by day divider");
return;
}
if idx == items_txn.len() && items_txn[idx - 1].is_day_divider() {
// The day divider may have been added for this local echo, remove it and let
// the next message decide whether it's required or not.
items_txn.remove(idx - 1);
}
// Adjust the day dividers, if needs be.
let mut adjuster = DayDividerAdjuster::default();
adjuster.run(&mut txn.items, &mut txn.meta);
}
items_txn.commit();
txn.commit();
return;
}
// Look for the local event by the transaction ID or event ID.
let result = rfind_event_item(&items_txn, |it| {
let result = rfind_event_item(&txn.items, |it| {
it.transaction_id() == Some(txn_id)
|| new_event_id.is_some()
&& it.event_id() == new_event_id
@@ -560,26 +556,27 @@ impl<P: RoomDataProvider> TimelineInner<P> {
let is_error = matches!(send_state, EventSendState::SendingFailed { .. });
let new_item = item.with_inner_kind(local_item.with_send_state(send_state));
items_txn.set(idx, new_item);
txn.items.set(idx, new_item);
if is_error {
// When there is an error, sending further messages is paused. This
// should be reflected in the timeline, so we set all other pending
// events to cancelled.
let num_items = items_txn.len();
let items = &mut txn.items;
let num_items = items.len();
for idx in 0..num_items {
let item = items_txn[idx].clone();
let item = &items[idx];
let Some(event_item) = item.as_event() else { continue };
let Some(local_item) = event_item.as_local() else { continue };
if matches!(&local_item.send_state, EventSendState::NotSentYet) {
let new_event_item =
event_item.with_kind(local_item.with_send_state(EventSendState::Cancelled));
items_txn.set(idx, item.with_kind(new_event_item));
items.set(idx, item.with_kind(new_event_item));
}
}
}
items_txn.commit();
txn.commit();
}
/// Reconcile the timeline with the result of a request to toggle a

View File

@@ -410,7 +410,7 @@ impl TimelineInnerState {
txn.commit();
}
fn transaction(&mut self) -> TimelineInnerStateTransaction<'_> {
pub(super) fn transaction(&mut self) -> TimelineInnerStateTransaction<'_> {
let items = self.items.transaction();
let meta = self.meta.clone();
TimelineInnerStateTransaction { items, previous_meta: &mut self.meta, meta }
@@ -645,7 +645,7 @@ impl TimelineInnerStateTransaction<'_> {
self.meta.update_read_marker(&mut self.items);
}
fn commit(self) {
pub(super) fn commit(self) {
let Self { items, previous_meta, meta } = self;
// Replace the pointer to the previous meta with the new one.