diff --git a/analysis_options.yaml b/analysis_options.yaml index 1e9930f..5ec54e5 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,6 +1,239 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. include: package:flutter_lints/flutter.yaml -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options analyzer: - exclude: [lib/generated_bindings.dart] \ No newline at end of file + language: + strict-casts: false + strict-raw-types: true + errors: + # treat missing required parameters as a warning (not a hint) + missing_required_param: warning + # treat missing returns as a warning (not a hint) + missing_return: warning + # not allowing having TODO comments in the code + # todo: warning + # allow self-reference to deprecated members (we do this because otherwise we have + # to annotate every member in every test, assert, etc, when we deprecate something) + deprecated_member_use_from_same_package: ignore + # Turned off until null-safe rollout is complete. + unnecessary_null_comparison: warning + exclude: + - "bin/cache/**" + # Ignore protoc generated files + - "dev/conductor/lib/proto/*" + - "lib/generated_bindings.dart" + +linter: + rules: + # This list is derived from the list of all available lints located at + # https://github.com/dart-lang/linter/blob/master/example/all.yaml + - always_declare_return_types + - always_put_control_body_on_new_line + # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 + - always_require_non_null_named_parameters + - always_specify_types + # - always_use_package_imports # we do this commonly + - annotate_overrides + # - avoid_annotating_with_dynamic # conflicts with always_specify_types + - avoid_bool_literals_in_conditional_expressions + # - avoid_catches_without_on_clauses # blocked on https://github.com/dart-lang/linter/issues/3023 + # - avoid_catching_errors # blocked on https://github.com/dart-lang/linter/issues/3023 + - avoid_classes_with_only_static_members + - avoid_double_and_int_checks + - avoid_dynamic_calls + - avoid_empty_else + - avoid_equals_and_hash_code_on_mutable_classes + - avoid_escaping_inner_quotes + - avoid_field_initializers_in_const_classes + # - avoid_final_parameters # incompatible with prefer_final_parameters + - avoid_function_literals_in_foreach_calls + - avoid_implementing_value_types + - avoid_init_to_null + - avoid_js_rounded_ints + # - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to + - avoid_null_checks_in_equality_operators + # - avoid_positional_boolean_parameters # would have been nice to enable this but by now there's too many places that break it + - avoid_print + # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) + - avoid_redundant_argument_values + - avoid_relative_lib_imports + - avoid_renaming_method_parameters + - avoid_return_types_on_setters + # - avoid_returning_null # still violated by some pre-nnbd code that we haven't yet migrated + - avoid_returning_null_for_future + - avoid_returning_null_for_void + # - avoid_returning_this # there are enough valid reasons to return `this` that this lint ends up with too many false positives + - avoid_setters_without_getters + - avoid_shadowing_type_parameters + - avoid_single_cascade_in_expression_statements + - avoid_slow_async_io + - avoid_type_to_string + - avoid_types_as_parameter_names + # - avoid_types_on_closure_parameters # conflicts with always_specify_types + - avoid_unnecessary_containers + - avoid_unused_constructor_parameters + - avoid_void_async + # - avoid_web_libraries_in_flutter # we use web libraries in web-specific code, and our tests prevent us from using them elsewhere + - await_only_futures + - camel_case_extensions + - camel_case_types + - cancel_subscriptions + # - cascade_invocations # doesn't match the typical style of this repo + - cast_nullable_to_non_nullable + # - close_sinks # not reliable enough + # - comment_references # blocked on https://github.com/dart-lang/linter/issues/1142 + # - conditional_uri_does_not_exist # not yet tested + # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 + - control_flow_in_finally + # - curly_braces_in_flow_control_structures # not required by flutter style + - depend_on_referenced_packages + - deprecated_consistency + # - diagnostic_describe_all_properties # enabled only at the framework level (packages/flutter/lib) + - directives_ordering + # - do_not_use_environment # there are appropriate times to use the environment, especially in our tests and build logic + - empty_catches + - empty_constructor_bodies + - empty_statements + - eol_at_end_of_file + - exhaustive_cases + - file_names + - hash_and_equals + - implementation_imports + # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 + - iterable_contains_unrelated_type + # - join_return_with_assignment # not required by flutter style + - leading_newlines_in_multiline_strings + - library_names + - library_prefixes + - library_private_types_in_public_api + # - lines_longer_than_80_chars # not required by flutter style + - list_remove_unrelated_type + # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/linter/issues/453 + - missing_whitespace_between_adjacent_strings + - no_adjacent_strings_in_list + - no_default_cases + - no_duplicate_case_values + - no_leading_underscores_for_library_prefixes + - no_leading_underscores_for_local_identifiers + - no_logic_in_create_state + # - no_runtimeType_toString # ok in tests; we enable this only in packages/ + - non_constant_identifier_names + - noop_primitive_operations + - null_check_on_nullable_type_parameter + - null_closures + # - omit_local_variable_types # opposite of always_specify_types + # - one_member_abstracts # too many false positives + - only_throw_errors # this does get disabled in a few places where we have legacy code that uses strings et al + - overridden_fields + - package_api_docs + - package_names + - package_prefixed_library_names + # - parameter_assignments # we do this commonly + - prefer_adjacent_string_concatenation + - prefer_asserts_in_initializer_lists + # - prefer_asserts_with_message # not required by flutter style + - prefer_collection_literals + - prefer_conditional_assignment + - prefer_const_constructors + - prefer_const_constructors_in_immutables + - prefer_const_declarations + - prefer_const_literals_to_create_immutables + # - prefer_constructors_over_static_methods # far too many false positives + - prefer_contains + # - prefer_double_quotes # opposite of prefer_single_quotes + - prefer_equal_for_default_values + # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods + - prefer_final_fields + - prefer_final_in_for_each + - prefer_final_locals + # - prefer_final_parameters # we should enable this one day when it can be auto-fixed (https://github.com/dart-lang/linter/issues/3104), see also parameter_assignments + - prefer_for_elements_to_map_fromIterable + - prefer_foreach + - prefer_function_declarations_over_variables + - prefer_generic_function_type_aliases + - prefer_if_elements_to_conditional_expressions + - prefer_if_null_operators + - prefer_initializing_formals + - prefer_inlined_adds + # - prefer_int_literals # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#use-double-literals-for-double-constants + - prefer_interpolation_to_compose_strings + - prefer_is_empty + - prefer_is_not_empty + - prefer_is_not_operator + - prefer_iterable_whereType + # - prefer_mixin # Has false positives, see https://github.com/dart-lang/linter/issues/3018 + # - prefer_null_aware_method_calls # "call()" is confusing to people new to the language since it's not documented anywhere + - prefer_null_aware_operators + - prefer_relative_imports + - prefer_single_quotes + - prefer_spread_collections + - prefer_typing_uninitialized_variables + - prefer_void_to_null + - provide_deprecation_message + # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml + - recursive_getters + # - require_trailing_commas # blocked on https://github.com/dart-lang/sdk/issues/47441 + - secure_pubspec_urls + - sized_box_for_whitespace + # - sized_box_shrink_expand # not yet tested + - slash_for_doc_comments + - sort_child_properties_last + - sort_constructors_first + # - sort_pub_dependencies # prevents separating pinned transitive dependencies + - sort_unnamed_constructors_first + - test_types_in_equals + - throw_in_finally + - tighten_type_of_initializing_formals + # - type_annotate_public_apis # subset of always_specify_types + - type_init_formals + # - unawaited_futures # too many false positives, especially with the way AnimationController works + - unnecessary_await_in_return + - unnecessary_brace_in_string_interps + - unnecessary_const + - unnecessary_constructor_name + # - unnecessary_final # conflicts with prefer_final_locals + - unnecessary_getters_setters + # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 + - unnecessary_late + - unnecessary_new + - unnecessary_null_aware_assignments + - unnecessary_null_checks + - unnecessary_null_in_if_null_operators + - unnecessary_nullable_for_final_variable_declarations + - unnecessary_overrides + - unnecessary_parenthesis + # - unnecessary_raw_strings # what's "necessary" is a matter of opinion; consistency across strings can help readability more than this lint + - unnecessary_statements + - unnecessary_string_escapes + - unnecessary_string_interpolations + - unnecessary_this + - unrelated_type_equality_checks + - unsafe_html + - use_build_context_synchronously + # - use_colored_box # not yet tested + # - use_decorated_box # not yet tested + # - use_enums # not yet tested + - use_full_hex_values_for_flutter_colors + - use_function_type_syntax_for_parameters + - use_if_null_to_convert_nulls_to_bools + - use_is_even_rather_than_modulo + - use_key_in_widget_constructors + - use_late_for_private_fields_and_variables + - use_named_constants + - use_raw_strings + - use_rethrow_when_possible + - use_setters_to_change_properties + # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 + - use_super_parameters + - use_test_throws_matchers + # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review + - valid_regexps + - void_checks \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock index 6496a23..e1c56f8 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" boolean_selector: dependency: transitive description: @@ -141,7 +141,7 @@ packages: path: ".." relative: true source: path - version: "0.3.1" + version: "0.3.2" font_awesome_flutter: dependency: "direct main" description: diff --git a/lib/flutter_zxing.dart b/lib/flutter_zxing.dart index 1f9d131..243c782 100644 --- a/lib/flutter_zxing.dart +++ b/lib/flutter_zxing.dart @@ -13,11 +13,13 @@ import 'generated_bindings.dart'; import 'isolate_utils.dart'; export 'generated_bindings.dart'; -export 'reader_widget.dart'; -export 'writer_widget.dart'; export 'image_converter.dart'; +export 'reader_widget.dart'; export 'scanner_overlay.dart'; +export 'writer_widget.dart'; +// TODO: fix below warning from lint +// ignore: avoid_classes_with_only_static_members /// The main class for reading barcodes from images or camera. class FlutterZxing { static const MethodChannel _channel = MethodChannel('flutter_zxing'); @@ -27,7 +29,7 @@ class FlutterZxing { return version; } - static final bindings = GeneratedBindings(dylib); + static final GeneratedBindings bindings = GeneratedBindings(dylib); static IsolateUtils? isolateUtils; @@ -39,7 +41,7 @@ class FlutterZxing { static String version() => bindings.version().cast().toDartString(); /// Starts reading barcode from the camera - static Future startCameraProcessing() async { + static Future startCameraProcessing() async { // Spawn a new isolate isolateUtils = IsolateUtils(); await isolateUtils?.startReadingBarcode(); @@ -66,7 +68,7 @@ class FlutterZxing { int cropHeight = 0, }) async { final Uint8List imageBytes = await path.readAsBytes(); - imglib.Image? image = imglib.decodeImage(imageBytes); + final imglib.Image? image = imglib.decodeImage(imageBytes); if (image == null) { return null; } @@ -91,7 +93,7 @@ class FlutterZxing { (await NetworkAssetBundle(Uri.parse(url)).load(url)) .buffer .asUint8List(); - imglib.Image? image = imglib.decodeImage(imageBytes); + final imglib.Image? image = imglib.decodeImage(imageBytes); if (image == null) { return null; } @@ -113,9 +115,9 @@ class FlutterZxing { static List readBarcodes(Uint8List bytes, int format, int width, int height, int cropWidth, int cropHeight) { - final result = bindings.readBarcodes( + final CodeResults result = bindings.readBarcodes( bytes.allocatePointer(), format, width, height, cropWidth, cropHeight); - List results = []; + final List results = []; for (int i = 0; i < result.count; i++) { results.add(result.results.elementAt(i).ref); } @@ -124,24 +126,31 @@ class FlutterZxing { static EncodeResult encodeBarcode(String contents, int width, int height, int format, int margin, int eccLevel) { - var result = bindings.encodeBarcode(contents.toNativeUtf8().cast(), - width, height, format, margin, eccLevel); + final EncodeResult result = bindings.encodeBarcode( + contents.toNativeUtf8().cast(), + width, + height, + format, + margin, + eccLevel); return result; } static Future processCameraImage(CameraImage image, {int format = Format.Any, double cropPercent = 0.5}) async { - var isolateData = IsolateData(image, format, cropPercent); - CodeResult result = await _inference(isolateData); + final IsolateData isolateData = IsolateData(image, format, cropPercent); + final CodeResult result = await _inference(isolateData); return result; } /// Runs inference in another isolate static Future _inference(IsolateData isolateData) async { - ReceivePort responsePort = ReceivePort(); + final ReceivePort responsePort = ReceivePort(); isolateUtils?.sendPort ?.send(isolateData..responsePort = responsePort.sendPort); - var results = await responsePort.first; + // TODO: fix below warning from lint + // ignore: always_specify_types + final results = await responsePort.first; return results; } @@ -153,7 +162,7 @@ DynamicLibrary _openDynamicLibrary() { if (Platform.isAndroid) { return DynamicLibrary.open('libflutter_zxing.so'); } else if (Platform.isWindows) { - return DynamicLibrary.open("flutter_zxing_windows_plugin.dll"); + return DynamicLibrary.open('flutter_zxing_windows_plugin.dll'); } return DynamicLibrary.process(); } @@ -163,8 +172,8 @@ DynamicLibrary dylib = _openDynamicLibrary(); extension Uint8ListBlobConversion on Uint8List { /// Allocates a pointer filled with the Uint8List data. Pointer allocatePointer() { - final blob = calloc(length); - final blobBytes = blob.asTypedList(length); + final Pointer blob = calloc(length); + final Int8List blobBytes = blob.asTypedList(length); blobBytes.setAll(0, this); return blob.cast(); } @@ -189,7 +198,7 @@ extension EncodeExt on EncodeResult { extension CodeFormat on Format { String get name => _formatNames[this] ?? 'Unknown'; - static final writerFormats = [ + static final List writerFormats = [ Format.QRCode, Format.DataMatrix, Format.Aztec, @@ -209,7 +218,7 @@ extension CodeFormat on Format { ]; } -final _formatNames = { +final Map _formatNames = { Format.None: 'None', Format.Aztec: 'Aztec', Format.Codabar: 'CodaBar', diff --git a/lib/image_converter.dart b/lib/image_converter.dart index f1cb8ea..b879745 100644 --- a/lib/image_converter.dart +++ b/lib/image_converter.dart @@ -17,7 +17,7 @@ Future convertImage(CameraImage image) async { } return img.getBytes(format: imglib.Format.luminance); } catch (e) { - debugPrint(">>>>>>>>>>>> ERROR: $e"); + debugPrint('>>>>>>>>>>>> ERROR: $e'); } return Uint8List(0); } @@ -33,21 +33,25 @@ imglib.Image convertBGRA8888(CameraImage image) { // ignore: unused_element imglib.Image convertYUV420(CameraImage image) { - var img = imglib.Image(image.width, image.height); // Create Image buffer + final imglib.Image img = + imglib.Image(image.width, image.height); // Create Image buffer - Plane plane = image.planes[0]; - const int shift = (0xFF << 24); + final Plane plane = image.planes[0]; + const int shift = 0xFF << 24; // Fill image buffer with plane[0] from YUV420_888 for (int x = 0; x < image.width; x++) { for (int planeOffset = 0; planeOffset < image.height * image.width; planeOffset += image.width) { + // TODO: fix below warning from lint + // ignore: always_specify_types final pixelColor = plane.bytes[planeOffset + x]; // color: 0x FF FF FF FF // A B G R // Calculate pixel color - var newVal = shift | (pixelColor << 16) | (pixelColor << 8) | pixelColor; + final int newVal = + shift | (pixelColor << 16) | (pixelColor << 8) | pixelColor; img.data[planeOffset + x] = newVal; } diff --git a/lib/isolate_utils.dart b/lib/isolate_utils.dart index a23ca96..2f2b463 100644 --- a/lib/isolate_utils.dart +++ b/lib/isolate_utils.dart @@ -1,5 +1,6 @@ import 'dart:isolate'; import 'dart:math'; +import 'dart:typed_data'; import 'package:camera/camera.dart'; @@ -9,26 +10,25 @@ import 'flutter_zxing.dart'; /// Bundles data to pass between Isolate class IsolateData { - CameraImage cameraImage; - int format; - double cropPercent; - - SendPort? responsePort; - IsolateData( this.cameraImage, this.format, this.cropPercent, ); + CameraImage cameraImage; + int format; + double cropPercent; + + SendPort? responsePort; } /// Manages separate Isolate instance for inference class IsolateUtils { - static const String kDebugName = "ZxingIsolate"; + static const String kDebugName = 'ZxingIsolate'; // ignore: unused_field Isolate? _isolate; - final _receivePort = ReceivePort(); + final ReceivePort _receivePort = ReceivePort(); SendPort? _sendPort; SendPort? get sendPort => _sendPort; @@ -49,21 +49,26 @@ class IsolateUtils { _sendPort = null; } - static void readBarcodeEntryPoint(SendPort sendPort) async { - final port = ReceivePort(); + static Future readBarcodeEntryPoint(SendPort sendPort) async { + final ReceivePort port = ReceivePort(); sendPort.send(port.sendPort); await for (final IsolateData? isolateData in port) { if (isolateData != null) { try { - final image = isolateData.cameraImage; - final cropPercent = isolateData.cropPercent; - final bytes = await convertImage(image); - final cropSize = + final CameraImage image = isolateData.cameraImage; + final double cropPercent = isolateData.cropPercent; + final Uint8List bytes = await convertImage(image); + final int cropSize = (min(image.width, image.height) * cropPercent).round(); - final result = FlutterZxing.readBarcode(bytes, isolateData.format, - image.width, image.height, cropSize, cropSize); + final CodeResult result = FlutterZxing.readBarcode( + bytes, + isolateData.format, + image.width, + image.height, + cropSize, + cropSize); isolateData.responsePort?.send(result); } catch (e) { diff --git a/lib/reader_widget.dart b/lib/reader_widget.dart index 9b6e40c..3eaf854 100644 --- a/lib/reader_widget.dart +++ b/lib/reader_widget.dart @@ -12,7 +12,7 @@ import 'isolate_utils.dart'; class ReaderWidget extends StatefulWidget { const ReaderWidget({ - Key? key, + super.key, required this.onScan, this.onControllerCreated, this.codeFormat = Format.Any, @@ -24,7 +24,7 @@ class ReaderWidget extends StatefulWidget { this.scanDelay = const Duration(milliseconds: 1000), // 1000ms delay this.cropPercent = 0.5, // 50% of the screen this.resolution = ResolutionPreset.high, - }) : super(key: key); + }); final Function(CodeResult) onScan; final Function(CameraController?)? onControllerCreated; @@ -46,7 +46,7 @@ class _ReaderWidgetState extends State with TickerProviderStateMixin { List? cameras; CameraController? controller; - var _cameraOn = false; + bool _cameraOn = false; double _zoom = 1.0; double _scaleFactor = 1.0; @@ -68,11 +68,11 @@ class _ReaderWidgetState extends State initStateAsync(); } - void initStateAsync() async { + Future initStateAsync() async { // Spawn a new isolate await FlutterZxing.startCameraProcessing(); - availableCameras().then((cameras) { + availableCameras().then((List cameras) { setState(() { this.cameras = cameras; if (cameras.isNotEmpty) { @@ -81,7 +81,7 @@ class _ReaderWidgetState extends State }); }); - SystemChannels.lifecycle.setMessageHandler((message) async { + SystemChannels.lifecycle.setMessageHandler((String? message) async { debugPrint(message); final CameraController? cameraController = controller; if (cameraController == null || !cameraController.value.isInitialized) { @@ -110,7 +110,7 @@ class _ReaderWidgetState extends State super.dispose(); } - void onNewCameraSelected(CameraDescription cameraDescription) async { + Future onNewCameraSelected(CameraDescription cameraDescription) async { if (controller != null) { await controller!.dispose(); } @@ -137,7 +137,9 @@ class _ReaderWidgetState extends State } cameraController.addListener(() { - if (mounted) setState(() {}); + if (mounted) { + setState(() {}); + } }); if (mounted) { @@ -148,11 +150,11 @@ class _ReaderWidgetState extends State widget.onControllerCreated?.call(cameraController); } - processCameraImage(CameraImage image) async { + Future processCameraImage(CameraImage image) async { if (!_isProcessing) { _isProcessing = true; try { - CodeResult result = await FlutterZxing.processCameraImage( + final CodeResult result = await FlutterZxing.processCameraImage( image, format: widget.codeFormat, cropPercent: widget.cropPercent, @@ -163,28 +165,30 @@ class _ReaderWidgetState extends State } widget.onScan(result); setState(() {}); - await Future.delayed(const Duration(seconds: 1)); + await Future.delayed(const Duration(seconds: 1)); } } on FileSystemException catch (e) { debugPrint(e.message); } catch (e) { debugPrint(e.toString()); } - await Future.delayed(widget.scanDelay); + await Future.delayed(widget.scanDelay); _isProcessing = false; } - return null; + return; } @override Widget build(BuildContext context) { - final size = MediaQuery.of(context).size; - final cropSize = min(size.width, size.height) * widget.cropPercent; + final Size size = MediaQuery.of(context).size; + final double cropSize = min(size.width, size.height) * widget.cropPercent; return Stack( - children: [ + children: [ // Camera preview - Center(child: _cameraPreviewWidget(cropSize)), + Center( + child: _cameraPreviewWidget(cropSize), + ), ], ); } @@ -192,23 +196,22 @@ class _ReaderWidgetState extends State // Display the preview from the camera. Widget _cameraPreviewWidget(double cropSize) { final CameraController? cameraController = controller; - if (cameras != null && cameras?.isEmpty == true) { + if (cameras != null && (cameras?.isEmpty ?? false)) { return const Text('No cameras found'); } else if (cameraController == null || !cameraController.value.isInitialized || !_cameraOn) { return const CircularProgressIndicator(); } else { - final size = MediaQuery.of(context).size; - var cameraMaxSize = max(size.width, size.height); + final Size size = MediaQuery.of(context).size; + final double cameraMaxSize = max(size.width, size.height); return Stack( - children: [ + children: [ SizedBox( width: cameraMaxSize, height: cameraMaxSize, child: ClipRRect( child: OverflowBox( - alignment: Alignment.center, child: FittedBox( fit: BoxFit.cover, child: SizedBox( @@ -237,10 +240,10 @@ class _ReaderWidgetState extends State ), if (widget.allowPinchZoom) GestureDetector( - onScaleStart: (details) { + onScaleStart: (ScaleStartDetails details) { _zoom = _scaleFactor; }, - onScaleUpdate: (details) { + onScaleUpdate: (ScaleUpdateDetails details) { _scaleFactor = (_zoom * details.scale).clamp(_minZoomLevel, _maxZoomLevel); cameraController.setZoomLevel(_scaleFactor); @@ -253,14 +256,10 @@ class _ReaderWidgetState extends State child: FloatingActionButton( onPressed: () { FlashMode mode = cameraController.value.flashMode; - switch (mode) { - case FlashMode.torch: - mode = FlashMode.off; - break; - case FlashMode.off: - mode = FlashMode.torch; - break; - default: + if (mode == FlashMode.torch) { + mode = FlashMode.off; + } else { + mode = FlashMode.torch; } cameraController.setFlashMode(mode); setState(() {}); @@ -281,8 +280,10 @@ class _ReaderWidgetState extends State return Icons.flash_on; case FlashMode.off: return Icons.flash_off; - default: - return Icons.flash_off; + case FlashMode.always: + return Icons.flash_on; + case FlashMode.auto: + return Icons.flash_auto; } } } diff --git a/lib/scanner_overlay.dart b/lib/scanner_overlay.dart index 7909024..dc7869d 100644 --- a/lib/scanner_overlay.dart +++ b/lib/scanner_overlay.dart @@ -54,31 +54,32 @@ class ScannerOverlay extends ShapeBorder { @override void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) { - final width = rect.width; - final borderWidthSize = width / 2; - final height = rect.height; - final borderOffset = borderWidth / 2; - final newBorderLength = borderLength > cutOutSize / 2 + borderWidth * 2 - ? borderWidthSize / 2 - : borderLength; - final newCutOutSize = + final double width = rect.width; + final double borderWidthSize = width / 2; + final double height = rect.height; + final double borderOffset = borderWidth / 2; + final double newBorderLength = + borderLength > cutOutSize / 2 + borderWidth * 2 + ? borderWidthSize / 2 + : borderLength; + final double newCutOutSize = cutOutSize < width ? cutOutSize : width - borderOffset; - final backgroundPaint = Paint() + final Paint backgroundPaint = Paint() ..color = overlayColor ..style = PaintingStyle.fill; - final borderPaint = Paint() + final Paint borderPaint = Paint() ..color = borderColor ..style = PaintingStyle.stroke ..strokeWidth = borderWidth; - final boxPaint = Paint() + final Paint boxPaint = Paint() ..color = borderColor ..style = PaintingStyle.fill ..blendMode = BlendMode.dstOut; - final cutOutRect = Rect.fromLTWH( + final Rect cutOutRect = Rect.fromLTWH( rect.left + width / 2 - newCutOutSize / 2 + borderOffset, rect.top + height / 2 - newCutOutSize / 2 + borderOffset, newCutOutSize - borderOffset * 2, diff --git a/lib/writer_widget.dart b/lib/writer_widget.dart index dc6fd24..e02dcab 100644 --- a/lib/writer_widget.dart +++ b/lib/writer_widget.dart @@ -7,10 +7,10 @@ import 'flutter_zxing.dart'; class WriterWidget extends StatefulWidget { const WriterWidget({ - Key? key, + super.key, this.onSuccess, this.onError, - }) : super(key: key); + }); final Function(EncodeResult, Uint8List?)? onSuccess; final Function(String)? onError; @@ -24,18 +24,18 @@ class _WriterWidgetState extends State final GlobalKey _formKey = GlobalKey(); final TextEditingController _textController = TextEditingController(); final TextEditingController _widthController = - TextEditingController(text: "300"); + TextEditingController(text: '300'); final TextEditingController _heightController = - TextEditingController(text: "300"); + TextEditingController(text: '300'); final TextEditingController _marginController = - TextEditingController(text: "10"); - final TextEditingController _eccController = TextEditingController(text: "0"); + TextEditingController(text: '10'); + final TextEditingController _eccController = TextEditingController(text: '0'); bool isAndroid() => Theme.of(context).platform == TargetPlatform.android; - final _maxTextLength = 2000; - final _supportedFormats = CodeFormat.writerFormats; - var _codeFormat = Format.QRCode; + final int _maxTextLength = 2000; + final List _supportedFormats = CodeFormat.writerFormats; + int _codeFormat = Format.QRCode; @override Widget build(BuildContext context) { @@ -47,7 +47,7 @@ class _WriterWidgetState extends State child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ + children: [ const SizedBox(height: 20), // Input multiline text TextFormField( @@ -55,7 +55,7 @@ class _WriterWidgetState extends State keyboardType: TextInputType.multiline, maxLines: null, maxLength: _maxTextLength, - onChanged: (value) { + onChanged: (String value) { setState(() {}); }, decoration: InputDecoration( @@ -65,8 +65,8 @@ class _WriterWidgetState extends State counterText: '${_textController.value.text.length} / $_maxTextLength', ), - validator: (value) { - if (value?.isEmpty == true) { + validator: (String? value) { + if (value?.isEmpty ?? false) { return 'Please enter some text'; } return null; @@ -77,12 +77,12 @@ class _WriterWidgetState extends State DropdownButtonFormField( value: _codeFormat, items: _supportedFormats - .map((format) => DropdownMenuItem( + .map((int format) => DropdownMenuItem( value: format, child: Text(FlutterZxing.formatName(format)), )) .toList(), - onChanged: (format) { + onChanged: (int? format) { setState(() { _codeFormat = format ?? Format.QRCode; }); @@ -90,7 +90,7 @@ class _WriterWidgetState extends State ), const SizedBox(height: 20), Row( - children: [ + children: [ Flexible( child: TextFormField( controller: _widthController, @@ -98,8 +98,8 @@ class _WriterWidgetState extends State decoration: const InputDecoration( labelText: 'Width', ), - validator: (value) { - final width = int.tryParse(value ?? ''); + validator: (String? value) { + final int? width = int.tryParse(value ?? ''); if (width == null) { return 'Invalid number'; } @@ -115,8 +115,8 @@ class _WriterWidgetState extends State decoration: const InputDecoration( labelText: 'Height', ), - validator: (value) { - final width = int.tryParse(value ?? ''); + validator: (String? value) { + final int? width = int.tryParse(value ?? ''); if (width == null) { return 'Invalid number'; } @@ -128,7 +128,7 @@ class _WriterWidgetState extends State ), const SizedBox(height: 20), Row( - children: [ + children: [ Flexible( child: TextFormField( controller: _marginController, @@ -136,8 +136,8 @@ class _WriterWidgetState extends State decoration: const InputDecoration( labelText: 'Margin', ), - validator: (value) { - final width = int.tryParse(value ?? ''); + validator: (String? value) { + final int? width = int.tryParse(value ?? ''); if (width == null) { return 'Invalid number'; } @@ -153,8 +153,8 @@ class _WriterWidgetState extends State decoration: const InputDecoration( labelText: 'ECC Level', ), - validator: (value) { - final width = int.tryParse(value ?? ''); + validator: (String? value) { + final int? width = int.tryParse(value ?? ''); if (width == null) { return 'Invalid number'; } @@ -182,18 +182,24 @@ class _WriterWidgetState extends State if (_formKey.currentState?.validate() ?? false) { _formKey.currentState?.save(); FocusScope.of(context).unfocus(); - final text = _textController.value.text; - final width = int.parse(_widthController.value.text); - final height = int.parse(_heightController.value.text); - final margin = int.parse(_marginController.value.text); - final ecc = int.parse(_eccController.value.text); - var result = FlutterZxing.encodeBarcode( + final String text = _textController.value.text; + final int width = int.parse(_widthController.value.text); + final int height = int.parse(_heightController.value.text); + final int margin = int.parse(_marginController.value.text); + final int ecc = int.parse(_eccController.value.text); + final EncodeResult result = FlutterZxing.encodeBarcode( text, width, height, _codeFormat, margin, ecc); String? error; if (result.isValidBool) { try { - final img = imglib.Image.fromBytes(width, height, result.bytes); - final encodedBytes = Uint8List.fromList(imglib.encodeJpg(img)); + final imglib.Image img = imglib.Image.fromBytes( + width, + height, + result.bytes, + ); + final Uint8List encodedBytes = Uint8List.fromList( + imglib.encodeJpg(img), + ); widget.onSuccess?.call(result, encodedBytes); } catch (e) { error = e.toString(); diff --git a/zxscanner/pubspec.lock b/zxscanner/pubspec.lock index e75dcfa..848613a 100644 --- a/zxscanner/pubspec.lock +++ b/zxscanner/pubspec.lock @@ -35,7 +35,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" boolean_selector: dependency: transitive description: @@ -300,7 +300,7 @@ packages: path: ".." relative: true source: path - version: "0.3.1" + version: "0.3.2" font_awesome_flutter: dependency: "direct main" description: