2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 13:36:50 +00:00

PartList display now utilizes infinite scrolling

This commit is contained in:
Oliver Walters 2021-03-01 12:48:19 +11:00
parent 11b9668b7f
commit 64e544c043
2 changed files with 72 additions and 64 deletions

View File

@ -371,7 +371,7 @@ class InvenTreeAPI {
} }
}); });
} }
bool checkPermission(String role, String permission) { bool checkPermission(String role, String permission) {
/* /*
* Check if the user has the given role.permission assigned * Check if the user has the given role.permission assigned

View File

@ -19,6 +19,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
class CategoryDisplayWidget extends StatefulWidget { class CategoryDisplayWidget extends StatefulWidget {
@ -124,8 +125,6 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
List<InvenTreePartCategory> _subcategories = List<InvenTreePartCategory>(); List<InvenTreePartCategory> _subcategories = List<InvenTreePartCategory>();
List<InvenTreePart> _parts = List<InvenTreePart>();
@override @override
Future<void> onBuild(BuildContext context) async { Future<void> onBuild(BuildContext context) async {
refresh(); refresh();
@ -154,20 +153,6 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
// Update state // Update state
setState(() {}); setState(() {});
}); });
// Request a list of parts under this category
await InvenTreePart().list(context, filters: {"category": "$pk"}).then((var parts) {
_parts.clear();
for (var part in parts) {
if (part is InvenTreePart) {
_parts.add(part);
}
}
// Update state
setState(() {});
});
} }
Widget getCategoryDescriptionCard() { Widget getCategoryDescriptionCard() {
@ -262,32 +247,6 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
return tiles; return tiles;
} }
List<Widget> partTiles() {
List<Widget> tiles = <Widget>[
getCategoryDescriptionCard(),
ListTile(
title: Text(
I18N.of(context).parts,
style: TextStyle(fontWeight: FontWeight.bold)
),
trailing: _parts.isNotEmpty ? Text("${_parts.length}") : null,
),
];
if (loading) {
tiles.add(progressIndicator());
} else if (_parts.length == 0) {
tiles.add(ListTile(
title: Text("No Parts"),
subtitle: Text("No parts available in this category")
));
} else {
tiles.add(PartList(_parts));
}
return tiles;
}
List<Widget> actionTiles() { List<Widget> actionTiles() {
List<Widget> tiles = [ List<Widget> tiles = [
@ -313,9 +272,7 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
children: detailTiles() children: detailTiles()
); );
case 1: case 1:
return ListView( return PaginatedPartList(category?.pk ?? null);
children: partTiles()
);
case 2: case 2:
return ListView( return ListView(
children: actionTiles() children: actionTiles()
@ -368,13 +325,67 @@ class SubcategoryList extends StatelessWidget {
} }
/* /**
* Builder for displaying a list of Part objects * Widget for displaying a list of Part objects within a PartCategory display.
*
* Uses server-side pagination for snappy results
*/ */
class PartList extends StatelessWidget {
final List<InvenTreePart> _parts;
PartList(this._parts); class PaginatedPartList extends StatefulWidget {
final int categoryId;
PaginatedPartList(this.categoryId);
@override
_PaginatedPartListState createState() => _PaginatedPartListState(categoryId);
}
class _PaginatedPartListState extends State<PaginatedPartList> {
static const _pageSize = 25;
final int categoryId;
_PaginatedPartListState(this.categoryId);
final PagingController<int, InvenTreePart> _pagingController = PagingController(firstPageKey: 0);
@override
void initState() {
_pagingController.addPageRequestListener((pageKey) {
_fetchPage(pageKey);
});
}
Future<void> _fetchPage(int pageKey) async {
try {
final page = await InvenTreePart().listPaginated(_pageSize, pageKey, filters: {"category": "${categoryId}"});
final isLastPage = page.length < _pageSize;
// Construct a list of part objects
List<InvenTreePart> parts = [];
for (var result in page.results) {
if (result is InvenTreePart) {
parts.add(result);
}
}
if (isLastPage) {
_pagingController.appendLastPage(parts);
} else {
final int nextPageKey = pageKey + page.length;
_pagingController.appendPage(parts, nextPageKey);
}
} catch (error) {
print("Error! - ${error.toString()}");
_pagingController.error = error;
}
}
void _openPart(BuildContext context, int pk) { void _openPart(BuildContext context, int pk) {
// Attempt to load the part information // Attempt to load the part information
@ -386,13 +397,7 @@ class PartList extends StatelessWidget {
}); });
} }
Widget _build(BuildContext context, int index) { Widget _buildPart(BuildContext context, InvenTreePart part) {
InvenTreePart part;
if (index < _parts.length) {
part = _parts[index];
}
return ListTile( return ListTile(
title: Text(part.fullname), title: Text(part.fullname),
subtitle: Text("${part.description}"), subtitle: Text("${part.description}"),
@ -406,15 +411,18 @@ class PartList extends StatelessWidget {
_openPart(context, part.pk); _openPart(context, part.pk);
}, },
); );
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListView.separated( return PagedListView<int, InvenTreePart>.separated(
shrinkWrap: true, pagingController: _pagingController,
physics: ClampingScrollPhysics(), builderDelegate: PagedChildBuilderDelegate<InvenTreePart>(
separatorBuilder: (_, __) => const Divider(height: 3), itemBuilder: (context, item, index) {
itemBuilder: _build, itemCount: _parts.length); return _buildPart(context, item);
}
),
separatorBuilder: (context, index) => const Divider(height: 1),
);
} }
} }