Julian Steenbakker
Committed by GitHub

Merge pull request #470 from juliansteenbakker/bug/parameter-not-resetting

fix: parameter not resetting
@@ -19,23 +19,6 @@ import dev.steenbakker.mobile_scanner.objects.MobileScannerStartParameters @@ -19,23 +19,6 @@ import dev.steenbakker.mobile_scanner.objects.MobileScannerStartParameters
19 import io.flutter.view.TextureRegistry 19 import io.flutter.view.TextureRegistry
20 import kotlin.math.roundToInt 20 import kotlin.math.roundToInt
21 21
22 -  
23 -typealias MobileScannerCallback = (barcodes: List<Map<String, Any?>>, image: ByteArray?, width: Int?, height: Int?) -> Unit  
24 -typealias AnalyzerCallback = (barcodes: List<Map<String, Any?>>?) -> Unit  
25 -typealias MobileScannerErrorCallback = (error: String) -> Unit  
26 -typealias TorchStateCallback = (state: Int) -> Unit  
27 -typealias MobileScannerStartedCallback = (parameters: MobileScannerStartParameters) -> Unit  
28 -  
29 -  
30 -class NoCamera : Exception()  
31 -class AlreadyStarted : Exception()  
32 -class AlreadyStopped : Exception()  
33 -class TorchError : Exception()  
34 -class CameraError : Exception()  
35 -class TorchWhenStopped : Exception()  
36 -class ZoomWhenStopped : Exception()  
37 -class ZoomNotInRange : Exception()  
38 -  
39 class MobileScanner( 22 class MobileScanner(
40 private val activity: Activity, 23 private val activity: Activity,
41 private val textureRegistry: TextureRegistry, 24 private val textureRegistry: TextureRegistry,
@@ -43,22 +26,21 @@ class MobileScanner( @@ -43,22 +26,21 @@ class MobileScanner(
43 private val mobileScannerErrorCallback: MobileScannerErrorCallback 26 private val mobileScannerErrorCallback: MobileScannerErrorCallback
44 ) { 27 ) {
45 28
  29 + /// Internal variables
46 private var cameraProvider: ProcessCameraProvider? = null 30 private var cameraProvider: ProcessCameraProvider? = null
47 private var camera: Camera? = null 31 private var camera: Camera? = null
48 private var preview: Preview? = null 32 private var preview: Preview? = null
49 private var textureEntry: TextureRegistry.SurfaceTextureEntry? = null 33 private var textureEntry: TextureRegistry.SurfaceTextureEntry? = null
50 - var scanWindow: List<Float>? = null  
51 -  
52 - private var detectionSpeed: DetectionSpeed = DetectionSpeed.NO_DUPLICATES  
53 - private var detectionTimeout: Long = 250 34 + private var scanner = BarcodeScanning.getClient()
54 private var lastScanned: List<String?>? = null 35 private var lastScanned: List<String?>? = null
55 -  
56 private var scannerTimeout = false 36 private var scannerTimeout = false
57 37
  38 + /// Configurable variables
  39 + var scanWindow: List<Float>? = null
  40 + private var detectionSpeed: DetectionSpeed = DetectionSpeed.NO_DUPLICATES
  41 + private var detectionTimeout: Long = 250
58 private var returnImage = false 42 private var returnImage = false
59 43
60 - private var scanner = BarcodeScanning.getClient()  
61 -  
62 /** 44 /**
63 * callback for the camera. Every frame is passed through this function. 45 * callback for the camera. Every frame is passed through this function.
64 */ 46 */
@@ -87,10 +69,10 @@ class MobileScanner( @@ -87,10 +69,10 @@ class MobileScanner(
87 69
88 val barcodeMap: MutableList<Map<String, Any?>> = mutableListOf() 70 val barcodeMap: MutableList<Map<String, Any?>> = mutableListOf()
89 71
90 - for ( barcode in barcodes) {  
91 - if(scanWindow != null) {  
92 - val match = isbarCodeInScanWindow(scanWindow!!, barcode, imageProxy)  
93 - if(!match) { 72 + for (barcode in barcodes) {
  73 + if (scanWindow != null) {
  74 + val match = isBarcodeInScanWindow(scanWindow!!, barcode, imageProxy)
  75 + if (!match) {
94 continue 76 continue
95 } else { 77 } else {
96 barcodeMap.add(barcode.data) 78 barcodeMap.add(barcode.data)
@@ -126,7 +108,11 @@ class MobileScanner( @@ -126,7 +108,11 @@ class MobileScanner(
126 108
127 // scales the scanWindow to the provided inputImage and checks if that scaled 109 // scales the scanWindow to the provided inputImage and checks if that scaled
128 // scanWindow contains the barcode 110 // scanWindow contains the barcode
129 - private fun isbarCodeInScanWindow(scanWindow: List<Float>, barcode: Barcode, inputImage: ImageProxy): Boolean { 111 + private fun isBarcodeInScanWindow(
  112 + scanWindow: List<Float>,
  113 + barcode: Barcode,
  114 + inputImage: ImageProxy
  115 + ): Boolean {
130 val barcodeBoundingBox = barcode.boundingBox ?: return false 116 val barcodeBoundingBox = barcode.boundingBox ?: return false
131 117
132 val imageWidth = inputImage.height 118 val imageWidth = inputImage.height
  1 +package dev.steenbakker.mobile_scanner
  2 +
  3 +import dev.steenbakker.mobile_scanner.objects.MobileScannerStartParameters
  4 +
  5 +typealias MobileScannerCallback = (barcodes: List<Map<String, Any?>>, image: ByteArray?, width: Int?, height: Int?) -> Unit
  6 +typealias AnalyzerCallback = (barcodes: List<Map<String, Any?>>?) -> Unit
  7 +typealias MobileScannerErrorCallback = (error: String) -> Unit
  8 +typealias TorchStateCallback = (state: Int) -> Unit
  9 +typealias MobileScannerStartedCallback = (parameters: MobileScannerStartParameters) -> Unit
  1 +package dev.steenbakker.mobile_scanner
  2 +
  3 +class NoCamera : Exception()
  4 +class AlreadyStarted : Exception()
  5 +class AlreadyStopped : Exception()
  6 +class TorchError : Exception()
  7 +class CameraError : Exception()
  8 +class TorchWhenStopped : Exception()
  9 +class ZoomWhenStopped : Exception()
  10 +class ZoomNotInRange : Exception()
@@ -230,6 +230,6 @@ class MobileScannerHandler( @@ -230,6 +230,6 @@ class MobileScannerHandler(
230 } 230 }
231 231
232 private fun updateScanWindow(call: MethodCall) { 232 private fun updateScanWindow(call: MethodCall) {
233 - mobileScanner!!.scanWindow = call.argument<List<Float>>("rect") 233 + mobileScanner!!.scanWindow = call.argument<List<Float>?>("rect")
234 } 234 }
235 } 235 }
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 archiveVersion = 1; 3 archiveVersion = 1;
4 classes = { 4 classes = {
5 }; 5 };
6 - objectVersion = 51; 6 + objectVersion = 54;
7 objects = { 7 objects = {
8 8
9 /* Begin PBXBuildFile section */ 9 /* Begin PBXBuildFile section */
@@ -199,6 +199,7 @@ @@ -199,6 +199,7 @@
199 /* Begin PBXShellScriptBuildPhase section */ 199 /* Begin PBXShellScriptBuildPhase section */
200 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 200 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
201 isa = PBXShellScriptBuildPhase; 201 isa = PBXShellScriptBuildPhase;
  202 + alwaysOutOfDate = 1;
202 buildActionMask = 2147483647; 203 buildActionMask = 2147483647;
203 files = ( 204 files = (
204 ); 205 );
@@ -213,6 +214,7 @@ @@ -213,6 +214,7 @@
213 }; 214 };
214 9740EEB61CF901F6004384FC /* Run Script */ = { 215 9740EEB61CF901F6004384FC /* Run Script */ = {
215 isa = PBXShellScriptBuildPhase; 216 isa = PBXShellScriptBuildPhase;
  217 + alwaysOutOfDate = 1;
216 buildActionMask = 2147483647; 218 buildActionMask = 2147483647;
217 files = ( 219 files = (
218 ); 220 );
@@ -49,5 +49,7 @@ @@ -49,5 +49,7 @@
49 </array> 49 </array>
50 <key>UIViewControllerBasedStatusBarAppearance</key> 50 <key>UIViewControllerBasedStatusBarAppearance</key>
51 <false/> 51 <false/>
  52 + <key>UIApplicationSupportsIndirectInputEvents</key>
  53 + <true/>
52 </dict> 54 </dict>
53 </plist> 55 </plist>
@@ -197,10 +197,4 @@ class _BarcodeScannerWithControllerState @@ -197,10 +197,4 @@ class _BarcodeScannerWithControllerState
197 ), 197 ),
198 ); 198 );
199 } 199 }
200 -  
201 - @override  
202 - void dispose() {  
203 - controller.dispose();  
204 - super.dispose();  
205 - }  
206 } 200 }
  1 +import 'package:flutter/material.dart';
  2 +import 'package:mobile_scanner/mobile_scanner.dart';
  3 +import 'package:mobile_scanner_example/scanner_error_widget.dart';
  4 +
  5 +class BarcodeScannerPageView extends StatefulWidget {
  6 + const BarcodeScannerPageView({Key? key}) : super(key: key);
  7 +
  8 + @override
  9 + _BarcodeScannerPageViewState createState() => _BarcodeScannerPageViewState();
  10 +}
  11 +
  12 +class _BarcodeScannerPageViewState extends State<BarcodeScannerPageView>
  13 + with SingleTickerProviderStateMixin {
  14 + BarcodeCapture? capture;
  15 +
  16 + Widget cameraView() {
  17 + return Builder(
  18 + builder: (context) {
  19 + return Stack(
  20 + children: [
  21 + MobileScanner(
  22 + startDelay: true,
  23 + controller: MobileScannerController(torchEnabled: true),
  24 + fit: BoxFit.contain,
  25 + errorBuilder: (context, error, child) {
  26 + return ScannerErrorWidget(error: error);
  27 + },
  28 + onDetect: (capture) {
  29 + setState(() {
  30 + this.capture = capture;
  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 + mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  42 + children: [
  43 + Center(
  44 + child: SizedBox(
  45 + width: MediaQuery.of(context).size.width - 120,
  46 + height: 50,
  47 + child: FittedBox(
  48 + child: Text(
  49 + capture?.barcodes.first.rawValue ??
  50 + 'Scan something!',
  51 + overflow: TextOverflow.fade,
  52 + style: Theme.of(context)
  53 + .textTheme
  54 + .headlineMedium!
  55 + .copyWith(color: Colors.white),
  56 + ),
  57 + ),
  58 + ),
  59 + ),
  60 + ],
  61 + ),
  62 + ),
  63 + ),
  64 + ],
  65 + );
  66 + },
  67 + );
  68 + }
  69 +
  70 + @override
  71 + Widget build(BuildContext context) {
  72 + return Scaffold(
  73 + backgroundColor: Colors.black,
  74 + body: PageView(
  75 + children: [
  76 + cameraView(),
  77 + Container(),
  78 + cameraView(),
  79 + cameraView(),
  80 + ],
  81 + ),
  82 + );
  83 + }
  84 +}
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:mobile_scanner_example/barcode_list_scanner_controller.dart'; 2 import 'package:mobile_scanner_example/barcode_list_scanner_controller.dart';
3 import 'package:mobile_scanner_example/barcode_scanner_controller.dart'; 3 import 'package:mobile_scanner_example/barcode_scanner_controller.dart';
  4 +import 'package:mobile_scanner_example/barcode_scanner_pageview.dart';
4 import 'package:mobile_scanner_example/barcode_scanner_returning_image.dart'; 5 import 'package:mobile_scanner_example/barcode_scanner_returning_image.dart';
5 import 'package:mobile_scanner_example/barcode_scanner_window.dart'; 6 import 'package:mobile_scanner_example/barcode_scanner_window.dart';
6 import 'package:mobile_scanner_example/barcode_scanner_without_controller.dart'; 7 import 'package:mobile_scanner_example/barcode_scanner_without_controller.dart';
@@ -84,6 +85,16 @@ class MyHome extends StatelessWidget { @@ -84,6 +85,16 @@ class MyHome extends StatelessWidget {
84 }, 85 },
85 child: const Text('MobileScanner with zoom slider'), 86 child: const Text('MobileScanner with zoom slider'),
86 ), 87 ),
  88 + ElevatedButton(
  89 + onPressed: () {
  90 + Navigator.of(context).push(
  91 + MaterialPageRoute(
  92 + builder: (context) => const BarcodeScannerPageView(),
  93 + ),
  94 + );
  95 + },
  96 + child: const Text('MobileScanner pageView'),
  97 + ),
87 ], 98 ],
88 ), 99 ),
89 ), 100 ),
@@ -36,6 +36,10 @@ class ScannerErrorWidget extends StatelessWidget { @@ -36,6 +36,10 @@ class ScannerErrorWidget extends StatelessWidget {
36 errorMessage, 36 errorMessage,
37 style: const TextStyle(color: Colors.white), 37 style: const TextStyle(color: Colors.white),
38 ), 38 ),
  39 + Text(
  40 + error.errorDetails?.message ?? '',
  41 + style: const TextStyle(color: Colors.white),
  42 + ),
39 ], 43 ],
40 ), 44 ),
41 ), 45 ),
1 -platform :osx, '10.13' 1 +platform :osx, '10.14'
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'
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 archiveVersion = 1; 3 archiveVersion = 1;
4 classes = { 4 classes = {
5 }; 5 };
6 - objectVersion = 51; 6 + objectVersion = 54;
7 objects = { 7 objects = {
8 8
9 /* Begin PBXAggregateTarget section */ 9 /* Begin PBXAggregateTarget section */
@@ -277,6 +277,7 @@ @@ -277,6 +277,7 @@
277 }; 277 };
278 3399D490228B24CF009A79C7 /* ShellScript */ = { 278 3399D490228B24CF009A79C7 /* ShellScript */ = {
279 isa = PBXShellScriptBuildPhase; 279 isa = PBXShellScriptBuildPhase;
  280 + alwaysOutOfDate = 1;
280 buildActionMask = 2147483647; 281 buildActionMask = 2147483647;
281 files = ( 282 files = (
282 ); 283 );
@@ -403,7 +404,7 @@ @@ -403,7 +404,7 @@
403 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 404 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
404 GCC_WARN_UNUSED_FUNCTION = YES; 405 GCC_WARN_UNUSED_FUNCTION = YES;
405 GCC_WARN_UNUSED_VARIABLE = YES; 406 GCC_WARN_UNUSED_VARIABLE = YES;
406 - MACOSX_DEPLOYMENT_TARGET = 10.13; 407 + MACOSX_DEPLOYMENT_TARGET = 10.14;
407 MTL_ENABLE_DEBUG_INFO = NO; 408 MTL_ENABLE_DEBUG_INFO = NO;
408 SDKROOT = macosx; 409 SDKROOT = macosx;
409 SWIFT_COMPILATION_MODE = wholemodule; 410 SWIFT_COMPILATION_MODE = wholemodule;
@@ -425,7 +426,7 @@ @@ -425,7 +426,7 @@
425 "$(inherited)", 426 "$(inherited)",
426 "@executable_path/../Frameworks", 427 "@executable_path/../Frameworks",
427 ); 428 );
428 - MACOSX_DEPLOYMENT_TARGET = 10.13; 429 + MACOSX_DEPLOYMENT_TARGET = 10.14;
429 PROVISIONING_PROFILE_SPECIFIER = ""; 430 PROVISIONING_PROFILE_SPECIFIER = "";
430 SWIFT_VERSION = 5.0; 431 SWIFT_VERSION = 5.0;
431 }; 432 };
@@ -483,7 +484,7 @@ @@ -483,7 +484,7 @@
483 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 484 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
484 GCC_WARN_UNUSED_FUNCTION = YES; 485 GCC_WARN_UNUSED_FUNCTION = YES;
485 GCC_WARN_UNUSED_VARIABLE = YES; 486 GCC_WARN_UNUSED_VARIABLE = YES;
486 - MACOSX_DEPLOYMENT_TARGET = 10.13; 487 + MACOSX_DEPLOYMENT_TARGET = 10.14;
487 MTL_ENABLE_DEBUG_INFO = YES; 488 MTL_ENABLE_DEBUG_INFO = YES;
488 ONLY_ACTIVE_ARCH = YES; 489 ONLY_ACTIVE_ARCH = YES;
489 SDKROOT = macosx; 490 SDKROOT = macosx;
@@ -530,7 +531,7 @@ @@ -530,7 +531,7 @@
530 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 531 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
531 GCC_WARN_UNUSED_FUNCTION = YES; 532 GCC_WARN_UNUSED_FUNCTION = YES;
532 GCC_WARN_UNUSED_VARIABLE = YES; 533 GCC_WARN_UNUSED_VARIABLE = YES;
533 - MACOSX_DEPLOYMENT_TARGET = 10.13; 534 + MACOSX_DEPLOYMENT_TARGET = 10.14;
534 MTL_ENABLE_DEBUG_INFO = NO; 535 MTL_ENABLE_DEBUG_INFO = NO;
535 SDKROOT = macosx; 536 SDKROOT = macosx;
536 SWIFT_COMPILATION_MODE = wholemodule; 537 SWIFT_COMPILATION_MODE = wholemodule;
@@ -552,7 +553,7 @@ @@ -552,7 +553,7 @@
552 "$(inherited)", 553 "$(inherited)",
553 "@executable_path/../Frameworks", 554 "@executable_path/../Frameworks",
554 ); 555 );
555 - MACOSX_DEPLOYMENT_TARGET = 10.13; 556 + MACOSX_DEPLOYMENT_TARGET = 10.14;
556 PROVISIONING_PROFILE_SPECIFIER = ""; 557 PROVISIONING_PROFILE_SPECIFIER = "";
557 SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 558 SWIFT_OPTIMIZATION_LEVEL = "-Onone";
558 SWIFT_VERSION = 5.0; 559 SWIFT_VERSION = 5.0;
@@ -573,7 +574,7 @@ @@ -573,7 +574,7 @@
573 "$(inherited)", 574 "$(inherited)",
574 "@executable_path/../Frameworks", 575 "@executable_path/../Frameworks",
575 ); 576 );
576 - MACOSX_DEPLOYMENT_TARGET = 10.13; 577 + MACOSX_DEPLOYMENT_TARGET = 10.14;
577 PROVISIONING_PROFILE_SPECIFIER = ""; 578 PROVISIONING_PROFILE_SPECIFIER = "";
578 SWIFT_VERSION = 5.0; 579 SWIFT_VERSION = 5.0;
579 }; 580 };
@@ -56,6 +56,12 @@ class MobileScanner extends StatefulWidget { @@ -56,6 +56,12 @@ class MobileScanner extends StatefulWidget {
56 /// [BoxFit] 56 /// [BoxFit]
57 final Rect? scanWindow; 57 final Rect? scanWindow;
58 58
  59 + /// Only set this to true if you are starting another instance of mobile_scanner
  60 + /// right after disposing the first one, like in a PageView.
  61 + ///
  62 + /// Default: false
  63 + final bool startDelay;
  64 +
59 /// Create a new [MobileScanner] using the provided [controller] 65 /// Create a new [MobileScanner] using the provided [controller]
60 /// and [onBarcodeDetected] callback. 66 /// and [onBarcodeDetected] callback.
61 const MobileScanner({ 67 const MobileScanner({
@@ -67,6 +73,7 @@ class MobileScanner extends StatefulWidget { @@ -67,6 +73,7 @@ class MobileScanner extends StatefulWidget {
67 this.onScannerStarted, 73 this.onScannerStarted,
68 this.placeholderBuilder, 74 this.placeholderBuilder,
69 this.scanWindow, 75 this.scanWindow,
  76 + this.startDelay = false,
70 super.key, 77 super.key,
71 }); 78 });
72 79
@@ -88,7 +95,7 @@ class _MobileScannerState extends State<MobileScanner> @@ -88,7 +95,7 @@ class _MobileScannerState extends State<MobileScanner>
88 95
89 MobileScannerException? _startException; 96 MobileScannerException? _startException;
90 97
91 - Widget __buildPlaceholderOrError(BuildContext context, Widget? child) { 98 + Widget _buildPlaceholderOrError(BuildContext context, Widget? child) {
92 final error = _startException; 99 final error = _startException;
93 100
94 if (error != null) { 101 if (error != null) {
@@ -104,18 +111,28 @@ class _MobileScannerState extends State<MobileScanner> @@ -104,18 +111,28 @@ class _MobileScannerState extends State<MobileScanner>
104 } 111 }
105 112
106 /// Start the given [scanner]. 113 /// Start the given [scanner].
107 - void _startScanner(MobileScannerController scanner) { 114 + Future<void> _startScanner() async {
  115 + if (widget.startDelay) {
  116 + await Future.delayed(const Duration(seconds: 1, milliseconds: 500));
  117 + }
  118 +
108 if (!_controller.autoStart) { 119 if (!_controller.autoStart) {
109 debugPrint( 120 debugPrint(
110 'mobile_scanner: not starting automatically because autoStart is set to false in the controller.', 121 'mobile_scanner: not starting automatically because autoStart is set to false in the controller.',
111 ); 122 );
112 return; 123 return;
113 } 124 }
114 - scanner.start().then((arguments) { 125 +
  126 + _barcodesSubscription = _controller.barcodes.listen(
  127 + widget.onDetect,
  128 + );
  129 +
  130 + _controller.start().then((arguments) {
115 // ignore: deprecated_member_use_from_same_package 131 // ignore: deprecated_member_use_from_same_package
116 widget.onStart?.call(arguments); 132 widget.onStart?.call(arguments);
117 widget.onScannerStarted?.call(arguments); 133 widget.onScannerStarted?.call(arguments);
118 }).catchError((error) { 134 }).catchError((error) {
  135 + debugPrint('mobile_scanner: $error');
119 if (mounted) { 136 if (mounted) {
120 setState(() { 137 setState(() {
121 _startException = error as MobileScannerException; 138 _startException = error as MobileScannerException;
@@ -129,14 +146,7 @@ class _MobileScannerState extends State<MobileScanner> @@ -129,14 +146,7 @@ class _MobileScannerState extends State<MobileScanner>
129 super.initState(); 146 super.initState();
130 WidgetsBinding.instance.addObserver(this); 147 WidgetsBinding.instance.addObserver(this);
131 _controller = widget.controller ?? MobileScannerController(); 148 _controller = widget.controller ?? MobileScannerController();
132 -  
133 - _barcodesSubscription = _controller.barcodes.listen(  
134 - widget.onDetect,  
135 - );  
136 -  
137 - if (!_controller.isStarting) {  
138 - _startScanner(_controller);  
139 - } 149 + _startScanner();
140 } 150 }
141 151
142 @override 152 @override
@@ -149,7 +159,7 @@ class _MobileScannerState extends State<MobileScanner> @@ -149,7 +159,7 @@ class _MobileScannerState extends State<MobileScanner>
149 switch (state) { 159 switch (state) {
150 case AppLifecycleState.resumed: 160 case AppLifecycleState.resumed:
151 _resumeFromBackground = false; 161 _resumeFromBackground = false;
152 - _startScanner(_controller); 162 + _startScanner();
153 break; 163 break;
154 case AppLifecycleState.paused: 164 case AppLifecycleState.paused:
155 _resumeFromBackground = true; 165 _resumeFromBackground = true;
@@ -228,7 +238,7 @@ class _MobileScannerState extends State<MobileScanner> @@ -228,7 +238,7 @@ class _MobileScannerState extends State<MobileScanner>
228 valueListenable: _controller.startArguments, 238 valueListenable: _controller.startArguments,
229 builder: (context, value, child) { 239 builder: (context, value, child) {
230 if (value == null) { 240 if (value == null) {
231 - return __buildPlaceholderOrError(context, child); 241 + return _buildPlaceholderOrError(context, child);
232 } 242 }
233 243
234 if (widget.scanWindow != null && scanWindow == null) { 244 if (widget.scanWindow != null && scanWindow == null) {
@@ -238,7 +248,8 @@ class _MobileScannerState extends State<MobileScanner> @@ -238,7 +248,8 @@ class _MobileScannerState extends State<MobileScanner>
238 value.size, 248 value.size,
239 Size(constraints.maxWidth, constraints.maxHeight), 249 Size(constraints.maxWidth, constraints.maxHeight),
240 ); 250 );
241 - _controller.updateScanWindow(scanWindow!); 251 +
  252 + _controller.updateScanWindow(scanWindow);
242 } 253 }
243 254
244 return ClipRect( 255 return ClipRect(
@@ -268,8 +279,10 @@ class _MobileScannerState extends State<MobileScanner> @@ -268,8 +279,10 @@ class _MobileScannerState extends State<MobileScanner>
268 279
269 @override 280 @override
270 void dispose() { 281 void dispose() {
  282 + _controller.updateScanWindow(null);
271 WidgetsBinding.instance.removeObserver(this); 283 WidgetsBinding.instance.removeObserver(this);
272 _barcodesSubscription?.cancel(); 284 _barcodesSubscription?.cancel();
  285 + _barcodesSubscription = null;
273 _controller.dispose(); 286 _controller.dispose();
274 super.dispose(); 287 super.dispose();
275 } 288 }
@@ -20,20 +20,7 @@ class MobileScannerController { @@ -20,20 +20,7 @@ class MobileScannerController {
20 @Deprecated('Instead, use the result of calling `start()` to determine if permissions were granted.') 20 @Deprecated('Instead, use the result of calling `start()` to determine if permissions were granted.')
21 this.onPermissionSet, 21 this.onPermissionSet,
22 this.autoStart = true, 22 this.autoStart = true,
23 - }) {  
24 - // In case a new instance is created before calling dispose()  
25 - if (controllerHashcode != null) {  
26 - stop();  
27 - }  
28 - controllerHashcode = hashCode;  
29 - events = _eventChannel  
30 - .receiveBroadcastStream()  
31 - .listen((data) => _handleEvent(data as Map));  
32 - }  
33 -  
34 - /// The hashcode of the controller to check if the correct object is mounted.  
35 - /// Must be static to keep the same value on new instances  
36 - static int? controllerHashcode; 23 + });
37 24
38 /// Select which camera should be used. 25 /// Select which camera should be used.
39 /// 26 ///
@@ -84,7 +71,7 @@ class MobileScannerController { @@ -84,7 +71,7 @@ class MobileScannerController {
84 Function(bool permissionGranted)? onPermissionSet; 71 Function(bool permissionGranted)? onPermissionSet;
85 72
86 /// Listen to events from the platform specific code 73 /// Listen to events from the platform specific code
87 - late StreamSubscription events; 74 + StreamSubscription? events;
88 75
89 /// A notifier that provides several arguments about the MobileScanner 76 /// A notifier that provides several arguments about the MobileScanner
90 final ValueNotifier<MobileScannerArguments?> startArguments = 77 final ValueNotifier<MobileScannerArguments?> startArguments =
@@ -164,6 +151,11 @@ class MobileScannerController { @@ -164,6 +151,11 @@ class MobileScannerController {
164 151
165 isStarting = true; 152 isStarting = true;
166 153
  154 + events?.cancel();
  155 + events = _eventChannel
  156 + .receiveBroadcastStream()
  157 + .listen((data) => _handleEvent(data as Map));
  158 +
167 // Check authorization status 159 // Check authorization status
168 if (!kIsWeb) { 160 if (!kIsWeb) {
169 final MobileScannerState state = MobileScannerState 161 final MobileScannerState state = MobileScannerState
@@ -327,11 +319,8 @@ class MobileScannerController { @@ -327,11 +319,8 @@ class MobileScannerController {
327 /// If you call this, you cannot use this controller object anymore. 319 /// If you call this, you cannot use this controller object anymore.
328 void dispose() { 320 void dispose() {
329 stop(); 321 stop();
330 - events.cancel(); 322 + events?.cancel();
331 _barcodesController.close(); 323 _barcodesController.close();
332 - if (hashCode == controllerHashcode) {  
333 - controllerHashcode = null;  
334 - }  
335 } 324 }
336 325
337 /// Handles a returning event from the platform side 326 /// Handles a returning event from the platform side
@@ -394,9 +383,13 @@ class MobileScannerController { @@ -394,9 +383,13 @@ class MobileScannerController {
394 } 383 }
395 } 384 }
396 385
397 - /// updates the native scanwindow  
398 - Future<void> updateScanWindow(Rect window) async {  
399 - final data = [window.left, window.top, window.right, window.bottom]; 386 + /// updates the native ScanWindow
  387 + Future<void> updateScanWindow(Rect? window) async {
  388 + List? data;
  389 + if (window != null) {
  390 + data = [window.left, window.top, window.right, window.bottom];
  391 + }
  392 +
400 await _methodChannel.invokeMethod('updateScanWindow', {'rect': data}); 393 await _methodChannel.invokeMethod('updateScanWindow', {'rect': data});
401 } 394 }
402 } 395 }