Simplfiy controller, expose scanDataStreamflutter-beta
| @@ -60,31 +60,39 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return Scaffold( | return Scaffold( | ||||
| body: Column( | body: Column( | ||||
| children: <Widget>[ | |||||
| QRView( | |||||
| key: qrKey, | |||||
| onQRViewCreated: _onQRViewCreated, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ); | |||||
| children: <Widget>[ | |||||
| Expanded( | |||||
| flex: 5, | |||||
| child: QRView( | |||||
| key: qrKey, | |||||
| onQRViewCreated: _onQRViewCreated, | |||||
| ), | |||||
| ), | |||||
| Expanded( | |||||
| flex: 1, | |||||
| child: Center( | |||||
| child: Text('Scan result: $qrText'), | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ); | |||||
| } | } | ||||
| void _onQRViewCreated(QRViewController controller) { | void _onQRViewCreated(QRViewController controller) { | ||||
| final channel = controller.channel; | |||||
| controller.init(qrKey); | |||||
| this.controller = controller; | this.controller = controller; | ||||
| channel.setMethodCallHandler((MethodCall call) async { | |||||
| switch (call.method) { | |||||
| case "onRecognizeQR": | |||||
| dynamic arguments = call.arguments; | |||||
| setState(() { | |||||
| qrText = arguments.toString(); | |||||
| }); | |||||
| } | |||||
| controller.scannedDataStream.listen((scanData) { | |||||
| setState(() { | |||||
| qrText = scanData; | |||||
| }); | |||||
| }); | }); | ||||
| } | } | ||||
| @override | |||||
| void dispose() { | |||||
| controller?.dispose(); | |||||
| super.dispose(); | |||||
| } | |||||
| } | } | ||||
| ``` | ``` | ||||
| @@ -104,9 +112,21 @@ controller.flipCamera(); | |||||
| ## Flash (Off/On) | ## Flash (Off/On) | ||||
| By default, flash is OFF. | By default, flash is OFF. | ||||
| ```dart | ```dart | ||||
| controller.flipFlash(); | |||||
| controller.toggleFlash(); | |||||
| ``` | |||||
| ## Resume/Pause | |||||
| Pause camera stream and scanner. | |||||
| ```dart | |||||
| controller.pause(); | |||||
| ``` | |||||
| Resume camera stream and scanner. | |||||
| ```dart | |||||
| controller.resume(); | |||||
| ``` | ``` | ||||
| # TODO'S: | # TODO'S: | ||||
| * iOS Native embedding is written to match what is supported in the framework as of the date of publication of this package. It needs to be improved as the framework support improves. | * iOS Native embedding is written to match what is supported in the framework as of the date of publication of this package. It needs to be improved as the framework support improves. | ||||
| * In future, options will be provided for default states. | * In future, options will be provided for default states. | ||||
| @@ -1,5 +1,4 @@ | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | |||||
| import 'package:qr_code_scanner/qr_code_scanner.dart'; | import 'package:qr_code_scanner/qr_code_scanner.dart'; | ||||
| void main() => runApp(MaterialApp(home: QRViewExample())); | void main() => runApp(MaterialApp(home: QRViewExample())); | ||||
| @@ -19,11 +18,11 @@ class QRViewExample extends StatefulWidget { | |||||
| } | } | ||||
| class _QRViewExampleState extends State<QRViewExample> { | class _QRViewExampleState extends State<QRViewExample> { | ||||
| final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | |||||
| var qrText = ""; | var qrText = ""; | ||||
| var flashState = flash_on; | var flashState = flash_on; | ||||
| var cameraState = front_camera; | var cameraState = front_camera; | ||||
| QRViewController controller; | QRViewController controller; | ||||
| final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| @@ -38,79 +37,86 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| flex: 4, | flex: 4, | ||||
| ), | ), | ||||
| Expanded( | Expanded( | ||||
| child: Column( | |||||
| children: <Widget>[ | |||||
| Text("This is the result of scan: $qrText"), | |||||
| Row( | |||||
| mainAxisAlignment: MainAxisAlignment.center, | |||||
| crossAxisAlignment: CrossAxisAlignment.center, | |||||
| children: <Widget>[ | |||||
| Container( | |||||
| margin: EdgeInsets.all(8.0), | |||||
| child: RaisedButton( | |||||
| onPressed: () { | |||||
| if (controller != null) { | |||||
| controller.toggleFlash(); | |||||
| if (_isFlashOn(flashState)) | |||||
| setState(() { | |||||
| flashState = flash_off; | |||||
| }); | |||||
| else | |||||
| setState(() { | |||||
| flashState = flash_on; | |||||
| }); | |||||
| } | |||||
| }, | |||||
| child: Text(flashState, style: TextStyle(fontSize: 20)), | |||||
| ), | |||||
| ), | |||||
| Container( | |||||
| margin: EdgeInsets.all(8.0), | |||||
| child: RaisedButton( | |||||
| onPressed: () { | |||||
| if (controller != null) { | |||||
| controller.flipCamera(); | |||||
| if (_isBackCamera(cameraState)) | |||||
| setState(() { | |||||
| cameraState = front_camera; | |||||
| }); | |||||
| else | |||||
| setState(() { | |||||
| cameraState = back_camera; | |||||
| }); | |||||
| } | |||||
| }, | |||||
| child: | |||||
| Text(cameraState, style: TextStyle(fontSize: 20)), | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| Row( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |||||
| crossAxisAlignment: CrossAxisAlignment.center, | |||||
| children: <Widget>[ | |||||
| Container( | |||||
| margin: EdgeInsets.only(bottom: 8.0), | |||||
| child: RaisedButton( | |||||
| onPressed: () { | |||||
| controller?.pauseCamera(); | |||||
| }, | |||||
| child: Text('pause', style: TextStyle(fontSize: 20)), | |||||
| child: FittedBox( | |||||
| fit: BoxFit.contain, | |||||
| child: Column( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |||||
| children: <Widget>[ | |||||
| Text("This is the result of scan: $qrText"), | |||||
| Row( | |||||
| mainAxisAlignment: MainAxisAlignment.center, | |||||
| crossAxisAlignment: CrossAxisAlignment.center, | |||||
| children: <Widget>[ | |||||
| Container( | |||||
| margin: EdgeInsets.all(8.0), | |||||
| child: RaisedButton( | |||||
| onPressed: () { | |||||
| if (controller != null) { | |||||
| controller.toggleFlash(); | |||||
| if (_isFlashOn(flashState)) { | |||||
| setState(() { | |||||
| flashState = flash_off; | |||||
| }); | |||||
| } else { | |||||
| setState(() { | |||||
| flashState = flash_on; | |||||
| }); | |||||
| } | |||||
| } | |||||
| }, | |||||
| child: | |||||
| Text(flashState, style: TextStyle(fontSize: 20)), | |||||
| ), | |||||
| ), | ), | ||||
| ), | |||||
| Container( | |||||
| margin: EdgeInsets.only(bottom: 8.0), | |||||
| child: RaisedButton( | |||||
| onPressed: () { | |||||
| controller.resumeCamera(); | |||||
| }, | |||||
| child: Text('resume', style: TextStyle(fontSize: 20)), | |||||
| Container( | |||||
| margin: EdgeInsets.all(8.0), | |||||
| child: RaisedButton( | |||||
| onPressed: () { | |||||
| if (controller != null) { | |||||
| controller.flipCamera(); | |||||
| if (_isBackCamera(cameraState)) { | |||||
| setState(() { | |||||
| cameraState = front_camera; | |||||
| }); | |||||
| } else { | |||||
| setState(() { | |||||
| cameraState = back_camera; | |||||
| }); | |||||
| } | |||||
| } | |||||
| }, | |||||
| child: | |||||
| Text(cameraState, style: TextStyle(fontSize: 20)), | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| Row( | |||||
| mainAxisAlignment: MainAxisAlignment.center, | |||||
| crossAxisAlignment: CrossAxisAlignment.center, | |||||
| children: <Widget>[ | |||||
| Container( | |||||
| margin: EdgeInsets.all(8.0), | |||||
| child: RaisedButton( | |||||
| onPressed: () { | |||||
| controller?.pauseCamera(); | |||||
| }, | |||||
| child: Text('pause', style: TextStyle(fontSize: 20)), | |||||
| ), | |||||
| ), | ), | ||||
| ) | |||||
| ], | |||||
| ), | |||||
| ], | |||||
| Container( | |||||
| margin: EdgeInsets.all(8.0), | |||||
| child: RaisedButton( | |||||
| onPressed: () { | |||||
| controller?.resumeCamera(); | |||||
| }, | |||||
| child: Text('resume', style: TextStyle(fontSize: 20)), | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | ), | ||||
| flex: 1, | flex: 1, | ||||
| ) | ) | ||||
| @@ -128,17 +134,17 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| } | } | ||||
| void _onQRViewCreated(QRViewController controller) { | void _onQRViewCreated(QRViewController controller) { | ||||
| final channel = controller.channel; | |||||
| controller.init(qrKey); | |||||
| this.controller = controller; | this.controller = controller; | ||||
| channel.setMethodCallHandler((MethodCall call) async { | |||||
| switch (call.method) { | |||||
| case "onRecognizeQR": | |||||
| dynamic arguments = call.arguments; | |||||
| setState(() { | |||||
| qrText = arguments.toString(); | |||||
| }); | |||||
| } | |||||
| controller.scannedDataStream.listen((scanData) { | |||||
| setState(() { | |||||
| qrText = scanData; | |||||
| }); | |||||
| }); | }); | ||||
| } | } | ||||
| @override | |||||
| void dispose() { | |||||
| controller.dispose(); | |||||
| super.dispose(); | |||||
| } | |||||
| } | } | ||||
| @@ -1,3 +1,5 @@ | |||||
| import 'dart:async'; | |||||
| import 'package:flutter/foundation.dart'; | import 'package:flutter/foundation.dart'; | ||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | import 'package:flutter/services.dart'; | ||||
| @@ -6,9 +8,11 @@ typedef void QRViewCreatedCallback(QRViewController controller); | |||||
| class QRView extends StatefulWidget { | class QRView extends StatefulWidget { | ||||
| const QRView({ | const QRView({ | ||||
| Key key, | |||||
| this.onQRViewCreated, | |||||
| }) : super(key: key); | |||||
| @required Key key, | |||||
| @required this.onQRViewCreated, | |||||
| }) : assert(key != null), | |||||
| assert(onQRViewCreated != null), | |||||
| super(key: key); | |||||
| final QRViewCreatedCallback onQRViewCreated; | final QRViewCreatedCallback onQRViewCreated; | ||||
| @@ -45,7 +49,7 @@ class _QRViewState extends State<QRView> { | |||||
| if (widget.onQRViewCreated == null) { | if (widget.onQRViewCreated == null) { | ||||
| return; | return; | ||||
| } | } | ||||
| widget.onQRViewCreated(new QRViewController._(id)); | |||||
| widget.onQRViewCreated(QRViewController._(id, widget.key)); | |||||
| } | } | ||||
| } | } | ||||
| @@ -71,31 +75,50 @@ class _CreationParams { | |||||
| } | } | ||||
| class QRViewController { | class QRViewController { | ||||
| QRViewController._(int id) | |||||
| : channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id'); | |||||
| final MethodChannel channel; | |||||
| static const scanMethodCall = "onRecognizeQR"; | |||||
| final MethodChannel _channel; | |||||
| StreamController<String> _scanUpdateController = StreamController<String>(); | |||||
| Stream<String> get scannedDataStream => _scanUpdateController.stream; | |||||
| void init(GlobalKey qrKey) { | |||||
| QRViewController._(int id, GlobalKey qrKey) | |||||
| : _channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id') { | |||||
| if (defaultTargetPlatform == TargetPlatform.iOS) { | if (defaultTargetPlatform == TargetPlatform.iOS) { | ||||
| final RenderBox renderBox = qrKey.currentContext.findRenderObject(); | final RenderBox renderBox = qrKey.currentContext.findRenderObject(); | ||||
| channel.invokeMethod("setDimensions", | |||||
| _channel.invokeMethod("setDimensions", | |||||
| {"width": renderBox.size.width, "height": renderBox.size.height}); | {"width": renderBox.size.width, "height": renderBox.size.height}); | ||||
| } | } | ||||
| _channel.setMethodCallHandler( | |||||
| (MethodCall call) async { | |||||
| switch (call.method) { | |||||
| case scanMethodCall: | |||||
| if (call.arguments != null) { | |||||
| _scanUpdateController.sink.add(call.arguments.toString()); | |||||
| } | |||||
| } | |||||
| }, | |||||
| ); | |||||
| } | } | ||||
| void flipCamera() { | void flipCamera() { | ||||
| channel.invokeMethod("flipCamera"); | |||||
| _channel.invokeMethod("flipCamera"); | |||||
| } | } | ||||
| void toggleFlash() { | void toggleFlash() { | ||||
| channel.invokeMethod("toggleFlash"); | |||||
| _channel.invokeMethod("toggleFlash"); | |||||
| } | } | ||||
| void pauseCamera() { | void pauseCamera() { | ||||
| channel.invokeMethod("pauseCamera"); | |||||
| _channel.invokeMethod("pauseCamera"); | |||||
| } | } | ||||
| void resumeCamera() { | void resumeCamera() { | ||||
| channel.invokeMethod("resumeCamera"); | |||||
| _channel.invokeMethod("resumeCamera"); | |||||
| } | |||||
| void dispose() { | |||||
| _scanUpdateController.close(); | |||||
| } | } | ||||
| } | } | ||||