2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-07-02 03:40:47 +00:00
Files
inventree-app/lib/barcode/handler.dart
Ben Hagen 4444884afa Format Code and Add Format Checks to CI (#643)
* Remove unused lib/generated/i18n.dart

* Use `fvm dart format .`

* Add contributing guidelines

* Enforce dart format

* Add `dart format off` directive to generated files
2025-06-24 09:55:01 +10:00

131 lines
3.7 KiB
Dart

import "package:flutter/material.dart";
import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
import "package:inventree/api.dart";
import "package:inventree/helpers.dart";
import "package:inventree/l10.dart";
import "package:inventree/barcode/tones.dart";
import "package:inventree/inventree/sentry.dart";
import "package:inventree/widget/dialogs.dart";
import "package:inventree/widget/snacks.dart";
/* Generic class which "handles" a barcode, by communicating with the InvenTree server,
* and handling match / unknown / error cases.
*
* Override functionality of this class to perform custom actions,
* based on the response returned from the InvenTree server
*/
class BarcodeHandler {
BarcodeHandler();
// Return the text to display on the barcode overlay
// Note: Will be overridden by child classes
String getOverlayText(BuildContext context) => "Barcode Overlay";
// Called when the server "matches" a barcode
Future<void> onBarcodeMatched(Map<String, dynamic> data) async {
// Override this function
}
// Called when the server does not know about a barcode
Future<void> onBarcodeUnknown(Map<String, dynamic> data) async {
// Override this function
barcodeFailureTone();
showSnackIcon(
(data["error"] ?? L10().barcodeNoMatch) as String,
success: false,
icon: Icons.qr_code,
);
}
// Called when the server returns an unhandled response
Future<void> onBarcodeUnhandled(Map<String, dynamic> data) async {
barcodeFailureTone();
showServerError("barcode/", L10().responseUnknown, data.toString());
}
/*
* Base function to capture and process barcode data.
*
* Returns true only if the barcode scanner should remain open
*/
Future<void> processBarcode(
String barcode, {
String url = "barcode/",
Map<String, dynamic> extra_data = const {},
}) async {
debug("Scanned barcode data: '${barcode}'");
barcode = barcode.trim();
// Empty barcode is invalid
if (barcode.isEmpty) {
barcodeFailureTone();
showSnackIcon(
L10().barcodeError,
icon: TablerIcons.exclamation_circle,
success: false,
);
return;
}
APIResponse? response;
try {
response = await InvenTreeAPI().post(
url,
body: {"barcode": barcode, ...extra_data},
expectedStatusCode: null, // Do not show an error on "unexpected code"
);
} catch (error, stackTrace) {
sentryReportError("Barcode.processBarcode", error, stackTrace);
response = null;
}
if (response == null) {
barcodeFailureTone();
showSnackIcon(L10().barcodeError, success: false);
return;
}
debug("Barcode scan response" + response.data.toString());
Map<String, dynamic> data = response.asMap();
// Handle strange response from the server
if (!response.isValid() || !response.isMap()) {
await onBarcodeUnknown({});
showSnackIcon(L10().serverError, success: false);
// We want to know about this one!
await sentryReportMessage(
"BarcodeHandler.processBarcode returned unexpected value",
context: {
"data": response.data?.toString() ?? "null",
"barcode": barcode,
"url": url,
"statusCode": response.statusCode.toString(),
"valid": response.isValid().toString(),
"error": response.error,
"errorDetail": response.errorDetail,
"className": "${this}",
},
);
} else if (data.containsKey("success")) {
await onBarcodeMatched(data);
} else if ((response.statusCode >= 400) || data.containsKey("error")) {
await onBarcodeUnknown(data);
} else {
await onBarcodeUnhandled(data);
}
}
}