@@ -971,6 +971,10 @@ impl Widget for RoomScreen {
971
971
// ▼ (down arrow) = collapsed/closed - items are hidden
972
972
let button_text = if * open { "▲" } else { "▼" } ;
973
973
wr. button ( id ! ( collapsible_button) ) . set_text ( cx, button_text) ;
974
+ // If the last item is a group of small state events, scroll to the end when it is expanded.
975
+ if range. end == tl_state. items . len ( ) && * open {
976
+ portal_list. smooth_scroll_to_end ( cx, 90.0 , None ) ;
977
+ }
974
978
}
975
979
}
976
980
}
@@ -1634,18 +1638,20 @@ impl RoomScreen {
1634
1638
tl. content_drawn_since_last_update . remove ( changed_indices. clone ( ) ) ;
1635
1639
tl. profile_drawn_since_last_update . remove ( changed_indices. clone ( ) ) ;
1636
1640
}
1637
- // Calculate the shift amount based on the difference between old and new lengths
1638
- let old_len = tl. items . len ( ) ;
1639
- let new_len = new_items. len ( ) ;
1640
- let shift = new_len as i32 - old_len as i32 ;
1641
- tl. items = new_items;
1642
- // Apply the shift to the small_state_groups.
1643
- for ( range, _) in & mut tl. small_state_groups {
1644
- let new_start = ( range. start as i32 + shift) . max ( 0 ) as usize ;
1645
- let new_end = ( range. end as i32 + shift) . max ( 0 ) as usize ;
1646
- * range = new_start..new_end;
1641
+ // Handles item_id changes whenever there is a backward pagination.
1642
+ if !is_append {
1643
+ // Calculate the shift amount based on the difference between old and new lengths
1644
+ let old_len = tl. items . len ( ) ;
1645
+ let new_len = new_items. len ( ) ;
1646
+ let shift = new_len as i32 - old_len as i32 ;
1647
+ tl. items = new_items;
1648
+ // Apply the shift to the small_state_groups.
1649
+ for ( range, _) in & mut tl. small_state_groups {
1650
+ let new_start = ( range. start as i32 + shift) . max ( 0 ) as usize ;
1651
+ let new_end = ( range. end as i32 + shift) . max ( 0 ) as usize ;
1652
+ * range = new_start..new_end;
1653
+ }
1647
1654
}
1648
-
1649
1655
done_loading = true ;
1650
1656
}
1651
1657
TimelineUpdate :: NewUnreadMessagesCount ( unread_messages_count) => {
@@ -4024,7 +4030,7 @@ fn is_small_state_event(
4024
4030
/// Dynamically updates small state groups as timeline items are processed.
4025
4031
/// This function is called during populate_small_state_event to build groups on-demand.
4026
4032
/// Since iteration starts from the biggest item_id and goes backwards, we handle reverse grouping.
4027
- /// Returns a tuple whether to display the message, and whether to display the debug button and whether collapsible list is expanded.
4033
+ /// Returns a tuple whether to display the message, and whether to display the collapsible button and whether collapsible list is expanded.
4028
4034
fn update_small_state_groups_for_item (
4029
4035
item_id : usize ,
4030
4036
current_item : & EventTimelineItem ,
@@ -4040,21 +4046,17 @@ fn update_small_state_groups_for_item(
4040
4046
4041
4047
// check if the next item (item_id + 1) is a small state event to continue grouping
4042
4048
let next_item_is_small_state = next_item
4043
- . and_then ( |timeline_item|
4044
- match timeline_item. kind ( ) {
4045
- TimelineItemKind :: Event ( event_tl_item) => Some ( event_tl_item) ,
4046
- _ => None
4047
- }
4048
- )
4049
+ . and_then ( |timeline_item| match timeline_item. kind ( ) {
4050
+ TimelineItemKind :: Event ( event_tl_item) => Some ( event_tl_item) ,
4051
+ _ => None ,
4052
+ } )
4049
4053
. map ( is_small_state_event)
4050
4054
. unwrap_or ( false ) ;
4051
4055
let previous_item_is_small_state = previous_item
4052
- . and_then ( |timeline_item|
4053
- match timeline_item. kind ( ) {
4054
- TimelineItemKind :: Event ( event_tl_item) => Some ( event_tl_item) ,
4055
- _ => None
4056
- }
4057
- )
4056
+ . and_then ( |timeline_item| match timeline_item. kind ( ) {
4057
+ TimelineItemKind :: Event ( event_tl_item) => Some ( event_tl_item) ,
4058
+ _ => None ,
4059
+ } )
4058
4060
. map ( is_small_state_event)
4059
4061
. unwrap_or ( false ) ;
4060
4062
if !previous_item_is_small_state && !next_item_is_small_state {
@@ -4070,7 +4072,7 @@ fn update_small_state_groups_for_item(
4070
4072
return ( * is_open, false , * is_open) ; // Item is in group but not at start, no debug button
4071
4073
}
4072
4074
}
4073
-
4075
+
4074
4076
// Since we're iterating backwards (from highest to lowest item_id),
4075
4077
for ( range, is_open) in small_state_groups. iter_mut ( ) {
4076
4078
if range. start == item_id + 1 {
@@ -4083,7 +4085,8 @@ fn update_small_state_groups_for_item(
4083
4085
}
4084
4086
}
4085
4087
if next_item_is_small_state {
4086
- small_state_groups. push ( ( item_id..item_id + 1 , false ) ) ;
4088
+ // Plus to include the next item into the group.
4089
+ small_state_groups. push ( ( item_id..( item_id + 2 ) , false ) ) ;
4087
4090
}
4088
4091
( false , false , false ) // Return collapsed state, no debug button
4089
4092
}
@@ -4323,22 +4326,29 @@ fn populate_small_state_event(
4323
4326
// - opened: whether this individual item should be rendered (based on group state)
4324
4327
// - show_collapsible_button: true if this item is the first in a collapsible group
4325
4328
// - expanded: current expansion state of the group (for button text)
4326
- let ( opened, show_collapsible_button, expanded) = update_small_state_groups_for_item ( item_id, event_tl_item, prev_event, next_event, small_state_groups) ;
4327
-
4329
+ let ( opened, show_collapsible_button, expanded) = update_small_state_groups_for_item (
4330
+ item_id,
4331
+ event_tl_item,
4332
+ prev_event,
4333
+ next_event,
4334
+ small_state_groups,
4335
+ ) ;
4328
4336
// Only show the collapsible button on the first item of each group
4329
- item. button ( id ! ( collapsible_button) ) . set_visible ( cx, show_collapsible_button) ;
4330
-
4337
+ item. button ( id ! ( collapsible_button) )
4338
+ . set_visible ( cx, show_collapsible_button) ;
4339
+
4331
4340
// Render logic based on group state
4332
4341
if opened {
4333
4342
// This item should be visible - set appropriate button text if this is a group leader
4334
4343
if show_collapsible_button {
4335
4344
// Update button text to show current group state:
4336
4345
// ▲ = group is expanded (click to collapse)
4337
- // ▼ = group is collapsed (click to expand)
4346
+ // ▼ = group is collapsed (click to expand)
4338
4347
let button_text = if expanded { "▲" } else { "▼" } ;
4339
- item. button ( id ! ( collapsible_button) ) . set_text ( cx, button_text) ;
4348
+ item. button ( id ! ( collapsible_button) )
4349
+ . set_text ( cx, button_text) ;
4340
4350
}
4341
-
4351
+
4342
4352
// Render the actual event content
4343
4353
event_content. populate_item_content (
4344
4354
cx,
0 commit comments