mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-28 05:26:47 +00:00
Add progress indicators to a bunch o' stuff
This commit is contained in:
parent
dba45c7600
commit
b1b85a33f8
@ -2,6 +2,7 @@
|
|||||||
import 'package:InvenTree/api.dart';
|
import 'package:InvenTree/api.dart';
|
||||||
import 'package:InvenTree/inventree/part.dart';
|
import 'package:InvenTree/inventree/part.dart';
|
||||||
import 'package:InvenTree/preferences.dart';
|
import 'package:InvenTree/preferences.dart';
|
||||||
|
import 'package:InvenTree/widget/progress.dart';
|
||||||
|
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
@ -155,13 +156,16 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text("${category.name}"),
|
title: Text("${category.name}",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold)
|
||||||
|
),
|
||||||
subtitle: Text("${category.description}"),
|
subtitle: Text("${category.description}"),
|
||||||
),
|
),
|
||||||
|
Divider(),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(I18N.of(context).parentCategory),
|
title: Text(I18N.of(context).parentCategory),
|
||||||
subtitle: Text("${category.parentpathstring}"),
|
subtitle: Text("${category.parentpathstring}"),
|
||||||
leading: FaIcon(FontAwesomeIcons.sitemap),
|
leading: FaIcon(FontAwesomeIcons.levelUpAlt),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (category.parentId < 0) {
|
if (category.parentId < 0) {
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)));
|
Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null)));
|
||||||
@ -204,37 +208,64 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> detailTiles() {
|
List<Widget> detailTiles() {
|
||||||
return <Widget>[
|
List<Widget> tiles = <Widget>[
|
||||||
getCategoryDescriptionCard(),
|
getCategoryDescriptionCard(),
|
||||||
Divider(),
|
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
I18N.of(context).subcategories,
|
I18N.of(context).subcategories,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold)
|
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<Widget> partTiles() {
|
List<Widget> partTiles() {
|
||||||
return <Widget>[
|
List<Widget> tiles = <Widget>[
|
||||||
getCategoryDescriptionCard(),
|
getCategoryDescriptionCard(),
|
||||||
Divider(),
|
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
I18N.of(context).parts,
|
I18N.of(context).parts,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold)
|
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<Widget> actionTiles() {
|
List<Widget> actionTiles() {
|
||||||
|
|
||||||
List<Widget> tiles = [
|
List<Widget> tiles = [
|
||||||
getCategoryDescriptionCard()
|
getCategoryDescriptionCard(),
|
||||||
|
ListTile(
|
||||||
|
title: Text(I18N.of(context).actions,
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold)
|
||||||
|
)
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
// TODO - Actions!
|
// TODO - Actions!
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:InvenTree/api.dart';
|
import 'package:InvenTree/api.dart';
|
||||||
import 'package:InvenTree/inventree/stock.dart';
|
import 'package:InvenTree/inventree/stock.dart';
|
||||||
import 'package:InvenTree/preferences.dart';
|
import 'package:InvenTree/preferences.dart';
|
||||||
|
import 'package:InvenTree/widget/progress.dart';
|
||||||
|
|
||||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||||
import 'package:InvenTree/widget/fields.dart';
|
import 'package:InvenTree/widget/fields.dart';
|
||||||
@ -235,16 +236,25 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
|||||||
List<Widget> detailTiles() {
|
List<Widget> detailTiles() {
|
||||||
List<Widget> tiles = [
|
List<Widget> tiles = [
|
||||||
locationDescriptionCard(),
|
locationDescriptionCard(),
|
||||||
Divider(),
|
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
I18N.of(context).sublocations,
|
I18N.of(context).sublocations,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold)
|
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;
|
return tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,16 +262,25 @@ List<Widget> detailTiles() {
|
|||||||
List<Widget> stockTiles() {
|
List<Widget> stockTiles() {
|
||||||
List<Widget> tiles = [
|
List<Widget> tiles = [
|
||||||
locationDescriptionCard(),
|
locationDescriptionCard(),
|
||||||
Divider(),
|
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
I18N.of(context).stockItems,
|
I18N.of(context).stockItems,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold)
|
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;
|
return tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:InvenTree/widget/progress.dart';
|
||||||
import 'package:InvenTree/widget/snacks.dart';
|
import 'package:InvenTree/widget/snacks.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
@ -172,6 +173,11 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
|
|||||||
headerTile()
|
headerTile()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
tiles.add(progressIndicator());
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
// Category information
|
// Category information
|
||||||
if (part.categoryName != null && part.categoryName.isNotEmpty) {
|
if (part.categoryName != null && part.categoryName.isNotEmpty) {
|
||||||
tiles.add(
|
tiles.add(
|
||||||
|
13
lib/widget/progress.dart
Normal file
13
lib/widget/progress.dart
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct a circular progress indicator
|
||||||
|
*/
|
||||||
|
Widget progressIndicator() {
|
||||||
|
|
||||||
|
return Center(
|
||||||
|
child: CircularProgressIndicator()
|
||||||
|
);
|
||||||
|
}
|
@ -16,6 +16,11 @@ abstract class RefreshableState<T extends StatefulWidget> extends State<T> {
|
|||||||
// Current tab index (used for widgets which display bottom tabs)
|
// Current tab index (used for widgets which display bottom tabs)
|
||||||
int tabIndex = 0;
|
int tabIndex = 0;
|
||||||
|
|
||||||
|
// Bool indicator
|
||||||
|
bool loading = false;
|
||||||
|
|
||||||
|
bool get loaded => !loading;
|
||||||
|
|
||||||
// Update current tab selection
|
// Update current tab selection
|
||||||
void onTabSelectionChanged(int index) {
|
void onTabSelectionChanged(int index) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -45,8 +50,16 @@ abstract class RefreshableState<T extends StatefulWidget> extends State<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> refresh() async {
|
Future<void> refresh() async {
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
loading = true;
|
||||||
|
});
|
||||||
|
|
||||||
await request(context);
|
await request(context);
|
||||||
setState(() {});
|
|
||||||
|
setState(() {
|
||||||
|
loading = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to construct an appbar (override if needed)
|
// Function to construct an appbar (override if needed)
|
||||||
|
@ -8,6 +8,7 @@ import 'package:InvenTree/widget/dialogs.dart';
|
|||||||
import 'package:InvenTree/widget/fields.dart';
|
import 'package:InvenTree/widget/fields.dart';
|
||||||
import 'package:InvenTree/widget/location_display.dart';
|
import 'package:InvenTree/widget/location_display.dart';
|
||||||
import 'package:InvenTree/widget/part_detail.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/refreshable_state.dart';
|
||||||
import 'package:InvenTree/widget/snacks.dart';
|
import 'package:InvenTree/widget/snacks.dart';
|
||||||
import 'package:InvenTree/widget/stock_item_test_results.dart';
|
import 'package:InvenTree/widget/stock_item_test_results.dart';
|
||||||
@ -314,6 +315,15 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
|||||||
color: item.statusColor
|
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()),
|
//trailing: Text(item.serialOrQuantityDisplay()),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -329,22 +339,29 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
|||||||
// Image / name / description
|
// Image / name / description
|
||||||
tiles.add(headerTile());
|
tiles.add(headerTile());
|
||||||
|
|
||||||
tiles.add(
|
if (loading) {
|
||||||
ListTile(
|
tiles.add(progressIndicator());
|
||||||
title: Text(I18N.of(context).part),
|
return tiles;
|
||||||
subtitle: Text("${item.partName}"),
|
}
|
||||||
leading: FaIcon(FontAwesomeIcons.shapes),
|
|
||||||
onTap: () {
|
// Quantity information
|
||||||
if (item.partId > 0) {
|
if (item.isSerialized()) {
|
||||||
InvenTreePart().get(context, item.partId).then((var part) {
|
tiles.add(
|
||||||
if (part is InvenTreePart) {
|
ListTile(
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part)));
|
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
|
// Location information
|
||||||
if ((item.locationId > 0) && (item.locationName != null) && (item.locationName.isNotEmpty)) {
|
if ((item.locationId > 0) && (item.locationName != null) && (item.locationName.isNotEmpty)) {
|
||||||
@ -373,24 +390,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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?
|
// Supplier part?
|
||||||
// TODO: Display supplier part info page?
|
// TODO: Display supplier part info page?
|
||||||
|
@ -4,6 +4,7 @@ import 'package:InvenTree/inventree/model.dart';
|
|||||||
import 'package:InvenTree/api.dart';
|
import 'package:InvenTree/api.dart';
|
||||||
import 'package:InvenTree/widget/dialogs.dart';
|
import 'package:InvenTree/widget/dialogs.dart';
|
||||||
import 'package:InvenTree/widget/fields.dart';
|
import 'package:InvenTree/widget/fields.dart';
|
||||||
|
import 'package:InvenTree/widget/progress.dart';
|
||||||
import 'package:InvenTree/widget/snacks.dart';
|
import 'package:InvenTree/widget/snacks.dart';
|
||||||
|
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
@ -166,8 +167,40 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
|
|||||||
List<Widget> resultsList() {
|
List<Widget> resultsList() {
|
||||||
List<Widget> tiles = [];
|
List<Widget> 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();
|
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) {
|
for (var item in results) {
|
||||||
|
|
||||||
bool _required = false;
|
bool _required = false;
|
||||||
@ -231,6 +264,7 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget getBody(BuildContext context) {
|
Widget getBody(BuildContext context) {
|
||||||
|
|
||||||
return ListView(
|
return ListView(
|
||||||
children: ListTile.divideTiles(
|
children: ListTile.divideTiles(
|
||||||
context: context,
|
context: context,
|
||||||
@ -239,6 +273,7 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
List<SpeedDialChild> actionButtons() {
|
List<SpeedDialChild> actionButtons() {
|
||||||
|
|
||||||
var buttons = List<SpeedDialChild>();
|
var buttons = List<SpeedDialChild>();
|
||||||
@ -253,14 +288,15 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
|
|||||||
|
|
||||||
return buttons;
|
return buttons;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget getFab(BuildContext context) {
|
Widget getFab(BuildContext context) {
|
||||||
return SpeedDial(
|
return FloatingActionButton(
|
||||||
visible: true,
|
child: Icon(FontAwesomeIcons.plus),
|
||||||
animatedIcon: AnimatedIcons.menu_close,
|
onPressed: () {
|
||||||
heroTag: 'stock-item-results-tab',
|
addTestResult();
|
||||||
children: actionButtons(),
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
42
pubspec.lock
42
pubspec.lock
@ -434,48 +434,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.4"
|
version: "4.0.4"
|
||||||
shared_preferences:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: shared_preferences
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.5.12+4"
|
|
||||||
shared_preferences_linux:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_linux
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.0.2+4"
|
|
||||||
shared_preferences_macos:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_macos
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.0.1+11"
|
|
||||||
shared_preferences_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_platform_interface
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.4"
|
|
||||||
shared_preferences_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_web
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.1.2+7"
|
|
||||||
shared_preferences_windows:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_windows
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.0.2+3"
|
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
Loading…
x
Reference in New Issue
Block a user