From b1b85a33f80362c8a5eeb3da1a259b2471119f5e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 11 Feb 2021 21:38:48 +1100 Subject: [PATCH] Add progress indicators to a bunch o' stuff --- lib/widget/category_display.dart | 49 ++++++++++++++---- lib/widget/location_display.dart | 29 +++++++++-- lib/widget/part_detail.dart | 6 +++ lib/widget/progress.dart | 13 +++++ lib/widget/refreshable_state.dart | 15 +++++- lib/widget/stock_detail.dart | 68 ++++++++++++------------- lib/widget/stock_item_test_results.dart | 46 +++++++++++++++-- pubspec.lock | 42 --------------- 8 files changed, 172 insertions(+), 96 deletions(-) create mode 100644 lib/widget/progress.dart diff --git a/lib/widget/category_display.dart b/lib/widget/category_display.dart index 57b9a88e..ffa22289 100644 --- a/lib/widget/category_display.dart +++ b/lib/widget/category_display.dart @@ -2,6 +2,7 @@ import 'package:InvenTree/api.dart'; import 'package:InvenTree/inventree/part.dart'; import 'package:InvenTree/preferences.dart'; +import 'package:InvenTree/widget/progress.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -155,13 +156,16 @@ class _CategoryDisplayState extends RefreshableState { child: Column( children: [ ListTile( - title: Text("${category.name}"), + title: Text("${category.name}", + style: TextStyle(fontWeight: FontWeight.bold) + ), subtitle: Text("${category.description}"), ), + Divider(), ListTile( title: Text(I18N.of(context).parentCategory), subtitle: Text("${category.parentpathstring}"), - leading: FaIcon(FontAwesomeIcons.sitemap), + leading: FaIcon(FontAwesomeIcons.levelUpAlt), onTap: () { if (category.parentId < 0) { Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); @@ -204,37 +208,64 @@ class _CategoryDisplayState extends RefreshableState { } List detailTiles() { - return [ + List tiles = [ getCategoryDescriptionCard(), - Divider(), ListTile( title: Text( I18N.of(context).subcategories, style: TextStyle(fontWeight: FontWeight.bold) ) ), - SubcategoryList(_subcategories), ]; + + if (loading) { + tiles.add(progressIndicator()); + } else if (_subcategories.length == 0) { + tiles.add(ListTile( + title: Text("No Subcategories"), + subtitle: Text("No subcategories available") + )); + } else { + tiles.add(SubcategoryList(_subcategories)); + } + + return tiles; } List partTiles() { - return [ + List tiles = [ getCategoryDescriptionCard(), - Divider(), ListTile( title: Text( I18N.of(context).parts, style: TextStyle(fontWeight: FontWeight.bold) ) ), - PartList(_parts) ]; + + 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 actionTiles() { List tiles = [ - getCategoryDescriptionCard() + getCategoryDescriptionCard(), + ListTile( + title: Text(I18N.of(context).actions, + style: TextStyle(fontWeight: FontWeight.bold) + ) + ) ]; // TODO - Actions! diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 1b2276fb..8f262a0b 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -1,6 +1,7 @@ import 'package:InvenTree/api.dart'; import 'package:InvenTree/inventree/stock.dart'; import 'package:InvenTree/preferences.dart'; +import 'package:InvenTree/widget/progress.dart'; import 'package:InvenTree/widget/refreshable_state.dart'; import 'package:InvenTree/widget/fields.dart'; @@ -235,16 +236,25 @@ class _LocationDisplayState extends RefreshableState { List detailTiles() { List tiles = [ locationDescriptionCard(), - Divider(), ListTile( title: Text( I18N.of(context).sublocations, style: TextStyle(fontWeight: FontWeight.bold) ), ), - SublocationList(_sublocations) ]; + if (loading) { + tiles.add(progressIndicator()); + } else if (_sublocations.length > 0) { + tiles.add(SublocationList(_sublocations)); + } else { + tiles.add(ListTile( + title: Text("No Sublocations"), + subtitle: Text("No sublocations available") + )); + } + return tiles; } @@ -252,16 +262,25 @@ List detailTiles() { List stockTiles() { List tiles = [ locationDescriptionCard(), - Divider(), ListTile( title: Text( I18N.of(context).stockItems, style: TextStyle(fontWeight: FontWeight.bold) ) - ), - StockList(_items), + ) ]; + if (loading) { + tiles.add(progressIndicator()); + } else if (_items.length > 0) { + tiles.add(StockList(_items)); + } else { + tiles.add(ListTile( + title: Text("No Stock Items"), + subtitle: Text("No stock items available in this location") + )); + } + return tiles; } diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 6c34fc53..9e47af4f 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:InvenTree/widget/progress.dart'; import 'package:InvenTree/widget/snacks.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; @@ -172,6 +173,11 @@ class _PartDisplayState extends RefreshableState { headerTile() ); + if (loading) { + tiles.add(progressIndicator()); + return tiles; + } + // Category information if (part.categoryName != null && part.categoryName.isNotEmpty) { tiles.add( diff --git a/lib/widget/progress.dart b/lib/widget/progress.dart new file mode 100644 index 00000000..9aaeb256 --- /dev/null +++ b/lib/widget/progress.dart @@ -0,0 +1,13 @@ + + +import 'package:flutter/material.dart'; + +/* + * Construct a circular progress indicator + */ +Widget progressIndicator() { + + return Center( + child: CircularProgressIndicator() + ); +} \ No newline at end of file diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 53ed0a8e..6a5dc052 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -16,6 +16,11 @@ abstract class RefreshableState extends State { // Current tab index (used for widgets which display bottom tabs) int tabIndex = 0; + // Bool indicator + bool loading = false; + + bool get loaded => !loading; + // Update current tab selection void onTabSelectionChanged(int index) { setState(() { @@ -45,8 +50,16 @@ abstract class RefreshableState extends State { } Future refresh() async { + + setState(() { + loading = true; + }); + await request(context); - setState(() {}); + + setState(() { + loading = false; + }); } // Function to construct an appbar (override if needed) diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 7b173410..9f018626 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -8,6 +8,7 @@ import 'package:InvenTree/widget/dialogs.dart'; import 'package:InvenTree/widget/fields.dart'; import 'package:InvenTree/widget/location_display.dart'; import 'package:InvenTree/widget/part_detail.dart'; +import 'package:InvenTree/widget/progress.dart'; import 'package:InvenTree/widget/refreshable_state.dart'; import 'package:InvenTree/widget/snacks.dart'; import 'package:InvenTree/widget/stock_item_test_results.dart'; @@ -314,6 +315,15 @@ class _StockItemDisplayState extends RefreshableState { color: item.statusColor ) ), + onTap: () { + if (item.partId > 0) { + InvenTreePart().get(context, item.partId).then((var part) { + if (part is InvenTreePart) { + Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); + } + }); + } + }, //trailing: Text(item.serialOrQuantityDisplay()), ) ); @@ -329,22 +339,29 @@ class _StockItemDisplayState extends RefreshableState { // Image / name / description tiles.add(headerTile()); - tiles.add( - ListTile( - title: Text(I18N.of(context).part), - subtitle: Text("${item.partName}"), - leading: FaIcon(FontAwesomeIcons.shapes), - onTap: () { - if (item.partId > 0) { - InvenTreePart().get(context, item.partId).then((var part) { - if (part is InvenTreePart) { - Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); - } - }); - } - }, - ) - ); + if (loading) { + tiles.add(progressIndicator()); + return tiles; + } + + // Quantity information + if (item.isSerialized()) { + tiles.add( + ListTile( + title: Text(I18N.of(context).serialNumber), + leading: FaIcon(FontAwesomeIcons.hashtag), + trailing: Text("${item.serialNumber}"), + ) + ); + } else { + tiles.add( + ListTile( + title: Text(I18N.of(context).quantity), + leading: FaIcon(FontAwesomeIcons.cubes), + trailing: Text("${item.quantityString}"), + ) + ); + } // Location information if ((item.locationId > 0) && (item.locationName != null) && (item.locationName.isNotEmpty)) { @@ -373,24 +390,7 @@ class _StockItemDisplayState extends RefreshableState { ); } - // Quantity information - if (item.isSerialized()) { - tiles.add( - ListTile( - title: Text(I18N.of(context).serialNumber), - leading: FaIcon(FontAwesomeIcons.hashtag), - trailing: Text("${item.serialNumber}"), - ) - ); - } else { - tiles.add( - ListTile( - title: Text(I18N.of(context).quantity), - leading: FaIcon(FontAwesomeIcons.cubes), - trailing: Text("${item.quantityString}"), - ) - ); - } + // Supplier part? // TODO: Display supplier part info page? diff --git a/lib/widget/stock_item_test_results.dart b/lib/widget/stock_item_test_results.dart index c903a2ce..70bee8b6 100644 --- a/lib/widget/stock_item_test_results.dart +++ b/lib/widget/stock_item_test_results.dart @@ -4,6 +4,7 @@ import 'package:InvenTree/inventree/model.dart'; import 'package:InvenTree/api.dart'; import 'package:InvenTree/widget/dialogs.dart'; import 'package:InvenTree/widget/fields.dart'; +import 'package:InvenTree/widget/progress.dart'; import 'package:InvenTree/widget/snacks.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -166,8 +167,40 @@ class _StockItemTestResultDisplayState extends RefreshableState resultsList() { List tiles = []; + tiles.add( + Card( + child: ListTile( + title: Text(item.partName), + subtitle: Text(item.partDescription), + leading: InvenTreeAPI().getImage(item.partImage), + ) + ) + ); + + tiles.add( + ListTile( + title: Text("Test Results", + style: TextStyle(fontWeight: FontWeight.bold) + ) + ) + ); + + if (loading) { + tiles.add(progressIndicator()); + return tiles; + } + var results = getTestResults(); + if (results.length == 0) { + tiles.add(ListTile( + title: Text("No Results"), + subtitle: Text("No test results available"), + )); + + return tiles; + } + for (var item in results) { bool _required = false; @@ -231,6 +264,7 @@ class _StockItemTestResultDisplayState extends RefreshableState actionButtons() { var buttons = List(); @@ -253,14 +288,15 @@ class _StockItemTestResultDisplayState extends RefreshableState