From d24d0fb54291e01fd77b5c2522df530373fec382 Mon Sep 17 00:00:00 2001 From: Kevin Boos Date: Wed, 14 Feb 2024 23:41:06 -0800 Subject: [PATCH 1/3] Stable positioning of timeline items across background updates is working. However, it could be more efficient by having the background timeline subscriber task include some information about where the changes were made, which would allow us to avoid searching the entire timeline list for the ID of the event that was previously shown at the top. Also added some infra for avoiding redundant drawing work based on whether a timeline item has been changed in the background, but that is not yet being used. --- Cargo.lock | 58 ++++++++++++++-------------- Cargo.toml | 3 +- src/home/room_screen.rs | 49 +++++++++++++++++++----- src/sliding_sync.rs | 83 ++++++++++++++++++++++++++++++++++++----- 4 files changed, 143 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a545a03e..e5f784aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1856,7 +1856,7 @@ dependencies = [ [[package]] name = "makepad-derive-live" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-live-id", "makepad-micro-proc-macro", @@ -1865,7 +1865,7 @@ dependencies = [ [[package]] name = "makepad-derive-wasm-bridge" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-micro-proc-macro", ] @@ -1873,7 +1873,7 @@ dependencies = [ [[package]] name = "makepad-derive-widget" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-live-id", "makepad-micro-proc-macro", @@ -1882,7 +1882,7 @@ dependencies = [ [[package]] name = "makepad-draw" version = "0.6.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "ab_glyph_rasterizer", "makepad-platform", @@ -1895,17 +1895,17 @@ dependencies = [ [[package]] name = "makepad-futures" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" [[package]] name = "makepad-futures-legacy" version = "0.7.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" [[package]] name = "makepad-html" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-live-id", ] @@ -1913,12 +1913,12 @@ dependencies = [ [[package]] name = "makepad-http" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" [[package]] name = "makepad-live-compiler" version = "0.5.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-derive-live", "makepad-live-tokenizer", @@ -1928,7 +1928,7 @@ dependencies = [ [[package]] name = "makepad-live-id" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-live-id-macros", ] @@ -1936,7 +1936,7 @@ dependencies = [ [[package]] name = "makepad-live-id-macros" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-micro-proc-macro", ] @@ -1944,7 +1944,7 @@ dependencies = [ [[package]] name = "makepad-live-tokenizer" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-live-id", "makepad-math", @@ -1954,17 +1954,17 @@ dependencies = [ [[package]] name = "makepad-math" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" [[package]] name = "makepad-micro-proc-macro" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" [[package]] name = "makepad-micro-serde" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-micro-serde-derive", ] @@ -1972,7 +1972,7 @@ dependencies = [ [[package]] name = "makepad-micro-serde-derive" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-micro-proc-macro", ] @@ -1980,12 +1980,12 @@ dependencies = [ [[package]] name = "makepad-objc-sys" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" [[package]] name = "makepad-platform" version = "0.6.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-futures", "makepad-futures-legacy", @@ -2000,7 +2000,7 @@ dependencies = [ [[package]] name = "makepad-shader-compiler" version = "0.5.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-live-compiler", ] @@ -2008,7 +2008,7 @@ dependencies = [ [[package]] name = "makepad-vector" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "ttf-parser", ] @@ -2016,7 +2016,7 @@ dependencies = [ [[package]] name = "makepad-wasm-bridge" version = "0.4.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-derive-wasm-bridge", "makepad-live-id", @@ -2025,7 +2025,7 @@ dependencies = [ [[package]] name = "makepad-widgets" version = "0.6.0" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-derive-widget", "makepad-draw", @@ -2037,16 +2037,16 @@ dependencies = [ [[package]] name = "makepad-windows" version = "0.51.1" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ - "windows-core 0.51.1 (git+https://github.com/makepad/makepad?branch=rik)", + "windows-core 0.51.1 (git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api)", "windows-targets", ] [[package]] name = "makepad-zune-core" version = "0.2.14" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "bitflags 2.4.1", ] @@ -2054,7 +2054,7 @@ dependencies = [ [[package]] name = "makepad-zune-inflate" version = "0.2.54" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "simd-adler32", ] @@ -2062,7 +2062,7 @@ dependencies = [ [[package]] name = "makepad-zune-jpeg" version = "0.3.17" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-zune-core", ] @@ -2070,7 +2070,7 @@ dependencies = [ [[package]] name = "makepad-zune-png" version = "0.2.1" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "makepad-zune-core", "makepad-zune-inflate", @@ -4831,7 +4831,7 @@ dependencies = [ [[package]] name = "windows-core" version = "0.51.1" -source = "git+https://github.com/makepad/makepad?branch=rik#9cceaf72acb1304ae13e82cc3775d15925636efc" +source = "git+https://github.com/kevinaboos/makepad?branch=extend_portal_list_item_api#6f0a560e9958d514b69fd9d83510d80a8ed1ea0a" dependencies = [ "windows-targets", ] diff --git a/Cargo.toml b/Cargo.toml index 904e4865..422ba33a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,8 @@ metadata.makepad-auto-version = "zqpv-Yj-K7WNVK2I8h5Okhho46Q=" [dependencies] -makepad-widgets = { git = "https://github.com/makepad/makepad", branch = "rik" } +# makepad-widgets = { git = "https://github.com/makepad/makepad", branch = "rik" } +makepad-widgets = { git = "https://github.com/kevinaboos/makepad", branch = "extend_portal_list_item_api" } anyhow = "1.0" diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index 794c577e..0953c342 100644 --- a/src/home/room_screen.rs +++ b/src/home/room_screen.rs @@ -1,7 +1,7 @@ //! A room screen is the UI page that displays a single Room's timeline of events/messages //! along with a message input bar at the bottom. -use std::{ops::DerefMut, sync::{Arc, Mutex}, collections::BTreeMap}; +use std::{collections::BTreeMap, ops::{DerefMut, RangeInclusive}, sync::{Arc, Mutex}}; use imbl::Vector; use makepad_widgets::*; @@ -602,9 +602,15 @@ impl RoomScreenRef { /// A message that is sent from a background async task to a room's timeline view /// for the purpose of update the Timeline UI contents or metadata. pub enum TimelineUpdate { - /// A update containing the entire list of timeline items for a room, - /// indicating that it has been updated in the background. - NewItems(Vector>), + /// The content of a room's timeline was updated in the background. + NewItems { + /// The entire list of timeline items (events) for a room. + items: Vector>, + /// The index of the first item in the `items` list that has changed. + /// Any items before this index are assumed to be unchanged and need not be redrawn, + /// while any items after this index are assumed to be changed and must be redrawn. + index_of_first_change: usize, + }, /// A notice that the start of the timeline has been reached, meaning that /// there is no need to send further backwards pagination requests. TimelineStartReached, @@ -641,9 +647,15 @@ struct TimelineUiState { /// When `true`, further backwards pagination requests will not be sent. fully_paginated: bool, - /// The list of items (events) in this room's timeline that our client currently knows about. + /// The list of items (events) in this room's timeline that our client currently knows about, + /// and the display state of each item (whether it needs to be redrawn). items: Vector>, + /// The range of items that have been updated since the last time the timeline was drawn. + /// This range is set on each background update to ensure that no changes items are missed; + /// thus, it is a conservative estimate that may include more items than necessary. + _updated_items: RangeInclusive, + /// The channel receiver for timeline updates for this room. /// /// Here we use a synchronous (non-async) channel because the receiver runs @@ -714,6 +726,7 @@ impl TimelineRef { // We assume timelines being viewed for the first time haven't been fully paginated. fully_paginated: false, items: Vector::new(), + updated_items: usize::MIN ..= usize::MAX, update_receiver, media_cache: MediaCache::new(MediaFormatConst::File), saved_state: SavedState::default(), @@ -750,12 +763,27 @@ impl Widget for Timeline { // Currently, a Signal event is only used to tell this widget that its timeline events // have been updated in the background. if let Event::Signal = event { + let portal_list = self.portal_list(id!(list)); let Some(tl) = self.tl_state.as_mut() else { return }; let mut done_loading = false; while let Ok(update) = tl.update_receiver.try_recv() { match update { - TimelineUpdate::NewItems(items) => { + TimelineUpdate::NewItems { items, index_of_first_change } => { + // Determine which item is currently visible the top of the screen + // so that we can jump back to that position instantly after applying this update. + let first_id = portal_list.first_id(); + if let Some(top_event_id) = tl.items.get(first_id).map(|item| item.unique_id()) { + for (idx, item) in items.iter().enumerate() { + if item.unique_id() == top_event_id { + log!("Timeline::handle_event(): jumping from top event index {first_id} to index {idx}"); + portal_list.set_first_id(idx); + break; + } + } + } tl.items = items; + + log!("Timeline::handle_event(): TODO: use index_of_first_change: {index_of_first_change}"); } TimelineUpdate::TimelineStartReached => { log!("Timeline::handle_event(): timeline start reached for room {}", tl.room_id); @@ -958,7 +986,7 @@ fn populate_message_view( } else { live_id!(Message) }; - let item = list.item(cx, item_id, template).unwrap(); + let (item, _existed) = list.item_with_existed(cx, item_id, template).unwrap(); item.label(id!(content.message)).set_text(&text.body); item } @@ -984,7 +1012,7 @@ fn populate_message_view( } else { live_id!(ImageMessage) }; - let item = list.item(cx, item_id, template).unwrap(); + let (item, _existed) = list.item_with_existed(cx, item_id, template).unwrap(); let img_ref = item.image(id!(body.content.message)); if let Some(data) = media_cache.try_get_media_or_fetch(mxc_uri, None) { @@ -1166,7 +1194,8 @@ fn populate_membership_change_view( format!("denied {}'s request to join this room.", change_user_id), }; - let item = list.item(cx, item_id, live_id!(SmallStateEvent)).unwrap(); + let (item, _existed) = list.item_with_existed(cx, item_id, live_id!(SmallStateEvent)).unwrap(); + set_timestamp(&item, id!(left_container.timestamp), event_tl_item.timestamp()); let username = set_avatar_and_get_username( cx, @@ -1192,7 +1221,7 @@ fn populate_profile_change_view( event_tl_item: &EventTimelineItem, change: &MemberProfileChange, ) -> WidgetRef { - let item = list.item(cx, item_id, live_id!(SmallStateEvent)).unwrap(); + let (item, _existed) = list.item_with_existed(cx, item_id, live_id!(SmallStateEvent)).unwrap(); let username = set_avatar_and_get_username( cx, item.avatar(id!(avatar)), diff --git a/src/sliding_sync.rs b/src/sliding_sync.rs index d0bb2457..218a2f87 100644 --- a/src/sliding_sync.rs +++ b/src/sliding_sync.rs @@ -1,5 +1,6 @@ use anyhow::{Result, bail}; use clap::Parser; +use eyeball_im::VectorDiff; use futures_util::{StreamExt, pin_mut}; use makepad_widgets::{SignalToUI, error, log}; use matrix_sdk::{ @@ -25,7 +26,7 @@ use tokio::{ sync::mpsc::{UnboundedSender, UnboundedReceiver}, task::JoinHandle, }; use unicode_segmentation::UnicodeSegmentation; -use std::{sync::{OnceLock, Mutex, Arc}, collections::BTreeMap}; +use std::{cmp::min, collections::BTreeMap, sync::{Arc, Mutex, OnceLock}}; use url::Url; use crate::{home::{rooms_list::{self, RoomPreviewEntry, RoomsListUpdate, RoomPreviewAvatar, enqueue_rooms_list_update}, room_screen::TimelineUpdate}, media_cache::MediaCacheEntry, utils::MEDIA_THUMBNAIL_FORMAT}; @@ -685,22 +686,84 @@ async fn timeline_subscriber_handler( log!("Starting timeline subscriber for room {room_id}..."); let (mut timeline_items, mut subscriber) = timeline.subscribe_batched().await; - sender.send(TimelineUpdate::NewItems(timeline_items.clone())) - .expect("Error: timeline update sender couldn't send update with initial items!"); + sender.send(TimelineUpdate::NewItems { + items: timeline_items.clone(), + index_of_first_change: 0, + }).expect("Error: timeline update sender couldn't send update with initial items!"); while let Some(batch) = subscriber.next().await { let num_updates = batch.len(); + let mut index_of_first_change = usize::MAX; for diff in batch { - diff.apply(&mut timeline_items); + match diff { + VectorDiff::Append { values } => { + index_of_first_change = min(index_of_first_change, timeline_items.len()); + log!("timeline_subscriber: diff Append {}, index_of_first_change: {index_of_first_change}", values.len()); + timeline_items.extend(values); + } + VectorDiff::Clear => { + log!("timeline_subscriber: diff Clear"); + index_of_first_change = 0; + timeline_items.clear(); + } + VectorDiff::PushFront { value } => { + log!("timeline_subscriber: diff PushFront"); + index_of_first_change = 0; + timeline_items.push_front(value); + } + VectorDiff::PushBack { value } => { + log!("timeline_subscriber: diff PushBack"); + index_of_first_change = min(index_of_first_change, timeline_items.len()); + timeline_items.push_back(value); + } + VectorDiff::PopFront => { + log!("timeline_subscriber: diff PopFront"); + index_of_first_change = 0; + timeline_items.pop_front(); + } + VectorDiff::PopBack => { + log!("timeline_subscriber: diff PopBack"); + timeline_items.pop_back(); + index_of_first_change = min(index_of_first_change, timeline_items.len().saturating_sub(1)); + } + VectorDiff::Insert { index, value } => { + log!("timeline_subscriber: diff Insert at {index}"); + index_of_first_change = min(index_of_first_change, index); + timeline_items.insert(index, value); + } + VectorDiff::Set { index, value } => { + log!("timeline_subscriber: diff Set at {index}"); + index_of_first_change = min(index_of_first_change, index); + timeline_items.set(index, value); + } + VectorDiff::Remove { index } => { + log!("timeline_subscriber: diff Remove at {index}"); + index_of_first_change = min(index_of_first_change, index.saturating_sub(1)); + timeline_items.remove(index); + } + VectorDiff::Truncate { length } => { + log!("timeline_subscriber: diff Truncate to length {length}"); + index_of_first_change = min(index_of_first_change, length.saturating_sub(1)); + timeline_items.truncate(length); + } + VectorDiff::Reset { values } => { + log!("timeline_subscriber: diff Reset, new length {}", values.len()); + index_of_first_change = 0; // we must assume that all items have changed. + timeline_items = values; + } + } } if num_updates > 0 { - log!("Timeline::handle_event(): applied {num_updates} updates for room {room_id}"); + log!("timeline_subscriber: applied {num_updates} updates for room {room_id}; first change at index {index_of_first_change}."); + + sender.send(TimelineUpdate::NewItems { + items: timeline_items.clone(), + index_of_first_change, + }).expect("Error: timeline update sender couldn't send update with new items!"); + + // Send a Makepad-level signal to update this room's timeline UI view. + SignalToUI::set_ui_signal(); } - sender.send(TimelineUpdate::NewItems(timeline_items.clone())) - .expect("Error: timeline update sender couldn't send update with new items!"); - - // Send a Makepad-level signal to update this room's timeline UI view. - SignalToUI::set_ui_signal(); } error!("Error: unexpectedly ended timeline subscriber for room {room_id}."); From fcba8a0cd33a3a7b7235c6b51e2b55b6ac9d6f4d Mon Sep 17 00:00:00 2001 From: Kevin Boos Date: Thu, 15 Feb 2024 13:49:43 -0800 Subject: [PATCH 2/3] Stable positioning is working; removed all overly-verbose log statements. Had to manually implement the `VectorDiff::apply()` function so we could interpose on what diffs were being applied and where. --- src/home/room_screen.rs | 7 +++---- src/sliding_sync.rs | 24 +++++++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index 0953c342..2c61705a 100644 --- a/src/home/room_screen.rs +++ b/src/home/room_screen.rs @@ -647,8 +647,7 @@ struct TimelineUiState { /// When `true`, further backwards pagination requests will not be sent. fully_paginated: bool, - /// The list of items (events) in this room's timeline that our client currently knows about, - /// and the display state of each item (whether it needs to be redrawn). + /// The list of items (events) in this room's timeline that our client currently knows about. items: Vector>, /// The range of items that have been updated since the last time the timeline was drawn. @@ -726,7 +725,7 @@ impl TimelineRef { // We assume timelines being viewed for the first time haven't been fully paginated. fully_paginated: false, items: Vector::new(), - updated_items: usize::MIN ..= usize::MAX, + _updated_items: usize::MIN ..= usize::MAX, update_receiver, media_cache: MediaCache::new(MediaFormatConst::File), saved_state: SavedState::default(), @@ -783,7 +782,7 @@ impl Widget for Timeline { } tl.items = items; - log!("Timeline::handle_event(): TODO: use index_of_first_change: {index_of_first_change}"); + // TODO: use index_of_first_change } TimelineUpdate::TimelineStartReached => { log!("Timeline::handle_event(): timeline start reached for room {}", tl.room_id); diff --git a/src/sliding_sync.rs b/src/sliding_sync.rs index 218a2f87..fb4ddf54 100644 --- a/src/sliding_sync.rs +++ b/src/sliding_sync.rs @@ -691,6 +691,8 @@ async fn timeline_subscriber_handler( index_of_first_change: 0, }).expect("Error: timeline update sender couldn't send update with initial items!"); + const LOG_DIFFS: bool = false; + while let Some(batch) = subscriber.next().await { let num_updates = batch.len(); let mut index_of_first_change = usize::MAX; @@ -698,56 +700,56 @@ async fn timeline_subscriber_handler( match diff { VectorDiff::Append { values } => { index_of_first_change = min(index_of_first_change, timeline_items.len()); - log!("timeline_subscriber: diff Append {}, index_of_first_change: {index_of_first_change}", values.len()); + if LOG_DIFFS { log!("timeline_subscriber: diff Append {}, index_of_first_change: {index_of_first_change}", values.len()); } timeline_items.extend(values); } VectorDiff::Clear => { - log!("timeline_subscriber: diff Clear"); + if LOG_DIFFS { log!("timeline_subscriber: diff Clear"); } index_of_first_change = 0; timeline_items.clear(); } VectorDiff::PushFront { value } => { - log!("timeline_subscriber: diff PushFront"); + if LOG_DIFFS { log!("timeline_subscriber: diff PushFront"); } index_of_first_change = 0; timeline_items.push_front(value); } VectorDiff::PushBack { value } => { - log!("timeline_subscriber: diff PushBack"); + if LOG_DIFFS { log!("timeline_subscriber: diff PushBack"); } index_of_first_change = min(index_of_first_change, timeline_items.len()); timeline_items.push_back(value); } VectorDiff::PopFront => { - log!("timeline_subscriber: diff PopFront"); + if LOG_DIFFS { log!("timeline_subscriber: diff PopFront"); } index_of_first_change = 0; timeline_items.pop_front(); } VectorDiff::PopBack => { - log!("timeline_subscriber: diff PopBack"); + if LOG_DIFFS { log!("timeline_subscriber: diff PopBack"); } timeline_items.pop_back(); index_of_first_change = min(index_of_first_change, timeline_items.len().saturating_sub(1)); } VectorDiff::Insert { index, value } => { - log!("timeline_subscriber: diff Insert at {index}"); + if LOG_DIFFS { log!("timeline_subscriber: diff Insert at {index}"); } index_of_first_change = min(index_of_first_change, index); timeline_items.insert(index, value); } VectorDiff::Set { index, value } => { - log!("timeline_subscriber: diff Set at {index}"); + if LOG_DIFFS { log!("timeline_subscriber: diff Set at {index}"); } index_of_first_change = min(index_of_first_change, index); timeline_items.set(index, value); } VectorDiff::Remove { index } => { - log!("timeline_subscriber: diff Remove at {index}"); + if LOG_DIFFS { log!("timeline_subscriber: diff Remove at {index}"); } index_of_first_change = min(index_of_first_change, index.saturating_sub(1)); timeline_items.remove(index); } VectorDiff::Truncate { length } => { - log!("timeline_subscriber: diff Truncate to length {length}"); + if LOG_DIFFS { log!("timeline_subscriber: diff Truncate to length {length}"); } index_of_first_change = min(index_of_first_change, length.saturating_sub(1)); timeline_items.truncate(length); } VectorDiff::Reset { values } => { - log!("timeline_subscriber: diff Reset, new length {}", values.len()); + if LOG_DIFFS { log!("timeline_subscriber: diff Reset, new length {}", values.len()); } index_of_first_change = 0; // we must assume that all items have changed. timeline_items = values; } From 12c9663807ff1b86a82d6bb204aa2393df694b4d Mon Sep 17 00:00:00 2001 From: Kevin Boos Date: Thu, 15 Feb 2024 13:51:05 -0800 Subject: [PATCH 3/3] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 617285b7..196dc47c 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ These are generally sorted in order of priority. If you're interested in helping - [x] Backwards pagination (upon viewing a room timeline) - [ ] Dynamic backwards pagination based on scroll position/movement - [ ] Loading animation while waiting for pagination request -- [ ] Stable positioning of events view during timeline update +- [x] Stable positioning of events view during timeline update - [x] Display simple text-only messages - [x] Display image messages (PNG, JPEG) - [ ] Rich text formatting for message bodies