浏览代码

Merge pull request #290 from juliuscanute/stable-null-safety

stable version of null-safety
flutter-beta
Julian Steenbakker 5 年前
committed by GitHub
父节点
当前提交
06e326e408
找不到此签名对应的密钥 GPG 密钥 ID: 4AEE18F83AFDEB23
共有 12 个文件被更改,包括 96 次插入255 次删除
  1. +13
    -15
      .github/workflows/dart.yml
  2. +1
    -107
      analysis_options.yaml
  3. +6
    -10
      example/lib/main.dart
  4. +2
    -5
      example/pubspec.yaml
  5. +3
    -11
      lib/src/lifecycle_event_handler.dart
  6. +52
    -55
      lib/src/qr_code_scanner.dart
  7. +5
    -10
      lib/src/qr_scanner_overlay_shape.dart
  8. +1
    -1
      lib/src/types/barcode.dart
  9. +6
    -37
      lib/src/types/barcode_format.dart
  10. +4
    -1
      lib/src/types/camera.dart
  11. +1
    -1
      lib/src/types/camera_exception.dart
  12. +2
    -2
      pubspec.yaml

+ 13
- 15
.github/workflows/dart.yml 查看文件

@@ -8,18 +8,16 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
java-version: '12.x'
- uses: subosito/flutter-action@v1
with:
channel: 'stable'
- name: Version
run: flutter doctor -v
- name: Install dependencies
run: flutter pub get
- name: Format
run: dartfmt -n --set-exit-if-changed .
- name: Linter
run: dartanalyzer . --options=analysis_options.yaml --fatal-hints
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: '12.x'
- uses: subosito/flutter-action@v1
- name: Version
run: flutter doctor -v
- name: Install dependencies
run: flutter pub get
- name: Format
run: flutter format -n --set-exit-if-changed .
- name: Linter
run: flutter analyze

+ 1
- 107
analysis_options.yaml 查看文件

@@ -1,107 +1 @@
include: package:pedantic/analysis_options.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
include: package:pedantic/analysis_options.yaml

+ 6
- 10
example/lib/main.dart 查看文件

@@ -7,17 +7,13 @@ import 'package:qr_code_scanner/qr_code_scanner.dart';
void main() => runApp(MaterialApp(home: QRViewExample()));

class QRViewExample extends StatefulWidget {
const QRViewExample({
Key key,
}) : super(key: key);

@override
State<StatefulWidget> createState() => _QRViewExampleState();
}

class _QRViewExampleState extends State<QRViewExample> {
Barcode result;
QRViewController controller;
Barcode? result;
QRViewController? controller;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');

// In order to get hot reload to work we need to pause the camera if the platform
@@ -26,9 +22,9 @@ class _QRViewExampleState extends State<QRViewExample> {
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
controller.pauseCamera();
controller!.pauseCamera();
}
controller.resumeCamera();
controller!.resumeCamera();
}

