Skip to content
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

reduce complexity of send_read_receipt based on scroll position #172

Closed
Closed
Changes from all commits
Commits
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
82 changes: 30 additions & 52 deletions src/home/room_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1297,13 +1297,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);
}
Expand Down Expand Up @@ -1426,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())
}
Expand Down Expand Up @@ -1713,8 +1714,9 @@ impl RoomScreen {
message_highlight_animation_state: MessageHighlightAnimationState::default(),
last_scrolled_index: usize::MAX,
prev_first_index: None,
read_event_hashmap: HashMap::new(),
marked_fully_read_queue: HashMap::new(),
last_displayed_event: None,
read_marker: None,
scroll_pass_read_marker: false,
};
(new_tl_state, true)
};
Expand Down Expand Up @@ -1857,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 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;
}
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 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;
Expand Down Expand Up @@ -2071,8 +2047,10 @@ struct TimelineUiState {
last_scrolled_index: usize,

prev_first_index: Option<usize>,
read_event_hashmap: HashMap<String, (OwnedRoomId, OwnedEventId, Instant, bool)>,
marked_fully_read_queue: HashMap<String, (OwnedRoomId, OwnedEventId)>,
last_displayed_event: Option<OwnedEventId>,
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
Expand Down