From 5657931dd606845bd50a609b3f5ac9a1294213c6 Mon Sep 17 00:00:00 2001 From: alanpoon Date: Fri, 4 Oct 2024 12:31:38 +0800 Subject: [PATCH 1/4] reduce complexity of send_read_receipt --- src/home/room_screen.rs | 65 +++++++++-------------------------------- 1 file changed, 13 insertions(+), 52 deletions(-) diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index a836df4f..038ef098 100644 --- a/src/home/room_screen.rs +++ b/src/home/room_screen.rs @@ -962,49 +962,16 @@ impl RoomScreen{ let Some(room_id) = self.room_id.as_ref() else { return }; if let Some(ref mut index) = tl_state.prev_first_index { // to detect change of scroll when scroll ends - if *index != first_index { + if *index != first_index { // scroll changed - self.fully_read_timer = cx.start_interval(5.0); - let time_now = std::time::Instant::now(); if first_index > *index { - // Store visible event messages with current time into a hashmap - let mut read_receipt_event = None; - for r in first_index .. (first_index + portal_list.visible_items() + 1) { - if let Some(v) = tl_state.items.get(r) { - if let Some(e) = v.as_event().and_then(|f| f.event_id()) { - read_receipt_event = Some(e.to_owned()); - if !tl_state.read_event_hashmap.contains_key(&e.to_string()) { - tl_state.read_event_hashmap.insert( - e.to_string(), - (room_id.clone(), e.to_owned(), time_now, false), - ); - } - } - } - } - if let Some(event_id) = read_receipt_event { - submit_async_request(MatrixRequest::ReadReceipt { room_id: room_id.clone(), event_id }); - } - let mut fully_read_receipt_event = None; - // Implements sending fully read receipts when message is scrolled out of first row - for r in *index..first_index { - if let Some(v) = tl_state.items.get(r).clone() { - if let Some(e) = v.as_event().and_then(|f| f.event_id()) { - let mut to_remove = vec![]; - for (event_id_string, (_, event_id)) in &tl_state.marked_fully_read_queue { - if e == event_id { - fully_read_receipt_event = Some(event_id.clone()); - to_remove.push(event_id_string.clone()); - } - } - for r in to_remove { - tl_state.marked_fully_read_queue.remove(&r); - } - } - } - } - if let Some(event_id) = fully_read_receipt_event { - submit_async_request(MatrixRequest::FullyReadReceipt { room_id: room_id.clone(), event_id: event_id.clone()}); + cx.stop_timer(self.fully_read_timer); + self.fully_read_timer = cx.start_interval(5.0); + let index_to_send_read = first_index + portal_list.visible_items(); + if let Some(event_id) = tl_state.items.get(index_to_send_read) + .and_then(|f|f.as_event()).and_then(|f|f.event_id()) { + submit_async_request(MatrixRequest::ReadReceipt { room_id: room_id.clone(), event_id: event_id.to_owned() }); + tl_state.last_displayed_event = Some(event_id.to_owned()); } } *index = first_index; @@ -1264,13 +1231,9 @@ impl Widget for RoomScreen { // Mark events as fully read after they have been displayed on screen for 5 seconds. if self.fully_read_timer.is_event(event).is_some() { - if let (Some(ref mut tl_state), Some(ref _room_id)) = (&mut self.tl_state, &self.room_id) { - for (k, (room, event, start, ref mut moved_to_queue)) in &mut tl_state.read_event_hashmap { - if start.elapsed() > std::time::Duration::new(5, 0) && !*moved_to_queue{ - tl_state.marked_fully_read_queue.insert(k.clone(), (room.clone(), event.clone())); - *moved_to_queue = true; - } - } + if let (Some(ref mut tl_state), Some(ref room_id)) = (&mut self.tl_state, &self.room_id) { + let Some(last_displayed_event) = &tl_state.last_displayed_event else { return }; + submit_async_request(MatrixRequest::FullyReadReceipt { room_id: room_id.clone(), event_id: last_displayed_event.clone()}); } cx.stop_timer(self.fully_read_timer); } @@ -1664,8 +1627,7 @@ impl RoomScreen { saved_state: SavedState::default(), message_highlight_animation_state: MessageHighlightAnimationState::default(), prev_first_index: None, - read_event_hashmap: HashMap::new(), - marked_fully_read_queue: HashMap::new(), + last_displayed_event: None, }; (new_tl_state, true) }; @@ -1918,8 +1880,7 @@ struct TimelineUiState { message_highlight_animation_state: MessageHighlightAnimationState, prev_first_index: Option, - read_event_hashmap: HashMap, - marked_fully_read_queue: HashMap, + last_displayed_event: Option, } /// The item index, scroll position, and optional unique IDs of the first `N` events From bb92afbd4e5502fb593148ff6627583b20671b2a Mon Sep 17 00:00:00 2001 From: alanpoon Date: Fri, 4 Oct 2024 13:44:31 +0800 Subject: [PATCH 2/4] cleanup --- src/home/room_screen.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index 038ef098..6622c815 100644 --- a/src/home/room_screen.rs +++ b/src/home/room_screen.rs @@ -967,9 +967,9 @@ impl RoomScreen{ if first_index > *index { cx.stop_timer(self.fully_read_timer); self.fully_read_timer = cx.start_interval(5.0); - let index_to_send_read = first_index + portal_list.visible_items(); - if let Some(event_id) = tl_state.items.get(index_to_send_read) - .and_then(|f|f.as_event()).and_then(|f|f.event_id()) { + if let Some(event_id) = tl_state.items.get(first_index + portal_list.visible_items()) + .and_then(|f| f.as_event() ) + .and_then(|f| f.event_id() ) { submit_async_request(MatrixRequest::ReadReceipt { room_id: room_id.clone(), event_id: event_id.to_owned() }); tl_state.last_displayed_event = Some(event_id.to_owned()); } From 925536594f05226eaee06ce6f2073a8c4c71b8c5 Mon Sep 17 00:00:00 2001 From: alanpoon Date: Fri, 4 Oct 2024 14:07:31 +0800 Subject: [PATCH 3/4] removed unnecessary import --- src/home/room_screen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index 6622c815..4a365d36 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::{borrow::Cow, collections::{BTreeMap, HashMap}, ops::{DerefMut, Range}, sync::{Arc, Mutex}, time::Instant}; +use std::{borrow::Cow, collections::BTreeMap, ops::{DerefMut, Range}, sync::{Arc, Mutex}}; use imbl::Vector; use makepad_widgets::*; From e4c1268913e4adbe2714255234956de709aca449 Mon Sep 17 00:00:00 2001 From: alanpoon Date: Sun, 13 Oct 2024 21:35:07 +0800 Subject: [PATCH 4/4] Added scroll past marker --- src/home/room_screen.rs | 66 ++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 41 deletions(-) diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index 4ef558aa..ab16893e 100644 --- a/src/home/room_screen.rs +++ b/src/home/room_screen.rs @@ -1422,6 +1422,11 @@ impl Widget for RoomScreen { (item, ItemDrawnStatus::both_drawn()) } TimelineItemKind::Virtual(VirtualTimelineItem::ReadMarker) => { + let prev_event = tl_items.get(tl_idx.saturating_sub(1)); + if let Some(event_id) = prev_event.and_then(|timeline|timeline.as_event()).and_then(|e|e.event_id()) { + tl_state.read_marker = Some((tl_idx,event_id.to_owned())); + tl_state.scroll_pass_read_marker = false; + } let item = list.item(cx, item_id, live_id!(ReadMarker)); (item, ItemDrawnStatus::both_drawn()) } @@ -1710,6 +1715,8 @@ impl RoomScreen { last_scrolled_index: usize::MAX, prev_first_index: None, last_displayed_event: None, + read_marker: None, + scroll_pass_read_marker: false, }; (new_tl_state, true) }; @@ -1852,54 +1859,28 @@ impl RoomScreen { return; } let first_index = portal_list.first_id(); - + let Some(tl_state) = self.tl_state.as_mut() else { return }; let Some(room_id) = self.room_id.as_ref() else { return }; if let Some(ref mut index) = tl_state.prev_first_index { // to detect change of scroll when scroll ends if *index != first_index { - // scroll changed - self.fully_read_timer = cx.start_interval(5.0); - let time_now = std::time::Instant::now(); - if first_index > *index { - // Store visible event messages with current time into a hashmap - let mut read_receipt_event = None; - for r in first_index .. (first_index + portal_list.visible_items() + 1) { - if let Some(v) = tl_state.items.get(r) { - if let Some(e) = v.as_event().and_then(|f| f.event_id()) { - read_receipt_event = Some(e.to_owned()); - if !tl_state.read_event_hashmap.contains_key(&e.to_string()) { - tl_state.read_event_hashmap.insert( - e.to_string(), - (room_id.clone(), e.to_owned(), time_now, false), - ); - } - } - } - } - if let Some(event_id) = read_receipt_event { - submit_async_request(MatrixRequest::ReadReceipt { room_id: room_id.clone(), event_id }); + // if the scroll ends on page that contains read marker, set scroll_pass_read_marker to true + if let Some((read_marker_index, _)) = tl_state.read_marker { + if read_marker_index >= first_index && read_marker_index <= first_index + portal_list.visible_items() { + tl_state.scroll_pass_read_marker = true; } - let mut fully_read_receipt_event = None; - // Implements sending fully read receipts when message is scrolled out of first row - for r in *index..first_index { - if let Some(v) = tl_state.items.get(r).clone() { - if let Some(e) = v.as_event().and_then(|f| f.event_id()) { - let mut to_remove = vec![]; - for (event_id_string, (_, event_id)) in &tl_state.marked_fully_read_queue { - if e == event_id { - fully_read_receipt_event = Some(event_id.clone()); - to_remove.push(event_id_string.clone()); - } - } - for r in to_remove { - tl_state.marked_fully_read_queue.remove(&r); - } - } - } + } + if first_index > *index { + if tl_state.scroll_pass_read_marker { + cx.stop_timer(self.fully_read_timer); + self.fully_read_timer = cx.start_interval(5.0); } - if let Some(event_id) = fully_read_receipt_event { - submit_async_request(MatrixRequest::FullyReadReceipt { room_id: room_id.clone(), event_id: event_id.clone()}); + if let Some(event_id) = tl_state.items.get(first_index + portal_list.visible_items()) + .and_then(|f| f.as_event() ) + .and_then(|f| f.event_id() ) { + submit_async_request(MatrixRequest::ReadReceipt { room_id: room_id.clone(), event_id: event_id.to_owned() }); + tl_state.last_displayed_event = Some(event_id.to_owned()); } } *index = first_index; @@ -2067,6 +2048,9 @@ struct TimelineUiState { prev_first_index: Option, last_displayed_event: Option, + read_marker: Option<(usize, OwnedEventId)>, + /// Only send fully read receipt after scroll + scroll_pass_read_marker: bool, } /// The item index, scroll position, and optional unique IDs of the first `N` events