diff --git a/lib/barcode.dart b/lib/barcode.dart index af7d5592..ab5c313a 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -23,7 +23,7 @@ import 'dart:io'; class BarcodeHandler { - /** + /* * Class which "handles" a barcode, by communicating with the InvenTree server, * and handling match / unknown / error cases. * @@ -36,7 +36,6 @@ class BarcodeHandler { BarcodeHandler(); QRViewController? _controller; - BuildContext? _context; void successTone() async { @@ -58,12 +57,12 @@ class BarcodeHandler { } } - Future onBarcodeMatched(Map data) async { + Future onBarcodeMatched(BuildContext context, Map data) async { // Called when the server "matches" a barcode // Override this function } - Future onBarcodeUnknown(Map data) async { + Future onBarcodeUnknown(BuildContext context, Map data) async { // Called when the server does not know about a barcode // Override this function @@ -76,7 +75,7 @@ class BarcodeHandler { ); } - Future onBarcodeUnhandled(Map data) async { + Future onBarcodeUnhandled(BuildContext context, Map data) async { failureTone(); @@ -86,8 +85,7 @@ class BarcodeHandler { _controller?.resumeCamera(); } - Future processBarcode(BuildContext? context, QRViewController? _controller, String barcode, {String url = "barcode/"}) async { - this._context = context; + Future processBarcode(BuildContext context, QRViewController? _controller, String barcode, {String url = "barcode/"}) async { this._controller = _controller; print("Scanned barcode data: ${barcode}"); @@ -106,20 +104,20 @@ class BarcodeHandler { if (response.data.containsKey('error')) { _controller?.resumeCamera(); - onBarcodeUnknown(response.data); + onBarcodeUnknown(context, response.data); } else if (response.data.containsKey('success')) { _controller?.resumeCamera(); - onBarcodeMatched(response.data); + onBarcodeMatched(context, response.data); } else { _controller?.resumeCamera(); - onBarcodeUnhandled(response.data); + onBarcodeUnhandled(context, response.data); } } } class BarcodeScanHandler extends BarcodeHandler { - /** + /* * Class for general barcode scanning. * Scan *any* barcode without context, and then redirect app to correct view */ @@ -128,7 +126,7 @@ class BarcodeScanHandler extends BarcodeHandler { String getOverlayText(BuildContext context) => L10().barcodeScanGeneral; @override - Future onBarcodeUnknown(Map data) async { + Future onBarcodeUnknown(BuildContext context, Map data) async { failureTone(); @@ -140,13 +138,10 @@ class BarcodeScanHandler extends BarcodeHandler { } @override - Future onBarcodeMatched(Map data) async { + Future onBarcodeMatched(BuildContext context, Map data) async { int pk = -1; - print("Handle barcode:"); - print(data); - // A stocklocation has been passed? if (data.containsKey('stocklocation')) { @@ -158,13 +153,8 @@ class BarcodeScanHandler extends BarcodeHandler { InvenTreeStockLocation().get(pk).then((var loc) { if (loc is InvenTreeStockLocation) { - - var _ctx = _context; - - if (_ctx != null) { - Navigator.of(_ctx).pop(); - Navigator.push(_ctx, MaterialPageRoute(builder: (context) => LocationDisplayWidget(loc))); - } + Navigator.of(context).pop(); + Navigator.push(context, MaterialPageRoute(builder: (context) => LocationDisplayWidget(loc))); } }); } else { @@ -187,16 +177,12 @@ class BarcodeScanHandler extends BarcodeHandler { InvenTreeStockItem().get(pk).then((var item) { - var _ctx = _context; - - if (_ctx != null) { // Dispose of the barcode scanner - Navigator.of(_ctx).pop(); + Navigator.of(context).pop(); if (item is InvenTreeStockItem) { - Navigator.push(_ctx, MaterialPageRoute(builder: (context) => StockDetailWidget(item))); + Navigator.push(context, MaterialPageRoute(builder: (context) => StockDetailWidget(item))); } - } }); } else { @@ -217,16 +203,12 @@ class BarcodeScanHandler extends BarcodeHandler { InvenTreePart().get(pk).then((var part) { - var _ctx = _context; - - if (_ctx != null) { // Dismiss the barcode scanner - Navigator.of(_ctx).pop(); + Navigator.of(context).pop(); if (part is InvenTreePart) { - Navigator.push(_ctx, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); + Navigator.push(context, MaterialPageRoute(builder: (context) => PartDetailWidget(part))); } - } }); } else { @@ -265,7 +247,7 @@ class BarcodeScanHandler extends BarcodeHandler { class StockItemBarcodeAssignmentHandler extends BarcodeHandler { - /** + /* * Barcode handler for assigning a new barcode to a stock item */ @@ -277,7 +259,7 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler { String getOverlayText(BuildContext context) => L10().barcodeScanAssign; @override - Future onBarcodeMatched(Map data) async { + Future onBarcodeMatched(BuildContext context, Map data) async { failureTone(); @@ -290,7 +272,7 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler { } @override - Future onBarcodeUnknown(Map data) async { + Future onBarcodeUnknown(BuildContext context, Map data) async { // If the barcode is unknown, we *can* assign it to the stock item! if (!data.containsKey("hash")) { @@ -310,14 +292,7 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler { failureTone(); - // Close the barcode scanner - _controller?.dispose(); - - var _ctx = (_context); - - if (_ctx != null) { - Navigator.of(_ctx).pop(); - } + Navigator.of(context).pop(); showSnackIcon( L10().barcodeAssigned, @@ -339,12 +314,8 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler { } } - - - - class StockItemScanIntoLocationHandler extends BarcodeHandler { - /** + /* * Barcode handler for scanning a provided StockItem into a scanned StockLocation */ @@ -356,11 +327,20 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler { String getOverlayText(BuildContext context) => L10().barcodeScanLocation; @override - Future onBarcodeMatched(Map data) async { + Future onBarcodeMatched(BuildContext context, Map data) async { // If the barcode points to a 'stocklocation', great! if (data.containsKey('stocklocation')) { // Extract location information - int location = data['stocklocation']['pk'] as int; + int location = (data['stocklocation']['pk'] ?? -1) as int; + + if (location == -1) { + showSnackIcon( + L10().invalidStockLocation, + success: false, + ); + + return; + } // Transfer stock to specified location final result = await item.transferStock(location); @@ -369,14 +349,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler { successTone(); - // Close the scanner - _controller?.dispose(); - - var _ctx = _context; - - if (_ctx != null) { - Navigator.of(_ctx).pop(); - } + Navigator.of(context).pop(); showSnackIcon( L10().barcodeScanIntoLocationSuccess, @@ -405,7 +378,7 @@ class StockItemScanIntoLocationHandler extends BarcodeHandler { class StockLocationScanInItemsHandler extends BarcodeHandler { - /** + /* * Barcode handler for scanning stock item(s) into the specified StockLocation */ @@ -417,7 +390,7 @@ class StockLocationScanInItemsHandler extends BarcodeHandler { String getOverlayText(BuildContext context) => L10().barcodeScanItem; @override - Future onBarcodeMatched(Map data) async { + Future onBarcodeMatched(BuildContext context, Map data) async { // Returned barcode must match a stock item if (data.containsKey('stockitem')) { @@ -489,33 +462,32 @@ class InvenTreeQRView extends StatefulWidget { class _QRViewState extends State { + final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); + QRViewController? _controller; final BarcodeHandler _handler; - BuildContext? _context; - // In order to get hot reload to work we need to pause the camera if the platform // is android, or resume the camera if the platform is iOS. @override void reassemble() { super.reassemble(); + if (Platform.isAndroid) { - _controller?.pauseCamera(); - } else if (Platform.isIOS) { - _controller?.resumeCamera(); + _controller!.pauseCamera(); } + + _controller!.resumeCamera(); } _QRViewState(this._handler) : super(); - final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); - - void _onViewCreated(QRViewController controller) { + void _onViewCreated(BuildContext context, QRViewController controller) { _controller = controller; controller.scannedDataStream.listen((barcode) { _controller?.pauseCamera(); - _handler.processBarcode(_context, _controller, barcode.code); + _handler.processBarcode(context, _controller, barcode.code); }); } @@ -528,9 +500,6 @@ class _QRViewState extends State { @override Widget build(BuildContext context) { - // Save the context for later on! - this._context = context; - return Scaffold( body: Stack( children: [ @@ -539,7 +508,9 @@ class _QRViewState extends State { Expanded( child: QRView( key: qrKey, - onQRViewCreated: _onViewCreated, + onQRViewCreated: (QRViewController controller) { + _onViewCreated(context, controller); + }, overlay: QrScannerOverlayShape( borderColor: Colors.red, borderRadius: 10, diff --git a/lib/inventree/sentry.dart b/lib/inventree/sentry.dart index 3d21160e..50ae4ee4 100644 --- a/lib/inventree/sentry.dart +++ b/lib/inventree/sentry.dart @@ -1,7 +1,7 @@ import 'dart:io'; -import 'package:device_info/device_info.dart'; -import 'package:package_info/package_info.dart'; +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:package_info_plus/package_info_plus.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:inventree/api.dart'; diff --git a/lib/main.dart b/lib/main.dart index 915b4731..e5997452 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,6 +8,7 @@ import 'package:inventree/widget/home.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:one_context/one_context.dart'; +import 'package:package_info_plus/package_info_plus.dart'; import 'dsn.dart'; @@ -17,14 +18,23 @@ import 'package:sentry_flutter/sentry_flutter.dart'; Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + await runZonedGuarded>(() async { + PackageInfo info = await PackageInfo.fromPlatform(); + String pkg = info.packageName; + String version = info.version; + String build = info.buildNumber; + + String release = "${pkg}@${version}:${build}"; + await Sentry.init((options) { options.dsn = SENTRY_DSN_KEY; + options.release = release; + options.environment = isInDebugMode() ? "debug" : "release"; }); - WidgetsFlutterBinding.ensureInitialized(); - // Pass any flutter errors off to the Sentry reporting context! FlutterError.onError = (FlutterErrorDetails details) async { diff --git a/lib/settings/about.dart b/lib/settings/about.dart index 22196ed2..de208666 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -6,7 +6,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:package_info/package_info.dart'; +import 'package:package_info_plus/package_info_plus.dart'; import 'package:inventree/l10.dart'; diff --git a/lib/settings/settings.dart b/lib/settings/settings.dart index d3a58113..8a0556cd 100644 --- a/lib/settings/settings.dart +++ b/lib/settings/settings.dart @@ -14,7 +14,7 @@ import 'package:url_launcher/url_launcher.dart'; import 'login.dart'; -import 'package:package_info/package_info.dart'; +import 'package:package_info_plus/package_info_plus.dart'; class InvenTreeSettingsWidget extends StatefulWidget { // InvenTree settings view diff --git a/lib/widget/company_detail.dart b/lib/widget/company_detail.dart index 1b7c2e72..123c9072 100644 --- a/lib/widget/company_detail.dart +++ b/lib/widget/company_detail.dart @@ -39,14 +39,6 @@ class _CompanyDetailState extends RefreshableState { // TODO } - void _saveCompany(Map values) async { - Navigator.of(context).pop(); - - await company.update(values: values); - - refresh(); - } - void editCompanyDialog() { // Values which can be edited @@ -54,55 +46,7 @@ class _CompanyDetailState extends RefreshableState { var _description; var _website; - showFormDialog(L10().edit, - key: _editCompanyKey, - actions: [ - TextButton( - child: Text(L10().cancel), - onPressed: () { - Navigator.pop(context); - }, - ), - TextButton( - child: Text(L10().save), - onPressed: () { - if (_editCompanyKey.currentState!.validate()) { - _editCompanyKey.currentState!.save(); - - _saveCompany({ - "name": _name, - "description": _description, - "website": _website, - }); - } - }, - ), - ], - fields: [ - StringField( - label: L10().name, - initial: company.name, - onSaved: (value) { - _name = value; - }, - ), - StringField( - label: L10().description, - initial: company.description, - onSaved: (value) { - _description = value; - }, - ), - StringField( - label: L10().website, - initial: company.website, - allowEmpty: true, - onSaved: (value) { - _website = value; - }, - ) - ] - ); + // TODO - API form } List _companyTiles() { diff --git a/lib/widget/dialogs.dart b/lib/widget/dialogs.dart index 8b0a6156..641a55c9 100644 --- a/lib/widget/dialogs.dart +++ b/lib/widget/dialogs.dart @@ -184,62 +184,47 @@ Future showTimeoutError() async { await showServerError(L10().timeout, L10().noResponse); } -void showFormDialog(String title, {String? acceptText, String? cancelText, GlobalKey? key, List? fields, List? actions, Function? callback}) { +void showFormDialog(String title, {String? acceptText, String? cancelText, GlobalKey? key, List? fields, Function? callback}) { - BuildContext? dialogContext; String _accept = acceptText ?? L10().save; String _cancel = cancelText ?? L10().cancel; - // Undefined actions = OK + Cancel - if (actions == null) { - actions = [ - TextButton( - child: Text(_cancel), - onPressed: () { - // Close the form - var _ctx = dialogContext; - if (_ctx != null) { - Navigator.pop(_ctx); - } - } - ), - TextButton( - child: Text(_accept), - onPressed: () { - - var _key = key; - - if (_key != null && _key.currentState != null) { - if (_key.currentState!.validate()) { - _key.currentState!.save(); - - // Close the dialog - var _ctx = dialogContext; - - if (_ctx != null) { - Navigator.pop(_ctx); - } - - // Callback - if (callback != null) { - callback(); - } - } - } - } - ) - ]; - } - List _fields = fields ?? []; OneContext().showDialog( builder: (BuildContext context) { - dialogContext = context; return AlertDialog( title: Text(title), - actions: actions, + actions: [ + TextButton( + child: Text(_cancel), + onPressed: () { + // Close the form + Navigator.pop(context); + } + ), + TextButton( + child: Text(_accept), + onPressed: () { + + var _key = key; + + if (_key != null && _key.currentState != null) { + if (_key.currentState!.validate()) { + _key.currentState!.save(); + + Navigator.pop(context); + + // Callback + if (callback != null) { + callback(); + } + } + } + } + ) + ], content: Form( key: key, child: SingleChildScrollView( diff --git a/pubspec.lock b/pubspec.lock index 36087b02..3c2e9310 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -113,20 +113,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.3" - device_info: + device_info_plus: dependency: "direct main" description: - name: device_info + name: device_info_plus url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" - device_info_platform_interface: + version: "2.1.0" + device_info_plus_linux: dependency: transitive description: - name: device_info_platform_interface + name: device_info_plus_linux url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.1.0" + device_info_plus_macos: + dependency: transitive + description: + name: device_info_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + device_info_plus_web: + dependency: transitive + description: + name: device_info_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + device_info_plus_windows: + dependency: transitive + description: + name: device_info_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" dropdown_search: dependency: "direct main" description: @@ -322,27 +350,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" - package_info: - dependency: "direct main" - description: - name: package_info - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" package_info_plus: - dependency: transitive + dependency: "direct main" description: name: package_info_plus url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.4" package_info_plus_linux: dependency: transitive description: name: package_info_plus_linux url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.3" package_info_plus_macos: dependency: transitive description: @@ -356,21 +377,21 @@ packages: name: package_info_plus_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" package_info_plus_web: dependency: transitive description: name: package_info_plus_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.3" package_info_plus_windows: dependency: transitive description: name: package_info_plus_windows url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.3" path: dependency: "direct main" description: @@ -454,7 +475,7 @@ packages: name: qr_code_scanner url: "https://pub.dartlang.org" source: hosted - version: "0.5.1" + version: "0.5.2" quiver: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 8e6901aa..fd3f75ce 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,9 +24,9 @@ dependencies: cupertino_icons: ^1.0.3 http: ^0.13.0 cached_network_image: ^3.0.0 # Download and cache remote images - qr_code_scanner: ^0.5.1 # Barcode scanning - package_info: ^2.0.0 # App information introspection - device_info: ^2.0.0 # Information about the device + qr_code_scanner: ^0.5.2 # Barcode scanning + package_info_plus: ^1.0.4 # App information introspection + device_info_plus: ^2.1.0 # Information about the device font_awesome_flutter: ^9.1.0 # FontAwesome icon set flutter_speed_dial: ^3.0.5 # FAB menu elements sentry_flutter: 5.0.0 # Error reporting