refactor
This commit is contained in:
@@ -4,8 +4,8 @@ use assets::CustomIconName;
|
||||
use dock::{BasePanel, DockArea, Panel, PanelEvent, add_center_panel, panel_handle};
|
||||
use gpui::prelude::*;
|
||||
use gpui::{
|
||||
AnyElement, App, Context, Entity, EventEmitter, FocusHandle, Focusable, Pixels, Render,
|
||||
SharedString, Size, WeakEntity, Window, div, px, size,
|
||||
AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable, Pixels,
|
||||
Render, SharedString, Size, Subscription, WeakEntity, Window, div, px, size,
|
||||
};
|
||||
use gpui_component::button::{Button, ButtonVariants};
|
||||
use gpui_component::dialog::{DialogDescription, DialogFooter, DialogHeader, DialogTitle};
|
||||
@@ -62,27 +62,38 @@ pub struct IssuesView {
|
||||
filter: IssueFilter,
|
||||
/// Per-row heights of the virtual list.
|
||||
item_sizes: Rc<Vec<Size<Pixels>>>,
|
||||
/// The filtered issue count [`Self::item_sizes`] was built for.
|
||||
issue_len: usize,
|
||||
/// Indices into the store's `issues` matching [`Self::filter`].
|
||||
visible_issues: Vec<usize>,
|
||||
/// Header counts `(total, open, closed)`, rebuilt with [`Self::visible_issues`].
|
||||
counts: (usize, usize, usize),
|
||||
/// Store version and filter the cached rows/counts were built from.
|
||||
cache_key: Option<(u64, IssueFilter)>,
|
||||
/// Filter [`Self::visible_issues`] was last rebuilt for.
|
||||
///
|
||||
/// A filter change notifies even when the visible rows are unchanged,
|
||||
/// e.g. switching between two empty filters.
|
||||
synced_filter: IssueFilter,
|
||||
/// Virtual list state of the issues list.
|
||||
scroll_handle: VirtualListScrollHandle,
|
||||
/// Rebuild the rows and re-render when the store's data changes.
|
||||
_subscription: Subscription,
|
||||
}
|
||||
|
||||
impl IssuesView {
|
||||
pub fn new(
|
||||
dock_area: WeakEntity<DockArea>,
|
||||
store: Entity<RepoStore>,
|
||||
_window: &mut Window,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
let repo_name = store.read(cx).name();
|
||||
|
||||
let subscription = cx.observe(&store, |this, _store, cx| {
|
||||
this.rebuild(cx);
|
||||
});
|
||||
|
||||
cx.defer_in(window, |this, _window, cx| {
|
||||
this.rebuild(cx);
|
||||
});
|
||||
|
||||
Self {
|
||||
focus_handle: cx.focus_handle(),
|
||||
dock_area,
|
||||
@@ -90,14 +101,60 @@ impl IssuesView {
|
||||
repo_name,
|
||||
filter: IssueFilter::Open,
|
||||
item_sizes: Rc::new(Vec::new()),
|
||||
issue_len: 0,
|
||||
visible_issues: Vec::new(),
|
||||
counts: (0, 0, 0),
|
||||
cache_key: None,
|
||||
synced_filter: IssueFilter::Open,
|
||||
scroll_handle: VirtualListScrollHandle::new(),
|
||||
_subscription: subscription,
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(&mut self, cx: &mut Context<Self>) {
|
||||
let filter = self.filter;
|
||||
|
||||
let (visible_issues, counts) = {
|
||||
let store = self.store.read(cx);
|
||||
let mut counts = (0usize, 0usize, 0usize);
|
||||
|
||||
let visible_issues: Vec<usize> = store
|
||||
.issues
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(ix, issue)| {
|
||||
let status = store.status_of(issue);
|
||||
counts.0 += 1;
|
||||
match status {
|
||||
RepoStatus::Open => counts.1 += 1,
|
||||
RepoStatus::Closed => counts.2 += 1,
|
||||
RepoStatus::Draft | RepoStatus::Applied => {}
|
||||
}
|
||||
filter.matches(status).then_some(ix)
|
||||
})
|
||||
.collect();
|
||||
|
||||
(visible_issues, counts)
|
||||
};
|
||||
|
||||
let filter_changed = self.synced_filter != filter;
|
||||
let visible_issues_changed = self.visible_issues != visible_issues;
|
||||
let counts_changed = self.counts != counts;
|
||||
|
||||
if !filter_changed && !visible_issues_changed && !counts_changed {
|
||||
return;
|
||||
}
|
||||
|
||||
self.item_sizes = Rc::new(vec![
|
||||
size(px(0.), px(ISSUE_ROW_HEIGHT));
|
||||
visible_issues.len()
|
||||
]);
|
||||
|
||||
self.synced_filter = filter;
|
||||
self.visible_issues = visible_issues;
|
||||
self.counts = counts;
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Open the detail panel of `issue_id` in the dock area.
|
||||
fn open_issue_detail(
|
||||
&mut self,
|
||||
@@ -199,7 +256,7 @@ impl IssuesView {
|
||||
.selected(self.filter == IssueFilter::All)
|
||||
.on_click(cx.listener(|this, _event, _window, cx| {
|
||||
this.filter = IssueFilter::All;
|
||||
cx.notify();
|
||||
this.rebuild(cx);
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
@@ -209,7 +266,7 @@ impl IssuesView {
|
||||
.selected(self.filter == IssueFilter::Open)
|
||||
.on_click(cx.listener(|this, _event, _window, cx| {
|
||||
this.filter = IssueFilter::Open;
|
||||
cx.notify();
|
||||
this.rebuild(cx);
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
@@ -219,7 +276,7 @@ impl IssuesView {
|
||||
.selected(self.filter == IssueFilter::Closed)
|
||||
.on_click(cx.listener(|this, _event, _window, cx| {
|
||||
this.filter = IssueFilter::Closed;
|
||||
cx.notify();
|
||||
this.rebuild(cx);
|
||||
})),
|
||||
),
|
||||
)
|
||||
@@ -324,41 +381,7 @@ impl Focusable for IssuesView {
|
||||
impl Render for IssuesView {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let filter = self.filter;
|
||||
|
||||
// Rows and counts are rebuilt only when the store refreshed or filter changed.
|
||||
let version = self.store.read(cx).version();
|
||||
|
||||
if self.cache_key != Some((version, filter)) {
|
||||
let store = self.store.read(cx);
|
||||
let mut counts = (0usize, 0usize, 0usize);
|
||||
self.visible_issues = store
|
||||
.issues
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(ix, issue)| {
|
||||
let status = store.status_of(issue);
|
||||
counts.0 += 1;
|
||||
match status {
|
||||
RepoStatus::Open => counts.1 += 1,
|
||||
RepoStatus::Closed => counts.2 += 1,
|
||||
RepoStatus::Draft | RepoStatus::Applied => {}
|
||||
}
|
||||
filter.matches(status).then_some(ix)
|
||||
})
|
||||
.collect();
|
||||
self.counts = counts;
|
||||
self.cache_key = Some((version, filter));
|
||||
}
|
||||
|
||||
let count = self.visible_issues.len();
|
||||
|
||||
// The virtual list's item count comes from `item_sizes`.
|
||||
// Rebuild it whenever the filtered issue count changes.
|
||||
if count != self.issue_len {
|
||||
self.issue_len = count;
|
||||
self.item_sizes = Rc::new(vec![size(px(0.), px(ISSUE_ROW_HEIGHT)); count]);
|
||||
}
|
||||
|
||||
let sizes = self.item_sizes.clone();
|
||||
let scroll_handle = self.scroll_handle.clone();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user