@override
@@ -46,7 +42,7 @@ class _QRViewExampleState extends State<QRViewExample> {
children: <Widget>[
if (result != null)
Text(
'Barcode Type: ${describeEnum(result.format)} Data: ${result.code}')
'Barcode Type: ${describeEnum(result!.format)} Data: ${result!.code}')
else
Text('Scan a code'),
Row(
@@ -79,7 +75,7 @@ class _QRViewExampleState extends State<QRViewExample> {
builder: (context, snapshot) {
if (snapshot.data != null) {
return Text(
'Camera facing ${describeEnum(snapshot.data)}');
'Camera facing ${describeEnum(snapshot.data!)}');
} else {
return Text('loading');
}


+ 2
- 5
example/pubspec.yaml 查看文件

@@ -3,17 +3,14 @@ description: Demonstrates how to use the flutter_qr plugin.
publish_to: 'none'

environment:
sdk: ">=2.6.0 <3.0.0"
sdk: '>=2.12.0 <3.0.0'

dependencies:
flutter:
sdk: flutter

# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2

dev_dependencies:
pedantic: ^1.11.0
flutter_test:
sdk: flutter



+ 3
- 11
lib/src/lifecycle_event_handler.dart 查看文件

@@ -3,28 +3,20 @@ import 'package:flutter/foundation.dart';

class LifecycleEventHandler extends WidgetsBindingObserver {
LifecycleEventHandler({
this.resumeCallBack,
this.suspendingCallBack,
required this.resumeCallBack,
});

final AsyncCallback resumeCallBack;
final AsyncCallback suspendingCallBack;
late final AsyncCallback resumeCallBack;

@override
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
switch (state) {
case AppLifecycleState.resumed:
if (resumeCallBack != null) {
await resumeCallBack();
}
await resumeCallBack();
break;
case AppLifecycleState.inactive:
case AppLifecycleState.paused:
case AppLifecycleState.detached:
if (suspendingCallBack != null) {
await suspendingCallBack();
}
break;
}
}
}

+ 52
- 55
lib/src/qr_code_scanner.dart 查看文件

@@ -20,23 +20,21 @@ typedef PermissionSetCallback = void Function(QRViewController, bool);
/// and the barcode scanner gets displayed.
class QRView extends StatefulWidget {
const QRView({
@required Key key,
@required this.onQRViewCreated,
required Key key,
required this.onQRViewCreated,
this.overlay,
this.overlayMargin = EdgeInsets.zero,
this.cameraFacing = CameraFacing.back,
this.onPermissionSet,
this.formatsAllowed,
}) : assert(key != null),
assert(onQRViewCreated != null),
super(key: key);
this.formatsAllowed = const <BarcodeFormat>[],
}) : super(key: key);

/// [onQRViewCreated] gets called when the view is created
final QRViewCreatedCallback onQRViewCreated;

/// Use [overlay] to provide an overlay for the view.
/// This can be used to create a certain scan area.
final QrScannerOverlayShape overlay;
final QrScannerOverlayShape? overlay;

/// Use [overlayMargin] to provide a margin to [overlay]
final EdgeInsetsGeometry overlayMargin;
@@ -48,7 +46,7 @@ class QRView extends StatefulWidget {
final CameraFacing cameraFacing;

/// Calls the provided [onPermissionSet] callback when the permission is set.
final PermissionSetCallback onPermissionSet;
final PermissionSetCallback? onPermissionSet;

/// Use [formatsAllowed] to specify which formats needs to be scanned.
final List<BarcodeFormat> formatsAllowed;
@@ -58,21 +56,14 @@ class QRView extends StatefulWidget {
}

class _QRViewState extends State<QRView> {
var _channel;
var _observer;
late MethodChannel _channel;
late LifecycleEventHandler _observer;

@override
void initState() {
super.initState();
_observer = LifecycleEventHandler(
resumeCallBack: () async => {
if (_channel != null)
{
QRViewController.updateDimensions(widget.key, _channel,
overlay: widget.overlay)
}
});
WidgetsBinding.instance.addObserver(_observer);
_observer = LifecycleEventHandler(resumeCallBack: updateDimensions);
WidgetsBinding.instance!.addObserver(_observer);
}

@override
@@ -90,15 +81,17 @@ class _QRViewState extends State<QRView> {
@override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(_observer);
WidgetsBinding.instance!.removeObserver(_observer);
}

bool onNotification(notification) {
Future.microtask(() => {
QRViewController.updateDimensions(widget.key, _channel,
overlay: widget.overlay)
});
Future<void> updateDimensions() async {
await QRViewController.updateDimensions(
widget.key as GlobalKey<State<StatefulWidget>>, _channel,
overlay: widget.overlay);
}

bool onNotification(notification) {
updateDimensions();
return false;
}

@@ -109,7 +102,7 @@ class _QRViewState extends State<QRView> {
Container(
padding: widget.overlayMargin,
decoration: ShapeDecoration(
shape: widget.overlay,
shape: widget.overlay!,
),
)
],
@@ -139,7 +132,7 @@ class _QRViewState extends State<QRView> {
break;
default:
throw UnsupportedError(
"Trying to use the default webview implementation for $defaultTargetPlatform but there isn't a default one");
"Trying to use the default qrview implementation for $defaultTargetPlatform but there isn't a default one");
}
return _platformQrView;
}
@@ -149,19 +142,21 @@ class _QRViewState extends State<QRView> {

// Start scan after creation of the view
final controller = QRViewController._(
_channel, widget.key, widget.onPermissionSet, widget.cameraFacing)
.._startScan(widget.key, widget.overlay, widget.formatsAllowed);
_channel,
widget.key as GlobalKey<State<StatefulWidget>>?,
widget.onPermissionSet,
widget.cameraFacing)
.._startScan(widget.key as GlobalKey<State<StatefulWidget>>,
widget.overlay, widget.formatsAllowed);

// Initialize the controller for controlling the QRView
if (widget.onQRViewCreated != null) {
widget.onQRViewCreated(controller);
}
widget.onQRViewCreated(controller);
}
}

