Proper pagination
This commit is contained in:
@@ -51,10 +51,13 @@ class TasQAdaptiveList<T> extends StatelessWidget {
|
||||
this.rowActions,
|
||||
this.onRowTap,
|
||||
this.rowsPerPage = 50,
|
||||
this.totalCount,
|
||||
this.pageOffset = 0,
|
||||
this.tableHeader,
|
||||
this.filterHeader,
|
||||
this.summaryDashboard,
|
||||
this.onRequestRefresh,
|
||||
this.onPageChanged,
|
||||
this.isLoading = false,
|
||||
});
|
||||
|
||||
@@ -78,6 +81,15 @@ class TasQAdaptiveList<T> extends StatelessWidget {
|
||||
/// Per CLAUDE.md: Standard page size is 50 items for Desktop.
|
||||
final int rowsPerPage;
|
||||
|
||||
/// Optional total number of rows in the full result set. When non-null
|
||||
/// and [items] contains only the current page, this value will be used
|
||||
/// as the `rowCount` for the table so pagination controls render correctly.
|
||||
final int? totalCount;
|
||||
|
||||
/// Offset of the first item in [items] relative to the full result set.
|
||||
/// Used when [totalCount] is provided and [items] represents a page.
|
||||
final int pageOffset;
|
||||
|
||||
/// Optional header widget for the desktop table.
|
||||
final Widget? tableHeader;
|
||||
|
||||
@@ -87,9 +99,21 @@ class TasQAdaptiveList<T> extends StatelessWidget {
|
||||
/// Optional summary dashboard widget (e.g., status counts).
|
||||
final Widget? summaryDashboard;
|
||||
|
||||
/// Callback when the user requests refresh (infinite scroll or pagination).
|
||||
/// Callback when the user requests refresh (infinite scroll or pagination.
|
||||
///
|
||||
/// * **Mobile** – invoked when the user scrolls to the end of the list.
|
||||
/// * **Desktop** – *not* triggered by page changes (see [onPageChanged]).
|
||||
final void Function()? onRequestRefresh;
|
||||
|
||||
/// Desktop-only callback invoked when the paginated table changes page.
|
||||
///
|
||||
/// The integer parameter is the first row index for the newly visible
|
||||
/// page, which corresponds directly to the `offset` value used by our
|
||||
/// server-side pagination providers. Consumers should update the
|
||||
/// associated query provider (e.g. `tasksQueryProvider`) so that the
|
||||
/// underlying stream/future is refreshed with the new range.
|
||||
final void Function(int firstRowIndex)? onPageChanged;
|
||||
|
||||
/// If true, shows a loading indicator for server-side pagination.
|
||||
final bool isLoading;
|
||||
|
||||
@@ -228,6 +252,8 @@ class TasQAdaptiveList<T> extends StatelessWidget {
|
||||
columns: columns,
|
||||
rowActions: rowActions,
|
||||
onRowTap: onRowTap,
|
||||
offset: pageOffset,
|
||||
totalCount: totalCount,
|
||||
);
|
||||
|
||||
// Use progressively smaller fractions of the viewport on larger screens
|
||||
@@ -248,7 +274,7 @@ class TasQAdaptiveList<T> extends StatelessWidget {
|
||||
);
|
||||
final effectiveRowsPerPage = math.min(
|
||||
rowsPerPage,
|
||||
math.max(1, items.length),
|
||||
math.max(1, totalCount ?? items.length),
|
||||
);
|
||||
|
||||
// wrap horizontal scroll with a visible scrollbar on desktop. the
|
||||
@@ -278,6 +304,7 @@ class TasQAdaptiveList<T> extends StatelessWidget {
|
||||
if (rowActions != null) const DataColumn(label: Text('Actions')),
|
||||
],
|
||||
source: dataSource,
|
||||
onPageChanged: onPageChanged,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -360,6 +387,8 @@ class _TasQTableSource<T> extends DataTableSource {
|
||||
required this.columns,
|
||||
required this.rowActions,
|
||||
required this.onRowTap,
|
||||
this.offset = 0,
|
||||
this.totalCount,
|
||||
});
|
||||
|
||||
final BuildContext context;
|
||||
@@ -367,11 +396,19 @@ class _TasQTableSource<T> extends DataTableSource {
|
||||
final List<TasQColumn<T>> columns;
|
||||
final TasQRowActions<T>? rowActions;
|
||||
final TasQRowTap<T>? onRowTap;
|
||||
final int offset;
|
||||
final int? totalCount;
|
||||
|
||||
@override
|
||||
DataRow? getRow(int index) {
|
||||
if (index >= items.length) return null;
|
||||
final item = items[index];
|
||||
// Map the global table index to the local items page using the
|
||||
// provided offset. If items contains the full dataset, offset will be
|
||||
// zero and this reduces to a direct index. If items contains only the
|
||||
// current page, index may be outside the local range — return null in
|
||||
// that case so the table can render blanks for non-loaded rows.
|
||||
final localIndex = index - offset;
|
||||
if (localIndex < 0 || localIndex >= items.length) return null;
|
||||
final item = items[localIndex];
|
||||
final cells = <DataCell>[];
|
||||
|
||||
for (final column in columns) {
|
||||
@@ -396,7 +433,7 @@ class _TasQTableSource<T> extends DataTableSource {
|
||||
bool get isRowCountApproximate => false;
|
||||
|
||||
@override
|
||||
int get rowCount => items.length;
|
||||
int get rowCount => totalCount ?? items.length;
|
||||
|
||||
@override
|
||||
int get selectedRowCount => 0;
|
||||
|
||||
Reference in New Issue
Block a user