diff --git a/lib/api.dart b/lib/api.dart index d61c9977..62d875ee 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -270,12 +270,10 @@ class InvenTreeAPI { print("PATCH: " + _url); - final response = await http.patch(_url, + return http.patch(_url, headers: _headers, body: _body, ); - - return response; } // Perform a POST request diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 58687de6..79adc760 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -126,6 +126,45 @@ class InvenTreeModel { return true; } + // POST data to update the model + Future update(BuildContext context, {Map values}) async { + + var addr = path.join(URL, pk.toString()); + + if (!addr.endsWith("/")) { + addr += "/"; + } + + showProgressDialog(context, "Updating ${NAME}", "Sending data to server"); + + var response = await api.patch(addr, body: values) + .timeout(Duration(seconds: 10)) + .catchError((e) { + + hideProgressDialog(context); + + if (e is TimeoutException) { + showErrorDialog(context, "Timeout", "No response from server"); + } else { + showErrorDialog(context, "Error", e.toString()); + } + + return null; + }); + + if (response == null) return false; + + hideProgressDialog(context); + + if (response.statusCode != 200) { + print("Error updating ${NAME}: Status code ${response.statusCode}"); + return false; + } + + return true; + + } + // Return the detail view for the associated pk Future get(BuildContext context, int pk, {Map filters}) async { diff --git a/lib/widget/fields.dart b/lib/widget/fields.dart index c401a7b8..53817659 100644 --- a/lib/widget/fields.dart +++ b/lib/widget/fields.dart @@ -3,12 +3,13 @@ import 'package:flutter/material.dart'; class QuantityField extends TextFormField { - QuantityField({String label = "", String hint = "", double max = null, TextEditingController controller}) : + QuantityField({String label = "", String hint = "", String initial = "", double max = null, TextEditingController controller}) : super( decoration: InputDecoration( labelText: label, hintText: hint, ), + initialValue: initial, controller: controller, keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), validator: (value) { diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 94b6d0a9..851c1d85 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -1,6 +1,7 @@ import 'package:InvenTree/inventree/part.dart'; import 'package:InvenTree/widget/category_display.dart'; +import 'package:InvenTree/widget/dialogs.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -24,6 +25,8 @@ class PartDetailWidget extends StatefulWidget { class _PartDisplayState extends RefreshableState { + final _editPartKey = GlobalKey(); + @override String getAppBarTitle(BuildContext context) { return "Part"; } @@ -40,6 +43,85 @@ class _PartDisplayState extends RefreshableState { await part.reload(context); } + void _savePart(Map values) async { + + Navigator.of(context).pop(); + + var response = await part.update(context, values: values); + + refresh(); + } + + void _editPartDialog() { + + // Values which can be edited + var _name; + var _description; + var _ipn; + var _revision; + + showFormDialog(context, "Edit Part", + key: _editPartKey, + actions: [ + FlatButton( + child: Text("Cancel"), + onPressed: () { + Navigator.pop(context); + }, + ), + FlatButton( + child: Text("Save"), + onPressed: () { + if (_editPartKey.currentState.validate()) { + _editPartKey.currentState.save(); + + _savePart({ + "name": _name, + "description": _description, + "IPN": _ipn, + }); + } + }, + ), + ], + fields: [ + TextFormField( + decoration: InputDecoration( + labelText: "Part Name", + hintText: "Enter part name", + ), + initialValue: part.name, + validator: (value) { + if (value.isEmpty) return "Name cannot be empty"; + return null; + }, + onSaved: (value) => _name = value, + ), + TextFormField( + decoration: InputDecoration( + labelText: "Part Description", + hintText: "Enter part description", + ), + initialValue: part.description, + validator: (value) { + if (value.isEmpty) return "Description cannot be empty"; + return null; + }, + onSaved: (value) => _description = value, + ), + TextFormField( + decoration: InputDecoration( + labelText: "Internal Part Number", + hintText: "Enter internal part number", + ), + initialValue: part.IPN, + onSaved: (value) => _ipn = value, + ) + ] + ); + + } + /* * Build a list of tiles to display under the part description */ @@ -58,7 +140,7 @@ class _PartDisplayState extends RefreshableState { ), trailing: IconButton( icon: FaIcon(FontAwesomeIcons.edit), - onPressed: null, + onPressed: _editPartDialog, ), ) )