From 6288088a655ebda5080c3ab3c2a526b21bc14846 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 3 Oct 2021 11:36:41 +1100 Subject: [PATCH] Adds "barcode" field handler for API forms --- lib/api_form.dart | 53 ++++++++++++++++++++++- lib/barcode.dart | 61 ++++++++++++++++++++++++++- lib/l10n | 2 +- lib/widget/purchase_order_detail.dart | 7 +++ 4 files changed, 118 insertions(+), 5 deletions(-) diff --git a/lib/api_form.dart b/lib/api_form.dart index 7fedbcdc..74c62ff6 100644 --- a/lib/api_form.dart +++ b/lib/api_form.dart @@ -7,6 +7,7 @@ import "package:date_field/date_field.dart"; import "package:inventree/api.dart"; import "package:inventree/app_colors.dart"; +import 'package:inventree/barcode.dart'; import "package:inventree/helpers.dart"; import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/sentry.dart"; @@ -269,7 +270,7 @@ class APIFormField { } // Construct a widget for this input - Widget constructField() { + Widget constructField(BuildContext context) { switch (type) { case "string": case "url": @@ -288,6 +289,8 @@ class APIFormField { return _constructFileField(); case "date": return _constructDateField(); + case "barcode": + return _constructBarcodeField(context); default: return ListTile( title: Text( @@ -300,6 +303,52 @@ class APIFormField { } } + // Field for capturing a barcode + Widget _constructBarcodeField(BuildContext context) { + + TextEditingController controller = TextEditingController(); + + String barcode = (value ?? "").toString(); + + if (barcode.isEmpty) { + barcode = L10().barcodeNotAssigned; + } + + controller.text = barcode; + + return InputDecorator( + decoration: InputDecoration( + labelText: required ? label + "*" : label, + labelStyle: _labelStyle(), + helperText: helpText, + helperStyle: _helperStyle(), + hintText: placeholderText, + ), + child: ListTile( + title: TextField( + readOnly: true, + controller: controller, + ), + trailing: IconButton( + icon: FaIcon(FontAwesomeIcons.qrcode), + onPressed: () async { + + var handler = UniqueBarcodeHandler((String hash) { + print("Scanned barcode: " + hash); + }); + + Navigator.push( + context, + MaterialPageRoute(builder: (context) => InvenTreeQRView(handler) + ) + ); + }, + ), + ) + ); + + } + // Field for displaying and selecting dates Widget _constructDateField() { @@ -937,7 +986,7 @@ class _APIFormWidgetState extends State { } } - widgets.add(field.constructField()); + widgets.add(field.constructField(context)); if (field.hasErrors()) { for (String error in field.errorMessages()) { diff --git a/lib/barcode.dart b/lib/barcode.dart index 3f44aa9c..de6283f0 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -305,7 +305,7 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler { } ).then((result) { if (result) { - failureTone(); + successTone(); Navigator.of(context).pop(); @@ -315,7 +315,7 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler { icon: FontAwesomeIcons.qrcode ); } else { - successTone(); + failureTone(); showSnackIcon( L10().barcodeNotAssigned, @@ -464,6 +464,63 @@ class StockLocationScanInItemsHandler extends BarcodeHandler { } +class UniqueBarcodeHandler extends BarcodeHandler { + /* + * Barcode handler for finding a "unique" barcode (one that does not match an item in the database) + */ + + UniqueBarcodeHandler(this.callback); + + // Callback function when a "unique" barcode hash is found + final Function(String) callback; + + @override + String getOverlayText(BuildContext context) => L10().barcodeScanAssign; + + @override + Future onBarcodeMatched(BuildContext context, Map data) async { + + failureTone(); + + // If the barcode is known, we can"t assign it to the stock item! + showSnackIcon( + L10().barcodeInUse, + icon: FontAwesomeIcons.qrcode, + success: false + ); + } + + @override + Future onBarcodeUnknown(BuildContext context, Map data) async { + // If the barcode is unknown, we *can* assign it to the stock item! + + if (!data.containsKey("hash")) { + showServerError( + L10().missingData, + L10().barcodeMissingHash, + ); + } else { + String hash = (data["hash"] ?? "") as String; + + if (hash.isEmpty) { + failureTone(); + + showSnackIcon( + L10().barcodeError, + success: false, + ); + } else { + + // Close the barcode scanner + Navigator.of(context).pop(); + + callback(hash); + } + } + } +} + + class InvenTreeQRView extends StatefulWidget { const InvenTreeQRView(this._handler, {Key? key}) : super(key: key); diff --git a/lib/l10n b/lib/l10n index 74d796f7..5f30fef9 160000 --- a/lib/l10n +++ b/lib/l10n @@ -1 +1 @@ -Subproject commit 74d796f7f1174fc27d5c031e18f4adbe1e16e6a4 +Subproject commit 5f30fef900ea027cd7fe90b2d87a6f02ced315c0 diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 6d6881cf..9a5cd703 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -195,6 +195,13 @@ class _PurchaseOrderDetailState extends RefreshableState