Julian Steenbakker

Merge branch 'master' into dependabot/gradle/android/com.android.tools.build-gradle-7.1.1

import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
... ... @@ -18,8 +16,10 @@ class _AnalyzeViewState extends State<AnalyzeView>
with SingleTickerProviderStateMixin {
String? barcode;
MobileScannerController controller = MobileScannerController(torchEnabled: true,
facing: CameraFacing.front,);
MobileScannerController controller = MobileScannerController(
torchEnabled: true,
facing: CameraFacing.front,
);
@override
Widget build(BuildContext context) {
... ... @@ -30,7 +30,7 @@ class _AnalyzeViewState extends State<AnalyzeView>
return Stack(
children: [
MobileScanner(
controller: controller,
controller: controller,
fit: BoxFit.contain,
// controller: MobileScannerController(
// torchEnabled: true,
... ... @@ -55,20 +55,22 @@ class _AnalyzeViewState extends State<AnalyzeView>
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);
}
},
),
iconSize: 32.0,
onPressed: () => controller.toggleTorch(),
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);
}
},
),
iconSize: 32.0,
onPressed: () => controller.toggleTorch(),
),
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width - 120,
... ...
... ... @@ -20,7 +20,7 @@ class _AnalyzeViewState extends State<AnalyzeView>
// CameraController cameraController = CameraController(context, width: 320, height: 150);
String? barcode = null;
String? barcode;
@override
Widget build(BuildContext context) {
... ... @@ -30,40 +30,41 @@ class _AnalyzeViewState extends State<AnalyzeView>
return Stack(
children: [
MobileScanner(
// fitScreen: false,
// fitScreen: false,
// controller: cameraController,
onDetect: (barcode, args) {
if (this.barcode != barcode.rawValue) {
this.barcode = barcode.rawValue;
if (barcode.corners != null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('${barcode.rawValue}'),
duration: const Duration(milliseconds: 200),
animation: null,
));
setState(() {
final List<Offset> points = [];
double factorWidth = args.size.width / 520;
// double factorHeight = wanted / args.size.height;
final size = MediaQuery.of(context).devicePixelRatio;
debugPrint('Size: ${barcode.corners}');
for (var point in barcode.corners!) {
final adjustedWith = point.dx ;
final adjustedHeight= point.dy ;
points.add(Offset(adjustedWith / size, adjustedHeight / size));
// points.add(Offset((point.dx ) / size,
// (point.dy) / size));
// final differenceWidth = (args.wantedSize!.width - args.size.width) / 2;
// final differenceHeight = (args.wantedSize!.height - args.size.height) / 2;
// points.add(Offset((point.dx + differenceWidth) / size,
// (point.dy + differenceHeight) / size));
}
this.points = points;
});
if (this.barcode != barcode.rawValue) {
this.barcode = barcode.rawValue;
if (barcode.corners != null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(barcode.rawValue),
duration: const Duration(milliseconds: 200),
animation: null,
));
setState(() {
final List<Offset> points = [];
// double factorWidth = args.size.width / 520;
// double factorHeight = wanted / args.size.height;
final size = MediaQuery.of(context).devicePixelRatio;
debugPrint('Size: ${barcode.corners}');
for (var point in barcode.corners!) {
final adjustedWith = point.dx;
final adjustedHeight = point.dy;
points.add(
Offset(adjustedWith / size, adjustedHeight / size));
// points.add(Offset((point.dx ) / size,
// (point.dy) / size));
// final differenceWidth = (args.wantedSize!.width - args.size.width) / 2;
// final differenceHeight = (args.wantedSize!.height - args.size.height) / 2;
// points.add(Offset((point.dx + differenceWidth) / size,
// (point.dy + differenceHeight) / size));
}
}
// Default 640 x480
}),
this.points = points;
});
}
}
// Default 640 x480
}),
CustomPaint(
painter: OpenPainter(points),
),
... ... @@ -108,7 +109,7 @@ class OpenPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
var paint1 = Paint()
..color = Color(0xff63aa65)
..color = const Color(0xff63aa65)
..strokeWidth = 10;
//draw points on canvas
canvas.drawPoints(PointMode.points, points, paint1);
... ...
... ... @@ -5,11 +5,8 @@
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mobile_scanner_example/main.dart';
void main() {
testWidgets('Verify Platform version', (WidgetTester tester) async {
// Build our app and trigger a frame.
... ...
... ... @@ -53,11 +53,11 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
case "start":
start(call, result)
case "torch":
torchNative(call, result)
switchTorch(call, result)
case "analyze":
analyzeNative(call, result)
switchAnalyzeMode(call, result)
case "stop":
stopNative(result)
stop(result)
default:
result(FlutterMethodNotImplemented)
}
... ... @@ -83,58 +83,59 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
return Unmanaged<CVPixelBuffer>.passRetained(latestBuffer)
}
// public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
//
// latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
// registry.textureFrameAvailable(textureId)
//
// switch analyzeMode {
// case 1: // barcode
// if analyzing {
// break
// }
// analyzing = true
// let buffer = CMSampleBufferGetImageBuffer(sampleBuffer)
// let image = VisionImage(image: buffer!.image)
// image.orientation = imageOrientation(
// deviceOrientation: UIDevice.current.orientation,
// defaultOrientation: .portrait
// )
//
// let scanner = BarcodeScanner.barcodeScanner()
// scanner.process(image) { [self] barcodes, error in
// if error == nil && barcodes != nil {
// for barcode in barcodes! {
// let event: [String: Any?] = ["name": "barcode", "data": barcode.data]
// sink?(event)
// }
// }
// analyzing = false
// }
// default: // none
// break
// }
// }
// Gets called when a new image is added to the buffer
public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
registry.textureFrameAvailable(textureId)
switch analyzeMode {
case 1: // barcode
if analyzing {
break
}
analyzing = true
let buffer = CMSampleBufferGetImageBuffer(sampleBuffer)
let image = VisionImage(image: buffer!.image)
image.orientation = imageOrientation(
deviceOrientation: UIDevice.current.orientation,
defaultOrientation: .portrait
)
let scanner = BarcodeScanner.barcodeScanner()
scanner.process(image) { [self] barcodes, error in
if error == nil && barcodes != nil {
for barcode in barcodes! {
let event: [String: Any?] = ["name": "barcode", "data": barcode.data]
sink?(event)
}
}
analyzing = false
}
default: // none
break
}
}
// func imageOrientation(
// deviceOrientation: UIDeviceOrientation,
// defaultOrientation: UIDeviceOrientation
// ) -> UIImage.Orientation {
// switch deviceOrientation {
// case .portrait:
// return position == .front ? .leftMirrored : .right
// case .landscapeLeft:
// return position == .front ? .downMirrored : .up
// case .portraitUpsideDown:
// return position == .front ? .rightMirrored : .left
// case .landscapeRight:
// return position == .front ? .upMirrored : .down
// case .faceDown, .faceUp, .unknown:
// return .up
// @unknown default:
// return imageOrientation(deviceOrientation: defaultOrientation, defaultOrientation: .portrait)
// }
// }
func imageOrientation(
deviceOrientation: UIDeviceOrientation,
defaultOrientation: UIDeviceOrientation
) -> UIImage.Orientation {
switch deviceOrientation {
case .portrait:
return position == .front ? .leftMirrored : .right
case .landscapeLeft:
return position == .front ? .downMirrored : .up
case .portraitUpsideDown:
return position == .front ? .rightMirrored : .left
case .landscapeRight:
return position == .front ? .upMirrored : .down
case .faceDown, .faceUp, .unknown:
return .up
@unknown default:
return imageOrientation(deviceOrientation: defaultOrientation, defaultOrientation: .portrait)
}
}
func checkPermission(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
let status = AVCaptureDevice.authorizationStatus(for: .video)
... ... @@ -158,22 +159,35 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
let argReader = MapArgumentReader(call.arguments as? [String: Any])
guard let ratio = argReader.int(key: "ratio"),
let torch = argReader.int(key: "torch"),
let facing = argReader.int(key: "facing") else {
result(FlutterError(code: "INVALID_ARGUMENT", message: "Missing a required argument", details: "Expecting targetWidth, targetHeight, formats, and optionally heartbeatTimeout"))
return
}
// let ratio: Int = argReader.int(key: "ratio")
let torch: Bool = argReader.bool(key: "torch") ?? false
let facing: Int = argReader.int(key: "facing") ?? 1
// Set the camera to use
position = facing == 0 ? AVCaptureDevice.Position.front : .back
// Open the camera device
if #available(iOS 10.0, *) {
device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: position).devices.first
} else {
device = AVCaptureDevice.devices(for: .video).filter({$0.position == position}).first
}
// Enable the torch if parameter is set and torch is available
if (device.hasTorch && device.isTorchAvailable) {
do {
try device.lockForConfiguration()
device.torchMode = torch ? .on : .off
device.unlockForConfiguration()
} catch {
error.throwNative(result)
}
}
device.addObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode), options: .new, context: nil)
captureSession.beginConfiguration()
// Add device input.
// Add device input
do {
let input = try AVCaptureDeviceInput(device: device)
captureSession.addInput(input)
... ... @@ -205,7 +219,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
result(answer)
}
func torchNative(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
func switchTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
do {
try device.lockForConfiguration()
device.torchMode = call.arguments as! Int == 1 ? .on : .off
... ... @@ -216,12 +230,12 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
}
}
func analyzeNative(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
func switchAnalyzeMode(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
analyzeMode = call.arguments as! Int
result(nil)
}
func stopNative(_ result: FlutterResult) {
func stop(_ result: FlutterResult) {
captureSession.stopRunning()
for input in captureSession.inputs {
captureSession.removeInput(input)
... ... @@ -241,6 +255,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
result(nil)
}
// Observer for torch state
public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
switch keyPath {
case "torchMode":
... ... @@ -269,6 +284,10 @@ class MapArgumentReader {
func int(key: String) -> Int? {
return (args?[key] as? NSNumber)?.intValue
}
func bool(key: String) -> Bool? {
return (args?[key] as? NSNumber)?.boolValue
}
func stringArray(key: String) -> [String]? {
return args?[key] as? [String]
... ...
... ... @@ -2,4 +2,4 @@ library mobile_scanner;
export 'src/mobile_scanner.dart';
export 'src/mobile_scanner_controller.dart';
export 'src/objects/barcode.dart';
\ No newline at end of file
export 'src/objects/barcode.dart';
... ...
... ... @@ -3,10 +3,7 @@ import 'package:mobile_scanner/mobile_scanner.dart';
import 'mobile_scanner_arguments.dart';
enum Ratio {
ratio_4_3,
ratio_16_9
}
enum Ratio { ratio_4_3, ratio_16_9 }
/// A widget showing a live camera preview.
class MobileScanner extends StatefulWidget {
... ... @@ -18,7 +15,8 @@ class MobileScanner extends StatefulWidget {
/// Create a [MobileScanner] with a [controller], the [controller] must has been initialized.
const MobileScanner(
{Key? key, this.onDetect, this.controller, this.fit = BoxFit.cover})
: assert((controller != null )), super(key: key);
: assert((controller != null)),
super(key: key);
@override
State<MobileScanner> createState() => _MobileScannerState();
... ... @@ -91,4 +89,4 @@ class _MobileScannerState extends State<MobileScanner>
controller.dispose();
super.dispose();
}
}
\ No newline at end of file
}
... ...
... ... @@ -11,5 +11,6 @@ class MobileScannerArguments {
final bool hasTorch;
/// Create a [MobileScannerArguments].
MobileScannerArguments({required this.textureId,required this.size, required this.hasTorch});
MobileScannerArguments(
{required this.textureId, required this.size, required this.hasTorch});
}
... ...
... ... @@ -38,7 +38,6 @@ class MobileScannerController {
int? _controllerHashcode;
StreamSubscription? events;
final ValueNotifier<MobileScannerArguments?> args = ValueNotifier(null);
final ValueNotifier<TorchState> torchState = ValueNotifier(TorchState.off);
late final ValueNotifier<CameraFacing> cameraFacingState;
... ... @@ -107,7 +106,8 @@ class MobileScannerController {
setAnalyzeMode(AnalyzeMode.barcode.index);
// Check authorization status
MobileScannerState state = MobileScannerState.values[await methodChannel.invokeMethod('state')];
MobileScannerState state =
MobileScannerState.values[await methodChannel.invokeMethod('state')];
switch (state) {
case MobileScannerState.undetermined:
final bool result = await methodChannel.invokeMethod('request');
... ... @@ -129,13 +129,18 @@ class MobileScannerController {
if (torchEnabled != null) arguments['torch'] = torchEnabled;
// Start the camera with arguments
final Map<String, dynamic>? startResult = await methodChannel.invokeMapMethod<String, dynamic>(
'start', arguments);
final Map<String, dynamic>? startResult = await methodChannel
.invokeMapMethod<String, dynamic>('start', arguments);
if (startResult == null) throw PlatformException(code: 'INITIALIZATION ERROR');
if (startResult == null) {
throw PlatformException(code: 'INITIALIZATION ERROR');
}
hasTorch = startResult['torchable'];
args.value = MobileScannerArguments(textureId: startResult['textureId'], size: toSize(startResult['size']), hasTorch: hasTorch);
args.value = MobileScannerArguments(
textureId: startResult['textureId'],
size: toSize(startResult['size']),
hasTorch: hasTorch);
}
Future<void> stop() async => await methodChannel.invokeMethod('stop');
... ... @@ -157,7 +162,8 @@ class MobileScannerController {
Future<void> switchCamera() async {
ensure('switchCamera');
await stop();
facing = facing == CameraFacing.back ? CameraFacing.front : CameraFacing.back;
facing =
facing == CameraFacing.back ? CameraFacing.front : CameraFacing.back;
start();
}
... ...
... ... @@ -490,7 +490,7 @@ enum BarcodeFormat {
/// Barcode format constant for Data Matrix.
///
/// Constant Value: 16
data_matrix,
dataMatrix,
/// Barcode format constant for EAN-13.
///
... ... @@ -510,17 +510,17 @@ enum BarcodeFormat {
/// Barcode format constant for QR Code.
///
/// Constant Value: 256
qr_code,
qrCode,
/// Barcode format constant for UPC-A.
///
/// Constant Value: 512
upc_a,
upcA,
/// Barcode format constant for UPC-E.
///
/// Constant Value: 1024
upc_e,
upcE,
/// Barcode format constant for PDF-417.
///
... ...
... ... @@ -29,7 +29,7 @@ BarcodeFormat toFormat(int value) {
case 8:
return BarcodeFormat.codebar;
case 16:
return BarcodeFormat.data_matrix;
return BarcodeFormat.dataMatrix;
case 32:
return BarcodeFormat.ean13;
case 64:
... ... @@ -37,11 +37,11 @@ BarcodeFormat toFormat(int value) {
case 128:
return BarcodeFormat.itf;
case 256:
return BarcodeFormat.qr_code;
return BarcodeFormat.qrCode;
case 512:
return BarcodeFormat.upc_a;
return BarcodeFormat.upcA;
case 1024:
return BarcodeFormat.upc_e;
return BarcodeFormat.upcE;
case 2048:
return BarcodeFormat.pdf417;
case 4096:
... ...
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mobile_scanner/src/mobile_scanner.dart';
void main() {
const MethodChannel channel = MethodChannel('mobile_scanner');
... ... @@ -16,5 +15,4 @@ void main() {
tearDown(() {
channel.setMockMethodCallHandler(null);
});
}
... ...