Simplify ListState API (#35685)

Follow up to: https://github.com/zed-industries/zed/pull/35670,
simplifies the List state APIs so you no longer have to worry about
strong vs. weak pointers when rendering list items.

Release Notes:

- N/A

---------

Co-authored-by: Agus Zubiaga <agus@zed.dev>
This commit is contained in:
Mikayla Maki 2025-08-05 17:02:26 -07:00 committed by GitHub
parent d0de81b0b4
commit 53175263a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 322 additions and 403 deletions

View file

@ -103,28 +103,16 @@ impl ChatPanel {
});
cx.new(|cx| {
let entity = cx.entity().downgrade();
let message_list = ListState::new(
0,
gpui::ListAlignment::Bottom,
px(1000.),
move |ix, window, cx| {
if let Some(entity) = entity.upgrade() {
entity.update(cx, |this: &mut Self, cx| {
this.render_message(ix, window, cx).into_any_element()
})
} else {
div().into_any()
}
},
);
let message_list = ListState::new(0, gpui::ListAlignment::Bottom, px(1000.));
message_list.set_scroll_handler(cx.listener(|this, event: &ListScrollEvent, _, cx| {
if event.visible_range.start < MESSAGE_LOADING_THRESHOLD {
this.load_more_messages(cx);
}
this.is_scrolled_to_bottom = !event.is_scrolled;
}));
message_list.set_scroll_handler(cx.listener(
|this: &mut Self, event: &ListScrollEvent, _, cx| {
if event.visible_range.start < MESSAGE_LOADING_THRESHOLD {
this.load_more_messages(cx);
}
this.is_scrolled_to_bottom = !event.is_scrolled;
},
));
let local_offset = chrono::Local::now().offset().local_minus_utc();
let mut this = Self {
@ -399,7 +387,7 @@ impl ChatPanel {
ix: usize,
window: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement {
) -> AnyElement {
let active_chat = &self.active_chat.as_ref().unwrap().0;
let (message, is_continuation_from_previous, is_admin) =
active_chat.update(cx, |active_chat, cx| {
@ -582,6 +570,7 @@ impl ChatPanel {
self.render_popover_buttons(message_id, can_delete_message, can_edit_message, cx)
.mt_neg_2p5(),
)
.into_any_element()
}
fn has_open_menu(&self, message_id: Option<u64>) -> bool {
@ -979,7 +968,13 @@ impl Render for ChatPanel {
)
.child(div().flex_grow().px_2().map(|this| {
if self.active_chat.is_some() {
this.child(list(self.message_list.clone()).size_full())
this.child(
list(
self.message_list.clone(),
cx.processor(Self::render_message),
)
.size_full(),
)
} else {
this.child(
div()

View file

@ -324,20 +324,6 @@ impl CollabPanel {
)
.detach();
let entity = cx.entity().downgrade();
let list_state = ListState::new(
0,
gpui::ListAlignment::Top,
px(1000.),
move |ix, window, cx| {
if let Some(entity) = entity.upgrade() {
entity.update(cx, |this, cx| this.render_list_entry(ix, window, cx))
} else {
div().into_any()
}
},
);
let mut this = Self {
width: None,
focus_handle: cx.focus_handle(),
@ -345,7 +331,7 @@ impl CollabPanel {
fs: workspace.app_state().fs.clone(),
pending_serialization: Task::ready(None),
context_menu: None,
list_state,
list_state: ListState::new(0, gpui::ListAlignment::Top, px(1000.)),
channel_name_editor,
filter_editor,
entries: Vec::default(),
@ -2431,7 +2417,13 @@ impl CollabPanel {
});
v_flex()
.size_full()
.child(list(self.list_state.clone()).size_full())
.child(
list(
self.list_state.clone(),
cx.processor(Self::render_list_entry),
)
.size_full(),
)
.child(
v_flex()
.child(div().mx_2().border_primary(cx).border_t_1())

View file

@ -118,16 +118,7 @@ impl NotificationPanel {
})
.detach();
let entity = cx.entity().downgrade();
let notification_list =
ListState::new(0, ListAlignment::Top, px(1000.), move |ix, window, cx| {
entity
.upgrade()
.and_then(|entity| {
entity.update(cx, |this, cx| this.render_notification(ix, window, cx))
})
.unwrap_or_else(|| div().into_any())
});
let notification_list = ListState::new(0, ListAlignment::Top, px(1000.));
notification_list.set_scroll_handler(cx.listener(
|this, event: &ListScrollEvent, _, cx| {
if event.count.saturating_sub(event.visible_range.end) < LOADING_THRESHOLD {
@ -687,7 +678,16 @@ impl Render for NotificationPanel {
),
)
} else {
this.child(list(self.notification_list.clone()).size_full())
this.child(
list(
self.notification_list.clone(),
cx.processor(|this, ix, window, cx| {
this.render_notification(ix, window, cx)
.unwrap_or_else(|| div().into_any())
}),
)
.size_full(),
)
}
})
}