Skip to content

fix(ui): Introduce Timeline regions #5000

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
c012d12
fix(ui): Offset the timeline index in the presence of a `TimelineStart`.
Hywan May 5, 2025
b3ca0a4
test: Add assert messages in the `assert_timeline_stream` macro.
Hywan May 5, 2025
cfc50dc
test(ui): Support `index [$nth] --- date divider ---` in `assert_time…
Hywan May 6, 2025
3871ddf
test(ui): Add a regression test.
Hywan May 6, 2025
d30dfec
refactor(ui): Add `ObservableItemsTransaction::push_timeline_start_if…
Hywan May 6, 2025
0b73f52
refactor(ui): Add `ObservableItemsTransaction::push_local`.
Hywan May 6, 2025
a5d9eec
refactor(ui): Add `ObservableItemsTransaction::has_local`.
Hywan May 6, 2025
f8967b2
chore(base): Move the `bitflags` dependency in the workspace.
Hywan May 7, 2025
43dbce5
feat(ui): Define _regions_ in the `Timeline`.
Hywan May 7, 2025
af465fc
refactor(ui): `DateDividerAdjuster` works on _remotes_ and _locals_ r…
Hywan May 7, 2025
ec09b40
refactor(ui): `ReadReceiptTimelineUpdate` works on _remotes_ region.
Hywan May 7, 2025
9092f44
refactor(ui): `TimelineMetadata` works on the _remotes_ region.
Hywan May 7, 2025
52b8ac0
refactor(ui): `TimelineStateTransaction` works on _remotes_ and _all_…
Hywan May 7, 2025
0122d11
refactor(ui): `EventHandler` uses regions to improve the code and avo…
Hywan May 7, 2025
29ae0eb
chore(ui): Make Clippy happy.
Hywan May 12, 2025
d108829
doc(ui): Add #5000 in the `CHANGELOG.md`.
Hywan May 12, 2025
b7149b0
test(ui): Add tests for `push_local` and `push_date_divider`.
Hywan May 12, 2025
4b0a2e6
doc(ui): Fix a typo in a comment.
Hywan May 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 31 additions & 19 deletions crates/matrix-sdk-ui/src/timeline/date_dividers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl DateDividerAdjuster {
let mut prev_item: Option<PrevItemDesc<'_>> = None;
let mut latest_event_ts = None;

for (i, item) in items.iter().enumerate() {
for (i, item) in items.iter_remotes_and_locals_regions() {
match item.kind() {
TimelineItemKind::Virtual(VirtualTimelineItem::DateDivider(ts)) => {
// Record what the last alive item pair is only if we haven't removed the date
Expand Down Expand Up @@ -163,7 +163,7 @@ impl DateDividerAdjuster {
// Also chase trailing date dividers explicitly, by iterating from the end to
// the start. Since they wouldn't be the prev_item of anything, we
// wouldn't analyze them in the previous loop.
for (i, item) in items.iter().enumerate().rev() {
for (i, item) in items.iter_remotes_and_locals_regions().rev() {
if item.is_date_divider() {
// The item is a trailing date divider: remove it, if it wasn't already
// scheduled for deletion.
Expand Down Expand Up @@ -192,8 +192,16 @@ impl DateDividerAdjuster {

// Only record the initial state if we've enabled the trace log level, and not
// otherwise.
let initial_state =
if event_enabled!(Level::TRACE) { Some(items.iter().cloned().collect()) } else { None };
let initial_state = if event_enabled!(Level::TRACE) {
Some(
items
.iter_remotes_and_locals_regions()
.map(|(_i, timeline_item)| timeline_item.clone())
.collect(),
)
} else {
None
};

self.process_ops(items, meta);

Expand Down Expand Up @@ -330,16 +338,10 @@ impl DateDividerAdjuster {
assert!(at >= 0);
let at = at as usize;

let item = meta.new_timeline_item(VirtualTimelineItem::DateDivider(ts));

// Keep push semantics, if we're inserting at the front or the back.
if at == items.len() {
items.push_back(item, None);
} else if at == 0 {
items.push_front(item, None);
} else {
items.insert(at, item, None);
}
items.push_date_divider(
at,
meta.new_timeline_item(VirtualTimelineItem::DateDivider(ts)),
);

offset += 1;
max_i = i;
Expand Down Expand Up @@ -404,7 +406,7 @@ impl DateDividerAdjuster {
// Assert invariants.
// 1. The timeline starts with a date divider, if it's not only virtual items.
{
let mut i = 0;
let mut i = items.first_remotes_region_index();
while let Some(item) = items.get(i) {
if let Some(virt) = item.as_virtual() {
if matches!(virt, VirtualTimelineItem::DateDivider(_)) {
Expand All @@ -423,7 +425,7 @@ impl DateDividerAdjuster {
// 2. There are no two date dividers following each other.
{
let mut prev_was_date_divider = false;
for (i, item) in items.iter().enumerate() {
for (i, item) in items.iter_remotes_and_locals_regions() {
if item.is_date_divider() {
if prev_was_date_divider {
report.errors.push(DateDividerInsertError::DuplicateDateDivider { at: i });
Expand All @@ -447,7 +449,7 @@ impl DateDividerAdjuster {
let mut prev_event_ts = None;
let mut prev_date_divider_ts = None;

for (i, item) in items.iter().enumerate() {
for (i, item) in items.iter_remotes_and_locals_regions() {
if let Some(ev) = item.as_event() {
let ts = ev.timestamp();

Expand Down Expand Up @@ -498,7 +500,10 @@ impl DateDividerAdjuster {
// end.
if let Some(state) = &report.initial_state {
if state.iter().any(|item| item.is_read_marker())
&& !report.final_state.iter().any(|item| item.is_read_marker())
&& !report
.final_state
.iter_remotes_and_locals_regions()
.any(|(_i, item)| item.is_read_marker())
{
report.errors.push(DateDividerInsertError::ReadMarkerDisappeared);
}
Expand Down Expand Up @@ -599,7 +604,14 @@ impl Display for DateDividerInvariantsReport<'_, '_> {
}

writeln!(f, "\nFinal state:")?;
write_items(f, self.final_state.iter().cloned().collect::<Vec<_>>().as_slice())?;
write_items(
f,
self.final_state
.iter_remotes_and_locals_regions()
.map(|(_i, item)| item.clone())
.collect::<Vec<_>>()
.as_slice(),
)?;

writeln!(f)?;
}
Expand Down