mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-29 14:06:47 +00:00
Stock display now uses infinite scroll
This commit is contained in:
parent
64e544c043
commit
d9a92216d2
@ -346,6 +346,8 @@ class _PaginatedPartListState extends State<PaginatedPartList> {
|
|||||||
|
|
||||||
static const _pageSize = 25;
|
static const _pageSize = 25;
|
||||||
|
|
||||||
|
String _searchTerm;
|
||||||
|
|
||||||
final int categoryId;
|
final int categoryId;
|
||||||
|
|
||||||
_PaginatedPartListState(this.categoryId);
|
_PaginatedPartListState(this.categoryId);
|
||||||
@ -357,12 +359,28 @@ class _PaginatedPartListState extends State<PaginatedPartList> {
|
|||||||
_pagingController.addPageRequestListener((pageKey) {
|
_pagingController.addPageRequestListener((pageKey) {
|
||||||
_fetchPage(pageKey);
|
_fetchPage(pageKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_pagingController.dispose();
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _fetchPage(int pageKey) async {
|
Future<void> _fetchPage(int pageKey) async {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final page = await InvenTreePart().listPaginated(_pageSize, pageKey, filters: {"category": "${categoryId}"});
|
Map<String, String> filters = {
|
||||||
|
"category": "${categoryId}",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_searchTerm != null && _searchTerm.isNotEmpty) {
|
||||||
|
filters["search"] = _searchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
final page = await InvenTreePart().listPaginated(_pageSize, pageKey, filters: filters);
|
||||||
final isLastPage = page.length < _pageSize;
|
final isLastPage = page.length < _pageSize;
|
||||||
|
|
||||||
// Construct a list of part objects
|
// Construct a list of part objects
|
||||||
@ -413,8 +431,34 @@ class _PaginatedPartListState extends State<PaginatedPartList> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateSearchTerm(String searchTerm) {
|
||||||
|
_searchTerm = searchTerm;
|
||||||
|
_pagingController.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
return CustomScrollView(
|
||||||
|
slivers: <Widget>[
|
||||||
|
// TODO: Introduce searching within the list
|
||||||
|
/*
|
||||||
|
SliverToBoxAdapter(child: TextField(
|
||||||
|
onChanged: updateSearchTerm,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
*/
|
||||||
|
PagedSliverList.separated(
|
||||||
|
pagingController: _pagingController,
|
||||||
|
builderDelegate: PagedChildBuilderDelegate<InvenTreePart>(
|
||||||
|
itemBuilder: (context, item, index) {
|
||||||
|
return _buildPart(context, item);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
separatorBuilder: (context, index) => const Divider(height: 1),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
return PagedListView<int, InvenTreePart>.separated(
|
return PagedListView<int, InvenTreePart>.separated(
|
||||||
pagingController: _pagingController,
|
pagingController: _pagingController,
|
||||||
builderDelegate: PagedChildBuilderDelegate<InvenTreePart>(
|
builderDelegate: PagedChildBuilderDelegate<InvenTreePart>(
|
||||||
|
@ -16,6 +16,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
|
|
||||||
class LocationDisplayWidget extends StatefulWidget {
|
class LocationDisplayWidget extends StatefulWidget {
|
||||||
|
|
||||||
@ -159,18 +160,6 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
|
||||||
await InvenTreeStockItem().list(context, filters: {"location": "$pk"}).then((var items) {
|
|
||||||
_items.clear();
|
|
||||||
|
|
||||||
for (var item in items) {
|
|
||||||
if (item is InvenTreeStockItem) {
|
|
||||||
_items.add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setState(() {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget locationDescriptionCard() {
|
Widget locationDescriptionCard() {
|
||||||
@ -240,9 +229,7 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
|||||||
children: detailTiles(),
|
children: detailTiles(),
|
||||||
);
|
);
|
||||||
case 1:
|
case 1:
|
||||||
return ListView(
|
return PaginatedStockList(location?.pk ?? null);
|
||||||
children: stockTiles(),
|
|
||||||
);
|
|
||||||
case 2:
|
case 2:
|
||||||
return ListView(
|
return ListView(
|
||||||
children: ListTile.divideTiles(
|
children: ListTile.divideTiles(
|
||||||
@ -300,6 +287,8 @@ List<Widget> detailTiles() {
|
|||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
tiles.add(progressIndicator());
|
tiles.add(progressIndicator());
|
||||||
} else if (_items.length > 0) {
|
} else if (_items.length > 0) {
|
||||||
@ -310,6 +299,7 @@ List<Widget> detailTiles() {
|
|||||||
subtitle: Text("No stock items available in this location")
|
subtitle: Text("No stock items available in this location")
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return tiles;
|
return tiles;
|
||||||
}
|
}
|
||||||
@ -403,10 +393,83 @@ class SublocationList extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StockList extends StatelessWidget {
|
/**
|
||||||
final List<InvenTreeStockItem> _items;
|
* Widget for displaying a list of stock items within a stock location.
|
||||||
|
*
|
||||||
|
* Users server-side pagination for snappy results
|
||||||
|
*/
|
||||||
|
|
||||||
StockList(this._items);
|
class PaginatedStockList extends StatefulWidget {
|
||||||
|
|
||||||
|
final int locationId;
|
||||||
|
|
||||||
|
PaginatedStockList(this.locationId);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_PaginatedStockListState createState() => _PaginatedStockListState(locationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class _PaginatedStockListState extends State<PaginatedStockList> {
|
||||||
|
|
||||||
|
static const _pageSize = 25;
|
||||||
|
|
||||||
|
String _searchTerm;
|
||||||
|
|
||||||
|
final int locationId;
|
||||||
|
|
||||||
|
_PaginatedStockListState(this.locationId);
|
||||||
|
|
||||||
|
final PagingController<int, InvenTreeStockItem> _pagingController = PagingController(firstPageKey: 0);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_pagingController.addPageRequestListener((pageKey) {
|
||||||
|
_fetchPage(pageKey);
|
||||||
|
});
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_pagingController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchPage(int pageKey) async {
|
||||||
|
try {
|
||||||
|
|
||||||
|
Map<String, String> filters = {
|
||||||
|
"location": "${locationId}"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_searchTerm != null && _searchTerm.isNotEmpty) {
|
||||||
|
filters["search"] = "${_searchTerm}";
|
||||||
|
}
|
||||||
|
|
||||||
|
final page = await InvenTreeStockItem().listPaginated(_pageSize, pageKey, filters: filters);
|
||||||
|
final isLastPage = page.length < _pageSize;
|
||||||
|
|
||||||
|
// Construct a list of stock item objects
|
||||||
|
List<InvenTreeStockItem> items = [];
|
||||||
|
|
||||||
|
for (var result in page.results) {
|
||||||
|
if (result is InvenTreeStockItem) {
|
||||||
|
items.add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLastPage) {
|
||||||
|
_pagingController.appendLastPage(items);
|
||||||
|
} else {
|
||||||
|
final int nextPageKey = pageKey + page.length;
|
||||||
|
_pagingController.appendPage(items, nextPageKey);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
_pagingController.error = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _openItem(BuildContext context, int pk) {
|
void _openItem(BuildContext context, int pk) {
|
||||||
InvenTreeStockItem().get(context, pk).then((var item) {
|
InvenTreeStockItem().get(context, pk).then((var item) {
|
||||||
@ -416,9 +479,7 @@ class StockList extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _build(BuildContext context, int index) {
|
Widget _buildItem(BuildContext context, InvenTreeStockItem item) {
|
||||||
InvenTreeStockItem item = _items[index];
|
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text("${item.partName}"),
|
title: Text("${item.partName}"),
|
||||||
subtitle: Text("${item.partDescription}"),
|
subtitle: Text("${item.partDescription}"),
|
||||||
@ -438,10 +499,19 @@ class StockList extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build (BuildContext context) {
|
Widget build (BuildContext context) {
|
||||||
return ListView.separated(
|
return CustomScrollView(
|
||||||
shrinkWrap: true,
|
slivers: <Widget>[
|
||||||
physics: ClampingScrollPhysics(),
|
// TODO - Search input
|
||||||
separatorBuilder: (_, __) => const Divider(height: 3),
|
PagedSliverList.separated(
|
||||||
itemBuilder: _build, itemCount: _items.length);
|
pagingController: _pagingController,
|
||||||
|
builderDelegate: PagedChildBuilderDelegate<InvenTreeStockItem>(
|
||||||
|
itemBuilder: (context, item, index) {
|
||||||
|
return _buildItem(context, item);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
separatorBuilder: (context, item) => const Divider(height: 1),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user