list: Add load_more. (#532)
This commit is contained in:
parent
e345bc9afb
commit
3773337e04
3 changed files with 104 additions and 12 deletions
|
|
@ -1,4 +1,5 @@
|
|||
use core::time;
|
||||
use std::time::Duration;
|
||||
|
||||
use fake::Fake;
|
||||
use gpui::{
|
||||
|
|
@ -135,6 +136,9 @@ struct CompanyListDelegate {
|
|||
matched_companies: Vec<Company>,
|
||||
selected_index: usize,
|
||||
confirmed_index: Option<usize>,
|
||||
query: String,
|
||||
loading: bool,
|
||||
is_eof: bool,
|
||||
}
|
||||
|
||||
impl ListDelegate for CompanyListDelegate {
|
||||
|
|
@ -149,6 +153,7 @@ impl ListDelegate for CompanyListDelegate {
|
|||
}
|
||||
|
||||
fn perform_search(&mut self, query: &str, _: &mut ViewContext<List<Self>>) -> Task<()> {
|
||||
self.query = query.to_string();
|
||||
self.matched_companies = self
|
||||
.companies
|
||||
.iter()
|
||||
|
|
@ -214,6 +219,38 @@ impl ListDelegate for CompanyListDelegate {
|
|||
|
||||
None
|
||||
}
|
||||
|
||||
fn can_load_more(&self, _: &AppContext) -> bool {
|
||||
return !self.loading && !self.is_eof;
|
||||
}
|
||||
|
||||
fn load_more_threshold(&self) -> usize {
|
||||
150
|
||||
}
|
||||
|
||||
fn load_more(&mut self, cx: &mut ViewContext<List<Self>>) {
|
||||
self.loading = true;
|
||||
|
||||
cx.spawn(|view, mut cx| async move {
|
||||
dbg!("Load more data");
|
||||
// Simulate network request, delay 1s to load data.
|
||||
Timer::after(Duration::from_secs(1)).await;
|
||||
|
||||
cx.update(|cx| {
|
||||
_ = view.update(cx, move |view, cx| {
|
||||
let query = view.delegate().query.clone();
|
||||
view.delegate_mut()
|
||||
.companies
|
||||
.extend((0..200).map(|_| random_company()));
|
||||
view.delegate_mut().perform_search(&query, cx);
|
||||
view.delegate_mut().loading = false;
|
||||
dbg!("Loaded more data len: ", view.delegate().companies.len());
|
||||
view.delegate_mut().is_eof = view.delegate().companies.len() >= 6000;
|
||||
});
|
||||
})
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
||||
impl CompanyListDelegate {
|
||||
|
|
@ -259,6 +296,9 @@ impl ListStory {
|
|||
companies,
|
||||
selected_index: 0,
|
||||
confirmed_index: None,
|
||||
query: "".to_string(),
|
||||
loading: false,
|
||||
is_eof: false,
|
||||
},
|
||||
cx,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::ops::Range;
|
||||
use std::time::Duration;
|
||||
use std::{cell::Cell, rc::Rc};
|
||||
|
||||
|
|
@ -77,6 +78,29 @@ pub trait ListDelegate: Sized + 'static {
|
|||
|
||||
/// Cancel the selection, e.g.: Pressed ESC.
|
||||
fn cancel(&mut self, cx: &mut ViewContext<List<Self>>) {}
|
||||
|
||||
/// Return true to enable load more data when scrolling to the bottom.
|
||||
///
|
||||
/// Default: true
|
||||
fn can_load_more(&self, cx: &AppContext) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns a threshold value (n rows), of course, when scrolling to the bottom,
|
||||
/// the remaining number of rows triggers `load_more`.
|
||||
///
|
||||
/// Default: 50 rows
|
||||
fn load_more_threshold(&self) -> usize {
|
||||
50
|
||||
}
|
||||
|
||||
/// Load more data when the table is scrolled to the bottom.
|
||||
///
|
||||
/// This will performed in a background task.
|
||||
///
|
||||
/// This is always called when the table is near the bottom,
|
||||
/// so you must check if there is more data to load or lock the loading state.
|
||||
fn load_more(&mut self, cx: &mut ViewContext<List<Self>>) {}
|
||||
}
|
||||
|
||||
pub struct List<D: ListDelegate> {
|
||||
|
|
@ -259,6 +283,31 @@ where
|
|||
cx.notify();
|
||||
}
|
||||
|
||||
/// Dispatch delegate's `load_more` method when the visible range is near the end.
|
||||
fn load_more_if_need(&mut self, visible_range: Range<usize>, cx: &mut ViewContext<Self>) {
|
||||
if !self.delegate.can_load_more(cx) {
|
||||
return;
|
||||
}
|
||||
|
||||
let items_count = self.delegate.items_count(cx);
|
||||
let threshold = self.delegate.load_more_threshold();
|
||||
if items_count < threshold {
|
||||
return;
|
||||
}
|
||||
|
||||
// Securely handle subtract logic to prevent attempt to subtract with overflow
|
||||
if visible_range.end >= items_count - threshold {
|
||||
cx.spawn(|view, mut cx| async move {
|
||||
cx.update(|cx| {
|
||||
view.update(cx, |view, cx| {
|
||||
view.delegate.load_more(cx);
|
||||
})
|
||||
})
|
||||
})
|
||||
.detach()
|
||||
}
|
||||
}
|
||||
|
||||
fn on_action_cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
|
||||
self.set_selected_index(None, cx);
|
||||
self.delegate.cancel(cx);
|
||||
|
|
@ -430,6 +479,8 @@ where
|
|||
this.child(
|
||||
uniform_list(view, "uniform-list", items_count, {
|
||||
move |list, visible_range, cx| {
|
||||
list.load_more_if_need(visible_range.clone(), cx);
|
||||
|
||||
visible_range
|
||||
.map(|ix| list.render_list_item(ix, cx))
|
||||
.collect::<Vec<_>>()
|
||||
|
|
|
|||
|
|
@ -583,26 +583,27 @@ where
|
|||
}
|
||||
|
||||
/// Dispatch delegate's `load_more` method when the visible range is near the end.
|
||||
fn load_more(&mut self, visible_range: Range<usize>, cx: &mut ViewContext<Self>) {
|
||||
fn load_more_if_need(&mut self, visible_range: Range<usize>, cx: &mut ViewContext<Self>) {
|
||||
if !self.delegate.can_load_more(cx) {
|
||||
return;
|
||||
}
|
||||
|
||||
let row_count = self.delegate.rows_count(cx);
|
||||
let load_more_count = self.delegate.load_more_threshold();
|
||||
let threshold = self.delegate.load_more_threshold();
|
||||
if row_count < threshold {
|
||||
return;
|
||||
}
|
||||
|
||||
// Securely handle subtract logic to prevent attempt to subtract with overflow
|
||||
if row_count >= load_more_count {
|
||||
if visible_range.end >= row_count - load_more_count {
|
||||
cx.spawn(|view, mut cx| async move {
|
||||
cx.update(|cx| {
|
||||
view.update(cx, |view, cx| {
|
||||
view.delegate.load_more(cx);
|
||||
})
|
||||
if visible_range.end >= row_count - threshold {
|
||||
cx.spawn(|view, mut cx| async move {
|
||||
cx.update(|cx| {
|
||||
view.update(cx, |view, cx| {
|
||||
view.delegate.load_more(cx);
|
||||
})
|
||||
})
|
||||
.detach()
|
||||
}
|
||||
})
|
||||
.detach()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1202,7 +1203,7 @@ where
|
|||
rows_count + extra_rows_needed,
|
||||
{
|
||||
move |table, visible_range, cx| {
|
||||
table.load_more(visible_range.clone(), cx);
|
||||
table.load_more_if_need(visible_range.clone(), cx);
|
||||
|
||||
if visible_range.end > rows_count {
|
||||
table.scroll_to_row(
|
||||
|
|
|
|||
Loading…
Reference in a new issue