@@ -804,11 +804,49 @@ struct TimelineUiState {
804
804
/// Currently this excludes avatars, as those are shared across multiple rooms.
805
805
media_cache : MediaCache ,
806
806
807
+ /// The index and scroll position of the first three events that have been drawn
808
+ /// in the most recent draw pass of this timeline's PortalList.
809
+ ///
810
+ /// We save three events because one of 3 adjacent timeline items is (practically)
811
+ /// guaranteed to be a standard real event that has a true unique ID.
812
+ /// (For example, not day dividers, not read markers, etc.)
813
+ ///
814
+ /// If any of the `event_ids` are `Some`, this indicates that the timeline was
815
+ /// fully cleared and is in the process of being restored via pagination,
816
+ /// but it has not yet been paginated enough to the point where one of events
817
+ /// in this list are visible.
818
+ /// Once the timeline has been sufficiently paginated to display
819
+ /// one of the events in this list, all `event_ids` should be set to `None`.`
820
+ first_three_events : FirstDrawnEvents < 3 > ,
821
+
807
822
/// The states relevant to the UI display of this timeline that are saved upon
808
823
/// a `Hide` action and restored upon a `Show` action.
809
824
saved_state : SavedState ,
810
825
}
811
826
827
+ /// The item index, scroll position, and optional unique IDs of the first `N` events
828
+ /// that have been drawn in the most recent draw pass of a timeline's PortalList.
829
+ #[ derive( Debug ) ]
830
+ struct FirstDrawnEvents < const N : usize > {
831
+ index_and_scroll : [ ItemIndexScroll ; N ] ,
832
+ event_ids : [ Option < OwnedEventId > ; N ] ,
833
+ }
834
+ impl < const N : usize > Default for FirstDrawnEvents < N > {
835
+ fn default ( ) -> Self {
836
+ Self {
837
+ index_and_scroll : std:: array:: from_fn ( |_| ItemIndexScroll :: default ( ) ) ,
838
+ event_ids : std:: array:: from_fn ( |_| None ) ,
839
+ }
840
+ }
841
+ }
842
+
843
+ ///
844
+ #[ derive( Clone , Copy , Debug , Default ) ]
845
+ struct ItemIndexScroll {
846
+ index : usize ,
847
+ scroll : f64 ,
848
+ }
849
+
812
850
/// States that are necessary to save in order to maintain a consistent UI display for a timeline.
813
851
///
814
852
/// These are saved when navigating away from a timeline (upon `Hide`)
@@ -854,6 +892,7 @@ impl Timeline {
854
892
content_drawn_since_last_update : RangeSet :: new ( ) ,
855
893
profile_drawn_since_last_update : RangeSet :: new ( ) ,
856
894
update_receiver,
895
+ first_three_events : Default :: default ( ) ,
857
896
media_cache : MediaCache :: new ( MediaFormatConst :: File , Some ( update_sender) ) ,
858
897
saved_state : SavedState :: default ( ) ,
859
898
} ;
@@ -1026,11 +1065,26 @@ impl Widget for Timeline {
1026
1065
if items. is_empty ( ) {
1027
1066
log ! ( "Timeline::handle_event(): timeline was cleared for room {}" , tl. room_id) ;
1028
1067
1029
- // TODO: Save the current first event ID before it gets removed
1068
+ // If the bottom of the timeline (the last event) is visible, then we should
1069
+ // set the timeline to live mode.
1070
+ // If the bottom of the timelien is *not* visible, then we should
1071
+ // set the timeline to Focused mode.
1072
+
1073
+ // TODO: Save the event IDs of the top 3 items before we apply this update,
1074
+ // which indicates this timeline is in the process of being restored,
1030
1075
// such that we can jump back to that position later after applying this update.
1031
1076
1032
1077
// TODO: here we need to re-build the timeline via TimelineBuilder
1033
1078
// and set the TimelineFocus to one of the above-saved event IDs.
1079
+
1080
+ // TODO: the docs for `TimelineBuilder::with_focus()` claim that the timeline's focus mode
1081
+ // can be changed after creation, but I do not see any methods to actually do that.
1082
+ // <https://matrix-org.github.io/matrix-rust-sdk/matrix_sdk_ui/timeline/struct.TimelineBuilder.html#method.with_focus>
1083
+ //
1084
+ // As such, we probably need to create a new async request enum variant
1085
+ // that tells the background async task to build a new timeline
1086
+ // (either in live mode or focused mode around one or more events)
1087
+ // and then replaces the existing timeline in ALL_ROOMS_INFO with the new one.
1034
1088
}
1035
1089
1036
1090
// Maybe todo?: we can often avoid the following loops that iterate over the `items` list
@@ -1126,8 +1180,10 @@ impl Widget for Timeline {
1126
1180
1127
1181
list. set_item_range ( cx, 0 , last_item_id) ;
1128
1182
1129
- while let Some ( item_id) = list. next_visible_item ( cx) {
1130
- // log!("Drawing item {}", item_id);
1183
+ let mut item_index_and_scroll_iter = tl_state. first_three_events . index_and_scroll . iter_mut ( ) ;
1184
+
1185
+ while let Some ( ( item_id, scroll) ) = list. next_visible_item_with_scroll ( cx) {
1186
+ // log!("Drawing item {} at scroll: {}", item_id, scroll_offset);
1131
1187
let item = if item_id == 0 {
1132
1188
list. item ( cx, item_id, live_id ! ( TopSpace ) ) . unwrap ( )
1133
1189
} else {
@@ -1139,6 +1195,14 @@ impl Widget for Timeline {
1139
1195
continue ;
1140
1196
} ;
1141
1197
1198
+ if let Some ( index_and_scroll) = item_index_and_scroll_iter. next ( ) {
1199
+ // log!("########### Saving item ID {} and scroll {} for room {}, at_end? {}",
1200
+ // item_id, scroll, room_id,
1201
+ // if list.is_at_end() { "Y" } else { "N" },
1202
+ // );
1203
+ * index_and_scroll = ItemIndexScroll { index : item_id, scroll } ;
1204
+ }
1205
+
1142
1206
// Determine whether this item's content and profile have been drawn since the last update.
1143
1207
// Pass this state to each of the `populate_*` functions so they can attempt to re-use
1144
1208
// an item in the timeline's portallist that was previously populated, if one exists.
0 commit comments