Просмотр исходного кода

Add support for null-safety (#278)

flutter-beta
Julian Steenbakker 5 лет назад
Родитель
Сommit
f60e7affae
Не найден GPG ключ соответствующий данной подписи Идентификатор GPG ключа: 16E437C7A3D94250
9 измененных файлов: 65 добавлений и 66 удалений
  1. +6
    -10
      example/lib/main.dart
  2. +1
    -1
      example/pubspec.yaml
  3. +4
    -4
      lib/src/lifecycle_event_handler.dart
  4. +45
    -42
      lib/src/qr_code_scanner.dart
  5. +3
    -3
      lib/src/qr_scanner_overlay_shape.dart
  6. +2
    -2
      lib/src/types/barcode.dart
  7. +1
    -1
      lib/src/types/barcode_format.dart
  8. +1
    -1
      lib/src/types/camera_exception.dart
  9. +2
    -2
      pubspec.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())); void main() => runApp(MaterialApp(home: QRViewExample()));


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

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


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


// In order to get hot reload to work we need to pause the camera if the platform // 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() { void reassemble() {
super.reassemble(); super.reassemble();
if (Platform.isAndroid) { if (Platform.isAndroid) {
controller.pauseCamera();
controller!.pauseCamera();
} }
controller.resumeCamera();
controller!.resumeCamera();
} }


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


+ 1
- 1
example/pubspec.yaml Просмотреть файл

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


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


dependencies: dependencies:
flutter: flutter:


+ 4
- 4
lib/src/lifecycle_event_handler.dart Просмотреть файл

@@ -7,22 +7,22 @@ class LifecycleEventHandler extends WidgetsBindingObserver {
this.suspendingCallBack, this.suspendingCallBack,
}); });


final AsyncCallback resumeCallBack;
final AsyncCallback suspendingCallBack;
final AsyncCallback? resumeCallBack;
final AsyncCallback? suspendingCallBack;


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


+ 45
- 42
lib/src/qr_code_scanner.dart Просмотреть файл

@@ -14,29 +14,27 @@ import 'types/camera_exception.dart';
import 'types/features.dart'; import 'types/features.dart';


typedef QRViewCreatedCallback = void Function(QRViewController); typedef QRViewCreatedCallback = void Function(QRViewController);
typedef PermissionSetCallback = void Function(QRViewController, bool);
typedef PermissionSetCallback = void Function(QRViewController, bool?);


/// The [QRView] is the view where the camera /// The [QRView] is the view where the camera
/// and the barcode scanner gets displayed. /// and the barcode scanner gets displayed.
class QRView extends StatefulWidget { class QRView extends StatefulWidget {
const QRView({ const QRView({
@required Key key,
@required this.onQRViewCreated,
required Key key,
required this.onQRViewCreated,
this.overlay, this.overlay,
this.overlayMargin = EdgeInsets.zero, this.overlayMargin = EdgeInsets.zero,
this.cameraFacing = CameraFacing.back, this.cameraFacing = CameraFacing.back,
this.onPermissionSet, this.onPermissionSet,
this.formatsAllowed, this.formatsAllowed,
}) : assert(key != null),
assert(onQRViewCreated != null),
super(key: key);
}) : super(key: key);


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


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


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


/// Calls the provided [onPermissionSet] callback when the permission is set. /// 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. /// Use [formatsAllowed] to specify which formats needs to be scanned.
final List<BarcodeFormat> formatsAllowed;
final List<BarcodeFormat>? formatsAllowed;


@override @override
State<StatefulWidget> createState() => _QRViewState(); State<StatefulWidget> createState() => _QRViewState();
@@ -59,7 +57,7 @@ class QRView extends StatefulWidget {


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


@override @override
void initState() { void initState() {
@@ -68,11 +66,12 @@ class _QRViewState extends State<QRView> {
resumeCallBack: () async => { resumeCallBack: () async => {
if (_channel != null) if (_channel != null)
{ {
QRViewController.updateDimensions(widget.key, _channel,
QRViewController.updateDimensions(
widget.key as GlobalKey<State<StatefulWidget>>, _channel,
overlay: widget.overlay) overlay: widget.overlay)
} }
}); });
WidgetsBinding.instance.addObserver(_observer);
WidgetsBinding.instance!.addObserver(_observer);
} }


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


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


@@ -109,7 +109,7 @@ class _QRViewState extends State<QRView> {
Container( Container(
padding: widget.overlayMargin, padding: widget.overlayMargin,
decoration: ShapeDecoration( decoration: ShapeDecoration(
shape: widget.overlay,
shape: widget.overlay!,
), ),
) )
], ],
@@ -149,13 +149,15 @@ class _QRViewState extends State<QRView> {


// Start scan after creation of the view // Start scan after creation of the view
final controller = QRViewController._( 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 // Initialize the controller for controlling the QRView
if (widget.onQRViewCreated != null) {
widget.onQRViewCreated(controller);
}
widget.onQRViewCreated(controller);
} }
} }