class _QrCameraSettings {
_QrCameraSettings({
this.cameraFacing,
this.cameraFacing = CameraFacing.unknown,
});

final CameraFacing cameraFacing;
@@ -174,8 +169,8 @@ class _QrCameraSettings {
}

class QRViewController {
QRViewController._(MethodChannel channel, GlobalKey qrKey,
PermissionSetCallback onPermissionSet, CameraFacing cameraFacing)
QRViewController._(MethodChannel channel, GlobalKey? qrKey,
PermissionSetCallback? onPermissionSet, CameraFacing cameraFacing)
: _channel = channel,
_cameraFacing = cameraFacing {
_channel.setMethodCallHandler((call) async {
@@ -186,9 +181,9 @@ class QRViewController {
final code = args['code'] as String;
final rawType = args['type'] as String;
// Raw bytes are only supported by Android.
final rawBytes = args['rawBytes'] as List<int>;
final rawBytes = args['rawBytes'] as List<int>?;
final format = BarcodeTypesExtension.fromString(rawType);
if (format != null) {
if (format != BarcodeFormat.unknown) {
final barcode = Barcode(code, format, rawBytes);
_scanUpdateController.sink.add(barcode);
} else {
@@ -197,15 +192,14 @@ class QRViewController {
}
break;
case 'onPermissionSet':
await getSystemFeatures(); // if we have no permission all features will not be avaible
if (call.arguments != null) {
if (call.arguments as bool) {
if (call.arguments != null && call.arguments is bool) {
if (call.arguments) {
_hasPermissions = true;
} else {
_hasPermissions = false;
}
if (onPermissionSet != null) {
onPermissionSet(this, call.arguments as bool);
onPermissionSet(this, call.arguments);
}
}
break;
@@ -220,20 +214,17 @@ class QRViewController {

Stream<Barcode> get scannedDataStream => _scanUpdateController.stream;

SystemFeatures _features;
bool _hasPermissions;

SystemFeatures get systemFeatures => _features;
bool _hasPermissions = false;
bool get hasPermissions => _hasPermissions;

/// Starts the barcode scanner
Future<void> _startScan(GlobalKey key, QrScannerOverlayShape overlay,
List<BarcodeFormat> barcodeFormats) async {
Future<void> _startScan(GlobalKey key, QrScannerOverlayShape? overlay,
List<BarcodeFormat>? barcodeFormats) async {
// We need to update the dimension before the scan is started.
try {
await QRViewController.updateDimensions(key, _channel, overlay: overlay);
return await _channel.invokeMethod(
'startScan', barcodeFormats?.map((e) => e.asInt())?.toList() ?? []);
'startScan', barcodeFormats?.map((e) => e.asInt()).toList() ?? []);
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
@@ -262,7 +253,7 @@ class QRViewController {
}

/// Get flashlight status
Future<bool> getFlashStatus() async {
Future<bool?> getFlashStatus() async {
try {
return await _channel.invokeMethod('getFlashInfo');
} on PlatformException catch (e) {
@@ -273,7 +264,7 @@ class QRViewController {
/// Toggles the flashlight between available modes
Future<void> toggleFlash() async {
try {
await _channel.invokeMethod('toggleFlash') as bool;
await _channel.invokeMethod('toggleFlash') as bool?;
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
@@ -311,7 +302,10 @@ class QRViewController {
try {
var features =
await _channel.invokeMapMethod<String, dynamic>('getSystemFeatures');
return SystemFeatures.fromJson(features);
if (features != null) {
return SystemFeatures.fromJson(features);
}
throw CameraException('Error', 'Could not get system features');
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
@@ -324,12 +318,13 @@ class QRViewController {
}

/// Updates the view dimensions for iOS.
static Future<void> updateDimensions(GlobalKey key, MethodChannel channel,
{QrScannerOverlayShape overlay}) async {
static Future<bool> updateDimensions(GlobalKey key, MethodChannel channel,
{QrScannerOverlayShape? overlay}) async {
if (defaultTargetPlatform == TargetPlatform.iOS) {
// Add small delay to ensure the renderbox is loaded
// Add small delay to ensure the render box is loaded
await Future.delayed(Duration(milliseconds: 100));
final RenderBox renderBox = key.currentContext.findRenderObject();
if (key.currentContext == null) return false;
final renderBox = key.currentContext!.findRenderObject() as RenderBox;
try {
await channel.invokeMethod('setDimensions', {
'width': renderBox.size.width,
@@ -337,9 +332,11 @@ class QRViewController {
'scanArea': overlay?.cutOutSize ?? 0,
'scanAreaOffset': overlay?.cutOutBottomOffset ?? 0
});
return true;
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}
return false;
}
}

+ 5
- 10
lib/src/qr_scanner_overlay_shape.dart 查看文件

@@ -11,10 +11,7 @@ class QrScannerOverlayShape extends ShapeBorder {
this.borderLength = 40,
this.cutOutSize = 250,
this.cutOutBottomOffset = 0,
}) : assert(
cutOutSize != null ??
cutOutSize != null ??
borderLength <= cutOutSize / 2 + borderWidth * 2,
}) : assert(borderLength <= cutOutSize / 2 + borderWidth * 2,
"Border can't be larger than ${cutOutSize / 2 + borderWidth * 2}");

final Color borderColor;
@@ -29,14 +26,14 @@ class QrScannerOverlayShape extends ShapeBorder {
EdgeInsetsGeometry get dimensions => const EdgeInsets.all(10);

@override
Path getInnerPath(Rect rect, {TextDirection textDirection}) {
Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
return Path()
..fillType = PathFillType.evenOdd
..addPath(getOuterPath(rect), Offset.zero);
}

@override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
Path _getLeftTopPath(Rect rect) {
return Path()
..moveTo(rect.left, rect.bottom)
@@ -60,7 +57,7 @@ class QrScannerOverlayShape extends ShapeBorder {
}

@override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
final width = rect.width;
final borderWidthSize = width / 2;
final height = rect.height;
@@ -68,9 +65,7 @@ class QrScannerOverlayShape extends ShapeBorder {
final _borderLength = borderLength > cutOutSize / 2 + borderWidth * 2
? borderWidthSize / 2
: borderLength;
final _cutOutSize = cutOutSize != null && cutOutSize < width
? cutOutSize
: width - borderOffset;
final _cutOutSize = cutOutSize < width ? cutOutSize : width - borderOffset;

final backgroundPaint = Paint()
..color = overlayColor


+ 1
- 1
lib/src/types/barcode.dart 查看文件

@@ -12,5 +12,5 @@ class Barcode {
final BarcodeFormat format;

/// Raw bytes are only supported by Android.
final List<int> rawBytes;
final List<int>? rawBytes;
}

+ 6
- 37
lib/src/types/barcode_format.dart 查看文件

@@ -53,7 +53,10 @@ enum BarcodeFormat {
upcE,

/// UPC/EAN extension format. Not a stand-alone format.
upcEanExtension
upcEanExtension,

/// Unknown
unknown
}

extension BarcodeTypesExtension on BarcodeFormat {
@@ -65,57 +68,40 @@ extension BarcodeTypesExtension on BarcodeFormat {
switch (format) {
case 'AZTEC':
return BarcodeFormat.aztec;
break;
case 'CODABAR':
return BarcodeFormat.codabar;
break;
case 'CODE_39':
return BarcodeFormat.code39;
break;
case 'CODE_93':
return BarcodeFormat.code93;
break;
case 'CODE_128':
return BarcodeFormat.code128;
break;
case 'DATA_MATRIX':
return BarcodeFormat.dataMatrix;
break;
case 'EAN_8':
return BarcodeFormat.ean8;
break;
case 'EAN_13':
return BarcodeFormat.ean13;
break;
case 'ITF':
return BarcodeFormat.itf;
break;
case 'MAXICODE':
return BarcodeFormat.maxicode;
break;
case 'PDF_417':
return BarcodeFormat.pdf417;
break;
case 'QR_CODE':
return BarcodeFormat.qrcode;
break;
case 'RSS14':
return BarcodeFormat.rss14;
break;
case 'RSS_EXPANDED':
return BarcodeFormat.rssExpanded;
break;
case 'UPC_A':
return BarcodeFormat.upcA;
break;
case 'UPC_E':
return BarcodeFormat.upcE;
break;
case 'UPC_EAN_EXTENSION':
return BarcodeFormat.upcEanExtension;
break;
default:
return null;
return BarcodeFormat.unknown;
}
}

@@ -123,57 +109,40 @@ extension BarcodeTypesExtension on BarcodeFormat {
switch (this) {
case BarcodeFormat.aztec:
return 'AZTEC';
break;
case BarcodeFormat.codabar:
return 'CODABAR';
break;
case BarcodeFormat.code39:
return 'CODE_39';
break;
case BarcodeFormat.code93:
return 'CODE_93';
break;
case BarcodeFormat.code128:
return 'CODE_128';
break;
case BarcodeFormat.dataMatrix:
return 'DATA_MATRIX';
break;
case BarcodeFormat.ean8:
return 'EAN_8';
break;
case BarcodeFormat.ean13:
return 'EAN_13';
break;
case BarcodeFormat.itf:
return 'ITF';
break;
case BarcodeFormat.maxicode:
return 'MAXICODE';
break;
case BarcodeFormat.pdf417:
return 'PDF_417';
break;
case BarcodeFormat.qrcode:
return 'QR_CODE';
break;
case BarcodeFormat.rss14:
return 'RSS14';
break;
case BarcodeFormat.rssExpanded:
return 'RSS_EXPANDED';
break;
case BarcodeFormat.upcA:
return 'UPC_A';
break;
case BarcodeFormat.upcE:
return 'UPC_E';
break;
case BarcodeFormat.upcEanExtension:
return 'UPC_EAN_EXTENSION';
break;
default:
return 'NOT_VALID';
return 'UNKNOWN';
}
}
}

+ 4
- 1
lib/src/types/camera.dart 查看文件

@@ -3,5 +3,8 @@ enum CameraFacing {
back,

/// Shows front facing camera.
front
front,

/// Unknown camera
unknown
}

+ 1
- 1
lib/src/types/camera_exception.dart 查看文件

@@ -7,7 +7,7 @@ class CameraException implements Exception {
String code;

/// Textual description of the error.
String description;
String? description;

@override
String toString() => 'CameraException($code, $description)';


+ 2
- 2
pubspec.yaml 查看文件

@@ -5,7 +5,7 @@ homepage: https://juliuscanute.com
repository: https://github.com/juliuscanute/qr_code_scanner

environment:
sdk: ">=2.6.0 <3.0.0"
sdk: '>=2.12.0 <3.0.0'
flutter: ">=1.10.0"

dependencies:
@@ -13,7 +13,7 @@ dependencies:
sdk: flutter

dev_dependencies:
pedantic: ^1.9.2
pedantic: ^1.11.0

flutter:
plugin:


正在加载...
取消
保存