Merge branch 'master' into web
# Conflicts: # lib/src/mobile_scanner.dart
Showing
18 changed files
with
538 additions
and
405 deletions
| 1 | +## 0.1.2 | ||
| 2 | +* MobileScannerArguments is now exported. [#7](https://github.com/juliansteenbakker/mobile_scanner/issues/7) | ||
| 3 | + | ||
| 4 | +Bugfixes: | ||
| 5 | +* Fixed application crashing when stop() or start() is called multiple times. [#5](https://github.com/juliansteenbakker/mobile_scanner/issues/5) | ||
| 6 | +* Fixes controller not being disposed correctly. [#23](https://github.com/juliansteenbakker/mobile_scanner/issues/23) | ||
| 7 | +* Catch error when no camera is found. [#19](https://github.com/juliansteenbakker/mobile_scanner/issues/19) | ||
| 8 | + | ||
| 9 | +## 0.1.1 | ||
| 10 | +mobile_scanner is now compatible with sdk >= 2.12 and flutter >= 2.2.0 | ||
| 11 | + | ||
| 1 | ## 0.1.0 | 12 | ## 0.1.0 |
| 2 | We now have MacOS support using Apple's Vision framework! | 13 | We now have MacOS support using Apple's Vision framework! |
| 3 | -Keep in mind that for now, only the raw value is supported. | 14 | +Keep in mind that for now, only the raw value of the barcode object is supported. |
| 15 | + | ||
| 16 | +Bugfixes: | ||
| 17 | +* Fixed a crash when dispose is called in a overridden method. [#5](https://github.com/juliansteenbakker/mobile_scanner/issues/5) | ||
| 4 | 18 | ||
| 5 | ## 0.0.3 | 19 | ## 0.0.3 |
| 6 | * Added some API docs and README | 20 | * Added some API docs and README |
| @@ -3,13 +3,13 @@ | @@ -3,13 +3,13 @@ | ||
| 3 | [](https://pub.dev/packages/mobile_scanner) | 3 | [](https://pub.dev/packages/mobile_scanner) |
| 4 | [](https://github.com/juliansteenbakker/mobile_scanner/actions/workflows/flutter.yml) | 4 | [](https://github.com/juliansteenbakker/mobile_scanner/actions/workflows/flutter.yml) |
| 5 | 5 | ||
| 6 | -A universal scanner for Flutter based on MLKit. Uses CameraX on Android and AVFoundation on iOS. | 6 | +A universal barcode and QR code scanner for Flutter based on MLKit. Uses CameraX on Android, AVFoundation on iOS and Apple Vision & AVFoundation on macOS. |
| 7 | 7 | ||
| 8 | ## Platform Support | 8 | ## Platform Support |
| 9 | 9 | ||
| 10 | | Android | iOS | MacOS | Web | Linux | Windows | | 10 | | Android | iOS | MacOS | Web | Linux | Windows | |
| 11 | | :-----: | :-: | :---: | :-: | :---: | :-----: | | 11 | | :-----: | :-: | :---: | :-: | :---: | :-----: | |
| 12 | -| ✔️ | ✔️ | | | | | | 12 | +| ✔️ | ✔️ | ✔️ | | | | |
| 13 | 13 | ||
| 14 | CameraX for Android requires at least SDK 21. | 14 | CameraX for Android requires at least SDK 21. |
| 15 | 15 |
| @@ -38,8 +38,8 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | @@ -38,8 +38,8 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | ||
| 38 | private var camera: Camera? = null | 38 | private var camera: Camera? = null |
| 39 | private var textureEntry: TextureRegistry.SurfaceTextureEntry? = null | 39 | private var textureEntry: TextureRegistry.SurfaceTextureEntry? = null |
| 40 | 40 | ||
| 41 | - @AnalyzeMode | ||
| 42 | - private var analyzeMode: Int = AnalyzeMode.NONE | 41 | +// @AnalyzeMode |
| 42 | +// private var analyzeMode: Int = AnalyzeMode.NONE | ||
| 43 | 43 | ||
| 44 | @ExperimentalGetImage | 44 | @ExperimentalGetImage |
| 45 | override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: MethodChannel.Result) { | 45 | override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: MethodChannel.Result) { |
| @@ -47,8 +47,8 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | @@ -47,8 +47,8 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | ||
| 47 | "state" -> checkPermission(result) | 47 | "state" -> checkPermission(result) |
| 48 | "request" -> requestPermission(result) | 48 | "request" -> requestPermission(result) |
| 49 | "start" -> start(call, result) | 49 | "start" -> start(call, result) |
| 50 | - "torch" -> switchTorch(call, result) | ||
| 51 | - "analyze" -> switchAnalyzeMode(call, result) | 50 | + "torch" -> toggleTorch(call, result) |
| 51 | +// "analyze" -> switchAnalyzeMode(call, result) | ||
| 52 | "stop" -> stop(result) | 52 | "stop" -> stop(result) |
| 53 | else -> result.notImplemented() | 53 | else -> result.notImplemented() |
| 54 | } | 54 | } |
| @@ -92,8 +92,8 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | @@ -92,8 +92,8 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | ||
| 92 | 92 | ||
| 93 | @ExperimentalGetImage | 93 | @ExperimentalGetImage |
| 94 | val analyzer = ImageAnalysis.Analyzer { imageProxy -> // YUV_420_888 format | 94 | val analyzer = ImageAnalysis.Analyzer { imageProxy -> // YUV_420_888 format |
| 95 | - when (analyzeMode) { | ||
| 96 | - AnalyzeMode.BARCODE -> { | 95 | +// when (analyzeMode) { |
| 96 | +// AnalyzeMode.BARCODE -> { | ||
| 97 | val mediaImage = imageProxy.image ?: return@Analyzer | 97 | val mediaImage = imageProxy.image ?: return@Analyzer |
| 98 | val inputImage = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees) | 98 | val inputImage = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees) |
| 99 | 99 | ||
| @@ -106,9 +106,9 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | @@ -106,9 +106,9 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | ||
| 106 | } | 106 | } |
| 107 | .addOnFailureListener { e -> Log.e(TAG, e.message, e) } | 107 | .addOnFailureListener { e -> Log.e(TAG, e.message, e) } |
| 108 | .addOnCompleteListener { imageProxy.close() } | 108 | .addOnCompleteListener { imageProxy.close() } |
| 109 | - } | ||
| 110 | - else -> imageProxy.close() | ||
| 111 | - } | 109 | +// } |
| 110 | +// else -> imageProxy.close() | ||
| 111 | +// } | ||
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | 114 | ||
| @@ -116,6 +116,10 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | @@ -116,6 +116,10 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | ||
| 116 | 116 | ||
| 117 | @ExperimentalGetImage | 117 | @ExperimentalGetImage |
| 118 | private fun start(call: MethodCall, result: MethodChannel.Result) { | 118 | private fun start(call: MethodCall, result: MethodChannel.Result) { |
| 119 | + if (camera != null) { | ||
| 120 | + result.error(TAG, "Called start() while already started!", null) | ||
| 121 | + return | ||
| 122 | + } | ||
| 119 | 123 | ||
| 120 | val facing: Int = call.argument<Int>("facing") ?: 0 | 124 | val facing: Int = call.argument<Int>("facing") ?: 0 |
| 121 | val ratio: Int? = call.argument<Int>("ratio") | 125 | val ratio: Int? = call.argument<Int>("ratio") |
| @@ -186,24 +190,32 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | @@ -186,24 +190,32 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: | ||
| 186 | }, executor) | 190 | }, executor) |
| 187 | } | 191 | } |
| 188 | 192 | ||
| 189 | - private fun switchTorch(call: MethodCall, result: MethodChannel.Result) { | ||
| 190 | - val state = call.arguments == 1 | ||
| 191 | - camera!!.cameraControl.enableTorch(state) | 193 | + private fun toggleTorch(call: MethodCall, result: MethodChannel.Result) { |
| 194 | + if (camera == null) { | ||
| 195 | + result.error(TAG,"Called toggleTorch() while stopped!", null) | ||
| 196 | + return | ||
| 197 | + } | ||
| 198 | + camera!!.cameraControl.enableTorch(call.arguments == 1) | ||
| 192 | result.success(null) | 199 | result.success(null) |
| 193 | } | 200 | } |
| 194 | 201 | ||
| 195 | - private fun switchAnalyzeMode(call: MethodCall, result: MethodChannel.Result) { | ||
| 196 | - analyzeMode = call.arguments as Int | ||
| 197 | - result.success(null) | ||
| 198 | - } | 202 | +// private fun switchAnalyzeMode(call: MethodCall, result: MethodChannel.Result) { |
| 203 | +// analyzeMode = call.arguments as Int | ||
| 204 | +// result.success(null) | ||
| 205 | +// } | ||
| 199 | 206 | ||
| 200 | private fun stop(result: MethodChannel.Result) { | 207 | private fun stop(result: MethodChannel.Result) { |
| 208 | + if (camera == null) { | ||
| 209 | + result.error(TAG,"Called stop() while already stopped!", null) | ||
| 210 | + return | ||
| 211 | + } | ||
| 212 | + | ||
| 201 | val owner = activity as LifecycleOwner | 213 | val owner = activity as LifecycleOwner |
| 202 | camera!!.cameraInfo.torchState.removeObservers(owner) | 214 | camera!!.cameraInfo.torchState.removeObservers(owner) |
| 203 | cameraProvider!!.unbindAll() | 215 | cameraProvider!!.unbindAll() |
| 204 | textureEntry!!.release() | 216 | textureEntry!!.release() |
| 205 | 217 | ||
| 206 | - analyzeMode = AnalyzeMode.NONE | 218 | +// analyzeMode = AnalyzeMode.NONE |
| 207 | camera = null | 219 | camera = null |
| 208 | textureEntry = null | 220 | textureEntry = null |
| 209 | cameraProvider = null | 221 | cameraProvider = null |
example/lib/barcode_scanner_controller.dart
0 → 100644
| 1 | +import 'package:flutter/material.dart'; | ||
| 2 | +import 'package:mobile_scanner/mobile_scanner.dart'; | ||
| 3 | + | ||
| 4 | +class BarcodeScannerWithController extends StatefulWidget { | ||
| 5 | + const BarcodeScannerWithController({Key? key}) : super(key: key); | ||
| 6 | + | ||
| 7 | + @override | ||
| 8 | + _BarcodeScannerWithControllerState createState() => | ||
| 9 | + _BarcodeScannerWithControllerState(); | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +class _BarcodeScannerWithControllerState | ||
| 13 | + extends State<BarcodeScannerWithController> | ||
| 14 | + with SingleTickerProviderStateMixin { | ||
| 15 | + String? barcode; | ||
| 16 | + | ||
| 17 | + MobileScannerController controller = MobileScannerController( | ||
| 18 | + torchEnabled: true, | ||
| 19 | + // facing: CameraFacing.front, | ||
| 20 | + ); | ||
| 21 | + | ||
| 22 | + @override | ||
| 23 | + Widget build(BuildContext context) { | ||
| 24 | + return MaterialApp( | ||
| 25 | + home: Scaffold( | ||
| 26 | + backgroundColor: Colors.black, | ||
| 27 | + body: Builder(builder: (context) { | ||
| 28 | + return Stack( | ||
| 29 | + children: [ | ||
| 30 | + MobileScanner( | ||
| 31 | + controller: controller, | ||
| 32 | + fit: BoxFit.contain, | ||
| 33 | + // controller: MobileScannerController( | ||
| 34 | + // torchEnabled: true, | ||
| 35 | + // facing: CameraFacing.front, | ||
| 36 | + // ), | ||
| 37 | + onDetect: (barcode, args) { | ||
| 38 | + if (this.barcode != barcode.rawValue) { | ||
| 39 | + setState(() { | ||
| 40 | + this.barcode = barcode.rawValue; | ||
| 41 | + }); | ||
| 42 | + } | ||
| 43 | + }), | ||
| 44 | + Align( | ||
| 45 | + alignment: Alignment.bottomCenter, | ||
| 46 | + child: Container( | ||
| 47 | + alignment: Alignment.bottomCenter, | ||
| 48 | + height: 100, | ||
| 49 | + color: Colors.black.withOpacity(0.4), | ||
| 50 | + child: Row( | ||
| 51 | + crossAxisAlignment: CrossAxisAlignment.center, | ||
| 52 | + mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||
| 53 | + children: [ | ||
| 54 | + IconButton( | ||
| 55 | + color: Colors.white, | ||
| 56 | + icon: ValueListenableBuilder( | ||
| 57 | + valueListenable: controller.torchState, | ||
| 58 | + builder: (context, state, child) { | ||
| 59 | + switch (state as TorchState) { | ||
| 60 | + case TorchState.off: | ||
| 61 | + return const Icon(Icons.flash_off, | ||
| 62 | + color: Colors.grey); | ||
| 63 | + case TorchState.on: | ||
| 64 | + return const Icon(Icons.flash_on, | ||
| 65 | + color: Colors.yellow); | ||
| 66 | + } | ||
| 67 | + }, | ||
| 68 | + ), | ||
| 69 | + iconSize: 32.0, | ||
| 70 | + onPressed: () => controller.toggleTorch(), | ||
| 71 | + ), | ||
| 72 | + Center( | ||
| 73 | + child: SizedBox( | ||
| 74 | + width: MediaQuery.of(context).size.width - 120, | ||
| 75 | + height: 50, | ||
| 76 | + child: FittedBox( | ||
| 77 | + child: Text( | ||
| 78 | + barcode ?? 'Scan something!', | ||
| 79 | + overflow: TextOverflow.fade, | ||
| 80 | + style: Theme.of(context) | ||
| 81 | + .textTheme | ||
| 82 | + .headline4! | ||
| 83 | + .copyWith(color: Colors.white), | ||
| 84 | + ), | ||
| 85 | + ), | ||
| 86 | + ), | ||
| 87 | + ), | ||
| 88 | + IconButton( | ||
| 89 | + color: Colors.white, | ||
| 90 | + icon: ValueListenableBuilder( | ||
| 91 | + valueListenable: controller.cameraFacingState, | ||
| 92 | + builder: (context, state, child) { | ||
| 93 | + switch (state as CameraFacing) { | ||
| 94 | + case CameraFacing.front: | ||
| 95 | + return const Icon(Icons.camera_front); | ||
| 96 | + case CameraFacing.back: | ||
| 97 | + return const Icon(Icons.camera_rear); | ||
| 98 | + } | ||
| 99 | + }, | ||
| 100 | + ), | ||
| 101 | + iconSize: 32.0, | ||
| 102 | + onPressed: () => controller.switchCamera(), | ||
| 103 | + ), | ||
| 104 | + ], | ||
| 105 | + ), | ||
| 106 | + ), | ||
| 107 | + ), | ||
| 108 | + ], | ||
| 109 | + ); | ||
| 110 | + }), | ||
| 111 | + ), | ||
| 112 | + ); | ||
| 113 | + } | ||
| 114 | +} |
| 1 | +import 'package:flutter/material.dart'; | ||
| 2 | +import 'package:mobile_scanner/mobile_scanner.dart'; | ||
| 3 | + | ||
| 4 | +class BarcodeScannerWithoutController extends StatefulWidget { | ||
| 5 | + const BarcodeScannerWithoutController({Key? key}) : super(key: key); | ||
| 6 | + | ||
| 7 | + @override | ||
| 8 | + _BarcodeScannerWithoutControllerState createState() => | ||
| 9 | + _BarcodeScannerWithoutControllerState(); | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +class _BarcodeScannerWithoutControllerState | ||
| 13 | + extends State<BarcodeScannerWithoutController> | ||
| 14 | + with SingleTickerProviderStateMixin { | ||
| 15 | + String? barcode; | ||
| 16 | + | ||
| 17 | + @override | ||
| 18 | + Widget build(BuildContext context) { | ||
| 19 | + return MaterialApp( | ||
| 20 | + home: Scaffold( | ||
| 21 | + backgroundColor: Colors.black, | ||
| 22 | + body: Builder(builder: (context) { | ||
| 23 | + return Stack( | ||
| 24 | + children: [ | ||
| 25 | + MobileScanner( | ||
| 26 | + fit: BoxFit.contain, | ||
| 27 | + onDetect: (barcode, args) { | ||
| 28 | + if (this.barcode != barcode.rawValue) { | ||
| 29 | + setState(() { | ||
| 30 | + this.barcode = barcode.rawValue; | ||
| 31 | + }); | ||
| 32 | + } | ||
| 33 | + }), | ||
| 34 | + Align( | ||
| 35 | + alignment: Alignment.bottomCenter, | ||
| 36 | + child: Container( | ||
| 37 | + alignment: Alignment.bottomCenter, | ||
| 38 | + height: 100, | ||
| 39 | + color: Colors.black.withOpacity(0.4), | ||
| 40 | + child: Row( | ||
| 41 | + crossAxisAlignment: CrossAxisAlignment.center, | ||
| 42 | + mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||
| 43 | + children: [ | ||
| 44 | + Center( | ||
| 45 | + child: SizedBox( | ||
| 46 | + width: MediaQuery.of(context).size.width - 120, | ||
| 47 | + height: 50, | ||
| 48 | + child: FittedBox( | ||
| 49 | + child: Text( | ||
| 50 | + barcode ?? 'Scan something!', | ||
| 51 | + overflow: TextOverflow.fade, | ||
| 52 | + style: Theme.of(context) | ||
| 53 | + .textTheme | ||
| 54 | + .headline4! | ||
| 55 | + .copyWith(color: Colors.white), | ||
| 56 | + ), | ||
| 57 | + ), | ||
| 58 | + ), | ||
| 59 | + ), | ||
| 60 | + ], | ||
| 61 | + ), | ||
| 62 | + ), | ||
| 63 | + ), | ||
| 64 | + ], | ||
| 65 | + ); | ||
| 66 | + }), | ||
| 67 | + ), | ||
| 68 | + ); | ||
| 69 | + } | ||
| 70 | +} |
| 1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
| 2 | -import 'package:mobile_scanner/mobile_scanner.dart'; | 2 | +import 'package:mobile_scanner_example/barcode_scanner_controller.dart'; |
| 3 | +import 'package:mobile_scanner_example/barcode_scanner_without_controller.dart'; | ||
| 3 | 4 | ||
| 4 | -void main() { | ||
| 5 | - runApp(const AnalyzeView()); | ||
| 6 | -} | 5 | +void main() => runApp(const MaterialApp(home: MyHome())); |
| 7 | 6 | ||
| 8 | -class AnalyzeView extends StatefulWidget { | ||
| 9 | - const AnalyzeView({Key? key}) : super(key: key); | ||
| 10 | - | ||
| 11 | - @override | ||
| 12 | - _AnalyzeViewState createState() => _AnalyzeViewState(); | ||
| 13 | -} | ||
| 14 | - | ||
| 15 | -class _AnalyzeViewState extends State<AnalyzeView> | ||
| 16 | - with SingleTickerProviderStateMixin { | ||
| 17 | - String? barcode; | ||
| 18 | - | ||
| 19 | - MobileScannerController controller = MobileScannerController( | ||
| 20 | - torchEnabled: true, | ||
| 21 | - facing: CameraFacing.front, | ||
| 22 | - ); | 7 | +class MyHome extends StatelessWidget { |
| 8 | + const MyHome({Key? key}) : super(key: key); | ||
| 23 | 9 | ||
| 24 | @override | 10 | @override |
| 25 | Widget build(BuildContext context) { | 11 | Widget build(BuildContext context) { |
| 26 | - return MaterialApp( | ||
| 27 | - home: Scaffold( | ||
| 28 | - backgroundColor: Colors.black, | ||
| 29 | - body: Builder(builder: (context) { | ||
| 30 | - return Stack( | ||
| 31 | - children: [ | ||
| 32 | - MobileScanner( | ||
| 33 | - controller: controller, | ||
| 34 | - fit: BoxFit.contain, | ||
| 35 | - // controller: MobileScannerController( | ||
| 36 | - // torchEnabled: true, | ||
| 37 | - // facing: CameraFacing.front, | ||
| 38 | - // ), | ||
| 39 | - onDetect: (barcode, args) { | ||
| 40 | - if (this.barcode != barcode.rawValue) { | ||
| 41 | - setState(() { | ||
| 42 | - this.barcode = barcode.rawValue; | ||
| 43 | - }); | ||
| 44 | - } | ||
| 45 | - }), | ||
| 46 | - Align( | ||
| 47 | - alignment: Alignment.bottomCenter, | ||
| 48 | - child: Container( | ||
| 49 | - alignment: Alignment.bottomCenter, | ||
| 50 | - height: 100, | ||
| 51 | - color: Colors.black.withOpacity(0.4), | ||
| 52 | - child: Row( | ||
| 53 | - crossAxisAlignment: CrossAxisAlignment.center, | ||
| 54 | - mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||
| 55 | - children: [ | ||
| 56 | - IconButton( | ||
| 57 | - color: Colors.white, | ||
| 58 | - icon: ValueListenableBuilder( | ||
| 59 | - valueListenable: controller.torchState, | ||
| 60 | - builder: (context, state, child) { | ||
| 61 | - switch (state as TorchState) { | ||
| 62 | - case TorchState.off: | ||
| 63 | - return const Icon(Icons.flash_off, | ||
| 64 | - color: Colors.grey); | ||
| 65 | - case TorchState.on: | ||
| 66 | - return const Icon(Icons.flash_on, | ||
| 67 | - color: Colors.yellow); | ||
| 68 | - } | ||
| 69 | - }, | ||
| 70 | - ), | ||
| 71 | - iconSize: 32.0, | ||
| 72 | - onPressed: () => controller.toggleTorch(), | ||
| 73 | - ), | ||
| 74 | - Center( | ||
| 75 | - child: SizedBox( | ||
| 76 | - width: MediaQuery.of(context).size.width - 120, | ||
| 77 | - height: 50, | ||
| 78 | - child: FittedBox( | ||
| 79 | - child: Text( | ||
| 80 | - barcode ?? 'Scan something!', | ||
| 81 | - overflow: TextOverflow.fade, | ||
| 82 | - style: Theme.of(context) | ||
| 83 | - .textTheme | ||
| 84 | - .headline4! | ||
| 85 | - .copyWith(color: Colors.white), | ||
| 86 | - ), | ||
| 87 | - ), | ||
| 88 | - ), | ||
| 89 | - ), | ||
| 90 | - IconButton( | ||
| 91 | - color: Colors.white, | ||
| 92 | - icon: ValueListenableBuilder( | ||
| 93 | - valueListenable: controller.cameraFacingState, | ||
| 94 | - builder: (context, state, child) { | ||
| 95 | - switch (state as CameraFacing) { | ||
| 96 | - case CameraFacing.front: | ||
| 97 | - return const Icon(Icons.camera_front); | ||
| 98 | - case CameraFacing.back: | ||
| 99 | - return const Icon(Icons.camera_rear); | ||
| 100 | - } | ||
| 101 | - }, | ||
| 102 | - ), | ||
| 103 | - iconSize: 32.0, | ||
| 104 | - onPressed: () => controller.switchCamera(), | ||
| 105 | - ), | ||
| 106 | - ], | ||
| 107 | - ), | ||
| 108 | - ), | ||
| 109 | - ), | ||
| 110 | - | ||
| 111 | - // Container( | ||
| 112 | - // alignment: Alignment.bottomCenter, | ||
| 113 | - // margin: EdgeInsets.only(bottom: 80.0), | ||
| 114 | - // child: IconButton( | ||
| 115 | - // icon: ValueListenableBuilder( | ||
| 116 | - // valueListenable: cameraController.torchState, | ||
| 117 | - // builder: (context, state, child) { | ||
| 118 | - // final color = | ||
| 119 | - // state == TorchState.off ? Colors.grey : Colors.white; | ||
| 120 | - // return Icon(Icons.bolt, color: color); | ||
| 121 | - // }, | ||
| 122 | - // ), | ||
| 123 | - // iconSize: 32.0, | ||
| 124 | - // onPressed: () => cameraController.torch(), | ||
| 125 | - // ), | ||
| 126 | - // ), | ||
| 127 | - ], | ||
| 128 | - ); | ||
| 129 | - }), | 12 | + return Scaffold( |
| 13 | + appBar: AppBar(title: const Text('Flutter Demo Home Page')), | ||
| 14 | + body: SizedBox( | ||
| 15 | + width: MediaQuery.of(context).size.width, | ||
| 16 | + height: MediaQuery.of(context).size.height, | ||
| 17 | + child: Column( | ||
| 18 | + mainAxisAlignment: MainAxisAlignment.center, | ||
| 19 | + crossAxisAlignment: CrossAxisAlignment.center, | ||
| 20 | + children: [ | ||
| 21 | + ElevatedButton( | ||
| 22 | + onPressed: () { | ||
| 23 | + Navigator.of(context).push(MaterialPageRoute( | ||
| 24 | + builder: (context) => const BarcodeScannerWithController(), | ||
| 25 | + )); | ||
| 26 | + }, | ||
| 27 | + child: const Text('MobileScanner with Controller'), | ||
| 28 | + ), | ||
| 29 | + ElevatedButton( | ||
| 30 | + onPressed: () { | ||
| 31 | + Navigator.of(context).push(MaterialPageRoute( | ||
| 32 | + builder: (context) => const BarcodeScannerWithoutController(), | ||
| 33 | + )); | ||
| 34 | + }, | ||
| 35 | + child: const Text('MobileScanner without Controller'), | ||
| 36 | + ), | ||
| 37 | + ], | ||
| 38 | + ), | ||
| 130 | ), | 39 | ), |
| 131 | ); | 40 | ); |
| 132 | } | 41 | } |
| 133 | - | ||
| 134 | - @override | ||
| 135 | - void dispose() { | ||
| 136 | - // cameraController.dispose(); | ||
| 137 | - super.dispose(); | ||
| 138 | - } | ||
| 139 | - | ||
| 140 | - void display(Barcode barcode) { | ||
| 141 | - Navigator.of(context).popAndPushNamed('display', arguments: barcode); | ||
| 142 | - } | ||
| 143 | } | 42 | } |
| 144 | - | ||
| 145 | -// import 'package:flutter/material.dart'; | ||
| 146 | -// import 'package:flutter/rendering.dart'; | ||
| 147 | -// import 'package:mobile_scanner/mobile_scanner.dart'; | ||
| 148 | -// | ||
| 149 | -// void main() { | ||
| 150 | -// debugPaintSizeEnabled = false; | ||
| 151 | -// runApp(HomePage()); | ||
| 152 | -// } | ||
| 153 | -// | ||
| 154 | -// class HomePage extends StatefulWidget { | ||
| 155 | -// @override | ||
| 156 | -// HomeState createState() => HomeState(); | ||
| 157 | -// } | ||
| 158 | -// | ||
| 159 | -// class HomeState extends State<HomePage> { | ||
| 160 | -// @override | ||
| 161 | -// Widget build(BuildContext context) { | ||
| 162 | -// return MaterialApp(home: MyApp()); | ||
| 163 | -// } | ||
| 164 | -// } | ||
| 165 | -// | ||
| 166 | -// class MyApp extends StatefulWidget { | ||
| 167 | -// @override | ||
| 168 | -// _MyAppState createState() => _MyAppState(); | ||
| 169 | -// } | ||
| 170 | -// | ||
| 171 | -// class _MyAppState extends State<MyApp> { | ||
| 172 | -// String? qr; | ||
| 173 | -// bool camState = false; | ||
| 174 | -// | ||
| 175 | -// @override | ||
| 176 | -// initState() { | ||
| 177 | -// super.initState(); | ||
| 178 | -// } | ||
| 179 | -// | ||
| 180 | -// @override | ||
| 181 | -// Widget build(BuildContext context) { | ||
| 182 | -// return Scaffold( | ||
| 183 | -// appBar: AppBar( | ||
| 184 | -// title: Text('Plugin example app'), | ||
| 185 | -// ), | ||
| 186 | -// body: Center( | ||
| 187 | -// child: Column( | ||
| 188 | -// crossAxisAlignment: CrossAxisAlignment.center, | ||
| 189 | -// mainAxisAlignment: MainAxisAlignment.center, | ||
| 190 | -// children: <Widget>[ | ||
| 191 | -// Expanded( | ||
| 192 | -// child: camState | ||
| 193 | -// ? Center( | ||
| 194 | -// child: SizedBox( | ||
| 195 | -// width: 300.0, | ||
| 196 | -// height: 600.0, | ||
| 197 | -// child: MobileScanner( | ||
| 198 | -// onError: (context, error) => Text( | ||
| 199 | -// error.toString(), | ||
| 200 | -// style: TextStyle(color: Colors.red), | ||
| 201 | -// ), | ||
| 202 | -// qrCodeCallback: (code) { | ||
| 203 | -// setState(() { | ||
| 204 | -// qr = code; | ||
| 205 | -// }); | ||
| 206 | -// }, | ||
| 207 | -// child: Container( | ||
| 208 | -// decoration: BoxDecoration( | ||
| 209 | -// color: Colors.transparent, | ||
| 210 | -// border: Border.all( | ||
| 211 | -// color: Colors.orange, | ||
| 212 | -// width: 10.0, | ||
| 213 | -// style: BorderStyle.solid), | ||
| 214 | -// ), | ||
| 215 | -// ), | ||
| 216 | -// ), | ||
| 217 | -// ), | ||
| 218 | -// ) | ||
| 219 | -// : Center(child: Text("Camera inactive"))), | ||
| 220 | -// Text("QRCODE: $qr"), | ||
| 221 | -// ], | ||
| 222 | -// ), | ||
| 223 | -// ), | ||
| 224 | -// floatingActionButton: FloatingActionButton( | ||
| 225 | -// child: Text( | ||
| 226 | -// "press me", | ||
| 227 | -// textAlign: TextAlign.center, | ||
| 228 | -// ), | ||
| 229 | -// onPressed: () { | ||
| 230 | -// setState(() { | ||
| 231 | -// camState = !camState; | ||
| 232 | -// }); | ||
| 233 | -// }), | ||
| 234 | -// ); | ||
| 235 | -// } | ||
| 236 | -// } |
| 1 | -platform :osx, '10.11' | 1 | +platform :osx, '10.13' |
| 2 | 2 | ||
| 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. |
| 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' | 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' |
| @@ -26,7 +26,7 @@ | @@ -26,7 +26,7 @@ | ||
| 26 | 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; | 26 | 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; |
| 27 | 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; | 27 | 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; |
| 28 | 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; | 28 | 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; |
| 29 | - 5225F51353DA345E2811B6A4 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65E614A1DF8B88C7B0CE1B97 /* Pods_Runner.framework */; }; | 29 | + 5B9BD2ADBC68B74D80B57DF1 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EC099C2B6D6B30BFB3FA6DB8 /* Pods_Runner.framework */; }; |
| 30 | /* End PBXBuildFile section */ | 30 | /* End PBXBuildFile section */ |
| 31 | 31 | ||
| 32 | /* Begin PBXContainerItemProxy section */ | 32 | /* Begin PBXContainerItemProxy section */ |
| @@ -67,12 +67,12 @@ | @@ -67,12 +67,12 @@ | ||
| 67 | 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; }; | 67 | 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; }; |
| 68 | 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; }; | 68 | 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; }; |
| 69 | 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; }; | 69 | 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; }; |
| 70 | - 65E614A1DF8B88C7B0CE1B97 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; | 70 | + 3CEE8DB43A84811F33EB0202 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; }; |
| 71 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; }; | 71 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; }; |
| 72 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; }; | 72 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; }; |
| 73 | - CB0901144E09E7D7CA20584F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; }; | ||
| 74 | - D522F9F6F348C5944077606B /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; }; | ||
| 75 | - F63009B5E287A1C82F9D7D2F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; }; | 73 | + A1CBC07680A8ED396DBB68C0 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; }; |
| 74 | + CAD760C57A57D903AB03B47A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; }; | ||
| 75 | + EC099C2B6D6B30BFB3FA6DB8 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; | ||
| 76 | /* End PBXFileReference section */ | 76 | /* End PBXFileReference section */ |
| 77 | 77 | ||
| 78 | /* Begin PBXFrameworksBuildPhase section */ | 78 | /* Begin PBXFrameworksBuildPhase section */ |
| @@ -80,19 +80,27 @@ | @@ -80,19 +80,27 @@ | ||
| 80 | isa = PBXFrameworksBuildPhase; | 80 | isa = PBXFrameworksBuildPhase; |
| 81 | buildActionMask = 2147483647; | 81 | buildActionMask = 2147483647; |
| 82 | files = ( | 82 | files = ( |
| 83 | - 5225F51353DA345E2811B6A4 /* Pods_Runner.framework in Frameworks */, | 83 | + 5B9BD2ADBC68B74D80B57DF1 /* Pods_Runner.framework in Frameworks */, |
| 84 | ); | 84 | ); |
| 85 | runOnlyForDeploymentPostprocessing = 0; | 85 | runOnlyForDeploymentPostprocessing = 0; |
| 86 | }; | 86 | }; |
| 87 | /* End PBXFrameworksBuildPhase section */ | 87 | /* End PBXFrameworksBuildPhase section */ |
| 88 | 88 | ||
| 89 | /* Begin PBXGroup section */ | 89 | /* Begin PBXGroup section */ |
| 90 | + 18927D60C719EB75FC0A6633 /* Frameworks */ = { | ||
| 91 | + isa = PBXGroup; | ||
| 92 | + children = ( | ||
| 93 | + EC099C2B6D6B30BFB3FA6DB8 /* Pods_Runner.framework */, | ||
| 94 | + ); | ||
| 95 | + name = Frameworks; | ||
| 96 | + sourceTree = "<group>"; | ||
| 97 | + }; | ||
| 90 | 20F8C9AA20C2A495C125E194 /* Pods */ = { | 98 | 20F8C9AA20C2A495C125E194 /* Pods */ = { |
| 91 | isa = PBXGroup; | 99 | isa = PBXGroup; |
| 92 | children = ( | 100 | children = ( |
| 93 | - CB0901144E09E7D7CA20584F /* Pods-Runner.debug.xcconfig */, | ||
| 94 | - D522F9F6F348C5944077606B /* Pods-Runner.release.xcconfig */, | ||
| 95 | - F63009B5E287A1C82F9D7D2F /* Pods-Runner.profile.xcconfig */, | 101 | + CAD760C57A57D903AB03B47A /* Pods-Runner.debug.xcconfig */, |
| 102 | + A1CBC07680A8ED396DBB68C0 /* Pods-Runner.release.xcconfig */, | ||
| 103 | + 3CEE8DB43A84811F33EB0202 /* Pods-Runner.profile.xcconfig */, | ||
| 96 | ); | 104 | ); |
| 97 | path = Pods; | 105 | path = Pods; |
| 98 | sourceTree = "<group>"; | 106 | sourceTree = "<group>"; |
| @@ -115,7 +123,7 @@ | @@ -115,7 +123,7 @@ | ||
| 115 | 33CEB47122A05771004F2AC0 /* Flutter */, | 123 | 33CEB47122A05771004F2AC0 /* Flutter */, |
| 116 | 33CC10EE2044A3C60003C045 /* Products */, | 124 | 33CC10EE2044A3C60003C045 /* Products */, |
| 117 | 20F8C9AA20C2A495C125E194 /* Pods */, | 125 | 20F8C9AA20C2A495C125E194 /* Pods */, |
| 118 | - 3539353E79638640B4999C09 /* Frameworks */, | 126 | + 18927D60C719EB75FC0A6633 /* Frameworks */, |
| 119 | ); | 127 | ); |
| 120 | sourceTree = "<group>"; | 128 | sourceTree = "<group>"; |
| 121 | }; | 129 | }; |
| @@ -162,14 +170,6 @@ | @@ -162,14 +170,6 @@ | ||
| 162 | path = Runner; | 170 | path = Runner; |
| 163 | sourceTree = "<group>"; | 171 | sourceTree = "<group>"; |
| 164 | }; | 172 | }; |
| 165 | - 3539353E79638640B4999C09 /* Frameworks */ = { | ||
| 166 | - isa = PBXGroup; | ||
| 167 | - children = ( | ||
| 168 | - 65E614A1DF8B88C7B0CE1B97 /* Pods_Runner.framework */, | ||
| 169 | - ); | ||
| 170 | - name = Frameworks; | ||
| 171 | - sourceTree = "<group>"; | ||
| 172 | - }; | ||
| 173 | /* End PBXGroup section */ | 173 | /* End PBXGroup section */ |
| 174 | 174 | ||
| 175 | /* Begin PBXNativeTarget section */ | 175 | /* Begin PBXNativeTarget section */ |
| @@ -177,13 +177,13 @@ | @@ -177,13 +177,13 @@ | ||
| 177 | isa = PBXNativeTarget; | 177 | isa = PBXNativeTarget; |
| 178 | buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; | 178 | buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; |
| 179 | buildPhases = ( | 179 | buildPhases = ( |
| 180 | - 696298230BDAD783AEC51C81 /* [CP] Check Pods Manifest.lock */, | 180 | + 20903D1E9D9F08576541FFD7 /* [CP] Check Pods Manifest.lock */, |
| 181 | 33CC10E92044A3C60003C045 /* Sources */, | 181 | 33CC10E92044A3C60003C045 /* Sources */, |
| 182 | 33CC10EA2044A3C60003C045 /* Frameworks */, | 182 | 33CC10EA2044A3C60003C045 /* Frameworks */, |
| 183 | 33CC10EB2044A3C60003C045 /* Resources */, | 183 | 33CC10EB2044A3C60003C045 /* Resources */, |
| 184 | 33CC110E2044A8840003C045 /* Bundle Framework */, | 184 | 33CC110E2044A8840003C045 /* Bundle Framework */, |
| 185 | 3399D490228B24CF009A79C7 /* ShellScript */, | 185 | 3399D490228B24CF009A79C7 /* ShellScript */, |
| 186 | - 8A90D2BC4083C5ACCEEBF32B /* [CP] Embed Pods Frameworks */, | 186 | + DF45614760BB9B24F49B2055 /* [CP] Embed Pods Frameworks */, |
| 187 | ); | 187 | ); |
| 188 | buildRules = ( | 188 | buildRules = ( |
| 189 | ); | 189 | ); |
| @@ -253,7 +253,7 @@ | @@ -253,7 +253,7 @@ | ||
| 253 | /* End PBXResourcesBuildPhase section */ | 253 | /* End PBXResourcesBuildPhase section */ |
| 254 | 254 | ||
| 255 | /* Begin PBXShellScriptBuildPhase section */ | 255 | /* Begin PBXShellScriptBuildPhase section */ |
| 256 | - 3399D490228B24CF009A79C7 /* ShellScript */ = { | 256 | + 20903D1E9D9F08576541FFD7 /* [CP] Check Pods Manifest.lock */ = { |
| 257 | isa = PBXShellScriptBuildPhase; | 257 | isa = PBXShellScriptBuildPhase; |
| 258 | buildActionMask = 2147483647; | 258 | buildActionMask = 2147483647; |
| 259 | files = ( | 259 | files = ( |
| @@ -261,58 +261,58 @@ | @@ -261,58 +261,58 @@ | ||
| 261 | inputFileListPaths = ( | 261 | inputFileListPaths = ( |
| 262 | ); | 262 | ); |
| 263 | inputPaths = ( | 263 | inputPaths = ( |
| 264 | + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", | ||
| 265 | + "${PODS_ROOT}/Manifest.lock", | ||
| 264 | ); | 266 | ); |
| 267 | + name = "[CP] Check Pods Manifest.lock"; | ||
| 265 | outputFileListPaths = ( | 268 | outputFileListPaths = ( |
| 266 | ); | 269 | ); |
| 267 | outputPaths = ( | 270 | outputPaths = ( |
| 271 | + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", | ||
| 268 | ); | 272 | ); |
| 269 | runOnlyForDeploymentPostprocessing = 0; | 273 | runOnlyForDeploymentPostprocessing = 0; |
| 270 | shellPath = /bin/sh; | 274 | shellPath = /bin/sh; |
| 271 | - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; | 275 | + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; |
| 276 | + showEnvVarsInLog = 0; | ||
| 272 | }; | 277 | }; |
| 273 | - 33CC111E2044C6BF0003C045 /* ShellScript */ = { | 278 | + 3399D490228B24CF009A79C7 /* ShellScript */ = { |
| 274 | isa = PBXShellScriptBuildPhase; | 279 | isa = PBXShellScriptBuildPhase; |
| 275 | buildActionMask = 2147483647; | 280 | buildActionMask = 2147483647; |
| 276 | files = ( | 281 | files = ( |
| 277 | ); | 282 | ); |
| 278 | inputFileListPaths = ( | 283 | inputFileListPaths = ( |
| 279 | - Flutter/ephemeral/FlutterInputs.xcfilelist, | ||
| 280 | ); | 284 | ); |
| 281 | inputPaths = ( | 285 | inputPaths = ( |
| 282 | - Flutter/ephemeral/tripwire, | ||
| 283 | ); | 286 | ); |
| 284 | outputFileListPaths = ( | 287 | outputFileListPaths = ( |
| 285 | - Flutter/ephemeral/FlutterOutputs.xcfilelist, | ||
| 286 | ); | 288 | ); |
| 287 | outputPaths = ( | 289 | outputPaths = ( |
| 288 | ); | 290 | ); |
| 289 | runOnlyForDeploymentPostprocessing = 0; | 291 | runOnlyForDeploymentPostprocessing = 0; |
| 290 | shellPath = /bin/sh; | 292 | shellPath = /bin/sh; |
| 291 | - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; | 293 | + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; |
| 292 | }; | 294 | }; |
| 293 | - 696298230BDAD783AEC51C81 /* [CP] Check Pods Manifest.lock */ = { | 295 | + 33CC111E2044C6BF0003C045 /* ShellScript */ = { |
| 294 | isa = PBXShellScriptBuildPhase; | 296 | isa = PBXShellScriptBuildPhase; |
| 295 | buildActionMask = 2147483647; | 297 | buildActionMask = 2147483647; |
| 296 | files = ( | 298 | files = ( |
| 297 | ); | 299 | ); |
| 298 | inputFileListPaths = ( | 300 | inputFileListPaths = ( |
| 301 | + Flutter/ephemeral/FlutterInputs.xcfilelist, | ||
| 299 | ); | 302 | ); |
| 300 | inputPaths = ( | 303 | inputPaths = ( |
| 301 | - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", | ||
| 302 | - "${PODS_ROOT}/Manifest.lock", | 304 | + Flutter/ephemeral/tripwire, |
| 303 | ); | 305 | ); |
| 304 | - name = "[CP] Check Pods Manifest.lock"; | ||
| 305 | outputFileListPaths = ( | 306 | outputFileListPaths = ( |
| 307 | + Flutter/ephemeral/FlutterOutputs.xcfilelist, | ||
| 306 | ); | 308 | ); |
| 307 | outputPaths = ( | 309 | outputPaths = ( |
| 308 | - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", | ||
| 309 | ); | 310 | ); |
| 310 | runOnlyForDeploymentPostprocessing = 0; | 311 | runOnlyForDeploymentPostprocessing = 0; |
| 311 | shellPath = /bin/sh; | 312 | shellPath = /bin/sh; |
| 312 | - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; | ||
| 313 | - showEnvVarsInLog = 0; | 313 | + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; |
| 314 | }; | 314 | }; |
| 315 | - 8A90D2BC4083C5ACCEEBF32B /* [CP] Embed Pods Frameworks */ = { | 315 | + DF45614760BB9B24F49B2055 /* [CP] Embed Pods Frameworks */ = { |
| 316 | isa = PBXShellScriptBuildPhase; | 316 | isa = PBXShellScriptBuildPhase; |
| 317 | buildActionMask = 2147483647; | 317 | buildActionMask = 2147483647; |
| 318 | files = ( | 318 | files = ( |
| @@ -3,7 +3,7 @@ description: Demonstrates how to use the mobile_scanner plugin. | @@ -3,7 +3,7 @@ description: Demonstrates how to use the mobile_scanner plugin. | ||
| 3 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev | 3 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev |
| 4 | 4 | ||
| 5 | environment: | 5 | environment: |
| 6 | - sdk: ">=2.16.0 <3.0.0" | 6 | + sdk: ">=2.12.0 <3.0.0" |
| 7 | 7 | ||
| 8 | dependencies: | 8 | dependencies: |
| 9 | flutter: | 9 | flutter: |
| @@ -23,7 +23,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | @@ -23,7 +23,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | ||
| 23 | var latestBuffer: CVImageBuffer! | 23 | var latestBuffer: CVImageBuffer! |
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | - var analyzeMode: Int = 0 | 26 | +// var analyzeMode: Int = 0 |
| 27 | var analyzing: Bool = false | 27 | var analyzing: Bool = false |
| 28 | var position = AVCaptureDevice.Position.back | 28 | var position = AVCaptureDevice.Position.back |
| 29 | 29 | ||
| @@ -53,9 +53,9 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | @@ -53,9 +53,9 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | ||
| 53 | case "start": | 53 | case "start": |
| 54 | start(call, result) | 54 | start(call, result) |
| 55 | case "torch": | 55 | case "torch": |
| 56 | - switchTorch(call, result) | ||
| 57 | - case "analyze": | ||
| 58 | - switchAnalyzeMode(call, result) | 56 | + toggleTorch(call, result) |
| 57 | +// case "analyze": | ||
| 58 | +// switchAnalyzeMode(call, result) | ||
| 59 | case "stop": | 59 | case "stop": |
| 60 | stop(result) | 60 | stop(result) |
| 61 | default: | 61 | default: |
| @@ -89,10 +89,10 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | @@ -89,10 +89,10 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | ||
| 89 | latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) | 89 | latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) |
| 90 | registry.textureFrameAvailable(textureId) | 90 | registry.textureFrameAvailable(textureId) |
| 91 | 91 | ||
| 92 | - switch analyzeMode { | ||
| 93 | - case 1: // barcode | 92 | +// switch analyzeMode { |
| 93 | +// case 1: // barcode | ||
| 94 | if analyzing { | 94 | if analyzing { |
| 95 | - break | 95 | + return |
| 96 | } | 96 | } |
| 97 | analyzing = true | 97 | analyzing = true |
| 98 | let buffer = CMSampleBufferGetImageBuffer(sampleBuffer) | 98 | let buffer = CMSampleBufferGetImageBuffer(sampleBuffer) |
| @@ -112,9 +112,9 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | @@ -112,9 +112,9 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | ||
| 112 | } | 112 | } |
| 113 | analyzing = false | 113 | analyzing = false |
| 114 | } | 114 | } |
| 115 | - default: // none | ||
| 116 | - break | ||
| 117 | - } | 115 | +// default: // none |
| 116 | +// break | ||
| 117 | +// } | ||
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | func imageOrientation( | 120 | func imageOrientation( |
| @@ -154,6 +154,13 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | @@ -154,6 +154,13 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | ||
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | func start(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { | 156 | func start(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { |
| 157 | + if (device != nil) { | ||
| 158 | + result(FlutterError(code: "MobileScanner", | ||
| 159 | + message: "Called start() while already started!", | ||
| 160 | + details: nil)) | ||
| 161 | + return | ||
| 162 | + } | ||
| 163 | + | ||
| 157 | textureId = registry.register(self) | 164 | textureId = registry.register(self) |
| 158 | captureSession = AVCaptureSession() | 165 | captureSession = AVCaptureSession() |
| 159 | 166 | ||
| @@ -173,6 +180,13 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | @@ -173,6 +180,13 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | ||
| 173 | device = AVCaptureDevice.devices(for: .video).filter({$0.position == position}).first | 180 | device = AVCaptureDevice.devices(for: .video).filter({$0.position == position}).first |
| 174 | } | 181 | } |
| 175 | 182 | ||
| 183 | + if (device == nil) { | ||
| 184 | + result(FlutterError(code: "MobileScanner", | ||
| 185 | + message: "No camera found or failed to open camera!", | ||
| 186 | + details: nil)) | ||
| 187 | + return | ||
| 188 | + } | ||
| 189 | + | ||
| 176 | // Enable the torch if parameter is set and torch is available | 190 | // Enable the torch if parameter is set and torch is available |
| 177 | if (device.hasTorch && device.isTorchAvailable) { | 191 | if (device.hasTorch && device.isTorchAvailable) { |
| 178 | do { | 192 | do { |
| @@ -219,7 +233,13 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | @@ -219,7 +233,13 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | ||
| 219 | result(answer) | 233 | result(answer) |
| 220 | } | 234 | } |
| 221 | 235 | ||
| 222 | - func switchTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { | 236 | + func toggleTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { |
| 237 | + if (device == nil) { | ||
| 238 | + result(FlutterError(code: "MobileScanner", | ||
| 239 | + message: "Called toggleTorch() while stopped!", | ||
| 240 | + details: nil)) | ||
| 241 | + return | ||
| 242 | + } | ||
| 223 | do { | 243 | do { |
| 224 | try device.lockForConfiguration() | 244 | try device.lockForConfiguration() |
| 225 | device.torchMode = call.arguments as! Int == 1 ? .on : .off | 245 | device.torchMode = call.arguments as! Int == 1 ? .on : .off |
| @@ -230,12 +250,18 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | @@ -230,12 +250,18 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | ||
| 230 | } | 250 | } |
| 231 | } | 251 | } |
| 232 | 252 | ||
| 233 | - func switchAnalyzeMode(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { | ||
| 234 | - analyzeMode = call.arguments as! Int | ||
| 235 | - result(nil) | ||
| 236 | - } | 253 | +// func switchAnalyzeMode(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { |
| 254 | +// analyzeMode = call.arguments as! Int | ||
| 255 | +// result(nil) | ||
| 256 | +// } | ||
| 237 | 257 | ||
| 238 | func stop(_ result: FlutterResult) { | 258 | func stop(_ result: FlutterResult) { |
| 259 | + if (device == nil) { | ||
| 260 | + result(FlutterError(code: "MobileScanner", | ||
| 261 | + message: "Called stop() while already stopped!", | ||
| 262 | + details: nil)) | ||
| 263 | + return | ||
| 264 | + } | ||
| 239 | captureSession.stopRunning() | 265 | captureSession.stopRunning() |
| 240 | for input in captureSession.inputs { | 266 | for input in captureSession.inputs { |
| 241 | captureSession.removeInput(input) | 267 | captureSession.removeInput(input) |
| @@ -246,7 +272,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | @@ -246,7 +272,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan | ||
| 246 | device.removeObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode)) | 272 | device.removeObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode)) |
| 247 | registry.unregisterTexture(textureId) | 273 | registry.unregisterTexture(textureId) |
| 248 | 274 | ||
| 249 | - analyzeMode = 0 | 275 | +// analyzeMode = 0 |
| 250 | latestBuffer = nil | 276 | latestBuffer = nil |
| 251 | captureSession = nil | 277 | captureSession = nil |
| 252 | device = nil | 278 | device = nil |
| @@ -2,4 +2,5 @@ library mobile_scanner; | @@ -2,4 +2,5 @@ library mobile_scanner; | ||
| 2 | 2 | ||
| 3 | export 'src/mobile_scanner.dart'; | 3 | export 'src/mobile_scanner.dart'; |
| 4 | export 'src/mobile_scanner_controller.dart'; | 4 | export 'src/mobile_scanner_controller.dart'; |
| 5 | +export 'src/mobile_scanner_arguments.dart'; | ||
| 5 | export 'src/objects/barcode.dart'; | 6 | export 'src/objects/barcode.dart'; |
| 1 | -import 'package:flutter/foundation.dart'; | ||
| 2 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
| 3 | import 'package:mobile_scanner/mobile_scanner.dart'; | 2 | import 'package:mobile_scanner/mobile_scanner.dart'; |
| 4 | 3 | ||
| @@ -29,10 +28,12 @@ class MobileScanner extends StatefulWidget { | @@ -29,10 +28,12 @@ class MobileScanner extends StatefulWidget { | ||
| 29 | final BoxFit fit; | 28 | final BoxFit fit; |
| 30 | 29 | ||
| 31 | /// Create a [MobileScanner] with a [controller], the [controller] must has been initialized. | 30 | /// Create a [MobileScanner] with a [controller], the [controller] must has been initialized. |
| 32 | - const MobileScanner( | ||
| 33 | - {Key? key, this.onDetect, this.controller, this.fit = BoxFit.cover}) | ||
| 34 | - : assert((controller != null)), | ||
| 35 | - super(key: key); | 31 | + const MobileScanner({ |
| 32 | + Key? key, | ||
| 33 | + this.onDetect, | ||
| 34 | + this.controller, | ||
| 35 | + this.fit = BoxFit.cover, | ||
| 36 | + }) : super(key: key); | ||
| 36 | 37 | ||
| 37 | @override | 38 | @override |
| 38 | State<MobileScanner> createState() => _MobileScannerState(); | 39 | State<MobileScanner> createState() => _MobileScannerState(); |
| @@ -40,30 +41,26 @@ class MobileScanner extends StatefulWidget { | @@ -40,30 +41,26 @@ class MobileScanner extends StatefulWidget { | ||
| 40 | 41 | ||
| 41 | class _MobileScannerState extends State<MobileScanner> | 42 | class _MobileScannerState extends State<MobileScanner> |
| 42 | with WidgetsBindingObserver { | 43 | with WidgetsBindingObserver { |
| 43 | - bool onScreen = true; | ||
| 44 | late MobileScannerController controller; | 44 | late MobileScannerController controller; |
| 45 | 45 | ||
| 46 | @override | 46 | @override |
| 47 | void initState() { | 47 | void initState() { |
| 48 | super.initState(); | 48 | super.initState(); |
| 49 | - if (widget.controller == null) { | ||
| 50 | - controller = MobileScannerController(); | ||
| 51 | - } else { | ||
| 52 | - controller = widget.controller!; | ||
| 53 | - } | 49 | + WidgetsBinding.instance?.addObserver(this); |
| 50 | + controller = widget.controller ?? MobileScannerController(); | ||
| 54 | } | 51 | } |
| 55 | 52 | ||
| 56 | @override | 53 | @override |
| 57 | void didChangeAppLifecycleState(AppLifecycleState state) { | 54 | void didChangeAppLifecycleState(AppLifecycleState state) { |
| 58 | - if (state == AppLifecycleState.resumed) { | ||
| 59 | - setState(() => onScreen = true); | ||
| 60 | - } else { | ||
| 61 | - if (onScreen) { | 55 | + switch (state) { |
| 56 | + case AppLifecycleState.resumed: | ||
| 57 | + controller.start(); | ||
| 58 | + break; | ||
| 59 | + case AppLifecycleState.inactive: | ||
| 60 | + case AppLifecycleState.paused: | ||
| 61 | + case AppLifecycleState.detached: | ||
| 62 | controller.stop(); | 62 | controller.stop(); |
| 63 | - } | ||
| 64 | - setState(() { | ||
| 65 | - onScreen = false; | ||
| 66 | - }); | 63 | + break; |
| 67 | } | 64 | } |
| 68 | } | 65 | } |
| 69 | 66 | ||
| @@ -76,7 +73,6 @@ class _MobileScannerState extends State<MobileScanner> | @@ -76,7 +73,6 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 76 | ); | 73 | ); |
| 77 | } else { | 74 | } else { |
| 78 | return LayoutBuilder(builder: (context, BoxConstraints constraints) { | 75 | return LayoutBuilder(builder: (context, BoxConstraints constraints) { |
| 79 | - if (!onScreen) return const Text("Camera Paused."); | ||
| 80 | return ValueListenableBuilder( | 76 | return ValueListenableBuilder( |
| 81 | valueListenable: controller.args, | 77 | valueListenable: controller.args, |
| 82 | builder: (context, value, child) { | 78 | builder: (context, value, child) { |
| @@ -109,13 +105,32 @@ class _MobileScannerState extends State<MobileScanner> | @@ -109,13 +105,32 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 109 | ); | 105 | ); |
| 110 | } | 106 | } |
| 111 | }); | 107 | }); |
| 108 | + } | ||
| 112 | }); | 109 | }); |
| 113 | } | 110 | } |
| 114 | } | 111 | } |
| 115 | 112 | ||
| 116 | @override | 113 | @override |
| 114 | + void didUpdateWidget(covariant MobileScanner oldWidget) { | ||
| 115 | + super.didUpdateWidget(oldWidget); | ||
| 116 | + if (oldWidget.controller == null) { | ||
| 117 | + if (widget.controller != null) { | ||
| 118 | + controller.dispose(); | ||
| 119 | + controller = widget.controller!; | ||
| 120 | + } | ||
| 121 | + } else { | ||
| 122 | + if (widget.controller == null) { | ||
| 123 | + controller = MobileScannerController(); | ||
| 124 | + } else if (oldWidget.controller != widget.controller) { | ||
| 125 | + controller = widget.controller!; | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + @override | ||
| 117 | void dispose() { | 131 | void dispose() { |
| 118 | controller.dispose(); | 132 | controller.dispose(); |
| 133 | + WidgetsBinding.instance?.removeObserver(this); | ||
| 119 | super.dispose(); | 134 | super.dispose(); |
| 120 | } | 135 | } |
| 121 | } | 136 | } |
| @@ -4,7 +4,6 @@ import 'package:flutter/cupertino.dart'; | @@ -4,7 +4,6 @@ import 'package:flutter/cupertino.dart'; | ||
| 4 | import 'package:flutter/services.dart'; | 4 | import 'package:flutter/services.dart'; |
| 5 | import 'package:mobile_scanner/mobile_scanner.dart'; | 5 | import 'package:mobile_scanner/mobile_scanner.dart'; |
| 6 | 6 | ||
| 7 | -import 'mobile_scanner_arguments.dart'; | ||
| 8 | import 'objects/barcode_utility.dart'; | 7 | import 'objects/barcode_utility.dart'; |
| 9 | 8 | ||
| 10 | /// The facing of a camera. | 9 | /// The facing of a camera. |
| @@ -27,7 +26,7 @@ enum TorchState { | @@ -27,7 +26,7 @@ enum TorchState { | ||
| 27 | on, | 26 | on, |
| 28 | } | 27 | } |
| 29 | 28 | ||
| 30 | -enum AnalyzeMode { none, barcode } | 29 | +// enum AnalyzeMode { none, barcode } |
| 31 | 30 | ||
| 32 | class MobileScannerController { | 31 | class MobileScannerController { |
| 33 | MethodChannel methodChannel = | 32 | MethodChannel methodChannel = |
| @@ -62,9 +61,9 @@ class MobileScannerController { | @@ -62,9 +61,9 @@ class MobileScannerController { | ||
| 62 | 61 | ||
| 63 | // Sets analyze mode and barcode stream | 62 | // Sets analyze mode and barcode stream |
| 64 | barcodesController = StreamController.broadcast( | 63 | barcodesController = StreamController.broadcast( |
| 65 | - onListen: () => setAnalyzeMode(AnalyzeMode.barcode.index), | ||
| 66 | - onCancel: () => setAnalyzeMode(AnalyzeMode.none.index), | ||
| 67 | - ); | 64 | + // onListen: () => setAnalyzeMode(AnalyzeMode.barcode.index), |
| 65 | + // onCancel: () => setAnalyzeMode(AnalyzeMode.none.index), | ||
| 66 | + ); | ||
| 68 | 67 | ||
| 69 | start(); | 68 | start(); |
| 70 | 69 | ||
| @@ -94,12 +93,13 @@ class MobileScannerController { | @@ -94,12 +93,13 @@ class MobileScannerController { | ||
| 94 | } | 93 | } |
| 95 | } | 94 | } |
| 96 | 95 | ||
| 97 | - void setAnalyzeMode(int mode) { | ||
| 98 | - if (hashCode != _controllerHashcode) { | ||
| 99 | - return; | ||
| 100 | - } | ||
| 101 | - methodChannel.invokeMethod('analyze', mode); | ||
| 102 | - } | 96 | + // TODO: Add more analyzers like text analyzer |
| 97 | + // void setAnalyzeMode(int mode) { | ||
| 98 | + // if (hashCode != _controllerHashcode) { | ||
| 99 | + // return; | ||
| 100 | + // } | ||
| 101 | + // methodChannel.invokeMethod('analyze', mode); | ||
| 102 | + // } | ||
| 103 | 103 | ||
| 104 | // List<BarcodeFormats>? formats = _defaultBarcodeFormats, | 104 | // List<BarcodeFormats>? formats = _defaultBarcodeFormats, |
| 105 | /// Start barcode scanning. This will first check if the required permissions | 105 | /// Start barcode scanning. This will first check if the required permissions |
| @@ -107,7 +107,7 @@ class MobileScannerController { | @@ -107,7 +107,7 @@ class MobileScannerController { | ||
| 107 | Future<void> start() async { | 107 | Future<void> start() async { |
| 108 | ensure('startAsync'); | 108 | ensure('startAsync'); |
| 109 | 109 | ||
| 110 | - setAnalyzeMode(AnalyzeMode.barcode.index); | 110 | + // setAnalyzeMode(AnalyzeMode.barcode.index); |
| 111 | // Check authorization status | 111 | // Check authorization status |
| 112 | MobileScannerState state = | 112 | MobileScannerState state = |
| 113 | MobileScannerState.values[await methodChannel.invokeMethod('state')]; | 113 | MobileScannerState.values[await methodChannel.invokeMethod('state')]; |
| @@ -132,8 +132,15 @@ class MobileScannerController { | @@ -132,8 +132,15 @@ class MobileScannerController { | ||
| 132 | if (torchEnabled != null) arguments['torch'] = torchEnabled; | 132 | if (torchEnabled != null) arguments['torch'] = torchEnabled; |
| 133 | 133 | ||
| 134 | // Start the camera with arguments | 134 | // Start the camera with arguments |
| 135 | - final Map<String, dynamic>? startResult = await methodChannel | ||
| 136 | - .invokeMapMethod<String, dynamic>('start', arguments); | 135 | + Map<String, dynamic>? startResult = {}; |
| 136 | + try { | ||
| 137 | + startResult = await methodChannel.invokeMapMethod<String, dynamic>( | ||
| 138 | + 'start', arguments); | ||
| 139 | + } on PlatformException catch (error) { | ||
| 140 | + debugPrint('${error.code}: ${error.message}'); | ||
| 141 | + // setAnalyzeMode(AnalyzeMode.none.index); | ||
| 142 | + return; | ||
| 143 | + } | ||
| 137 | 144 | ||
| 138 | if (startResult == null) { | 145 | if (startResult == null) { |
| 139 | throw PlatformException(code: 'INITIALIZATION ERROR'); | 146 | throw PlatformException(code: 'INITIALIZATION ERROR'); |
| @@ -146,17 +153,32 @@ class MobileScannerController { | @@ -146,17 +153,32 @@ class MobileScannerController { | ||
| 146 | hasTorch: hasTorch); | 153 | hasTorch: hasTorch); |
| 147 | } | 154 | } |
| 148 | 155 | ||
| 149 | - Future<void> stop() async => await methodChannel.invokeMethod('stop'); | 156 | + Future<void> stop() async { |
| 157 | + try { | ||
| 158 | + await methodChannel.invokeMethod('stop'); | ||
| 159 | + } on PlatformException catch (error) { | ||
| 160 | + debugPrint('${error.code}: ${error.message}'); | ||
| 161 | + } | ||
| 162 | + } | ||
| 150 | 163 | ||
| 151 | /// Switches the torch on or off. | 164 | /// Switches the torch on or off. |
| 152 | /// | 165 | /// |
| 153 | /// Only works if torch is available. | 166 | /// Only works if torch is available. |
| 154 | - void toggleTorch() { | 167 | + Future<void> toggleTorch() async { |
| 155 | ensure('toggleTorch'); | 168 | ensure('toggleTorch'); |
| 156 | - if (!hasTorch) return; | 169 | + if (!hasTorch) { |
| 170 | + debugPrint('Device has no torch/flash.'); | ||
| 171 | + return; | ||
| 172 | + } | ||
| 173 | + | ||
| 157 | TorchState state = | 174 | TorchState state = |
| 158 | torchState.value == TorchState.off ? TorchState.on : TorchState.off; | 175 | torchState.value == TorchState.off ? TorchState.on : TorchState.off; |
| 159 | - methodChannel.invokeMethod('torch', state.index); | 176 | + |
| 177 | + try { | ||
| 178 | + await methodChannel.invokeMethod('torch', state.index); | ||
| 179 | + } on PlatformException catch (error) { | ||
| 180 | + debugPrint('${error.code}: ${error.message}'); | ||
| 181 | + } | ||
| 160 | } | 182 | } |
| 161 | 183 | ||
| 162 | /// Switches the torch on or off. | 184 | /// Switches the torch on or off. |
| @@ -164,10 +186,16 @@ class MobileScannerController { | @@ -164,10 +186,16 @@ class MobileScannerController { | ||
| 164 | /// Only works if torch is available. | 186 | /// Only works if torch is available. |
| 165 | Future<void> switchCamera() async { | 187 | Future<void> switchCamera() async { |
| 166 | ensure('switchCamera'); | 188 | ensure('switchCamera'); |
| 167 | - await stop(); | 189 | + try { |
| 190 | + await methodChannel.invokeMethod('stop'); | ||
| 191 | + } on PlatformException catch (error) { | ||
| 192 | + debugPrint( | ||
| 193 | + '${error.code}: camera is stopped! Please start before switching camera.'); | ||
| 194 | + return; | ||
| 195 | + } | ||
| 168 | facing = | 196 | facing = |
| 169 | facing == CameraFacing.back ? CameraFacing.front : CameraFacing.back; | 197 | facing == CameraFacing.back ? CameraFacing.front : CameraFacing.back; |
| 170 | - start(); | 198 | + await start(); |
| 171 | } | 199 | } |
| 172 | 200 | ||
| 173 | /// Disposes the controller and closes all listeners. | 201 | /// Disposes the controller and closes all listeners. |
| @@ -25,7 +25,7 @@ class Barcode { | @@ -25,7 +25,7 @@ class Barcode { | ||
| 25 | /// It's only available when the barcode is encoded in the UTF-8 format, and for non-UTF8 ones use [rawBytes] instead. | 25 | /// It's only available when the barcode is encoded in the UTF-8 format, and for non-UTF8 ones use [rawBytes] instead. |
| 26 | /// | 26 | /// |
| 27 | /// Returns null if the raw value can not be determined. | 27 | /// Returns null if the raw value can not be determined. |
| 28 | - final String rawValue; | 28 | + final String? rawValue; |
| 29 | 29 | ||
| 30 | /// Returns format type of the barcode value. | 30 | /// Returns format type of the barcode value. |
| 31 | /// | 31 | /// |
| @@ -63,7 +63,21 @@ class Barcode { | @@ -63,7 +63,21 @@ class Barcode { | ||
| 63 | /// Gets parsed WiFi AP details. | 63 | /// Gets parsed WiFi AP details. |
| 64 | final WiFi? wifi; | 64 | final WiFi? wifi; |
| 65 | 65 | ||
| 66 | - 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}); | 66 | + Barcode( |
| 67 | + {this.corners, | ||
| 68 | + this.format = BarcodeFormat.ean13, | ||
| 69 | + this.rawBytes, | ||
| 70 | + this.type = BarcodeType.text, | ||
| 71 | + this.calendarEvent, | ||
| 72 | + this.contactInfo, | ||
| 73 | + this.driverLicense, | ||
| 74 | + this.email, | ||
| 75 | + this.geoPoint, | ||
| 76 | + this.phone, | ||
| 77 | + this.sms, | ||
| 78 | + this.url, | ||
| 79 | + this.wifi, | ||
| 80 | + required this.rawValue}); | ||
| 67 | 81 | ||
| 68 | /// Create a [Barcode] from native data. | 82 | /// Create a [Barcode] from native data. |
| 69 | Barcode.fromNative(Map<dynamic, dynamic> data) | 83 | Barcode.fromNative(Map<dynamic, dynamic> data) |
| @@ -151,22 +165,22 @@ class ContactInfo { | @@ -151,22 +165,22 @@ class ContactInfo { | ||
| 151 | /// Gets contact person's organization. | 165 | /// Gets contact person's organization. |
| 152 | /// | 166 | /// |
| 153 | /// Returns null if not available. | 167 | /// Returns null if not available. |
| 154 | - final String organization; | 168 | + final String? organization; |
| 155 | 169 | ||
| 156 | /// Gets contact person's phones. | 170 | /// Gets contact person's phones. |
| 157 | /// | 171 | /// |
| 158 | /// Returns an empty list if nothing found. | 172 | /// Returns an empty list if nothing found. |
| 159 | - final List<Phone> phones; | 173 | + final List<Phone>? phones; |
| 160 | 174 | ||
| 161 | /// Gets contact person's title. | 175 | /// Gets contact person's title. |
| 162 | /// | 176 | /// |
| 163 | /// Returns null if not available. | 177 | /// Returns null if not available. |
| 164 | - final String title; | 178 | + final String? title; |
| 165 | 179 | ||
| 166 | /// Gets contact person's urls. | 180 | /// Gets contact person's urls. |
| 167 | /// | 181 | /// |
| 168 | /// Returns an empty list if nothing found. | 182 | /// Returns an empty list if nothing found. |
| 169 | - final List<String> urls; | 183 | + final List<String>? urls; |
| 170 | 184 | ||
| 171 | /// Create a [ContactInfo] from native data. | 185 | /// Create a [ContactInfo] from native data. |
| 172 | ContactInfo.fromNative(Map<dynamic, dynamic> data) | 186 | ContactInfo.fromNative(Map<dynamic, dynamic> data) |
| @@ -188,7 +202,9 @@ class Address { | @@ -188,7 +202,9 @@ class Address { | ||
| 188 | final List<String> addressLines; | 202 | final List<String> addressLines; |
| 189 | 203 | ||
| 190 | /// Gets type of the address. | 204 | /// Gets type of the address. |
| 191 | - final AddressType type; | 205 | + /// |
| 206 | + /// Returns null if not available. | ||
| 207 | + final AddressType? type; | ||
| 192 | 208 | ||
| 193 | /// Create a [Address] from native data. | 209 | /// Create a [Address] from native data. |
| 194 | Address.fromNative(Map<dynamic, dynamic> data) | 210 | Address.fromNative(Map<dynamic, dynamic> data) |
| @@ -201,37 +217,37 @@ class PersonName { | @@ -201,37 +217,37 @@ class PersonName { | ||
| 201 | /// Gets first name. | 217 | /// Gets first name. |
| 202 | /// | 218 | /// |
| 203 | /// Returns null if not available. | 219 | /// Returns null if not available. |
| 204 | - final String first; | 220 | + final String? first; |
| 205 | 221 | ||
| 206 | /// Gets middle name. | 222 | /// Gets middle name. |
| 207 | /// | 223 | /// |
| 208 | /// Returns null if not available. | 224 | /// Returns null if not available. |
| 209 | - final String middle; | 225 | + final String? middle; |
| 210 | 226 | ||
| 211 | /// Gets last name. | 227 | /// Gets last name. |
| 212 | /// | 228 | /// |
| 213 | /// Returns null if not available. | 229 | /// Returns null if not available. |
| 214 | - final String last; | 230 | + final String? last; |
| 215 | 231 | ||
| 216 | /// Gets prefix of the name. | 232 | /// Gets prefix of the name. |
| 217 | /// | 233 | /// |
| 218 | /// Returns null if not available. | 234 | /// Returns null if not available. |
| 219 | - final String prefix; | 235 | + final String? prefix; |
| 220 | 236 | ||
| 221 | /// Gets suffix of the person's name. | 237 | /// Gets suffix of the person's name. |
| 222 | /// | 238 | /// |
| 223 | /// Returns null if not available. | 239 | /// Returns null if not available. |
| 224 | - final String suffix; | 240 | + final String? suffix; |
| 225 | 241 | ||
| 226 | /// Gets the properly formatted name. | 242 | /// Gets the properly formatted name. |
| 227 | /// | 243 | /// |
| 228 | /// Returns null if not available. | 244 | /// Returns null if not available. |
| 229 | - final String formattedName; | 245 | + final String? formattedName; |
| 230 | 246 | ||
| 231 | /// Designates a text string to be set as the kana name in the phonebook. Used for Japanese contacts. | 247 | /// Designates a text string to be set as the kana name in the phonebook. Used for Japanese contacts. |
| 232 | /// | 248 | /// |
| 233 | /// Returns null if not available. | 249 | /// Returns null if not available. |
| 234 | - final String pronunciation; | 250 | + final String? pronunciation; |
| 235 | 251 | ||
| 236 | /// Create a [PersonName] from native data. | 252 | /// Create a [PersonName] from native data. |
| 237 | PersonName.fromNative(Map<dynamic, dynamic> data) | 253 | PersonName.fromNative(Map<dynamic, dynamic> data) |
| @@ -249,74 +265,74 @@ class DriverLicense { | @@ -249,74 +265,74 @@ class DriverLicense { | ||
| 249 | /// Gets city of holder's address. | 265 | /// Gets city of holder's address. |
| 250 | /// | 266 | /// |
| 251 | /// Returns null if not available. | 267 | /// Returns null if not available. |
| 252 | - final String addressCity; | 268 | + final String? addressCity; |
| 253 | 269 | ||
| 254 | /// Gets state of holder's address. | 270 | /// Gets state of holder's address. |
| 255 | /// | 271 | /// |
| 256 | /// Returns null if not available. | 272 | /// Returns null if not available. |
| 257 | - final String addressState; | 273 | + final String? addressState; |
| 258 | 274 | ||
| 259 | /// Gets holder's street address. | 275 | /// Gets holder's street address. |
| 260 | /// | 276 | /// |
| 261 | /// Returns null if not available. | 277 | /// Returns null if not available. |
| 262 | - final String addressStreet; | 278 | + final String? addressStreet; |
| 263 | 279 | ||
| 264 | /// Gets postal code of holder's address. | 280 | /// Gets postal code of holder's address. |
| 265 | /// | 281 | /// |
| 266 | /// Returns null if not available. | 282 | /// Returns null if not available. |
| 267 | - final String addressZip; | 283 | + final String? addressZip; |
| 268 | 284 | ||
| 269 | /// Gets birth date of the holder. | 285 | /// Gets birth date of the holder. |
| 270 | /// | 286 | /// |
| 271 | /// Returns null if not available. | 287 | /// Returns null if not available. |
| 272 | - final String birthDate; | 288 | + final String? birthDate; |
| 273 | 289 | ||
| 274 | /// Gets "DL" for driver licenses, "ID" for ID cards. | 290 | /// Gets "DL" for driver licenses, "ID" for ID cards. |
| 275 | /// | 291 | /// |
| 276 | /// Returns null if not available. | 292 | /// Returns null if not available. |
| 277 | - final String documentType; | 293 | + final String? documentType; |
| 278 | 294 | ||
| 279 | /// Gets expiry date of the license. | 295 | /// Gets expiry date of the license. |
| 280 | /// | 296 | /// |
| 281 | /// Returns null if not available. | 297 | /// Returns null if not available. |
| 282 | - final String expiryDate; | 298 | + final String? expiryDate; |
| 283 | 299 | ||
| 284 | /// Gets holder's first name. | 300 | /// Gets holder's first name. |
| 285 | /// | 301 | /// |
| 286 | /// Returns null if not available. | 302 | /// Returns null if not available. |
| 287 | - final String firstName; | 303 | + final String? firstName; |
| 288 | 304 | ||
| 289 | /// Gets holder's gender. 1 - male, 2 - female. | 305 | /// Gets holder's gender. 1 - male, 2 - female. |
| 290 | /// | 306 | /// |
| 291 | /// Returns null if not available. | 307 | /// Returns null if not available. |
| 292 | - final String gender; | 308 | + final String? gender; |
| 293 | 309 | ||
| 294 | /// Gets issue date of the license. | 310 | /// Gets issue date of the license. |
| 295 | /// | 311 | /// |
| 296 | /// The date format depends on the issuing country. MMDDYYYY for the US, YYYYMMDD for Canada. | 312 | /// The date format depends on the issuing country. MMDDYYYY for the US, YYYYMMDD for Canada. |
| 297 | /// | 313 | /// |
| 298 | /// Returns null if not available. | 314 | /// Returns null if not available. |
| 299 | - final String issueDate; | 315 | + final String? issueDate; |
| 300 | 316 | ||
| 301 | /// Gets the three-letter country code in which DL/ID was issued. | 317 | /// Gets the three-letter country code in which DL/ID was issued. |
| 302 | /// | 318 | /// |
| 303 | /// Returns null if not available. | 319 | /// Returns null if not available. |
| 304 | - final String issuingCountry; | 320 | + final String? issuingCountry; |
| 305 | 321 | ||
| 306 | /// Gets holder's last name. | 322 | /// Gets holder's last name. |
| 307 | /// | 323 | /// |
| 308 | /// Returns null if not available. | 324 | /// Returns null if not available. |
| 309 | - final String lastName; | 325 | + final String? lastName; |
| 310 | 326 | ||
| 311 | /// Gets driver license ID number. | 327 | /// Gets driver license ID number. |
| 312 | /// | 328 | /// |
| 313 | /// Returns null if not available. | 329 | /// Returns null if not available. |
| 314 | - final String licenseNumber; | 330 | + final String? licenseNumber; |
| 315 | 331 | ||
| 316 | /// Gets holder's middle name. | 332 | /// Gets holder's middle name. |
| 317 | /// | 333 | /// |
| 318 | /// Returns null if not available. | 334 | /// Returns null if not available. |
| 319 | - final String middleName; | 335 | + final String? middleName; |
| 320 | 336 | ||
| 321 | /// Create a [DriverLicense] from native data. | 337 | /// Create a [DriverLicense] from native data. |
| 322 | DriverLicense.fromNative(Map<dynamic, dynamic> data) | 338 | DriverLicense.fromNative(Map<dynamic, dynamic> data) |
| @@ -341,22 +357,23 @@ class Email { | @@ -341,22 +357,23 @@ class Email { | ||
| 341 | /// Gets email's address. | 357 | /// Gets email's address. |
| 342 | /// | 358 | /// |
| 343 | /// Returns null if not available. | 359 | /// Returns null if not available. |
| 344 | - final String address; | 360 | + final String? address; |
| 345 | 361 | ||
| 346 | /// Gets email's body. | 362 | /// Gets email's body. |
| 347 | /// | 363 | /// |
| 348 | /// Returns null if not available. | 364 | /// Returns null if not available. |
| 349 | - final String body; | 365 | + final String? body; |
| 350 | 366 | ||
| 351 | /// Gets email's subject. | 367 | /// Gets email's subject. |
| 352 | /// | 368 | /// |
| 353 | /// Returns null if not available. | 369 | /// Returns null if not available. |
| 354 | - final String subject; | 370 | + final String? subject; |
| 355 | 371 | ||
| 356 | /// Gets type of the email. | 372 | /// Gets type of the email. |
| 357 | /// | 373 | /// |
| 358 | /// See also [EmailType]. | 374 | /// See also [EmailType]. |
| 359 | - final EmailType type; | 375 | + /// Returns null if not available. |
| 376 | + final EmailType? type; | ||
| 360 | 377 | ||
| 361 | /// Create a [Email] from native data. | 378 | /// Create a [Email] from native data. |
| 362 | Email.fromNative(Map<dynamic, dynamic> data) | 379 | Email.fromNative(Map<dynamic, dynamic> data) |
| @@ -369,10 +386,10 @@ class Email { | @@ -369,10 +386,10 @@ class Email { | ||
| 369 | /// GPS coordinates from a 'GEO:' or similar QRCode type. | 386 | /// GPS coordinates from a 'GEO:' or similar QRCode type. |
| 370 | class GeoPoint { | 387 | class GeoPoint { |
| 371 | /// Gets the latitude. | 388 | /// Gets the latitude. |
| 372 | - final double latitude; | 389 | + final double? latitude; |
| 373 | 390 | ||
| 374 | /// Gets the longitude. | 391 | /// Gets the longitude. |
| 375 | - final double longitude; | 392 | + final double? longitude; |
| 376 | 393 | ||
| 377 | /// Create a [GeoPoint] from native data. | 394 | /// Create a [GeoPoint] from native data. |
| 378 | GeoPoint.fromNative(Map<dynamic, dynamic> data) | 395 | GeoPoint.fromNative(Map<dynamic, dynamic> data) |
| @@ -385,12 +402,13 @@ class Phone { | @@ -385,12 +402,13 @@ class Phone { | ||
| 385 | /// Gets phone number. | 402 | /// Gets phone number. |
| 386 | /// | 403 | /// |
| 387 | /// Returns null if not available. | 404 | /// Returns null if not available. |
| 388 | - final String number; | 405 | + final String? number; |
| 389 | 406 | ||
| 390 | /// Gets type of the phone number. | 407 | /// Gets type of the phone number. |
| 391 | /// | 408 | /// |
| 392 | /// See also [PhoneType]. | 409 | /// See also [PhoneType]. |
| 393 | - final PhoneType type; | 410 | + /// Returns null if not available. |
| 411 | + final PhoneType? type; | ||
| 394 | 412 | ||
| 395 | /// Create a [Phone] from native data. | 413 | /// Create a [Phone] from native data. |
| 396 | Phone.fromNative(Map<dynamic, dynamic> data) | 414 | Phone.fromNative(Map<dynamic, dynamic> data) |
| @@ -403,12 +421,12 @@ class SMS { | @@ -403,12 +421,12 @@ class SMS { | ||
| 403 | /// Gets the message content of the sms. | 421 | /// Gets the message content of the sms. |
| 404 | /// | 422 | /// |
| 405 | /// Returns null if not available. | 423 | /// Returns null if not available. |
| 406 | - final String message; | 424 | + final String? message; |
| 407 | 425 | ||
| 408 | /// Gets the phone number of the sms. | 426 | /// Gets the phone number of the sms. |
| 409 | /// | 427 | /// |
| 410 | /// Returns null if not available. | 428 | /// Returns null if not available. |
| 411 | - final String phoneNumber; | 429 | + final String? phoneNumber; |
| 412 | 430 | ||
| 413 | /// Create a [SMS] from native data. | 431 | /// Create a [SMS] from native data. |
| 414 | SMS.fromNative(Map<dynamic, dynamic> data) | 432 | SMS.fromNative(Map<dynamic, dynamic> data) |
| @@ -421,12 +439,12 @@ class UrlBookmark { | @@ -421,12 +439,12 @@ class UrlBookmark { | ||
| 421 | /// Gets the title of the bookmark. | 439 | /// Gets the title of the bookmark. |
| 422 | /// | 440 | /// |
| 423 | /// Returns null if not available. | 441 | /// Returns null if not available. |
| 424 | - final String title; | 442 | + final String? title; |
| 425 | 443 | ||
| 426 | /// Gets the url of the bookmark. | 444 | /// Gets the url of the bookmark. |
| 427 | /// | 445 | /// |
| 428 | /// Returns null if not available. | 446 | /// Returns null if not available. |
| 429 | - final String url; | 447 | + final String? url; |
| 430 | 448 | ||
| 431 | /// Create a [UrlBookmark] from native data. | 449 | /// Create a [UrlBookmark] from native data. |
| 432 | UrlBookmark.fromNative(Map<dynamic, dynamic> data) | 450 | UrlBookmark.fromNative(Map<dynamic, dynamic> data) |
| @@ -444,12 +462,12 @@ class WiFi { | @@ -444,12 +462,12 @@ class WiFi { | ||
| 444 | /// Gets the ssid of the WIFI. | 462 | /// Gets the ssid of the WIFI. |
| 445 | /// | 463 | /// |
| 446 | /// Returns null if not available. | 464 | /// Returns null if not available. |
| 447 | - final String ssid; | 465 | + final String? ssid; |
| 448 | 466 | ||
| 449 | /// Gets the password of the WIFI. | 467 | /// Gets the password of the WIFI. |
| 450 | /// | 468 | /// |
| 451 | /// Returns null if not available. | 469 | /// Returns null if not available. |
| 452 | - final String password; | 470 | + final String? password; |
| 453 | 471 | ||
| 454 | /// Create a [WiFi] from native data. | 472 | /// Create a [WiFi] from native data. |
| 455 | WiFi.fromNative(Map<dynamic, dynamic> data) | 473 | WiFi.fromNative(Map<dynamic, dynamic> data) |
| @@ -22,7 +22,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | @@ -22,7 +22,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | ||
| 22 | var latestBuffer: CVImageBuffer! | 22 | var latestBuffer: CVImageBuffer! |
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | - var analyzeMode: Int = 0 | 25 | +// var analyzeMode: Int = 0 |
| 26 | var analyzing: Bool = false | 26 | var analyzing: Bool = false |
| 27 | var position = AVCaptureDevice.Position.back | 27 | var position = AVCaptureDevice.Position.back |
| 28 | 28 | ||
| @@ -52,9 +52,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | @@ -52,9 +52,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | ||
| 52 | case "start": | 52 | case "start": |
| 53 | start(call, result) | 53 | start(call, result) |
| 54 | case "torch": | 54 | case "torch": |
| 55 | - switchTorch(call, result) | ||
| 56 | - case "analyze": | ||
| 57 | - switchAnalyzeMode(call, result) | 55 | + toggleTorch(call, result) |
| 56 | +// case "analyze": | ||
| 57 | +// switchAnalyzeMode(call, result) | ||
| 58 | case "stop": | 58 | case "stop": |
| 59 | stop(result) | 59 | stop(result) |
| 60 | default: | 60 | default: |
| @@ -92,14 +92,14 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | @@ -92,14 +92,14 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | ||
| 92 | latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) | 92 | latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) |
| 93 | registry.textureFrameAvailable(textureId) | 93 | registry.textureFrameAvailable(textureId) |
| 94 | 94 | ||
| 95 | - switch analyzeMode { | ||
| 96 | - case 1: // barcode | 95 | +// switch analyzeMode { |
| 96 | +// case 1: // barcode | ||
| 97 | 97 | ||
| 98 | // Limit the analyzer because the texture output will freeze otherwise | 98 | // Limit the analyzer because the texture output will freeze otherwise |
| 99 | if i / 10 == 1 { | 99 | if i / 10 == 1 { |
| 100 | i = 0 | 100 | i = 0 |
| 101 | } else { | 101 | } else { |
| 102 | - break | 102 | + return |
| 103 | } | 103 | } |
| 104 | let imageRequestHandler = VNImageRequestHandler( | 104 | let imageRequestHandler = VNImageRequestHandler( |
| 105 | cvPixelBuffer: latestBuffer, | 105 | cvPixelBuffer: latestBuffer, |
| @@ -129,9 +129,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | @@ -129,9 +129,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | ||
| 129 | print(error) | 129 | print(error) |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | - default: // none | ||
| 133 | - break | ||
| 134 | - } | 132 | +// default: // none |
| 133 | +// break | ||
| 134 | +// } | ||
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | func checkPermission(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { | 137 | func checkPermission(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { |
| @@ -159,6 +159,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | @@ -159,6 +159,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | ||
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | func start(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { | 161 | func start(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { |
| 162 | + if (device != nil) { | ||
| 163 | + result(FlutterError(code: "MobileScanner", | ||
| 164 | + message: "Called start() while already started!", | ||
| 165 | + details: nil)) | ||
| 166 | + return | ||
| 167 | + } | ||
| 168 | + | ||
| 162 | textureId = registry.register(self) | 169 | textureId = registry.register(self) |
| 163 | captureSession = AVCaptureSession() | 170 | captureSession = AVCaptureSession() |
| 164 | 171 | ||
| @@ -178,6 +185,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | @@ -178,6 +185,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | ||
| 178 | device = AVCaptureDevice.devices(for: .video).filter({$0.position == position}).first | 185 | device = AVCaptureDevice.devices(for: .video).filter({$0.position == position}).first |
| 179 | } | 186 | } |
| 180 | 187 | ||
| 188 | + if (device == nil) { | ||
| 189 | + result(FlutterError(code: "MobileScanner", | ||
| 190 | + message: "No camera found or failed to open camera!", | ||
| 191 | + details: nil)) | ||
| 192 | + return | ||
| 193 | + } | ||
| 194 | + | ||
| 181 | // Enable the torch if parameter is set and torch is available | 195 | // Enable the torch if parameter is set and torch is available |
| 182 | if (device.hasTorch) { | 196 | if (device.hasTorch) { |
| 183 | do { | 197 | do { |
| @@ -222,7 +236,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | @@ -222,7 +236,13 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | ||
| 222 | result(answer) | 236 | result(answer) |
| 223 | } | 237 | } |
| 224 | 238 | ||
| 225 | - func switchTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { | 239 | + func toggleTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { |
| 240 | + if (device == nil) { | ||
| 241 | + result(FlutterError(code: "MobileScanner", | ||
| 242 | + message: "Called toggleTorch() while stopped!", | ||
| 243 | + details: nil)) | ||
| 244 | + return | ||
| 245 | + } | ||
| 226 | do { | 246 | do { |
| 227 | try device.lockForConfiguration() | 247 | try device.lockForConfiguration() |
| 228 | device.torchMode = call.arguments as! Int == 1 ? .on : .off | 248 | device.torchMode = call.arguments as! Int == 1 ? .on : .off |
| @@ -232,13 +252,19 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | @@ -232,13 +252,19 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | ||
| 232 | result(FlutterError(code: error.localizedDescription, message: nil, details: nil)) | 252 | result(FlutterError(code: error.localizedDescription, message: nil, details: nil)) |
| 233 | } | 253 | } |
| 234 | } | 254 | } |
| 235 | - | ||
| 236 | - func switchAnalyzeMode(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { | ||
| 237 | - analyzeMode = call.arguments as! Int | ||
| 238 | - result(nil) | ||
| 239 | - } | ||
| 240 | - | 255 | + |
| 256 | +// func switchAnalyzeMode(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { | ||
| 257 | +// analyzeMode = call.arguments as! Int | ||
| 258 | +// result(nil) | ||
| 259 | +// } | ||
| 260 | + | ||
| 241 | func stop(_ result: FlutterResult) { | 261 | func stop(_ result: FlutterResult) { |
| 262 | + if (device == nil) { | ||
| 263 | + result(FlutterError(code: "MobileScanner", | ||
| 264 | + message: "Called stop() while already stopped!", | ||
| 265 | + details: nil)) | ||
| 266 | + return | ||
| 267 | + } | ||
| 242 | captureSession.stopRunning() | 268 | captureSession.stopRunning() |
| 243 | for input in captureSession.inputs { | 269 | for input in captureSession.inputs { |
| 244 | captureSession.removeInput(input) | 270 | captureSession.removeInput(input) |
| @@ -249,7 +275,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | @@ -249,7 +275,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, | ||
| 249 | device.removeObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode)) | 275 | device.removeObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode)) |
| 250 | registry.unregisterTexture(textureId) | 276 | registry.unregisterTexture(textureId) |
| 251 | 277 | ||
| 252 | - analyzeMode = 0 | 278 | +// analyzeMode = 0 |
| 253 | latestBuffer = nil | 279 | latestBuffer = nil |
| 254 | captureSession = nil | 280 | captureSession = nil |
| 255 | device = nil | 281 | device = nil |
macos/Classes/Util.swift
deleted
100644 → 0
| 1 | - |
| 1 | name: mobile_scanner | 1 | name: mobile_scanner |
| 2 | -description: A universal scanner for Flutter based on MLKit. Uses CameraX on Android and AVFoundation on iOS. | ||
| 3 | -version: 0.1.0 | 2 | +description: A universal barcode and QR code scanner for Flutter based on MLKit. Uses CameraX on Android, AVFoundation on iOS and Apple Vision & AVFoundation on macOS. |
| 3 | +version: 0.1.2 | ||
| 4 | repository: https://github.com/juliansteenbakker/mobile_scanner | 4 | repository: https://github.com/juliansteenbakker/mobile_scanner |
| 5 | 5 | ||
| 6 | environment: | 6 | environment: |
| 7 | - sdk: ">=2.16.0 <3.0.0" | ||
| 8 | - flutter: ">=2.5.0" | 7 | + sdk: ">=2.12.0 <3.0.0" |
| 8 | + flutter: ">=2.2.0" | ||
| 9 | 9 | ||
| 10 | dependencies: | 10 | dependencies: |
| 11 | js: ^0.6.4 | 11 | js: ^0.6.4 |
-
Please register or login to post a comment