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 core::time;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use fake::Fake;
|
use fake::Fake;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
|
|
@ -135,6 +136,9 @@ struct CompanyListDelegate {
|
||||||
matched_companies: Vec<Company>,
|
matched_companies: Vec<Company>,
|
||||||
selected_index: usize,
|
selected_index: usize,
|
||||||
confirmed_index: Option<usize>,
|
confirmed_index: Option<usize>,
|
||||||
|
query: String,
|
||||||
|
loading: bool,
|
||||||
|
is_eof: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListDelegate for CompanyListDelegate {
|
impl ListDelegate for CompanyListDelegate {
|
||||||
|
|
@ -149,6 +153,7 @@ impl ListDelegate for CompanyListDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_search(&mut self, query: &str, _: &mut ViewContext<List<Self>>) -> Task<()> {
|
fn perform_search(&mut self, query: &str, _: &mut ViewContext<List<Self>>) -> Task<()> {
|
||||||
|
self.query = query.to_string();
|
||||||
self.matched_companies = self
|
self.matched_companies = self
|
||||||
.companies
|
.companies
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -214,6 +219,38 @@ impl ListDelegate for CompanyListDelegate {
|
||||||
|
|
||||||
None
|
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 {
|
impl CompanyListDelegate {
|
||||||
|
|
@ -259,6 +296,9 @@ impl ListStory {
|
||||||
companies,
|
companies,
|
||||||
selected_index: 0,
|
selected_index: 0,
|
||||||
confirmed_index: None,
|
confirmed_index: None,
|
||||||
|
query: "".to_string(),
|
||||||
|
loading: false,
|
||||||
|
is_eof: false,
|
||||||
},
|
},
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::ops::Range;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{cell::Cell, rc::Rc};
|
use std::{cell::Cell, rc::Rc};
|
||||||
|
|
||||||
|
|
@ -77,6 +78,29 @@ pub trait ListDelegate: Sized + 'static {
|
||||||
|
|
||||||
/// Cancel the selection, e.g.: Pressed ESC.
|
/// Cancel the selection, e.g.: Pressed ESC.
|
||||||
fn cancel(&mut self, cx: &mut ViewContext<List<Self>>) {}
|
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> {
|
pub struct List<D: ListDelegate> {
|
||||||
|
|
@ -259,6 +283,31 @@ where
|
||||||
cx.notify();
|
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>) {
|
fn on_action_cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
|
||||||
self.set_selected_index(None, cx);
|
self.set_selected_index(None, cx);
|
||||||
self.delegate.cancel(cx);
|
self.delegate.cancel(cx);
|
||||||
|
|
@ -430,6 +479,8 @@ where
|
||||||
this.child(
|
this.child(
|
||||||
uniform_list(view, "uniform-list", items_count, {
|
uniform_list(view, "uniform-list", items_count, {
|
||||||
move |list, visible_range, cx| {
|
move |list, visible_range, cx| {
|
||||||
|
list.load_more_if_need(visible_range.clone(), cx);
|
||||||
|
|
||||||
visible_range
|
visible_range
|
||||||
.map(|ix| list.render_list_item(ix, cx))
|
.map(|ix| list.render_list_item(ix, cx))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
|
|
||||||
|
|
@ -583,26 +583,27 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatch delegate's `load_more` method when the visible range is near the end.
|
/// 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) {
|
if !self.delegate.can_load_more(cx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let row_count = self.delegate.rows_count(cx);
|
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
|
// Securely handle subtract logic to prevent attempt to subtract with overflow
|
||||||
if row_count >= load_more_count {
|
if visible_range.end >= row_count - threshold {
|
||||||
if visible_range.end >= row_count - load_more_count {
|
cx.spawn(|view, mut cx| async move {
|
||||||
cx.spawn(|view, mut cx| async move {
|
cx.update(|cx| {
|
||||||
cx.update(|cx| {
|
view.update(cx, |view, cx| {
|
||||||
view.update(cx, |view, cx| {
|
view.delegate.load_more(cx);
|
||||||
view.delegate.load_more(cx);
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.detach()
|
})
|
||||||
}
|
.detach()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1202,7 +1203,7 @@ where
|
||||||
rows_count + extra_rows_needed,
|
rows_count + extra_rows_needed,
|
||||||
{
|
{
|
||||||
move |table, visible_range, cx| {
|
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 {
|
if visible_range.end > rows_count {
|
||||||
table.scroll_to_row(
|
table.scroll_to_row(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue