mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-11-03 23:05:44 +00:00 
			
		
		
		
	Update Requirements (#541)
* Update package requiremenst * github workflow updates * ios build updates * Theme adjustments * Further updates * Fix typo * Deprecated imperative apply of Flutter's Gradle plugins Ref: https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply * Refactor wedge scanner * Add context checks * Adjust behaviour if testing * Further refactoring * Moar checks * Logic fix * Fix for wedge scanner test * Fix for barcode processing * Fix * Yet another fix
This commit is contained in:
		@@ -2,6 +2,7 @@ import "package:flutter/material.dart";
 | 
			
		||||
 | 
			
		||||
import "package:flutter_speed_dial/flutter_speed_dial.dart";
 | 
			
		||||
import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
 | 
			
		||||
import "package:inventree/helpers.dart";
 | 
			
		||||
import "package:inventree/inventree/sales_order.dart";
 | 
			
		||||
import "package:inventree/preferences.dart";
 | 
			
		||||
import "package:inventree/widget/order/sales_order_detail.dart";
 | 
			
		||||
@@ -46,17 +47,20 @@ Future<void> barcodeFailure(String msg, dynamic extra) async {
 | 
			
		||||
      msg,
 | 
			
		||||
      success: false,
 | 
			
		||||
    onAction: () {
 | 
			
		||||
        OneContext().showDialog(
 | 
			
		||||
          builder: (BuildContext context) => SimpleDialog(
 | 
			
		||||
            title: Text(L10().barcodeError),
 | 
			
		||||
            children: <Widget>[
 | 
			
		||||
              ListTile(
 | 
			
		||||
                title: Text(L10().responseData),
 | 
			
		||||
                subtitle: Text(extra.toString())
 | 
			
		||||
              )
 | 
			
		||||
            ]
 | 
			
		||||
          )
 | 
			
		||||
        );
 | 
			
		||||
        if (hasContext()) {
 | 
			
		||||
          OneContext().showDialog(
 | 
			
		||||
              builder: (BuildContext context) =>
 | 
			
		||||
                  SimpleDialog(
 | 
			
		||||
                      title: Text(L10().barcodeError),
 | 
			
		||||
                      children: <Widget>[
 | 
			
		||||
                        ListTile(
 | 
			
		||||
                            title: Text(L10().responseData),
 | 
			
		||||
                            subtitle: Text(extra.toString())
 | 
			
		||||
                        )
 | 
			
		||||
                      ]
 | 
			
		||||
                  )
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@@ -277,17 +281,20 @@ class BarcodeScanHandler extends BarcodeHandler {
 | 
			
		||||
        success: false,
 | 
			
		||||
        onAction: () {
 | 
			
		||||
 | 
			
		||||
          OneContext().showDialog(
 | 
			
		||||
              builder: (BuildContext context) => SimpleDialog(
 | 
			
		||||
                title: Text(L10().unknownResponse),
 | 
			
		||||
                children: <Widget>[
 | 
			
		||||
                  ListTile(
 | 
			
		||||
                    title: Text(L10().responseData),
 | 
			
		||||
                    subtitle: Text(data.toString()),
 | 
			
		||||
                  )
 | 
			
		||||
                ],
 | 
			
		||||
              )
 | 
			
		||||
          );
 | 
			
		||||
          if (hasContext()) {
 | 
			
		||||
            OneContext().showDialog(
 | 
			
		||||
                builder: (BuildContext context) =>
 | 
			
		||||
                    SimpleDialog(
 | 
			
		||||
                      title: Text(L10().unknownResponse),
 | 
			
		||||
                      children: <Widget>[
 | 
			
		||||
                        ListTile(
 | 
			
		||||
                          title: Text(L10().responseData),
 | 
			
		||||
                          subtitle: Text(data.toString()),
 | 
			
		||||
                        )
 | 
			
		||||
                      ],
 | 
			
		||||
                    )
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
import "package:flutter/material.dart";
 | 
			
		||||
import "package:inventree/helpers.dart";
 | 
			
		||||
import "package:one_context/one_context.dart";
 | 
			
		||||
 | 
			
		||||
import "package:inventree/preferences.dart";
 | 
			
		||||
@@ -43,7 +44,7 @@ class InvenTreeBarcodeControllerState extends State<InvenTreeBarcodeController>
 | 
			
		||||
   * Barcode data should be passed as a string
 | 
			
		||||
   */
 | 
			
		||||
  Future<void> handleBarcodeData(String? data) async {
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Check that the data is valid, and this view is still mounted
 | 
			
		||||
    if (!mounted || data == null || data.isEmpty) {
 | 
			
		||||
      return;
 | 
			
		||||
@@ -58,7 +59,11 @@ class InvenTreeBarcodeControllerState extends State<InvenTreeBarcodeController>
 | 
			
		||||
      processingBarcode = true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    BuildContext? context = OneContext.hasContext ? OneContext().context : null;
 | 
			
		||||
    BuildContext? context;
 | 
			
		||||
 | 
			
		||||
    if (hasContext()) {
 | 
			
		||||
      context = OneContext.hasContext ? OneContext().context : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    showLoadingOverlay(context);
 | 
			
		||||
    await pauseScan();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,175 +0,0 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Custom keyboard listener which allows the app to act as a keyboard "wedge",
 | 
			
		||||
 * and intercept barcodes from any compatible scanner.
 | 
			
		||||
 *
 | 
			
		||||
 * Note: This code was copied from https://github.com/fuadreza/flutter_barcode_listener/blob/master/lib/flutter_barcode_listener.dart
 | 
			
		||||
 *
 | 
			
		||||
 * If that code becomes available on pub.dev, we can remove this file and reference that library
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import "dart:async";
 | 
			
		||||
 | 
			
		||||
import "package:flutter/material.dart";
 | 
			
		||||
import "package:flutter/services.dart";
 | 
			
		||||
 | 
			
		||||
typedef BarcodeScannedCallback = void Function(String barcode);
 | 
			
		||||
 | 
			
		||||
/// This widget will listen for raw PHYSICAL keyboard events
 | 
			
		||||
/// even when other controls have primary focus.
 | 
			
		||||
/// It will buffer all characters coming in specifed `bufferDuration` time frame
 | 
			
		||||
/// that end with line feed character and call callback function with result.
 | 
			
		||||
/// Keep in mind this widget will listen for events even when not visible.
 | 
			
		||||
/// Windows seems to be using the [RawKeyDownEvent] instead of the
 | 
			
		||||
/// [RawKeyUpEvent], this behaviour can be managed by setting [useKeyDownEvent].
 | 
			
		||||
class BarcodeKeyboardListener extends StatefulWidget {
 | 
			
		||||
 | 
			
		||||
  /// This widget will listen for raw PHYSICAL keyboard events
 | 
			
		||||
  /// even when other controls have primary focus.
 | 
			
		||||
  /// It will buffer all characters coming in specifed `bufferDuration` time frame
 | 
			
		||||
  /// that end with line feed character and call callback function with result.
 | 
			
		||||
  /// Keep in mind this widget will listen for events even when not visible.
 | 
			
		||||
  const BarcodeKeyboardListener(
 | 
			
		||||
      {Key? key,
 | 
			
		||||
 | 
			
		||||
        /// Child widget to be displayed.
 | 
			
		||||
        required this.child,
 | 
			
		||||
 | 
			
		||||
        /// Callback to be called when barcode is scanned.
 | 
			
		||||
        required Function(String) onBarcodeScanned,
 | 
			
		||||
 | 
			
		||||
        /// When experiencing issueswith empty barcodes on Windows,
 | 
			
		||||
        /// set this value to true. Default value is `false`.
 | 
			
		||||
        this.useKeyDownEvent = false,
 | 
			
		||||
 | 
			
		||||
        /// Maximum time between two key events.
 | 
			
		||||
        /// If time between two key events is longer than this value
 | 
			
		||||
        /// previous keys will be ignored.
 | 
			
		||||
        Duration bufferDuration = hundredMs})
 | 
			
		||||
      : _onBarcodeScanned = onBarcodeScanned,
 | 
			
		||||
        _bufferDuration = bufferDuration,
 | 
			
		||||
        super(key: key);
 | 
			
		||||
 | 
			
		||||
  final Widget child;
 | 
			
		||||
  final BarcodeScannedCallback _onBarcodeScanned;
 | 
			
		||||
  final Duration _bufferDuration;
 | 
			
		||||
  final bool useKeyDownEvent;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  _BarcodeKeyboardListenerState createState() => _BarcodeKeyboardListenerState(
 | 
			
		||||
      _onBarcodeScanned, _bufferDuration, useKeyDownEvent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Duration aSecond = Duration(seconds: 1);
 | 
			
		||||
const Duration hundredMs = Duration(milliseconds: 100);
 | 
			
		||||
const String lineFeed = "\n";
 | 
			
		||||
 | 
			
		||||
class _BarcodeKeyboardListenerState extends State<BarcodeKeyboardListener> {
 | 
			
		||||
 | 
			
		||||
  _BarcodeKeyboardListenerState(this._onBarcodeScannedCallback,
 | 
			
		||||
      this._bufferDuration, this._useKeyDownEvent) {
 | 
			
		||||
    RawKeyboard.instance.addListener(_keyBoardCallback);
 | 
			
		||||
    _keyboardSubscription =
 | 
			
		||||
        _controller.stream.where((char) => char != null).listen(onKeyEvent);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  List<String> _scannedChars = [];
 | 
			
		||||
  DateTime? _lastScannedCharCodeTime;
 | 
			
		||||
  late StreamSubscription<String?> _keyboardSubscription;
 | 
			
		||||
 | 
			
		||||
  final BarcodeScannedCallback _onBarcodeScannedCallback;
 | 
			
		||||
  final Duration _bufferDuration;
 | 
			
		||||
 | 
			
		||||
  final _controller = StreamController<String?>();
 | 
			
		||||
 | 
			
		||||
  final bool _useKeyDownEvent;
 | 
			
		||||
 | 
			
		||||
  bool _isShiftPressed = false;
 | 
			
		||||
  void onKeyEvent(String? char) {
 | 
			
		||||
    //remove any pending characters older than bufferDuration value
 | 
			
		||||
    checkPendingCharCodesToClear();
 | 
			
		||||
    _lastScannedCharCodeTime = DateTime.now();
 | 
			
		||||
    if (char == lineFeed) {
 | 
			
		||||
      _onBarcodeScannedCallback.call(_scannedChars.join());
 | 
			
		||||
      resetScannedCharCodes();
 | 
			
		||||
    } else {
 | 
			
		||||
      //add character to list of scanned characters;
 | 
			
		||||
      _scannedChars.add(char!);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void checkPendingCharCodesToClear() {
 | 
			
		||||
    if (_lastScannedCharCodeTime != null) {
 | 
			
		||||
      if (_lastScannedCharCodeTime!
 | 
			
		||||
          .isBefore(DateTime.now().subtract(_bufferDuration))) {
 | 
			
		||||
        resetScannedCharCodes();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void resetScannedCharCodes() {
 | 
			
		||||
    _lastScannedCharCodeTime = null;
 | 
			
		||||
    _scannedChars = [];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void addScannedCharCode(String charCode) {
 | 
			
		||||
    _scannedChars.add(charCode);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void _keyBoardCallback(RawKeyEvent keyEvent) {
 | 
			
		||||
    if (keyEvent.logicalKey.keyId > 255 &&
 | 
			
		||||
        keyEvent.data.logicalKey != LogicalKeyboardKey.enter &&
 | 
			
		||||
        keyEvent.data.logicalKey != LogicalKeyboardKey.shiftLeft) return;
 | 
			
		||||
    if ((!_useKeyDownEvent && keyEvent is RawKeyUpEvent) ||
 | 
			
		||||
        (_useKeyDownEvent && keyEvent is RawKeyDownEvent)) {
 | 
			
		||||
      if (keyEvent.data is RawKeyEventDataAndroid) {
 | 
			
		||||
        if (keyEvent.data.logicalKey == LogicalKeyboardKey.shiftLeft) {
 | 
			
		||||
          _isShiftPressed = true;
 | 
			
		||||
        } else {
 | 
			
		||||
          if (_isShiftPressed) {
 | 
			
		||||
            _isShiftPressed = false;
 | 
			
		||||
            _controller.sink.add(String.fromCharCode(
 | 
			
		||||
                ((keyEvent.data) as RawKeyEventDataAndroid).codePoint).toUpperCase());
 | 
			
		||||
          } else {
 | 
			
		||||
            _controller.sink.add(String.fromCharCode(
 | 
			
		||||
                ((keyEvent.data) as RawKeyEventDataAndroid).codePoint));
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      } else if (keyEvent.data is RawKeyEventDataFuchsia) {
 | 
			
		||||
        _controller.sink.add(String.fromCharCode(
 | 
			
		||||
            ((keyEvent.data) as RawKeyEventDataFuchsia).codePoint));
 | 
			
		||||
      } else if (keyEvent.data.logicalKey == LogicalKeyboardKey.enter) {
 | 
			
		||||
        _controller.sink.add(lineFeed);
 | 
			
		||||
      } else if (keyEvent.data is RawKeyEventDataWeb) {
 | 
			
		||||
        _controller.sink.add(((keyEvent.data) as RawKeyEventDataWeb).keyLabel);
 | 
			
		||||
      } else if (keyEvent.data is RawKeyEventDataLinux) {
 | 
			
		||||
        _controller.sink
 | 
			
		||||
            .add(((keyEvent.data) as RawKeyEventDataLinux).keyLabel);
 | 
			
		||||
      } else if (keyEvent.data is RawKeyEventDataWindows) {
 | 
			
		||||
        _controller.sink.add(String.fromCharCode(
 | 
			
		||||
            ((keyEvent.data) as RawKeyEventDataWindows).keyCode));
 | 
			
		||||
      } else if (keyEvent.data is RawKeyEventDataMacOs) {
 | 
			
		||||
        _controller.sink
 | 
			
		||||
            .add(((keyEvent.data) as RawKeyEventDataMacOs).characters);
 | 
			
		||||
      } else if (keyEvent.data is RawKeyEventDataIos) {
 | 
			
		||||
        _controller.sink
 | 
			
		||||
            .add(((keyEvent.data) as RawKeyEventDataIos).characters);
 | 
			
		||||
      } else {
 | 
			
		||||
        _controller.sink.add(keyEvent.character);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return widget.child;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void dispose() {
 | 
			
		||||
    _keyboardSubscription.cancel();
 | 
			
		||||
    _controller.close();
 | 
			
		||||
    RawKeyboard.instance.removeListener(_keyBoardCallback);
 | 
			
		||||
    super.dispose();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -42,7 +42,7 @@ class BarcodeScanStockLocationHandler extends BarcodeHandler {
 | 
			
		||||
 | 
			
		||||
        final bool result = await onLocationScanned(_loc);
 | 
			
		||||
 | 
			
		||||
        if (result && OneContext.hasContext) {
 | 
			
		||||
        if (result && hasContext()) {
 | 
			
		||||
          OneContext().pop();
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,12 @@
 | 
			
		||||
 | 
			
		||||
import "package:flutter/material.dart";
 | 
			
		||||
import "package:flutter/services.dart";
 | 
			
		||||
import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
 | 
			
		||||
 | 
			
		||||
import "package:inventree/app_colors.dart";
 | 
			
		||||
import "package:inventree/barcode/controller.dart";
 | 
			
		||||
import "package:inventree/barcode/handler.dart";
 | 
			
		||||
import "package:inventree/barcode/flutter_barcode_listener.dart";
 | 
			
		||||
 | 
			
		||||
import "package:inventree/l10.dart";
 | 
			
		||||
import "package:inventree/helpers.dart";
 | 
			
		||||
 | 
			
		||||
@@ -31,6 +32,12 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState {
 | 
			
		||||
 | 
			
		||||
  bool get scanning => mounted && canScan;
 | 
			
		||||
 | 
			
		||||
  final FocusNode _focusNode = FocusNode();
 | 
			
		||||
 | 
			
		||||
  List<String> _scannedCharacters = [];
 | 
			
		||||
 | 
			
		||||
  DateTime? _lastScanTime;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Future<void> pauseScan() async {
 | 
			
		||||
 | 
			
		||||
@@ -51,6 +58,45 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Callback for a single key press / scan
 | 
			
		||||
  void handleKeyEvent(KeyEvent event) {
 | 
			
		||||
 | 
			
		||||
    if (!scanning) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Look only for key-down events
 | 
			
		||||
    if (event is! KeyDownEvent) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Ignore events without a character code
 | 
			
		||||
    if (event.character == null) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DateTime now = DateTime.now();
 | 
			
		||||
 | 
			
		||||
    // Throw away old characters
 | 
			
		||||
    if (_lastScanTime == null || _lastScanTime!.isBefore(now.subtract(Duration(milliseconds: 250)))) {
 | 
			
		||||
      _scannedCharacters.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _lastScanTime = now;
 | 
			
		||||
 | 
			
		||||
    if (event.character == "\n") {
 | 
			
		||||
      if (_scannedCharacters.isNotEmpty) {
 | 
			
		||||
        // Debug output required for unit testing
 | 
			
		||||
        debug("scanned: ${_scannedCharacters.join()}");
 | 
			
		||||
        handleBarcodeData(_scannedCharacters.join());
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      _scannedCharacters.clear();
 | 
			
		||||
    } else {
 | 
			
		||||
      _scannedCharacters.add(event.character!);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
 | 
			
		||||
@@ -66,8 +112,9 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState {
 | 
			
		||||
            Spacer(flex: 5),
 | 
			
		||||
            Icon(TablerIcons.barcode, size: 64),
 | 
			
		||||
            Spacer(flex: 5),
 | 
			
		||||
            BarcodeKeyboardListener(
 | 
			
		||||
              useKeyDownEvent: true,
 | 
			
		||||
            KeyboardListener(
 | 
			
		||||
              autofocus: true,
 | 
			
		||||
              focusNode: _focusNode,
 | 
			
		||||
              child: SizedBox(
 | 
			
		||||
                child: CircularProgressIndicator(
 | 
			
		||||
                  color: scanning ? COLOR_ACTION : COLOR_PROGRESS
 | 
			
		||||
@@ -75,13 +122,16 @@ class _WedgeBarcodeControllerState extends InvenTreeBarcodeControllerState {
 | 
			
		||||
                width: 64,
 | 
			
		||||
                height: 64,
 | 
			
		||||
              ),
 | 
			
		||||
              onBarcodeScanned: (String barcode) {
 | 
			
		||||
                debug("scanned: ${barcode}");
 | 
			
		||||
                if (scanning) {
 | 
			
		||||
                  // Process the barcode data
 | 
			
		||||
                  handleBarcodeData(barcode);
 | 
			
		||||
                }
 | 
			
		||||
              onKeyEvent: (event) {
 | 
			
		||||
                handleKeyEvent(event);
 | 
			
		||||
              },
 | 
			
		||||
              // onBarcodeScanned: (String barcode) {
 | 
			
		||||
              //   debug("scanned: ${barcode}");
 | 
			
		||||
              //   if (scanning) {
 | 
			
		||||
              //     // Process the barcode data
 | 
			
		||||
              //     handleBarcodeData(barcode);
 | 
			
		||||
              //   }
 | 
			
		||||
              // },
 | 
			
		||||
            ),
 | 
			
		||||
            Spacer(flex: 5),
 | 
			
		||||
            Padding(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user