Perform scroll interactions through the ListState

This commit is contained in:
Marshall Bowers 2023-12-15 12:10:40 -05:00
parent 6c10ff8548
commit b478a4c4d5

View File

@ -178,9 +178,10 @@ use gpui::{
actions, canvas, div, fill, img, impl_actions, list, overlay, point, prelude::*, px, rems, actions, canvas, div, fill, img, impl_actions, list, overlay, point, prelude::*, px, rems,
serde_json, size, Action, AnyElement, AppContext, AsyncWindowContext, Bounds, ClipboardItem, serde_json, size, Action, AnyElement, AppContext, AsyncWindowContext, Bounds, ClipboardItem,
DismissEvent, Div, EventEmitter, FocusHandle, Focusable, FocusableView, Hsla, DismissEvent, Div, EventEmitter, FocusHandle, Focusable, FocusableView, Hsla,
InteractiveElement, IntoElement, Length, ListState, Model, MouseDownEvent, ParentElement, InteractiveElement, IntoElement, Length, ListOffset, ListState, Model, MouseDownEvent,
Pixels, Point, PromptLevel, Quad, Render, RenderOnce, ScrollHandle, SharedString, Size, ParentElement, Pixels, Point, PromptLevel, Quad, Render, RenderOnce, ScrollHandle,
Stateful, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, SharedString, Size, Stateful, Styled, Subscription, Task, View, ViewContext, VisualContext,
WeakView,
}; };
use project::{Fs, Project}; use project::{Fs, Project};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
@ -314,7 +315,6 @@ pub struct CollabPanel {
client: Arc<Client>, client: Arc<Client>,
project: Model<Project>, project: Model<Project>,
match_candidates: Vec<StringMatchCandidate>, match_candidates: Vec<StringMatchCandidate>,
scroll_handle: ScrollHandle,
subscriptions: Vec<Subscription>, subscriptions: Vec<Subscription>,
collapsed_sections: Vec<Section>, collapsed_sections: Vec<Section>,
collapsed_channels: Vec<ChannelId>, collapsed_channels: Vec<ChannelId>,
@ -469,7 +469,6 @@ impl CollabPanel {
project: workspace.project().clone(), project: workspace.project().clone(),
subscriptions: Vec::default(), subscriptions: Vec::default(),
match_candidates: Vec::default(), match_candidates: Vec::default(),
scroll_handle: ScrollHandle::new(),
collapsed_sections: vec![Section::Offline], collapsed_sections: vec![Section::Offline],
collapsed_channels: Vec::default(), collapsed_channels: Vec::default(),
workspace: workspace.weak_handle(), workspace: workspace.weak_handle(),
@ -585,6 +584,13 @@ impl CollabPanel {
); );
} }
fn scroll_to_item(&mut self, ix: usize) {
self.list_state.scroll_to(ListOffset {
item_ix: ix,
offset_in_item: px(0.),
})
}
fn update_entries(&mut self, select_same_item: bool, cx: &mut ViewContext<Self>) { fn update_entries(&mut self, select_same_item: bool, cx: &mut ViewContext<Self>) {
let channel_store = self.channel_store.read(cx); let channel_store = self.channel_store.read(cx);
let user_store = self.user_store.read(cx); let user_store = self.user_store.read(cx);
@ -968,7 +974,7 @@ impl CollabPanel {
for (ix, entry) in self.entries.iter().enumerate() { for (ix, entry) in self.entries.iter().enumerate() {
if *entry == prev_selected_entry { if *entry == prev_selected_entry {
self.selection = Some(ix); self.selection = Some(ix);
self.scroll_handle.scroll_to_item(ix); self.scroll_to_item(ix);
break; break;
} }
} }
@ -979,16 +985,19 @@ impl CollabPanel {
None None
} else { } else {
let ix = prev_selection.min(self.entries.len() - 1); let ix = prev_selection.min(self.entries.len() - 1);
self.scroll_handle.scroll_to_item(ix); self.scroll_to_item(ix);
Some(ix) Some(ix)
} }
}); });
} }
if scroll_to_top { if scroll_to_top {
self.scroll_handle.scroll_to_item(0) self.scroll_to_item(0)
} else { } else {
let (old_index, old_offset) = self.scroll_handle.logical_scroll_top(); let ListOffset {
item_ix: old_index,
offset_in_item: old_offset,
} = self.list_state.logical_scroll_top();
// Attempt to maintain the same scroll position. // Attempt to maintain the same scroll position.
if let Some(old_top_entry) = old_entries.get(old_index) { if let Some(old_top_entry) = old_entries.get(old_index) {
let (new_index, new_offset) = self let (new_index, new_offset) = self
@ -1014,8 +1023,9 @@ impl CollabPanel {
}) })
.unwrap_or_else(|| (old_index, old_offset)); .unwrap_or_else(|| (old_index, old_offset));
self.scroll_handle // TODO: How to handle this with `list`?
.set_logical_scroll_top(new_index, new_offset); // self.scroll_handle
// .set_logical_scroll_top(new_index, new_offset);
} }
} }
@ -1506,7 +1516,7 @@ impl CollabPanel {
} }
if let Some(ix) = self.selection { if let Some(ix) = self.selection {
self.scroll_handle.scroll_to_item(ix) self.scroll_to_item(ix)
} }
cx.notify(); cx.notify();
} }
@ -1518,7 +1528,7 @@ impl CollabPanel {
} }
if let Some(ix) = self.selection { if let Some(ix) = self.selection {
self.scroll_handle.scroll_to_item(ix) self.scroll_to_item(ix)
} }
cx.notify(); cx.notify();
} }
@ -1841,14 +1851,15 @@ impl CollabPanel {
let Some(channel) = self.selected_channel() else { let Some(channel) = self.selected_channel() else {
return; return;
}; };
let Some(bounds) = self // TODO: How to handle now that we're using `list`?
.selection // let Some(bounds) = self
.and_then(|ix| self.scroll_handle.bounds_for_item(ix)) // .selection
else { // .and_then(|ix| self.scroll_handle.bounds_for_item(ix))
return; // else {
}; // return;
// };
self.deploy_channel_context_menu(bounds.center(), channel.id, self.selection.unwrap(), cx); //
// self.deploy_channel_context_menu(bounds.center(), channel.id, self.selection.unwrap(), cx);
cx.stop_propagation(); cx.stop_propagation();
} }