Julian Steenbakker
Committed by GitHub

Merge pull request #110 from juliansteenbakker/lint

Apply flutter lint
# mobile_scanner
[![pub package](https://img.shields.io/pub/v/mobile_scanner.svg)](https://pub.dev/packages/mobile_scanner)
[![style: lint](https://img.shields.io/badge/style-lint-4BC0F5.svg)](https://pub.dev/packages/lint)
[![mobile_scanner](https://github.com/juliansteenbakker/mobile_scanner/actions/workflows/flutter.yml/badge.svg)](https://github.com/juliansteenbakker/mobile_scanner/actions/workflows/flutter.yml)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/juliansteenbakker?label=Want%20personal%20and%20fast%20support%3F%20Sponsor%20me%20and%20I%27ll%20contact%20you%21)](https://github.com/sponsors/juliansteenbakker)
... ...
include: package:flutter_lints/flutter.yaml
linter:
rules:
unawaited_futures: true
\ No newline at end of file
include: package:lint/analysis_options_package.yaml
\ No newline at end of file
... ...
# 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
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
include: package:lint/analysis_options.yaml
\ No newline at end of file
... ...
... ... @@ -355,7 +355,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 75Y2P2WSQQ;
DEVELOPMENT_TEAM = 3K8Q7WKS3W;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
... ... @@ -484,7 +484,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 75Y2P2WSQQ;
DEVELOPMENT_TEAM = 3K8Q7WKS3W;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
... ... @@ -507,7 +507,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 75Y2P2WSQQ;
DEVELOPMENT_TEAM = 3K8Q7WKS3W;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
... ...
... ... @@ -27,10 +27,11 @@ class _BarcodeScannerWithControllerState
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Builder(builder: (context) {
return Stack(
children: [
MobileScanner(
body: Builder(
builder: (context) {
return Stack(
children: [
MobileScanner(
controller: controller,
fit: BoxFit.contain,
// allowDuplicates: true,
... ... @@ -42,112 +43,130 @@ class _BarcodeScannerWithControllerState
setState(() {
this.barcode = barcode.rawValue;
});
}),
Align(
alignment: Alignment.bottomCenter,
child: Container(
},
),
Align(
alignment: Alignment.bottomCenter,
height: 100,
color: Colors.black.withOpacity(0.4),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
color: Colors.white,
icon: ValueListenableBuilder(
valueListenable: controller.torchState,
builder: (context, state, child) {
switch (state as TorchState) {
case TorchState.off:
return const Icon(Icons.flash_off,
color: Colors.grey);
case TorchState.on:
return const Icon(Icons.flash_on,
color: Colors.yellow);
}
},
child: Container(
alignment: Alignment.bottomCenter,
height: 100,
color: Colors.black.withOpacity(0.4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
color: Colors.white,
icon: ValueListenableBuilder(
valueListenable: controller.torchState,
builder: (context, state, child) {
if (state == null) {
return const Icon(
Icons.flash_off,
color: Colors.grey,
);
}
switch (state as TorchState) {
case TorchState.off:
return const Icon(
Icons.flash_off,
color: Colors.grey,
);
case TorchState.on:
return const Icon(
Icons.flash_on,
color: Colors.yellow,
);
}
},
),
iconSize: 32.0,
onPressed: () => controller.toggleTorch(),
),
iconSize: 32.0,
onPressed: () => controller.toggleTorch(),
),
IconButton(
IconButton(
color: Colors.white,
icon: isStarted
? const Icon(Icons.stop)
: const Icon(Icons.play_arrow),
iconSize: 32.0,
onPressed: () => setState(() {
isStarted
? controller.stop()
: controller.start();
isStarted = !isStarted;
})),
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width - 200,
height: 50,
child: FittedBox(
child: Text(
barcode ?? 'Scan something!',
overflow: TextOverflow.fade,
style: Theme.of(context)
.textTheme
.headline4!
.copyWith(color: Colors.white),
isStarted ? controller.stop() : controller.start();
isStarted = !isStarted;
}),
),
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width - 200,
height: 50,
child: FittedBox(
child: Text(
barcode ?? 'Scan something!',
overflow: TextOverflow.fade,
style: Theme.of(context)
.textTheme
.headline4!
.copyWith(color: Colors.white),
),
),
),
),
),
IconButton(
color: Colors.white,
icon: ValueListenableBuilder(
valueListenable: controller.cameraFacingState,
builder: (context, state, child) {
switch (state as CameraFacing) {
case CameraFacing.front:
IconButton(
color: Colors.white,
icon: ValueListenableBuilder(
valueListenable: controller.cameraFacingState,
builder: (context, state, child) {
if (state == null) {
return const Icon(Icons.camera_front);
case CameraFacing.back:
return const Icon(Icons.camera_rear);
}
switch (state as CameraFacing) {
case CameraFacing.front:
return const Icon(Icons.camera_front);
case CameraFacing.back:
return const Icon(Icons.camera_rear);
}
},
),
iconSize: 32.0,
onPressed: () => controller.switchCamera(),
),
IconButton(
color: Colors.white,
icon: const Icon(Icons.image),
iconSize: 32.0,
onPressed: () async {
final ImagePicker _picker = ImagePicker();
// Pick an image
final XFile? image = await _picker.pickImage(
source: ImageSource.gallery,
);
if (image != null) {
if (await controller.analyzeImage(image.path)) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Barcode found!'),
backgroundColor: Colors.green,
),
);
} else {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('No barcode found!'),
backgroundColor: Colors.red,
),
);
}
}
},
),
iconSize: 32.0,
onPressed: () => controller.switchCamera(),
),
IconButton(
color: Colors.white,
icon: const Icon(Icons.image),
iconSize: 32.0,
onPressed: () async {
final ImagePicker _picker = ImagePicker();
// Pick an image
final XFile? image = await _picker.pickImage(
source: ImageSource.gallery);
if (image != null) {
if (await controller.analyzeImage(image.path)) {
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(
content: Text('Barcode found!'),
backgroundColor: Colors.green,
));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(
content: Text('No barcode found!'),
backgroundColor: Colors.red,
));
}
}
},
),
],
],
),
),
),
),
],
);
}),
],
);
},
),
);
}
}
... ...
... ... @@ -18,50 +18,52 @@ class _BarcodeScannerWithoutControllerState
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Builder(builder: (context) {
return Stack(
children: [
MobileScanner(
body: Builder(
builder: (context) {
return Stack(
children: [
MobileScanner(
fit: BoxFit.contain,
// allowDuplicates: false,
onDetect: (barcode, args) {
setState(() {
this.barcode = barcode.rawValue;
});
}),
Align(
alignment: Alignment.bottomCenter,
child: Container(
},
),
Align(
alignment: Alignment.bottomCenter,
height: 100,
color: Colors.black.withOpacity(0.4),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width - 120,
height: 50,
child: FittedBox(
child: Text(
barcode ?? 'Scan something!',
overflow: TextOverflow.fade,
style: Theme.of(context)
.textTheme
.headline4!
.copyWith(color: Colors.white),
child: Container(
alignment: Alignment.bottomCenter,
height: 100,
color: Colors.black.withOpacity(0.4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width - 120,
height: 50,
child: FittedBox(
child: Text(
barcode ?? 'Scan something!',
overflow: TextOverflow.fade,
style: Theme.of(context)
.textTheme
.headline4!
.copyWith(color: Colors.white),
),
),
),
),
),
],
],
),
),
),
),
],
);
}),
],
);
},
),
);
}
}
... ...
... ... @@ -16,21 +16,25 @@ class MyHome extends StatelessWidget {
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const BarcodeScannerWithController(),
));
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const BarcodeScannerWithController(),
),
);
},
child: const Text('MobileScanner with Controller'),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const BarcodeScannerWithoutController(),
));
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
const BarcodeScannerWithoutController(),
),
);
},
child: const Text('MobileScanner without Controller'),
),
... ...
... ... @@ -6,9 +6,9 @@ environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
image_picker: ^0.8.4+9
flutter:
sdk: flutter
image_picker: ^0.8.4+9
mobile_scanner:
path: ../
... ... @@ -16,7 +16,7 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.4
lint: ^1.8.2
flutter:
uses-material-design: true
... ...
library mobile_scanner;
export 'src/mobile_scanner.dart';
export 'src/mobile_scanner_controller.dart';
export 'src/mobile_scanner_arguments.dart';
export 'src/mobile_scanner_controller.dart';
export 'src/objects/barcode.dart';
... ...
import 'dart:async';
import 'dart:html' as html;
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:mobile_scanner/src/web/jsqr.dart';
import 'dart:html' as html;
import 'dart:ui' as ui;
import 'package:mobile_scanner/src/web/media.dart';
/// This plugin is the web implementation of mobile_scanner.
/// It only supports QR codes.
class MobileScannerWebPlugin {
static void registerWith(Registrar registrar) {
PluginEventChannel event = PluginEventChannel(
'dev.steenbakker.mobile_scanner/scanner/event',
const StandardMethodCodec(),
registrar);
MethodChannel channel = MethodChannel(
'dev.steenbakker.mobile_scanner/scanner/method',
const StandardMethodCodec(),
registrar);
final PluginEventChannel event = PluginEventChannel(
'dev.steenbakker.mobile_scanner/scanner/event',
const StandardMethodCodec(),
registrar,
);
final MethodChannel channel = MethodChannel(
'dev.steenbakker.mobile_scanner/scanner/method',
const StandardMethodCodec(),
registrar,
);
final MobileScannerWebPlugin instance = MobileScannerWebPlugin();
WidgetsFlutterBinding.ensureInitialized();
... ... @@ -51,16 +52,17 @@ class MobileScannerWebPlugin {
Future<dynamic> handleMethodCall(MethodCall call) async {
switch (call.method) {
case 'start':
return await _start(call.arguments);
return _start(call.arguments as Map);
case 'torch':
return await _torch(call.arguments);
return _torch(call.arguments);
case 'stop':
return await cancel();
return cancel();
default:
throw PlatformException(
code: 'Unimplemented',
details: "The mobile_scanner plugin for web doesn't implement "
"the method '${call.method}'");
code: 'Unimplemented',
details: "The mobile_scanner plugin for web doesn't implement "
"the method '${call.method}'",
);
}
}
... ... @@ -77,21 +79,22 @@ class MobileScannerWebPlugin {
}
/// Starts the video stream and the scanner
Future<Map> _start(arguments) async {
Future<Map> _start(Map arguments) async {
vidDiv.children = [video];
var cameraFacing = CameraFacing.front;
if (arguments.containsKey('facing')) {
cameraFacing = CameraFacing.values[arguments['facing']];
cameraFacing = CameraFacing.values[arguments['facing'] as int];
}
// See https://github.com/flutter/flutter/issues/41563
// ignore: UNDEFINED_PREFIXED_NAME
// ignore: UNDEFINED_PREFIXED_NAME, avoid_dynamic_calls
ui.platformViewRegistry.registerViewFactory(
viewID,
(int id) => vidDiv
..style.width = '100%'
..style.height = '100%');
viewID,
(int id) => vidDiv
..style.width = '100%'
..style.height = '100%',
);
// Check if stream is running
if (_localStream != null) {
... ... @@ -104,13 +107,14 @@ class MobileScannerWebPlugin {
try {
// Check if browser supports multiple camera's and set if supported
Map? capabilities =
final Map? capabilities =
html.window.navigator.mediaDevices?.getSupportedConstraints();
if (capabilities != null && capabilities['facingMode']) {
var constraints = {
if (capabilities != null && capabilities['facingMode'] as bool) {
final constraints = {
'video': VideoOptions(
facingMode:
(cameraFacing == CameraFacing.front ? 'user' : 'environment'))
facingMode:
cameraFacing == CameraFacing.front ? 'user' : 'environment',
)
};
_localStream =
... ... @@ -156,6 +160,8 @@ class MobileScannerWebPlugin {
final sources =
await html.window.navigator.mediaDevices!.enumerateDevices();
for (final e in sources) {
// TODO:
// ignore: avoid_dynamic_calls
if (e.kind == 'videoinput') {
return true;
}
... ...
... ... @@ -28,13 +28,13 @@ class MobileScanner extends StatefulWidget {
final bool allowDuplicates;
/// Create a [MobileScanner] with a [controller], the [controller] must has been initialized.
const MobileScanner(
{Key? key,
this.onDetect,
this.controller,
this.fit = BoxFit.cover,
this.allowDuplicates = false})
: super(key: key);
const MobileScanner({
Key? key,
this.onDetect,
this.controller,
this.fit = BoxFit.cover,
this.allowDuplicates = false,
}) : super(key: key);
@override
State<MobileScanner> createState() => _MobileScannerState();
... ... @@ -69,8 +69,9 @@ class _MobileScannerState extends State<MobileScanner>
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, BoxConstraints constraints) {
return ValueListenableBuilder(
return LayoutBuilder(
builder: (context, BoxConstraints constraints) {
return ValueListenableBuilder(
valueListenable: controller.args,
builder: (context, value, child) {
value = value as MobileScannerArguments?;
... ... @@ -81,10 +82,10 @@ class _MobileScannerState extends State<MobileScanner>
if (!widget.allowDuplicates) {
if (lastScanned != barcode.rawValue) {
lastScanned = barcode.rawValue;
widget.onDetect!(barcode, value as MobileScannerArguments);
widget.onDetect!(barcode, value! as MobileScannerArguments);
}
} else {
widget.onDetect!(barcode, value as MobileScannerArguments);
widget.onDetect!(barcode, value! as MobileScannerArguments);
}
});
return ClipRect(
... ... @@ -104,8 +105,10 @@ class _MobileScannerState extends State<MobileScanner>
),
);
}
});
});
},
);
},
);
}
@override
... ...
... ... @@ -13,6 +13,10 @@ class MobileScannerArguments {
final String? webId;
/// Create a [MobileScannerArguments].
MobileScannerArguments(
{this.textureId, required this.size, required this.hasTorch, this.webId});
MobileScannerArguments({
this.textureId,
required this.size,
required this.hasTorch,
this.webId,
});
}
... ...
... ... @@ -5,8 +5,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'objects/barcode_utility.dart';
import 'package:mobile_scanner/src/objects/barcode_utility.dart';
/// The facing of a camera.
enum CameraFacing {
... ... @@ -56,11 +55,12 @@ class MobileScannerController {
Stream<Barcode> get barcodes => barcodesController.stream;
MobileScannerController(
{this.facing = CameraFacing.back,
this.ratio,
this.torchEnabled,
this.formats}) {
MobileScannerController({
this.facing = CameraFacing.back,
this.ratio,
this.torchEnabled,
this.formats,
}) {
// In case a new instance is created before calling dispose()
if (_controllerHashcode != null) {
stop();
... ... @@ -80,26 +80,30 @@ class MobileScannerController {
// Listen to events from the platform specific code
events = eventChannel
.receiveBroadcastStream()
.listen((data) => handleEvent(data));
.listen((data) => handleEvent(data as Map));
}
void handleEvent(Map<dynamic, dynamic> event) {
void handleEvent(Map event) {
final name = event['name'];
final data = event['data'];
switch (name) {
case 'torchState':
final state = TorchState.values[data];
final state = TorchState.values[data as int];
torchState.value = state;
break;
case 'barcode':
final barcode = Barcode.fromNative(data);
final barcode = Barcode.fromNative(data as Map);
barcodesController.add(barcode);
break;
case 'barcodeMac':
barcodesController.add(Barcode(rawValue: data['payload']));
barcodesController.add(
Barcode(
rawValue: (data as Map)['payload'] as String,
),
);
break;
case 'barcodeWeb':
barcodesController.add(Barcode(rawValue: data));
barcodesController.add(Barcode(rawValue: data as String));
break;
default:
throw UnimplementedError();
... ... @@ -129,11 +133,12 @@ class MobileScannerController {
// Check authorization status
if (!kIsWeb) {
MobileScannerState state =
MobileScannerState.values[await methodChannel.invokeMethod('state')];
MobileScannerState state = MobileScannerState
.values[await methodChannel.invokeMethod('state') as int];
switch (state) {
case MobileScannerState.undetermined:
final bool result = await methodChannel.invokeMethod('request');
final bool result =
await methodChannel.invokeMethod('request') as bool;
state = result
? MobileScannerState.authorized
: MobileScannerState.denied;
... ... @@ -149,7 +154,7 @@ class MobileScannerController {
cameraFacingState.value = facing;
// Set the starting arguments for the camera
Map arguments = {};
final Map arguments = {};
arguments['facing'] = facing.index;
if (ratio != null) arguments['ratio'] = ratio;
if (torchEnabled != null) arguments['torch'] = torchEnabled;
... ... @@ -166,7 +171,9 @@ class MobileScannerController {
Map<String, dynamic>? startResult = {};
try {
startResult = await methodChannel.invokeMapMethod<String, dynamic>(
'start', arguments);
'start',
arguments,
);
} on PlatformException catch (error) {
debugPrint('${error.code}: ${error.message}');
isStarting = false;
... ... @@ -179,18 +186,23 @@ class MobileScannerController {
throw PlatformException(code: 'INITIALIZATION ERROR');
}
hasTorch = startResult['torchable'];
hasTorch = startResult['torchable'] as bool;
if (kIsWeb) {
args.value = MobileScannerArguments(
webId: startResult['ViewID'],
size: Size(startResult['videoWidth'], startResult['videoHeight']),
hasTorch: hasTorch);
webId: startResult['ViewID'] as String?,
size: Size(
startResult['videoWidth'] as double,
startResult['videoHeight'] as double,
),
hasTorch: hasTorch,
);
} else {
args.value = MobileScannerArguments(
textureId: startResult['textureId'],
size: toSize(startResult['size']),
hasTorch: hasTorch);
textureId: startResult['textureId'] as int,
size: toSize(startResult['size'] as Map),
hasTorch: hasTorch,
);
}
isStarting = false;
... ... @@ -214,7 +226,7 @@ class MobileScannerController {
return;
}
TorchState state =
final TorchState state =
torchState.value == TorchState.off ? TorchState.on : TorchState.off;
try {
... ... @@ -233,7 +245,8 @@ class MobileScannerController {
await methodChannel.invokeMethod('stop');
} on PlatformException catch (error) {
debugPrint(
'${error.code}: camera is stopped! Please start before switching camera.');
'${error.code}: camera is stopped! Please start before switching camera.',
);
return;
}
facing =
... ... @@ -247,7 +260,7 @@ class MobileScannerController {
///
/// [path] The path of the image on the devices
Future<bool> analyzeImage(String path) async {
return await methodChannel.invokeMethod('analyzeImage', path);
return methodChannel.invokeMethod('analyzeImage', path) as bool;
}
/// Disposes the MobileScannerController and closes all listeners.
... ...
import 'dart:typed_data';
import 'dart:ui';
import 'barcode_utility.dart';
import 'package:mobile_scanner/src/objects/barcode_utility.dart';
/// Represents a single recognized barcode and its value.
class Barcode {
... ... @@ -63,38 +63,39 @@ class Barcode {
/// Gets parsed WiFi AP details.
final WiFi? wifi;
Barcode(
{this.corners,
this.format = BarcodeFormat.ean13,
this.rawBytes,
this.type = BarcodeType.text,
this.calendarEvent,
this.contactInfo,
this.driverLicense,
this.email,
this.geoPoint,
this.phone,
this.sms,
this.url,
this.wifi,
required this.rawValue});
Barcode({
this.corners,
this.format = BarcodeFormat.ean13,
this.rawBytes,
this.type = BarcodeType.text,
this.calendarEvent,
this.contactInfo,
this.driverLicense,
this.email,
this.geoPoint,
this.phone,
this.sms,
this.url,
this.wifi,
required this.rawValue,
});
/// Create a [Barcode] from native data.
Barcode.fromNative(Map<dynamic, dynamic> data)
: corners = toCorners(data['corners']),
format = toFormat(data['format']),
rawBytes = data['rawBytes'],
rawValue = data['rawValue'],
type = BarcodeType.values[data['type']],
calendarEvent = toCalendarEvent(data['calendarEvent']),
contactInfo = toContactInfo(data['contactInfo']),
driverLicense = toDriverLicense(data['driverLicense']),
email = toEmail(data['email']),
geoPoint = toGeoPoint(data['geoPoint']),
phone = toPhone(data['phone']),
sms = toSMS(data['sms']),
url = toUrl(data['url']),
wifi = toWiFi(data['wifi']);
Barcode.fromNative(Map data)
: corners = toCorners(data['corners'] as List?),
format = toFormat(data['format'] as int),
rawBytes = data['rawBytes'] as Uint8List?,
rawValue = data['rawValue'] as String?,
type = BarcodeType.values[data['type'] as int],
calendarEvent = toCalendarEvent(data['calendarEvent'] as Map?),
contactInfo = toContactInfo(data['contactInfo'] as Map?),
driverLicense = toDriverLicense(data['driverLicense'] as Map?),
email = toEmail(data['email'] as Map?),
geoPoint = toGeoPoint(data['geoPoint'] as Map?),
phone = toPhone(data['phone'] as Map?),
sms = toSMS(data['sms'] as Map?),
url = toUrl(data['url'] as Map?),
wifi = toWiFi(data['wifi'] as Map?);
}
/// A calendar event extracted from QRCode.
... ... @@ -135,14 +136,18 @@ class CalendarEvent {
final String? summary;
/// Create a [CalendarEvent] from native data.
CalendarEvent.fromNative(Map<dynamic, dynamic> data)
: description = data['description'],
start = DateTime.tryParse(data['start']),
end = DateTime.tryParse(data['end']),
location = data['location'],
organizer = data['organizer'],
status = data['status'],
summary = data['summary'];
CalendarEvent.fromNative(Map data)
: description = data['description'] as String?,
start = data['start'] != null
? DateTime.tryParse(data['start'] as String)
: null,
end = data['end'] != null
? DateTime.tryParse(data['end'] as String)
: null,
location = data['location'] as String?,
organizer = data['organizer'] as String?,
status = data['status'] as String?,
summary = data['summary'] as String?;
}
/// A person's or organization's business card. For example a VCARD.
... ... @@ -183,17 +188,20 @@ class ContactInfo {
final List<String>? urls;
/// Create a [ContactInfo] from native data.
ContactInfo.fromNative(Map<dynamic, dynamic> data)
ContactInfo.fromNative(Map data)
: addresses = List.unmodifiable(
data['addresses'].map((e) => Address.fromNative(e))),
emails =
List.unmodifiable(data['emails'].map((e) => Email.fromNative(e))),
name = toName(data['name']),
organization = data['organization'],
phones =
List.unmodifiable(data['phones'].map((e) => Phone.fromNative(e))),
title = data['title'],
urls = List.unmodifiable(data['urls']);
(data['addresses'] as List).map((e) => Address.fromNative(e as Map)),
),
emails = List.unmodifiable(
(data['emails'] as List).map((e) => Email.fromNative(e as Map)),
),
name = toName(data['name'] as Map?),
organization = data['organization'] as String?,
phones = List.unmodifiable(
(data['phones'] as List).map((e) => Phone.fromNative(e as Map)),
),
title = data['title'] as String?,
urls = List.unmodifiable(data['urls'] as List);
}
/// An address.
... ... @@ -207,9 +215,9 @@ class Address {
final AddressType? type;
/// Create a [Address] from native data.
Address.fromNative(Map<dynamic, dynamic> data)
: addressLines = List.unmodifiable(data['addressLines']),
type = AddressType.values[data['type']];
Address.fromNative(Map data)
: addressLines = List.unmodifiable(data['addressLines'] as List),
type = AddressType.values[data['type'] as int];
}
/// A person's name, both formatted version and individual name components.
... ... @@ -250,14 +258,14 @@ class PersonName {
final String? pronunciation;
/// Create a [PersonName] from native data.
PersonName.fromNative(Map<dynamic, dynamic> data)
: first = data['first'],
middle = data['middle'],
last = data['last'],
prefix = data['prefix'],
suffix = data['suffix'],
formattedName = data['formattedName'],
pronunciation = data['pronunciation'];
PersonName.fromNative(Map data)
: first = data['first'] as String?,
middle = data['middle'] as String?,
last = data['last'] as String?,
prefix = data['prefix'] as String?,
suffix = data['suffix'] as String?,
formattedName = data['formattedName'] as String?,
pronunciation = data['pronunciation'] as String?;
}
/// A driver license or ID card.
... ... @@ -335,21 +343,21 @@ class DriverLicense {
final String? middleName;
/// Create a [DriverLicense] from native data.
DriverLicense.fromNative(Map<dynamic, dynamic> data)
: addressCity = data['addressCity'],
addressState = data['addressState'],
addressStreet = data['addressStreet'],
addressZip = data['addressZip'],
birthDate = data['birthDate'],
documentType = data['documentType'],
expiryDate = data['expiryDate'],
firstName = data['firstName'],
gender = data['gender'],
issueDate = data['issueDate'],
issuingCountry = data['issuingCountry'],
lastName = data['lastName'],
licenseNumber = data['licenseNumber'],
middleName = data['middleName'];
DriverLicense.fromNative(Map data)
: addressCity = data['addressCity'] as String?,
addressState = data['addressState'] as String?,
addressStreet = data['addressStreet'] as String?,
addressZip = data['addressZip'] as String?,
birthDate = data['birthDate'] as String?,
documentType = data['documentType'] as String?,
expiryDate = data['expiryDate'] as String?,
firstName = data['firstName'] as String?,
gender = data['gender'] as String?,
issueDate = data['issueDate'] as String?,
issuingCountry = data['issuingCountry'] as String?,
lastName = data['lastName'] as String?,
licenseNumber = data['licenseNumber'] as String?,
middleName = data['middleName'] as String?;
}
/// An email message from a 'MAILTO:' or similar QRCode type.
... ... @@ -376,11 +384,11 @@ class Email {
final EmailType? type;
/// Create a [Email] from native data.
Email.fromNative(Map<dynamic, dynamic> data)
: address = data['address'],
body = data['body'],
subject = data['subject'],
type = EmailType.values[data['type']];
Email.fromNative(Map data)
: address = data['address'] as String?,
body = data['body'] as String?,
subject = data['subject'] as String?,
type = EmailType.values[data['type'] as int];
}
/// GPS coordinates from a 'GEO:' or similar QRCode type.
... ... @@ -392,9 +400,9 @@ class GeoPoint {
final double? longitude;
/// Create a [GeoPoint] from native data.
GeoPoint.fromNative(Map<dynamic, dynamic> data)
: latitude = data['latitude'],
longitude = data['longitude'];
GeoPoint.fromNative(Map data)
: latitude = data['latitude'] as double?,
longitude = data['longitude'] as double?;
}
/// Phone number info.
... ... @@ -411,9 +419,9 @@ class Phone {
final PhoneType? type;
/// Create a [Phone] from native data.
Phone.fromNative(Map<dynamic, dynamic> data)
: number = data['number'],
type = PhoneType.values[data['type']];
Phone.fromNative(Map data)
: number = data['number'] as String?,
type = PhoneType.values[data['type'] as int];
}
/// A sms message from a 'SMS:' or similar QRCode type.
... ... @@ -429,9 +437,9 @@ class SMS {
final String? phoneNumber;
/// Create a [SMS] from native data.
SMS.fromNative(Map<dynamic, dynamic> data)
: message = data['message'],
phoneNumber = data['phoneNumber'];
SMS.fromNative(Map data)
: message = data['message'] as String?,
phoneNumber = data['phoneNumber'] as String?;
}
/// A URL and title from a 'MEBKM:' or similar QRCode type.
... ... @@ -447,9 +455,9 @@ class UrlBookmark {
final String? url;
/// Create a [UrlBookmark] from native data.
UrlBookmark.fromNative(Map<dynamic, dynamic> data)
: title = data['title'],
url = data['url'];
UrlBookmark.fromNative(Map data)
: title = data['title'] as String?,
url = data['url'] as String?;
}
/// A wifi network parameters from a 'WIFI:' or similar QRCode type.
... ... @@ -470,10 +478,10 @@ class WiFi {
final String? password;
/// Create a [WiFi] from native data.
WiFi.fromNative(Map<dynamic, dynamic> data)
: encryptionType = EncryptionType.values[data['encryptionType']],
ssid = data['ssid'],
password = data['password'];
WiFi.fromNative(Map data)
: encryptionType = EncryptionType.values[data['encryptionType'] as int],
ssid = data['ssid'] as String?,
password = data['password'] as String?;
}
enum BarcodeFormat {
... ...
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'barcode.dart';
Size toSize(Map<dynamic, dynamic> data) {
final width = data['width'];
final height = data['height'];
Size toSize(Map data) {
final width = data['width'] as double;
final height = data['height'] as double;
return Size(width, height);
}
List<Offset>? toCorners(List<dynamic>? data) {
List<Offset>? toCorners(List? data) {
if (data != null) {
return List.unmodifiable(data.map((e) => Offset(e['x'], e['y'])));
return List.unmodifiable(
data.map((e) => Offset((e as Map)['x'] as double, e['y'] as double)),
);
} else {
return null;
}
... ... @@ -51,7 +52,7 @@ BarcodeFormat toFormat(int value) {
}
}
CalendarEvent? toCalendarEvent(Map<dynamic, dynamic>? data) {
CalendarEvent? toCalendarEvent(Map? data) {
if (data != null) {
return CalendarEvent.fromNative(data);
} else {
... ... @@ -59,15 +60,15 @@ CalendarEvent? toCalendarEvent(Map<dynamic, dynamic>? data) {
}
}
DateTime? toDateTime(Map<dynamic, dynamic>? data) {
DateTime? toDateTime(Map<String, dynamic>? data) {
if (data != null) {
final year = data['year'];
final month = data['month'];
final day = data['day'];
final hour = data['hours'];
final minute = data['minutes'];
final second = data['seconds'];
return data['isUtc']
final year = data['year'] as int;
final month = data['month'] as int;
final day = data['day'] as int;
final hour = data['hours'] as int;
final minute = data['minutes'] as int;
final second = data['seconds'] as int;
return data['isUtc'] as bool
? DateTime.utc(year, month, day, hour, minute, second)
: DateTime(year, month, day, hour, minute, second);
} else {
... ... @@ -75,7 +76,7 @@ DateTime? toDateTime(Map<dynamic, dynamic>? data) {
}
}
ContactInfo? toContactInfo(Map<dynamic, dynamic>? data) {
ContactInfo? toContactInfo(Map? data) {
if (data != null) {
return ContactInfo.fromNative(data);
} else {
... ... @@ -83,7 +84,7 @@ ContactInfo? toContactInfo(Map<dynamic, dynamic>? data) {
}
}
PersonName? toName(Map<dynamic, dynamic>? data) {
PersonName? toName(Map? data) {
if (data != null) {
return PersonName.fromNative(data);
} else {
... ... @@ -91,7 +92,7 @@ PersonName? toName(Map<dynamic, dynamic>? data) {
}
}
DriverLicense? toDriverLicense(Map<dynamic, dynamic>? data) {
DriverLicense? toDriverLicense(Map? data) {
if (data != null) {
return DriverLicense.fromNative(data);
} else {
... ... @@ -99,7 +100,7 @@ DriverLicense? toDriverLicense(Map<dynamic, dynamic>? data) {
}
}
Email? toEmail(Map<dynamic, dynamic>? data) {
Email? toEmail(Map? data) {
if (data != null) {
return Email.fromNative(data);
} else {
... ... @@ -107,7 +108,7 @@ Email? toEmail(Map<dynamic, dynamic>? data) {
}
}
GeoPoint? toGeoPoint(Map<dynamic, dynamic>? data) {
GeoPoint? toGeoPoint(Map? data) {
if (data != null) {
return GeoPoint.fromNative(data);
} else {
... ... @@ -115,7 +116,7 @@ GeoPoint? toGeoPoint(Map<dynamic, dynamic>? data) {
}
}
Phone? toPhone(Map<dynamic, dynamic>? data) {
Phone? toPhone(Map? data) {
if (data != null) {
return Phone.fromNative(data);
} else {
... ... @@ -123,7 +124,7 @@ Phone? toPhone(Map<dynamic, dynamic>? data) {
}
}
SMS? toSMS(Map<dynamic, dynamic>? data) {
SMS? toSMS(Map? data) {
if (data != null) {
return SMS.fromNative(data);
} else {
... ... @@ -131,7 +132,7 @@ SMS? toSMS(Map<dynamic, dynamic>? data) {
}
}
UrlBookmark? toUrl(Map<dynamic, dynamic>? data) {
UrlBookmark? toUrl(Map? data) {
if (data != null) {
return UrlBookmark.fromNative(data);
} else {
... ... @@ -139,7 +140,7 @@ UrlBookmark? toUrl(Map<dynamic, dynamic>? data) {
}
}
WiFi? toWiFi(Map<dynamic, dynamic>? data) {
WiFi? toWiFi(Map? data) {
if (data != null) {
return WiFi.fromNative(data);
} else {
... ...
... ... @@ -4,7 +4,7 @@ library jsqr;
import 'package:js/js.dart';
@JS('jsQR')
external Code? jsQR(var data, int? width, int? height);
external Code? jsQR(dynamic data, int? width, int? height);
@JS()
class Code {
... ...
... ... @@ -25,8 +25,12 @@ class VideoOptions {
external Map get width;
external Map get height;
external factory VideoOptions(
{String? facingMode, DeviceIdOptions? deviceId, Map? width, Map? height});
external factory VideoOptions({
String? facingMode,
DeviceIdOptions? deviceId,
Map? width,
Map? height,
});
}
@JS()
... ...
... ... @@ -4,7 +4,7 @@ library qrscanner;
import 'package:js/js.dart';
@JS('QrScanner')
external String scanImage(var data);
external String scanImage(dynamic data);
@JS()
class QrScanner {
... ...
... ... @@ -8,16 +8,16 @@ environment:
flutter: ">=1.10.0"
dependencies:
js: ^0.6.3
flutter:
sdk: flutter
flutter_web_plugins:
sdk: flutter
js: ^0.6.3
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.4
lint: ^1.8.2
flutter:
plugin:
... ...