| @@ -22,4 +22,4 @@ jobs: | |||||
| - name: Format | - name: Format | ||||
| run: dartfmt -n --set-exit-if-changed . | run: dartfmt -n --set-exit-if-changed . | ||||
| - name: Linter | - name: Linter | ||||
| run: dartanalyzer . --fatal-hints | |||||
| run: dartanalyzer . --options=analysis_options.yaml --fatal-hints | |||||
| @@ -0,0 +1,106 @@ | |||||
| include: package:pedantic/analysis_options.1.9.0.yaml | |||||
| linter: | |||||
| rules: | |||||
| - always_put_required_named_parameters_first | |||||
| - always_require_non_null_named_parameters | |||||
| - avoid_annotating_with_dynamic | |||||
| - avoid_bool_literals_in_conditional_expressions | |||||
| - avoid_catching_errors | |||||
| - avoid_classes_with_only_static_members | |||||
| - avoid_empty_else | |||||
| - avoid_init_to_null | |||||
| - avoid_null_checks_in_equality_operators | |||||
| - avoid_print | |||||
| - avoid_relative_lib_imports | |||||
| - avoid_return_types_on_setters | |||||
| - avoid_returning_null | |||||
| - avoid_returning_null_for_future | |||||
| - avoid_returning_null_for_void | |||||
| - avoid_shadowing_type_parameters | |||||
| - avoid_single_cascade_in_expression_statements | |||||
| - avoid_types_as_parameter_names | |||||
| - avoid_types_on_closure_parameters | |||||
| - avoid_void_async | |||||
| - await_only_futures | |||||
| - camel_case_types | |||||
| - cancel_subscriptions | |||||
| - cascade_invocations | |||||
| - close_sinks | |||||
| - comment_references | |||||
| - constant_identifier_names | |||||
| - control_flow_in_finally | |||||
| - curly_braces_in_flow_control_structures | |||||
| - directives_ordering | |||||
| - empty_catches | |||||
| - empty_constructor_bodies | |||||
| - empty_statements | |||||
| - file_names | |||||
| - hash_and_equals | |||||
| - implementation_imports | |||||
| - invariant_booleans | |||||
| - iterable_contains_unrelated_type | |||||
| - join_return_with_assignment | |||||
| - library_names | |||||
| - library_prefixes | |||||
| - list_remove_unrelated_type | |||||
| - no_duplicate_case_values | |||||
| - non_constant_identifier_names | |||||
| - null_closures | |||||
| - only_throw_errors | |||||
| - overridden_fields | |||||
| - package_api_docs | |||||
| - package_names | |||||
| - package_prefixed_library_names | |||||
| - prefer_collection_literals | |||||
| - prefer_conditional_assignment | |||||
| - prefer_const_declarations | |||||
| - prefer_contains | |||||
| - prefer_equal_for_default_values | |||||
| - prefer_final_fields | |||||
| - prefer_for_elements_to_map_fromIterable | |||||
| - prefer_foreach | |||||
| - prefer_function_declarations_over_variables | |||||
| - prefer_if_elements_to_conditional_expressions | |||||
| - prefer_if_null_operators | |||||
| - prefer_initializing_formals | |||||
| - prefer_inlined_adds | |||||
| - prefer_int_literals | |||||
| - prefer_interpolation_to_compose_strings | |||||
| - prefer_is_empty | |||||
| - prefer_is_not_empty | |||||
| - prefer_iterable_whereType | |||||
| - prefer_null_aware_operators | |||||
| - prefer_void_to_null | |||||
| - provide_deprecation_message | |||||
| - recursive_getters | |||||
| - slash_for_doc_comments | |||||
| - sort_child_properties_last | |||||
| - sort_constructors_first | |||||
| - sort_pub_dependencies | |||||
| - sort_unnamed_constructors_first | |||||
| - test_types_in_equals | |||||
| - throw_in_finally | |||||
| - type_init_formals | |||||
| - unawaited_futures | |||||
| - unnecessary_await_in_return | |||||
| - unnecessary_brace_in_string_interps | |||||
| - unnecessary_const | |||||
| - unnecessary_getters_setters | |||||
| - unnecessary_lambdas | |||||
| - unnecessary_new | |||||
| - unnecessary_null_aware_assignments | |||||
| - unnecessary_null_in_if_null_operators | |||||
| - unnecessary_overrides | |||||
| - unnecessary_parenthesis | |||||
| - unnecessary_statements | |||||
| - unnecessary_this | |||||
| - unrelated_type_equality_checks | |||||
| - unsafe_html | |||||
| - use_full_hex_values_for_flutter_colors | |||||
| - use_function_type_syntax_for_parameters | |||||
| - use_rethrow_when_possible | |||||
| - use_setters_to_change_properties | |||||
| - use_string_buffers | |||||
| - use_to_and_as_if_applicable | |||||
| - valid_regexps | |||||
| - void_checks | |||||
| @@ -3,10 +3,10 @@ import 'package:qr_code_scanner/qr_code_scanner.dart'; | |||||
| void main() => runApp(MaterialApp(home: QRViewExample())); | void main() => runApp(MaterialApp(home: QRViewExample())); | ||||
| const flash_on = "FLASH ON"; | |||||
| const flash_off = "FLASH OFF"; | |||||
| const front_camera = "FRONT CAMERA"; | |||||
| const back_camera = "BACK CAMERA"; | |||||
| const flashOn = 'FLASH ON'; | |||||
| const flashOff = 'FLASH OFF'; | |||||
| const frontCamera = 'FRONT CAMERA'; | |||||
| const backCamera = 'BACK CAMERA'; | |||||
| class QRViewExample extends StatefulWidget { | class QRViewExample extends StatefulWidget { | ||||
| const QRViewExample({ | const QRViewExample({ | ||||
| @@ -18,9 +18,9 @@ class QRViewExample extends StatefulWidget { | |||||
| } | } | ||||
| class _QRViewExampleState extends State<QRViewExample> { | class _QRViewExampleState extends State<QRViewExample> { | ||||
| var qrText = ""; | |||||
| var flashState = flash_on; | |||||
| var cameraState = front_camera; | |||||
| var qrText = ''; | |||||
| var flashState = flashOn; | |||||
| var cameraState = frontCamera; | |||||
| QRViewController controller; | QRViewController controller; | ||||
| final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | ||||
| @@ -30,6 +30,7 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| body: Column( | body: Column( | ||||
| children: <Widget>[ | children: <Widget>[ | ||||
| Expanded( | Expanded( | ||||
| flex: 4, | |||||
| child: QRView( | child: QRView( | ||||
| key: qrKey, | key: qrKey, | ||||
| onQRViewCreated: _onQRViewCreated, | onQRViewCreated: _onQRViewCreated, | ||||
| @@ -41,32 +42,32 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| cutOutSize: 300, | cutOutSize: 300, | ||||
| ), | ), | ||||
| ), | ), | ||||
| flex: 4, | |||||
| ), | ), | ||||
| Expanded( | Expanded( | ||||
| flex: 1, | |||||
| child: FittedBox( | child: FittedBox( | ||||
| fit: BoxFit.contain, | fit: BoxFit.contain, | ||||
| child: Column( | child: Column( | ||||
| mainAxisAlignment: MainAxisAlignment.spaceEvenly, | mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||||
| children: <Widget>[ | children: <Widget>[ | ||||
| Text("This is the result of scan: $qrText"), | |||||
| Text('This is the result of scan: $qrText'), | |||||
| Row( | Row( | ||||
| mainAxisAlignment: MainAxisAlignment.center, | mainAxisAlignment: MainAxisAlignment.center, | ||||
| crossAxisAlignment: CrossAxisAlignment.center, | crossAxisAlignment: CrossAxisAlignment.center, | ||||
| children: <Widget>[ | children: <Widget>[ | ||||
| Container( | Container( | ||||
| margin: EdgeInsets.all(8.0), | |||||
| margin: EdgeInsets.all(8), | |||||
| child: RaisedButton( | child: RaisedButton( | ||||
| onPressed: () { | onPressed: () { | ||||
| if (controller != null) { | if (controller != null) { | ||||
| controller.toggleFlash(); | controller.toggleFlash(); | ||||
| if (_isFlashOn(flashState)) { | if (_isFlashOn(flashState)) { | ||||
| setState(() { | setState(() { | ||||
| flashState = flash_off; | |||||
| flashState = flashOff; | |||||
| }); | }); | ||||
| } else { | } else { | ||||
| setState(() { | setState(() { | ||||
| flashState = flash_on; | |||||
| flashState = flashOn; | |||||
| }); | }); | ||||
| } | } | ||||
| } | } | ||||
| @@ -76,18 +77,18 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| ), | ), | ||||
| ), | ), | ||||
| Container( | Container( | ||||
| margin: EdgeInsets.all(8.0), | |||||
| margin: EdgeInsets.all(8), | |||||
| child: RaisedButton( | child: RaisedButton( | ||||
| onPressed: () { | onPressed: () { | ||||
| if (controller != null) { | if (controller != null) { | ||||
| controller.flipCamera(); | controller.flipCamera(); | ||||
| if (_isBackCamera(cameraState)) { | if (_isBackCamera(cameraState)) { | ||||
| setState(() { | setState(() { | ||||
| cameraState = front_camera; | |||||
| cameraState = frontCamera; | |||||
| }); | }); | ||||
| } else { | } else { | ||||
| setState(() { | setState(() { | ||||
| cameraState = back_camera; | |||||
| cameraState = backCamera; | |||||
| }); | }); | ||||
| } | } | ||||
| } | } | ||||
| @@ -103,7 +104,7 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| crossAxisAlignment: CrossAxisAlignment.center, | crossAxisAlignment: CrossAxisAlignment.center, | ||||
| children: <Widget>[ | children: <Widget>[ | ||||
| Container( | Container( | ||||
| margin: EdgeInsets.all(8.0), | |||||
| margin: EdgeInsets.all(8), | |||||
| child: RaisedButton( | child: RaisedButton( | ||||
| onPressed: () { | onPressed: () { | ||||
| controller?.pauseCamera(); | controller?.pauseCamera(); | ||||
| @@ -112,7 +113,7 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| ), | ), | ||||
| ), | ), | ||||
| Container( | Container( | ||||
| margin: EdgeInsets.all(8.0), | |||||
| margin: EdgeInsets.all(8), | |||||
| child: RaisedButton( | child: RaisedButton( | ||||
| onPressed: () { | onPressed: () { | ||||
| controller?.resumeCamera(); | controller?.resumeCamera(); | ||||
| @@ -125,19 +126,18 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| ], | ], | ||||
| ), | ), | ||||
| ), | ), | ||||
| flex: 1, | |||||
| ) | ) | ||||
| ], | ], | ||||
| ), | ), | ||||
| ); | ); | ||||
| } | } | ||||
| _isFlashOn(String current) { | |||||
| return flash_on == current; | |||||
| bool _isFlashOn(String current) { | |||||
| return flashOn == current; | |||||
| } | } | ||||
| _isBackCamera(String current) { | |||||
| return back_camera == current; | |||||
| bool _isBackCamera(String current) { | |||||
| return backCamera == current; | |||||
| } | } | ||||
| void _onQRViewCreated(QRViewController controller) { | void _onQRViewCreated(QRViewController controller) { | ||||
| @@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | import 'package:flutter/services.dart'; | ||||
| typedef void QRViewCreatedCallback(QRViewController controller); | |||||
| typedef QRViewCreatedCallback = void Function(QRViewController); | |||||
| class QRView extends StatefulWidget { | class QRView extends StatefulWidget { | ||||
| const QRView({ | const QRView({ | ||||
| @@ -29,13 +29,14 @@ class _QRViewState extends State<QRView> { | |||||
| return Stack( | return Stack( | ||||
| children: [ | children: [ | ||||
| _getPlatformQrView(), | _getPlatformQrView(), | ||||
| widget.overlay != null | |||||
| ? Container( | |||||
| decoration: ShapeDecoration( | |||||
| shape: widget.overlay, | |||||
| ), | |||||
| ) | |||||
| : Container(), | |||||
| if (widget.overlay != null) | |||||
| Container( | |||||
| decoration: ShapeDecoration( | |||||
| shape: widget.overlay, | |||||
| ), | |||||
| ) | |||||
| else | |||||
| Container(), | |||||
| ], | ], | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -94,23 +95,15 @@ class _CreationParams { | |||||
| } | } | ||||
| class QRViewController { | class QRViewController { | ||||
| static const scanMethodCall = "onRecognizeQR"; | |||||
| final MethodChannel _channel; | |||||
| StreamController<String> _scanUpdateController = StreamController<String>(); | |||||
| Stream<String> get scannedDataStream => _scanUpdateController.stream; | |||||
| QRViewController._(int id, GlobalKey qrKey) | QRViewController._(int id, GlobalKey qrKey) | ||||
| : _channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id') { | : _channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id') { | ||||
| if (defaultTargetPlatform == TargetPlatform.iOS) { | if (defaultTargetPlatform == TargetPlatform.iOS) { | ||||
| final RenderBox renderBox = qrKey.currentContext.findRenderObject(); | final RenderBox renderBox = qrKey.currentContext.findRenderObject(); | ||||
| _channel.invokeMethod("setDimensions", | |||||
| {"width": renderBox.size.width, "height": renderBox.size.height}); | |||||
| _channel.invokeMethod('setDimensions', | |||||
| {'width': renderBox.size.width, 'height': renderBox.size.height}); | |||||
| } | } | ||||
| _channel.setMethodCallHandler( | _channel.setMethodCallHandler( | ||||
| (MethodCall call) async { | |||||
| (call) async { | |||||
| switch (call.method) { | switch (call.method) { | ||||
| case scanMethodCall: | case scanMethodCall: | ||||
| if (call.arguments != null) { | if (call.arguments != null) { | ||||
| @@ -121,20 +114,29 @@ class QRViewController { | |||||
| ); | ); | ||||
| } | } | ||||
| static const scanMethodCall = 'onRecognizeQR'; | |||||
| final MethodChannel _channel; | |||||
| final StreamController<String> _scanUpdateController = | |||||
| StreamController<String>(); | |||||
| Stream<String> get scannedDataStream => _scanUpdateController.stream; | |||||
| void flipCamera() { | void flipCamera() { | ||||
| _channel.invokeMethod("flipCamera"); | |||||
| _channel.invokeMethod('flipCamera'); | |||||
| } | } | ||||
| void toggleFlash() { | void toggleFlash() { | ||||
| _channel.invokeMethod("toggleFlash"); | |||||
| _channel.invokeMethod('toggleFlash'); | |||||
| } | } | ||||
| void pauseCamera() { | void pauseCamera() { | ||||
| _channel.invokeMethod("pauseCamera"); | |||||
| _channel.invokeMethod('pauseCamera'); | |||||
| } | } | ||||
| void resumeCamera() { | void resumeCamera() { | ||||
| _channel.invokeMethod("resumeCamera"); | |||||
| _channel.invokeMethod('resumeCamera'); | |||||
| } | } | ||||
| void dispose() { | void dispose() { | ||||
| @@ -3,13 +3,6 @@ import 'dart:ui'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| class QrScannerOverlayShape extends ShapeBorder { | class QrScannerOverlayShape extends ShapeBorder { | ||||
| final Color borderColor; | |||||
| final double borderWidth; | |||||
| final Color overlayColor; | |||||
| final double borderRadius; | |||||
| final double borderLength; | |||||
| final double cutOutSize; | |||||
| QrScannerOverlayShape({ | QrScannerOverlayShape({ | ||||
| this.borderColor = Colors.red, | this.borderColor = Colors.red, | ||||
| this.borderWidth = 3.0, | this.borderWidth = 3.0, | ||||
| @@ -18,15 +11,20 @@ class QrScannerOverlayShape extends ShapeBorder { | |||||
| this.borderLength = 40, | this.borderLength = 40, | ||||
| this.cutOutSize = 250, | this.cutOutSize = 250, | ||||
| }) : assert( | }) : assert( | ||||
| cutOutSize != null | |||||
| ? cutOutSize != null | |||||
| ? borderLength <= cutOutSize / 2 + borderWidth * 2 | |||||
| : true | |||||
| : true, | |||||
| cutOutSize != null ?? | |||||
| cutOutSize != null ?? | |||||
| borderLength <= cutOutSize / 2 + borderWidth * 2, | |||||
| "Border can't be larger than ${cutOutSize / 2 + borderWidth * 2}"); | "Border can't be larger than ${cutOutSize / 2 + borderWidth * 2}"); | ||||
| final Color borderColor; | |||||
| final double borderWidth; | |||||
| final Color overlayColor; | |||||
| final double borderRadius; | |||||
| final double borderLength; | |||||
| final double cutOutSize; | |||||
| @override | @override | ||||
| EdgeInsetsGeometry get dimensions => const EdgeInsets.all(10.0); | |||||
| EdgeInsetsGeometry get dimensions => const EdgeInsets.all(10); | |||||
| @override | @override | ||||
| Path getInnerPath(Rect rect, {TextDirection textDirection}) { | Path getInnerPath(Rect rect, {TextDirection textDirection}) { | ||||
| @@ -93,12 +91,11 @@ class QrScannerOverlayShape extends ShapeBorder { | |||||
| _cutOutSize - borderOffset * 2, | _cutOutSize - borderOffset * 2, | ||||
| ); | ); | ||||
| canvas.saveLayer( | |||||
| rect, | |||||
| backgroundPaint, | |||||
| ); | |||||
| canvas | canvas | ||||
| ..saveLayer( | |||||
| rect, | |||||
| backgroundPaint, | |||||
| ) | |||||
| ..drawRect( | ..drawRect( | ||||
| rect, | rect, | ||||
| backgroundPaint, | backgroundPaint, | ||||
| @@ -6,12 +6,15 @@ homepage: https://juliuscanute.com | |||||
| repository: https://github.com/juliuscanute/qr_code_scanner | repository: https://github.com/juliuscanute/qr_code_scanner | ||||
| environment: | environment: | ||||
| sdk: ">=2.0.0-dev.68.0 <3.0.0" | |||||
| sdk: ">=2.3.0 <3.0.0" | |||||
| dependencies: | dependencies: | ||||
| flutter: | flutter: | ||||
| sdk: flutter | sdk: flutter | ||||
| dev_dependencies: | |||||
| pedantic: ^1.9.0 | |||||
| flutter: | flutter: | ||||
| plugin: | plugin: | ||||
| androidPackage: net.touchcapture.qr.flutterqr | androidPackage: net.touchcapture.qr.flutterqr | ||||