table: Add load_more delegate method and called when scrolled near the bottom. (#183)

https://github.com/user-attachments/assets/03001a21-6a3d-4c06-a00c-9dea8208e357
This commit is contained in:
Jason Lee 2024-08-28 15:12:42 +08:00 committed by GitHub
parent a5217df13e
commit 237b0f6956
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 86 additions and 4 deletions

View file

@ -1,12 +1,16 @@
use std::time::Duration;
use fake::Fake;
use gpui::{
div, img, IntoElement, ParentElement, Pixels, Render, SharedString, Styled, View, ViewContext,
VisualContext as _, WindowContext,
div, img, IntoElement, ParentElement, Pixels, Render, SharedString, Styled, Timer, View,
ViewContext, VisualContext as _, WindowContext,
};
use ui::{
checkbox::Checkbox,
h_flex,
indicator::Indicator,
label::Label,
prelude::FluentBuilder as _,
table::{ColSort, Table, TableDelegate, TableEvent},
theme::ActiveTheme as _,
v_flex, Icon, IconName, Selectable,
@ -84,6 +88,8 @@ struct CustomerTableDelegate {
col_order: bool,
col_sort: bool,
col_selection: bool,
loading: bool,
is_eof: bool,
}
impl CustomerTableDelegate {
@ -111,6 +117,8 @@ impl CustomerTableDelegate {
col_order: true,
col_sort: true,
col_selection: true,
loading: false,
is_eof: false,
}
}
}
@ -322,6 +330,32 @@ impl TableDelegate for CustomerTableDelegate {
}
}
}
fn can_load_more(&self) -> bool {
return !self.loading && !self.is_eof;
}
fn load_more_threshold(&self) -> usize {
150
}
fn load_more(&mut self, cx: &mut ViewContext<Table<Self>>) {
self.loading = true;
cx.spawn(|view, mut cx| async move {
// Simulate network request, delay 1s to load data.
Timer::after(Duration::from_secs(1)).await;
cx.update(|cx| {
let _ = view.update(cx, |view, _| {
view.delegate_mut().customers.extend(randome_customers(200));
view.delegate_mut().loading = false;
view.delegate_mut().is_eof = view.delegate().customers.len() >= 6000;
});
})
})
.detach();
}
}
pub struct TableStory {
@ -438,7 +472,12 @@ impl Render for TableStory {
.label("Column Selection")
.selected(delegate.col_selection)
.on_click(cx.listener(Self::toggle_col_selection)),
),
)
.when(delegate.loading, |this| {
this.child(h_flex().gap_1().child(Indicator::new()).child("Loading..."))
})
.child(format!("Total Rows: {}", delegate.rows_count()))
.when(delegate.is_eof, |this| this.child("Is loaded all data.")),
)
.child(self.table.clone())
}

View file

@ -1,4 +1,4 @@
use std::{cell::Cell, rc::Rc};
use std::{cell::Cell, ops::Range, rc::Rc};
use crate::{
h_flex,
@ -198,6 +198,29 @@ pub trait TableDelegate: Sized + 'static {
.child(Icon::new(IconName::Inbox).size_12())
.into_any_element()
}
/// Return true to enable load more data when scrolling to the bottom.
///
/// Default: true
fn can_load_more(&self) -> 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<Table<Self>>) {}
}
impl<D> Table<D>
@ -650,6 +673,24 @@ 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>) {
if !self.delegate.can_load_more() {
return;
}
if visible_range.end >= self.delegate.rows_count() - self.delegate.load_more_threshold() {
cx.spawn(|view, mut cx| async move {
cx.update(|cx| {
view.update(cx, |view, cx| {
view.delegate.load_more(cx);
})
})
})
.detach();
}
}
fn move_col(&mut self, col_ix: usize, to_ix: usize, cx: &mut ViewContext<Self>) {
if col_ix == to_ix {
return;
@ -746,6 +787,8 @@ where
uniform_list(view, "table-uniform-list", rows_count, {
let horizontal_scroll_handle = horizontal_scroll_handle.clone();
move |table, visible_range, cx| {
table.load_more(visible_range.clone(), cx);
visible_range
.map(|row_ix| {
table