diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index 360b528c..ab16893e 100644 --- a/src/home/room_screen.rs +++ b/src/home/room_screen.rs @@ -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); } @@ -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()) } @@ -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) }; @@ -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; @@ -2071,8 +2047,10 @@ struct TimelineUiState { last_scrolled_index: usize, prev_first_index: Option, - read_event_hashmap: HashMap, - marked_fully_read_queue: HashMap, + 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