ui: Move timeline item creation helpers into TimelineInnerState

This commit is contained in:
Jonas Platte
2023-07-28 12:32:08 +02:00
committed by Jonas Platte
parent e5f021f5cf
commit 7dfe8cedbb
5 changed files with 76 additions and 90 deletions

View File

@@ -14,7 +14,6 @@
use std::sync::Arc;
use chrono::{Datelike, Local, TimeZone};
use eyeball_im::{ObservableVector, ObservableVectorEntry};
use indexmap::{map::Entry, IndexMap};
use matrix_sdk::deserialized_responses::EncryptionInfo;
@@ -50,13 +49,16 @@ use super::{
RemoteEventTimelineItem,
},
find_read_marker,
item::{new_timeline_item, timeline_item},
item::timeline_item,
read_receipts::maybe_add_implicit_read_receipt,
rfind_event_by_id, rfind_event_item, EventTimelineItem, Message, OtherState, ReactionGroup,
ReactionSenderData, Sticker, TimelineDetails, TimelineInnerState, TimelineItem,
TimelineItemContent, VirtualTimelineItem, DEFAULT_SANITIZER_MODE,
};
use crate::{events::SyncTimelineEventWithoutContent, timeline::InReplyToDetails};
use crate::{
events::SyncTimelineEventWithoutContent,
timeline::{timestamp_to_date, InReplyToDetails},
};
#[derive(Clone)]
pub(super) enum Flow {
@@ -713,26 +715,22 @@ impl<'a> TimelineEventHandler<'a> {
{
let old_ts = latest_event.timestamp();
if let Some(day_divider_item) = maybe_create_day_divider_from_timestamps(
old_ts,
timestamp,
&mut self.state.next_internal_id,
) {
if let Some(day_divider_item) =
self.state.maybe_create_day_divider_from_timestamps(old_ts, timestamp)
{
trace!("Adding day divider (local)");
self.state.items.push_back(day_divider_item);
}
} else {
// If there is no event item, there is no day divider yet.
trace!("Adding first day divider (local)");
self.state.items.push_back(new_timeline_item(
VirtualTimelineItem::DayDivider(timestamp),
&mut self.state.next_internal_id,
));
let day_divider =
self.state.new_timeline_item(VirtualTimelineItem::DayDivider(timestamp));
self.state.items.push_back(day_divider);
}
self.state
.items
.push_back(new_timeline_item(item, &mut self.state.next_internal_id));
let item = self.state.new_timeline_item(item);
self.state.items.push_back(item);
}
Flow::Remote { position: TimelineItemPosition::Start, event_id, .. } => {
@@ -753,19 +751,16 @@ impl<'a> TimelineEventHandler<'a> {
if let Some(VirtualTimelineItem::DayDivider(divider_ts)) =
self.state.items.front().and_then(|item| item.as_virtual())
{
if let Some(day_divider_item) = maybe_create_day_divider_from_timestamps(
*divider_ts,
timestamp,
&mut self.state.next_internal_id,
) {
if let Some(day_divider_item) =
self.state.maybe_create_day_divider_from_timestamps(*divider_ts, timestamp)
{
self.state.items.push_front(day_divider_item);
}
} else {
// The list must always start with a day divider.
self.state.items.push_front(new_timeline_item(
VirtualTimelineItem::DayDivider(timestamp),
&mut self.state.next_internal_id,
));
let day_divider =
self.state.new_timeline_item(VirtualTimelineItem::DayDivider(timestamp));
self.state.items.push_front(day_divider);
}
if self.track_read_receipts {
@@ -778,9 +773,8 @@ impl<'a> TimelineEventHandler<'a> {
);
}
self.state
.items
.insert(1, new_timeline_item(item, &mut self.state.next_internal_id));
let item = self.state.new_timeline_item(item);
self.state.items.insert(1, item);
}
Flow::Remote {
@@ -921,11 +915,7 @@ impl<'a> TimelineEventHandler<'a> {
// If a day divider was removed for an item about to be moved and we
// now need to add a new one, reuse the previous one's ID.
Some(day_divider_id) => day_divider_id,
None => {
let internal_id = self.state.next_internal_id;
self.state.next_internal_id += 1;
internal_id
}
None => self.state.next_internal_id(),
};
let day_divider_item =
@@ -941,10 +931,8 @@ impl<'a> TimelineEventHandler<'a> {
} else {
// If there is no event item, there is no day divider yet.
trace!("Adding first day divider (remote)");
let new_day_divider = new_timeline_item(
VirtualTimelineItem::DayDivider(timestamp),
&mut self.state.next_internal_id,
);
let new_day_divider =
self.state.new_timeline_item(VirtualTimelineItem::DayDivider(timestamp));
if should_push {
self.state.items.push_back(new_day_divider);
} else {
@@ -968,11 +956,7 @@ impl<'a> TimelineEventHandler<'a> {
// echo) was removed and we now need to add it again, reuse
// the previous item's ID.
Some(id) => id,
None => {
let internal_id = self.state.next_internal_id;
self.state.next_internal_id += 1;
internal_id
}
None => self.state.next_internal_id(),
};
trace!("Adding new remote timeline item after all non-pending events");
@@ -987,9 +971,8 @@ impl<'a> TimelineEventHandler<'a> {
#[cfg(feature = "e2e-encryption")]
Flow::Remote { position: TimelineItemPosition::Update(idx), .. } => {
trace!("Updating timeline item at position {idx}");
self.state
.items
.set(*idx, new_timeline_item(item, &mut self.state.next_internal_id));
let item = self.state.new_timeline_item(item);
self.state.items.set(*idx, item);
}
}
@@ -1101,34 +1084,3 @@ fn _update_timeline_item(
debug!("Timeline item not found, discarding {action}");
}
}
#[derive(PartialEq)]
struct Date {
year: i32,
month: u32,
day: u32,
}
/// Converts a timestamp since Unix Epoch to a year, month and day.
fn timestamp_to_date(ts: MilliSecondsSinceUnixEpoch) -> Date {
let datetime = Local
.timestamp_millis_opt(ts.0.into())
// Only returns `None` if date is after Dec 31, 262143 BCE.
.single()
// Fallback to the current date to avoid issues with malicious
// homeservers.
.unwrap_or_else(Local::now);
Date { year: datetime.year(), month: datetime.month(), day: datetime.day() }
}
/// Returns a new day divider item for the new timestamp if it is on a different
/// day than the old timestamp
fn maybe_create_day_divider_from_timestamps(
old_ts: MilliSecondsSinceUnixEpoch,
new_ts: MilliSecondsSinceUnixEpoch,
next_internal_id: &mut u64,
) -> Option<Arc<TimelineItem>> {
(timestamp_to_date(old_ts) != timestamp_to_date(new_ts))
.then(|| new_timeline_item(VirtualTimelineItem::DayDivider(new_ts), next_internal_id))
}

View File

@@ -56,7 +56,7 @@ use super::{
compare_events_positions,
event_handler::{HandleEventResult, TimelineItemPosition},
event_item::EventItemIdentifier,
item::{new_timeline_item, timeline_item},
item::timeline_item,
reactions::ReactionToggleResult,
rfind_event_by_id, rfind_event_item,
traits::RoomDataProvider,
@@ -1029,8 +1029,8 @@ async fn fetch_replied_to_event(
});
let event_item = item.with_content(TimelineItemContent::Message(reply), None);
let state_ref = &mut *state;
state_ref.items.set(index, new_timeline_item(event_item, &mut state_ref.next_internal_id));
let new_timeline_item = state.new_timeline_item(event_item);
state.items.set(index, new_timeline_item);
// Don't hold the state lock while the network request is made
drop(state);

View File

@@ -41,16 +41,17 @@ use crate::{
event_item::EventItemIdentifier,
item::timeline_item,
reactions::{ReactionToggleResult, Reactions},
rfind_event_item,
rfind_event_item, timestamp_to_date,
traits::RoomDataProvider,
AnnotationKey, Error as TimelineError, Profile, ReactionSenderData, TimelineItem,
TimelineItemKind, VirtualTimelineItem,
},
};
#[derive(Debug)]
pub(in crate::timeline) struct TimelineInnerState {
pub items: ObservableVector<Arc<TimelineItem>>,
pub next_internal_id: u64,
next_internal_id: u64,
pub reactions: Reactions,
pub fully_read_event: Option<OwnedEventId>,
/// Whether the fully-read marker item should try to be updated when an
@@ -87,6 +88,27 @@ impl TimelineInnerState {
}
}
pub fn next_internal_id(&mut self) -> u64 {
let val = self.next_internal_id;
self.next_internal_id += 1;
val
}
pub fn new_timeline_item(&mut self, kind: impl Into<TimelineItemKind>) -> Arc<TimelineItem> {
timeline_item(kind, self.next_internal_id())
}
/// Returns a new day divider item for the new timestamp if it is on a
/// different day than the old timestamp
pub fn maybe_create_day_divider_from_timestamps(
&mut self,
old_ts: MilliSecondsSinceUnixEpoch,
new_ts: MilliSecondsSinceUnixEpoch,
) -> Option<Arc<TimelineItem>> {
(timestamp_to_date(old_ts) != timestamp_to_date(new_ts))
.then(|| self.new_timeline_item(VirtualTimelineItem::DayDivider(new_ts)))
}
pub async fn handle_sync_timeline<P: RoomDataProvider>(
&mut self,
timeline: Timeline,

View File

@@ -119,12 +119,3 @@ pub(crate) fn timeline_item(
) -> Arc<TimelineItem> {
Arc::new(TimelineItem { kind: kind.into(), internal_id })
}
pub(crate) fn new_timeline_item(
kind: impl Into<TimelineItemKind>,
next_internal_id: &mut u64,
) -> Arc<TimelineItem> {
let internal_id = *next_internal_id;
*next_internal_id += 1;
timeline_item(kind, internal_id)
}

View File

@@ -19,6 +19,7 @@
use std::{ops::Deref, pin::Pin, sync::Arc, task::Poll, time::Duration};
use async_std::sync::{Condvar, Mutex};
use chrono::{Datelike, Local, TimeZone};
use eyeball::{SharedObservable, Subscriber};
use eyeball_im::VectorDiff;
use futures_core::Stream;
@@ -43,7 +44,7 @@ use ruma::{
room::{message::sanitize::HtmlSanitizerMode, redaction::RoomRedactionEventContent},
AnyMessageLikeEventContent,
},
EventId, OwnedEventId, OwnedTransactionId, TransactionId, UserId,
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, TransactionId, UserId,
};
use thiserror::Error;
use tokio::sync::mpsc::Sender;
@@ -819,3 +820,23 @@ fn compare_events_positions(
Some(RelativePosition::After)
}
}
#[derive(PartialEq)]
struct Date {
year: i32,
month: u32,
day: u32,
}
/// Converts a timestamp since Unix Epoch to a year, month and day.
fn timestamp_to_date(ts: MilliSecondsSinceUnixEpoch) -> Date {
let datetime = Local
.timestamp_millis_opt(ts.0.into())
// Only returns `None` if date is after Dec 31, 262143 BCE.
.single()
// Fallback to the current date to avoid issues with malicious
// homeservers.
.unwrap_or_else(Local::now);
Date { year: datetime.year(), month: datetime.month(), day: datetime.day() }
}