@@ -164,18 +166,18 @@ class _QrCameraSettings {
this.cameraFacing, this.cameraFacing,
}); });


final CameraFacing cameraFacing;
final CameraFacing? cameraFacing;


Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return <String, dynamic>{ return <String, dynamic>{
'cameraFacing': cameraFacing.index,
'cameraFacing': cameraFacing!.index,
}; };
} }
} }


class QRViewController { class QRViewController {
QRViewController._(MethodChannel channel, GlobalKey qrKey,
PermissionSetCallback onPermissionSet, CameraFacing cameraFacing)
QRViewController._(MethodChannel channel, GlobalKey? qrKey,
PermissionSetCallback? onPermissionSet, CameraFacing cameraFacing)
: _channel = channel, : _channel = channel,
_cameraFacing = cameraFacing { _cameraFacing = cameraFacing {
_channel.setMethodCallHandler((call) async { _channel.setMethodCallHandler((call) async {
@@ -183,10 +185,10 @@ class QRViewController {
case 'onRecognizeQR': case 'onRecognizeQR':
if (call.arguments != null) { if (call.arguments != null) {
final args = call.arguments as Map; final args = call.arguments as Map;
final code = args['code'] as String;
final rawType = args['type'] as String;
final code = args['code'] as String?;
final rawType = args['type'] as String?;
// Raw bytes are only supported by Android. // 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); final format = BarcodeTypesExtension.fromString(rawType);
if (format != null) { if (format != null) {
final barcode = Barcode(code, format, rawBytes); final barcode = Barcode(code, format, rawBytes);
@@ -205,7 +207,7 @@ class QRViewController {
_hasPermissions = false; _hasPermissions = false;
} }
if (onPermissionSet != null) { if (onPermissionSet != null) {
onPermissionSet(this, call.arguments as bool);
onPermissionSet(this, call.arguments as bool?);
} }
} }
break; break;
@@ -213,27 +215,27 @@ class QRViewController {
}); });
} }


final MethodChannel _channel;
late final MethodChannel _channel;
final CameraFacing _cameraFacing; final CameraFacing _cameraFacing;
final StreamController<Barcode> _scanUpdateController = final StreamController<Barcode> _scanUpdateController =
StreamController<Barcode>(); StreamController<Barcode>();


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


SystemFeatures _features;
bool _hasPermissions;
SystemFeatures? _features;
bool? _hasPermissions;


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


/// Starts the barcode scanner /// 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. // We need to update the dimension before the scan is started.
try { try {
await QRViewController.updateDimensions(key, _channel, overlay: overlay); await QRViewController.updateDimensions(key, _channel, overlay: overlay);
return await _channel.invokeMethod( return await _channel.invokeMethod(
'startScan', barcodeFormats?.map((e) => e.asInt())?.toList() ?? []);
'startScan', barcodeFormats?.map((e) => e.asInt()).toList() ?? []);
} on PlatformException catch (e) { } on PlatformException catch (e) {
throw CameraException(e.code, e.message); throw CameraException(e.code, e.message);
} }
@@ -242,7 +244,7 @@ class QRViewController {
/// Gets information about which camera is active. /// Gets information about which camera is active.
Future<CameraFacing> getCameraInfo() async { Future<CameraFacing> getCameraInfo() async {
try { try {
var cameraFacing = await _channel.invokeMethod('getCameraInfo') as int;
var cameraFacing = await _channel.invokeMethod('getCameraInfo') as int?;
if (cameraFacing == -1) return _cameraFacing; if (cameraFacing == -1) return _cameraFacing;
return CameraFacing return CameraFacing
.values[await _channel.invokeMethod('getCameraInfo') as int]; .values[await _channel.invokeMethod('getCameraInfo') as int];
@@ -262,7 +264,7 @@ class QRViewController {
} }


/// Get flashlight status /// Get flashlight status
Future<bool> getFlashStatus() async {
Future<bool?> getFlashStatus() async {
try { try {
return await _channel.invokeMethod('getFlashInfo'); return await _channel.invokeMethod('getFlashInfo');
} on PlatformException catch (e) { } on PlatformException catch (e) {
@@ -273,7 +275,7 @@ class QRViewController {
/// Toggles the flashlight between available modes /// Toggles the flashlight between available modes
Future<void> toggleFlash() async { Future<void> toggleFlash() async {
try { try {
await _channel.invokeMethod('toggleFlash') as bool;
await _channel.invokeMethod('toggleFlash') as bool?;
} on PlatformException catch (e) { } on PlatformException catch (e) {
throw CameraException(e.code, e.message); throw CameraException(e.code, e.message);
} }
@@ -310,7 +312,8 @@ class QRViewController {
Future<SystemFeatures> getSystemFeatures() async { Future<SystemFeatures> getSystemFeatures() async {
try { try {
var features = var features =
await _channel.invokeMapMethod<String, dynamic>('getSystemFeatures');
await (_channel.invokeMapMethod<String, dynamic>('getSystemFeatures')
as FutureOr<Map<String, dynamic>>);
return SystemFeatures.fromJson(features); return SystemFeatures.fromJson(features);
} on PlatformException catch (e) { } on PlatformException catch (e) {
throw CameraException(e.code, e.message); throw CameraException(e.code, e.message);
@@ -325,11 +328,11 @@ class QRViewController {


/// Updates the view dimensions for iOS. /// Updates the view dimensions for iOS.
static Future<void> updateDimensions(GlobalKey key, MethodChannel channel, static Future<void> updateDimensions(GlobalKey key, MethodChannel channel,
{QrScannerOverlayShape overlay}) async {
{QrScannerOverlayShape? overlay}) async {
if (defaultTargetPlatform == TargetPlatform.iOS) { if (defaultTargetPlatform == TargetPlatform.iOS) {
// Add small delay to ensure the renderbox is loaded // Add small delay to ensure the renderbox is loaded
await Future.delayed(Duration(milliseconds: 100)); await Future.delayed(Duration(milliseconds: 100));
final RenderBox renderBox = key.currentContext.findRenderObject();
final renderBox = key.currentContext!.findRenderObject() as RenderBox;
try { try {
await channel.invokeMethod('setDimensions', { await channel.invokeMethod('setDimensions', {
'width': renderBox.size.width, 'width': renderBox.size.width,


+ 3
- 3
lib/src/qr_scanner_overlay_shape.dart Просмотреть файл

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


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


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


@override @override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
final width = rect.width; final width = rect.width;
final borderWidthSize = width / 2; final borderWidthSize = width / 2;
final height = rect.height; final height = rect.height;


+ 2
- 2
lib/src/types/barcode.dart Просмотреть файл

@@ -8,9 +8,9 @@ import 'barcode_format.dart';
class Barcode { class Barcode {
Barcode(this.code, this.format, this.rawBytes); Barcode(this.code, this.format, this.rawBytes);


final String code;
final String? code;
final BarcodeFormat format; final BarcodeFormat format;


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

+ 1
- 1
lib/src/types/barcode_format.dart Просмотреть файл

@@ -61,7 +61,7 @@ extension BarcodeTypesExtension on BarcodeFormat {
return index; return index;
} }


static BarcodeFormat fromString(String format) {
static BarcodeFormat? fromString(String? format) {
switch (format) { switch (format) {
case 'AZTEC': case 'AZTEC':
return BarcodeFormat.aztec; return BarcodeFormat.aztec;


+ 1
- 1
lib/src/types/camera_exception.dart Просмотреть файл

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


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


@override @override
String toString() => 'CameraException($code, $description)'; 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 repository: https://github.com/juliuscanute/qr_code_scanner


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


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


dev_dependencies: dev_dependencies:
pedantic: ^1.9.2
pedantic: ^1.11.0


flutter: flutter:
plugin: plugin:


Загрузка…
Отмена
Сохранить