mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-28 13:36:50 +00:00
Merge branch 'snackbars'
This commit is contained in:
commit
3ec7ed217e
@ -1,4 +1,5 @@
|
||||
import 'package:InvenTree/inventree/part.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'model.dart';
|
||||
@ -323,6 +324,15 @@ class InvenTreeStockItem extends InvenTreeModel {
|
||||
|
||||
double get quantity => double.tryParse(jsondata['quantity'].toString() ?? '0');
|
||||
|
||||
String get quantityString {
|
||||
|
||||
if (quantity.toInt() == quantity) {
|
||||
return quantity.toInt().toString();
|
||||
} else {
|
||||
return quantity.toString();
|
||||
}
|
||||
}
|
||||
|
||||
int get locationId => jsondata['location'] as int ?? -1;
|
||||
|
||||
bool isSerialized() => serialNumber != null && quantity.toInt() == 1;
|
||||
@ -382,51 +392,81 @@ class InvenTreeStockItem extends InvenTreeModel {
|
||||
return item;
|
||||
}
|
||||
|
||||
Future<http.Response> countStock(double quan, {String notes}) async {
|
||||
/*
|
||||
* Perform stocktake action:
|
||||
*
|
||||
* - Add
|
||||
* - Remove
|
||||
* - Count
|
||||
*/
|
||||
Future<bool> adjustStock(BuildContext context, String endpoint, double q, {String notes}) async {
|
||||
|
||||
// Cannot 'count' a serialized StockItem
|
||||
// Serialized stock cannot be adjusted
|
||||
if (isSerialized()) {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cannot count negative stock
|
||||
if (quan < 0) {
|
||||
return null;
|
||||
// Cannot handle negative stock
|
||||
if (q < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return api.post("/stock/count/", body: {
|
||||
"item": {
|
||||
"pk": "${pk}",
|
||||
"quantity": "${quan}",
|
||||
},
|
||||
"notes": notes ?? '',
|
||||
var response = await api.post(
|
||||
endpoint,
|
||||
body: {
|
||||
"item": {
|
||||
"pk": "${pk}",
|
||||
"quantity": "${q}",
|
||||
},
|
||||
"notes": notes ?? '',
|
||||
}).timeout(Duration(seconds: 10)).catchError((error) {
|
||||
if (error is TimeoutException) {
|
||||
showTimeoutError(context);
|
||||
} else if (error is SocketException) {
|
||||
showServerError(
|
||||
context,
|
||||
I18N.of(context).connectionRefused,
|
||||
error.toString()
|
||||
);
|
||||
} else {
|
||||
// Re-throw the error, let sentry handle it!
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Null response if error
|
||||
return null;
|
||||
});
|
||||
|
||||
if (response == null) return false;
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
showStatusCodeError(context, response.statusCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stock adjustment succeeded!
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<http.Response> addStock(double quan, {String notes}) async {
|
||||
Future<bool> countStock(BuildContext context, double q, {String notes}) async {
|
||||
|
||||
if (isSerialized() || quan <= 0) return null;
|
||||
final bool result = await adjustStock(context, "/stock/count", q, notes: notes);
|
||||
|
||||
return api.post("/stock/add/", body: {
|
||||
"item": {
|
||||
"pk": "${pk}",
|
||||
"quantity": "${quan}",
|
||||
},
|
||||
"notes": notes ?? '',
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<http.Response> removeStock(double quan, {String notes}) async {
|
||||
Future<bool> addStock(BuildContext context, double q, {String notes}) async {
|
||||
|
||||
if (isSerialized() || quan <= 0) return null;
|
||||
final bool result = await adjustStock(context, "/stock/add/", q, notes: notes);
|
||||
|
||||
return api.post("/stock/remove/", body: {
|
||||
"item": {
|
||||
"pk": "${pk}",
|
||||
"quantity": "${quan}",
|
||||
},
|
||||
"notes": notes ?? '',
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<bool> removeStock(BuildContext context, double q, {String notes}) async {
|
||||
|
||||
final bool result = await adjustStock(context, "/stock/remove/", q, notes: notes);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<http.Response> transferStock(int location, {double quantity, String notes}) async {
|
||||
|
2
lib/l10n
2
lib/l10n
@ -1 +1 @@
|
||||
Subproject commit 249e4964a08b79e53df7e1ea18b051de0d307905
|
||||
Subproject commit ed3bd59b15b2c69b9a21649a0e0507efd811c1a1
|
@ -5,6 +5,9 @@ import 'package:InvenTree/preferences.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:InvenTree/widget/part_detail.dart';
|
||||
import 'package:InvenTree/widget/drawer.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
@ -28,6 +31,8 @@ class CategoryDisplayWidget extends StatefulWidget {
|
||||
|
||||
class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
|
||||
|
||||
final _editCategoryKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
String getAppBarTitle(BuildContext context) => I18N.of(context).partCategory;
|
||||
|
||||
@ -37,11 +42,54 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
|
||||
IconButton(
|
||||
icon: FaIcon(FontAwesomeIcons.edit),
|
||||
tooltip: I18N.of(context).edit,
|
||||
onPressed: null,
|
||||
onPressed: _editCategoryDialog,
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
void _editCategory(Map<String, String> values) async {
|
||||
|
||||
final bool result = await category.update(context, values: values);
|
||||
|
||||
showSnackIcon(
|
||||
refreshableKey,
|
||||
result ? "Category edited" : "Category editing failed",
|
||||
success: result
|
||||
);
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void _editCategoryDialog() {
|
||||
|
||||
var _name;
|
||||
var _description;
|
||||
|
||||
showFormDialog(
|
||||
context,
|
||||
I18N.of(context).editCategory,
|
||||
key: _editCategoryKey,
|
||||
callback: () {
|
||||
_editCategory({
|
||||
"name": _name,
|
||||
"description": _description
|
||||
});
|
||||
},
|
||||
fields: <Widget>[
|
||||
StringField(
|
||||
label: I18N.of(context).name,
|
||||
initial: category.name,
|
||||
onSaved: (value) => _name = value
|
||||
),
|
||||
StringField(
|
||||
label: I18N.of(context).description,
|
||||
initial: category.description,
|
||||
onSaved: (value) => _description = value
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
_CategoryDisplayState(this.category) {}
|
||||
|
||||
// The local InvenTreePartCategory object
|
||||
@ -61,6 +109,11 @@ class _CategoryDisplayState extends RefreshableState<CategoryDisplayWidget> {
|
||||
|
||||
int pk = category?.pk ?? -1;
|
||||
|
||||
// Update the category
|
||||
if (category != null) {
|
||||
await category.reload(context);
|
||||
}
|
||||
|
||||
// Request a list of sub-categories under this one
|
||||
await InvenTreePartCategory().list(context, filters: {"parent": "$pk"}).then((var cats) {
|
||||
_subcategories.clear();
|
||||
@ -266,7 +319,7 @@ class PartList extends StatelessWidget {
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
title: Text("${part.name}"),
|
||||
title: Text(part.fullname),
|
||||
subtitle: Text("${part.description}"),
|
||||
trailing: Text("${part.inStockString}"),
|
||||
leading: InvenTreeAPI().getImage(
|
||||
|
@ -161,7 +161,39 @@ void hideProgressDialog(BuildContext context) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
void showFormDialog(BuildContext context, String title, {GlobalKey<FormState> key, List<Widget> fields, List<Widget> actions}) {
|
||||
void showFormDialog(BuildContext context, String title, {GlobalKey<FormState> key, List<Widget> fields, List<Widget> actions, Function callback}) {
|
||||
|
||||
// Undefined actions = OK + Cancel
|
||||
if (actions == null) {
|
||||
actions = <Widget>[
|
||||
FlatButton(
|
||||
child: Text(I18N.of(context).cancel),
|
||||
onPressed: () {
|
||||
// Close the form
|
||||
Navigator.pop(context);
|
||||
}
|
||||
),
|
||||
FlatButton(
|
||||
child: Text(I18N.of(context).save),
|
||||
onPressed: () {
|
||||
if (key.currentState.validate()) {
|
||||
key.currentState.save();
|
||||
|
||||
// Close the dialog
|
||||
Navigator.pop(context);
|
||||
|
||||
// Callback
|
||||
if (callback != null) {
|
||||
callback();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
|
@ -1,13 +1,18 @@
|
||||
import 'package:InvenTree/api.dart';
|
||||
import 'package:InvenTree/inventree/stock.dart';
|
||||
import 'package:InvenTree/preferences.dart';
|
||||
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/widget/dialogs.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:InvenTree/widget/stock_detail.dart';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
|
||||
class LocationDisplayWidget extends StatefulWidget {
|
||||
|
||||
@ -25,6 +30,8 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
||||
|
||||
final InvenTreeStockLocation location;
|
||||
|
||||
final _editLocationKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
String getAppBarTitle(BuildContext context) { return "Stock Location"; }
|
||||
|
||||
@ -33,13 +40,53 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
||||
return <Widget>[
|
||||
IconButton(
|
||||
icon: FaIcon(FontAwesomeIcons.edit),
|
||||
tooltip: "Edit",
|
||||
// TODO - Edit stock location
|
||||
onPressed: null,
|
||||
tooltip: I18N.of(context).edit,
|
||||
onPressed: _editLocationDialog,
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
void _editLocation(Map<String, String> values) async {
|
||||
|
||||
final bool result = await location.update(context, values: values);
|
||||
|
||||
showSnackIcon(
|
||||
refreshableKey,
|
||||
result ? "Location edited" : "Location editing failed",
|
||||
success: result
|
||||
);
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void _editLocationDialog() {
|
||||
// Values which an be edited
|
||||
var _name;
|
||||
var _description;
|
||||
|
||||
showFormDialog(context, I18N.of(context).editLocation,
|
||||
key: _editLocationKey,
|
||||
callback: () {
|
||||
_editLocation({
|
||||
"name": _name,
|
||||
"description": _description
|
||||
});
|
||||
},
|
||||
fields: <Widget> [
|
||||
StringField(
|
||||
label: I18N.of(context).name,
|
||||
initial: location.name,
|
||||
onSaved: (value) => _name = value,
|
||||
),
|
||||
StringField(
|
||||
label: I18N.of(context).description,
|
||||
initial: location.description,
|
||||
onSaved: (value) => _description = value,
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
_LocationDisplayState(this.location) {}
|
||||
|
||||
List<InvenTreeStockLocation> _sublocations = List<InvenTreeStockLocation>();
|
||||
@ -67,6 +114,11 @@ class _LocationDisplayState extends RefreshableState<LocationDisplayWidget> {
|
||||
|
||||
int pk = location?.pk ?? -1;
|
||||
|
||||
// Reload location information
|
||||
if (location != null) {
|
||||
await location.reload(context);
|
||||
}
|
||||
|
||||
// Request a list of sub-locations under this one
|
||||
await InvenTreeStockLocation().list(context, filters: {"parent": "$pk"}).then((var locs) {
|
||||
_sublocations.clear();
|
||||
|
@ -1,4 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -74,9 +76,13 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
|
||||
|
||||
void _savePart(Map<String, String> values) async {
|
||||
|
||||
Navigator.of(context).pop();
|
||||
final bool result = await part.update(context, values: values);
|
||||
|
||||
var response = await part.update(context, values: values);
|
||||
showSnackIcon(
|
||||
refreshableKey,
|
||||
result ? "Part edited" : "Part editing failed",
|
||||
success: result
|
||||
);
|
||||
|
||||
refresh();
|
||||
}
|
||||
@ -96,34 +102,18 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
|
||||
var _name;
|
||||
var _description;
|
||||
var _ipn;
|
||||
var _revision;
|
||||
var _keywords;
|
||||
|
||||
showFormDialog(context, I18N.of(context).editPart,
|
||||
key: _editPartKey,
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(I18N.of(context).cancel),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
FlatButton(
|
||||
child: Text(I18N.of(context).save),
|
||||
onPressed: () {
|
||||
if (_editPartKey.currentState.validate()) {
|
||||
_editPartKey.currentState.save();
|
||||
|
||||
_savePart({
|
||||
"name": _name,
|
||||
"description": _description,
|
||||
"IPN": _ipn,
|
||||
"keywords": _keywords,
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
callback: () {
|
||||
_savePart({
|
||||
"name": _name,
|
||||
"description": _description,
|
||||
"IPN": _ipn,
|
||||
"keywords": _keywords
|
||||
});
|
||||
},
|
||||
fields: <Widget>[
|
||||
StringField(
|
||||
label: I18N.of(context).name,
|
||||
@ -163,7 +153,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => FullScreenWidget(part.name, part.image))
|
||||
MaterialPageRoute(builder: (context) => FullScreenWidget(part.fullname, part.image))
|
||||
);
|
||||
}),
|
||||
)
|
||||
|
@ -58,7 +58,7 @@ class _PartStockDisplayState extends RefreshableState<PartStockDetailWidget> {
|
||||
title: Text(part.fullname),
|
||||
subtitle: Text(part.description),
|
||||
leading: InvenTreeAPI().getImage(part.thumbnail),
|
||||
trailing: Text('${part.inStock}'),
|
||||
trailing: Text(part.inStockString),
|
||||
)
|
||||
),
|
||||
PartStockList(part.stockItems),
|
||||
|
@ -8,6 +8,8 @@ import 'package:InvenTree/widget/drawer.dart';
|
||||
|
||||
abstract class RefreshableState<T extends StatefulWidget> extends State<T> {
|
||||
|
||||
final refreshableKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
// Storage for context once "Build" is called
|
||||
BuildContext context;
|
||||
|
||||
@ -80,6 +82,7 @@ abstract class RefreshableState<T extends StatefulWidget> extends State<T> {
|
||||
this.context = context;
|
||||
|
||||
return Scaffold(
|
||||
key: refreshableKey,
|
||||
appBar: getAppBar(context),
|
||||
drawer: getDrawer(context),
|
||||
floatingActionButton: getFab(context),
|
||||
|
36
lib/widget/snacks.dart
Normal file
36
lib/widget/snacks.dart
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
/*
|
||||
* Display a snackbar with:
|
||||
*
|
||||
* a) Text on the left
|
||||
* b) Icon on the right
|
||||
*
|
||||
* | Text <icon> |
|
||||
*/
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
void showSnackIcon(GlobalKey<ScaffoldState> key, String text, {IconData icon, bool success}) {
|
||||
|
||||
// Hide the current snackbar
|
||||
key.currentState.hideCurrentSnackBar();
|
||||
|
||||
// If icon not specified, use the success status
|
||||
if (icon == null) {
|
||||
icon = (success == false) ? FontAwesomeIcons.timesCircle : FontAwesomeIcons.checkCircle;
|
||||
}
|
||||
|
||||
key.currentState.showSnackBar(
|
||||
SnackBar(
|
||||
content: Row(
|
||||
children: [
|
||||
Text(text),
|
||||
Spacer(),
|
||||
FaIcon(icon)
|
||||
]
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:InvenTree/barcode.dart';
|
||||
import 'package:InvenTree/inventree/stock.dart';
|
||||
@ -8,6 +9,7 @@ import 'package:InvenTree/widget/fields.dart';
|
||||
import 'package:InvenTree/widget/location_display.dart';
|
||||
import 'package:InvenTree/widget/part_detail.dart';
|
||||
import 'package:InvenTree/widget/refreshable_state.dart';
|
||||
import 'package:InvenTree/widget/snacks.dart';
|
||||
import 'package:InvenTree/widget/stock_item_test_results.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -22,6 +24,7 @@ import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class StockDetailWidget extends StatefulWidget {
|
||||
|
||||
@ -67,14 +70,12 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
||||
double quantity = double.parse(_quantityController.text);
|
||||
_quantityController.clear();
|
||||
|
||||
// Await response to prevent the button from being pressed multiple times
|
||||
var response = await item.addStock(quantity, notes: _notesController.text);
|
||||
final bool result = await item.addStock(context, quantity, notes: _notesController.text);
|
||||
_notesController.clear();
|
||||
|
||||
// TODO - Handle error cases
|
||||
refresh();
|
||||
_stockUpdateMessage(result);
|
||||
|
||||
// TODO - Display a snackbar here indicating the action was successful (or otherwise)
|
||||
refresh();
|
||||
}
|
||||
|
||||
void _addStockDialog() async {
|
||||
@ -108,20 +109,27 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
void _stockUpdateMessage(bool result) {
|
||||
|
||||
showSnackIcon(
|
||||
refreshableKey,
|
||||
result ? "Stock item updated" : "Stock item updated failed",
|
||||
success: result
|
||||
);
|
||||
}
|
||||
|
||||
void _removeStock() async {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
double quantity = double.parse(_quantityController.text);
|
||||
_quantityController.clear();
|
||||
|
||||
var response = await item.removeStock(quantity, notes: _notesController.text);
|
||||
_notesController.clear();
|
||||
final bool result = await item.removeStock(context, quantity, notes: _notesController.text);
|
||||
|
||||
// TODO - Handle error cases
|
||||
_stockUpdateMessage(result);
|
||||
|
||||
refresh();
|
||||
|
||||
// TODO - Display a snackbar here indicating the action was successful (or otherwise)
|
||||
}
|
||||
|
||||
void _removeStockDialog() {
|
||||
@ -163,19 +171,16 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
||||
double quantity = double.parse(_quantityController.text);
|
||||
_quantityController.clear();
|
||||
|
||||
var response = await item.countStock(quantity, notes: _notesController.text);
|
||||
_notesController.clear();
|
||||
final bool result = await item.countStock(context, quantity, notes: _notesController.text);
|
||||
|
||||
// TODO - Handle error cases, timeout, etc
|
||||
_stockUpdateMessage(result);
|
||||
|
||||
refresh();
|
||||
|
||||
// TODO - Display a snackbar here indicating the action was successful (or otherwise)
|
||||
}
|
||||
|
||||
void _countStockDialog() async {
|
||||
|
||||
_quantityController.text = item.quantity.toString();
|
||||
_quantityController.text = item.quantityString;
|
||||
_notesController.clear();
|
||||
|
||||
showFormDialog(context, I18N.of(context).countStock,
|
||||
@ -191,7 +196,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
||||
fields: <Widget> [
|
||||
QuantityField(
|
||||
label: I18N.of(context).countStock,
|
||||
hint: "${item.quantity}",
|
||||
hint: "${item.quantityString}",
|
||||
controller: _quantityController,
|
||||
),
|
||||
TextFormField(
|
||||
@ -230,7 +235,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
||||
|
||||
InvenTreeStockLocation selectedLocation;
|
||||
|
||||
_quantityController.text = "${item.quantity}";
|
||||
_quantityController.text = "${item.quantityString}";
|
||||
|
||||
showFormDialog(context, I18N.of(context).transferStock,
|
||||
key: _moveStockKey,
|
||||
@ -382,7 +387,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
||||
ListTile(
|
||||
title: Text(I18N.of(context).quantity),
|
||||
leading: FaIcon(FontAwesomeIcons.cubes),
|
||||
trailing: Text("${item.quantity}"),
|
||||
trailing: Text("${item.quantityString}"),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -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/snacks.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
@ -46,24 +47,20 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
|
||||
|
||||
void uploadTestResult(String name, bool result, String value, String notes, File attachment) async {
|
||||
|
||||
item.uploadTestResult(
|
||||
context,
|
||||
name,
|
||||
result,
|
||||
final success = await item.uploadTestResult(
|
||||
context, name, result,
|
||||
value: value,
|
||||
notes: notes,
|
||||
attachment: attachment
|
||||
).then((bool success) {
|
||||
if (success) {
|
||||
// TODO - Show a SnackBar here!
|
||||
refresh();
|
||||
} else {
|
||||
showErrorDialog(
|
||||
context,
|
||||
I18N.of(context).error,
|
||||
"Could not upload test result to server");
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
showSnackIcon(
|
||||
refreshableKey,
|
||||
success ? "Test result uploaded" : "Could not upload test result",
|
||||
success: success
|
||||
);
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void addTestResult({String name = '', bool nameIsEditable = true, bool result = false, String value = '', bool valueRequired = false, bool attachmentRequired = false}) async {
|
||||
@ -76,24 +73,9 @@ class _StockItemTestResultDisplayState extends RefreshableState<StockItemTestRes
|
||||
|
||||
showFormDialog(context, "Add Test Data",
|
||||
key: _addResultKey,
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text(I18N.of(context).cancel),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
FlatButton(
|
||||
child: Text(I18N.of(context).save),
|
||||
onPressed: () {
|
||||
if (_addResultKey.currentState.validate()) {
|
||||
_addResultKey.currentState.save();
|
||||
Navigator.pop(context);
|
||||
uploadTestResult(_name, _result, _value, _notes, _attachment);
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
callback: () {
|
||||
uploadTestResult(_name, _result, _value, _notes, _attachment);
|
||||
},
|
||||
fields: <Widget>[
|
||||
StringField(
|
||||
label: "Test Name",
|
||||
|
Loading…
x
Reference in New Issue
Block a user