Navaron Bracke

deprecate onPermissionSet; refactor error handling for start(); return instead o…

…f trowing if there is no torch
@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
6 import 'package:flutter/services.dart'; 6 import 'package:flutter/services.dart';
7 import 'package:mobile_scanner/mobile_scanner.dart'; 7 import 'package:mobile_scanner/mobile_scanner.dart';
8 import 'package:mobile_scanner/src/barcode_utility.dart'; 8 import 'package:mobile_scanner/src/barcode_utility.dart';
  9 +import 'package:mobile_scanner/src/enums/mobile_scanner_error_code.dart';
9 import 'package:mobile_scanner/src/mobile_scanner_exception.dart'; 10 import 'package:mobile_scanner/src/mobile_scanner_exception.dart';
10 11
11 /// The [MobileScannerController] holds all the logic of this plugin, 12 /// The [MobileScannerController] holds all the logic of this plugin,
@@ -18,6 +19,9 @@ class MobileScannerController { @@ -18,6 +19,9 @@ class MobileScannerController {
18 this.torchEnabled = false, 19 this.torchEnabled = false,
19 this.formats, 20 this.formats,
20 this.returnImage = false, 21 this.returnImage = false,
  22 + @Deprecated(
  23 + 'Instead, handle permission errors using the result of the `start()` method.',
  24 + )
21 this.onPermissionSet, 25 this.onPermissionSet,
22 }) { 26 }) {
23 // In case a new instance is created before calling dispose() 27 // In case a new instance is created before calling dispose()
@@ -74,6 +78,9 @@ class MobileScannerController { @@ -74,6 +78,9 @@ class MobileScannerController {
74 static const EventChannel _eventChannel = 78 static const EventChannel _eventChannel =
75 EventChannel('dev.steenbakker.mobile_scanner/scanner/event'); 79 EventChannel('dev.steenbakker.mobile_scanner/scanner/event');
76 80
  81 + @Deprecated(
  82 + 'Instead, handle permission errors using the result of the `start()` method.',
  83 + )
77 Function(bool permissionGranted)? onPermissionSet; 84 Function(bool permissionGranted)? onPermissionSet;
78 85
79 /// Listen to events from the platform specific code 86 /// Listen to events from the platform specific code
@@ -115,8 +122,14 @@ class MobileScannerController { @@ -115,8 +122,14 @@ class MobileScannerController {
115 return arguments; 122 return arguments;
116 } 123 }
117 124
118 - /// Start barcode scanning. This will first check if the required permissions  
119 - /// are set. 125 + /// Start scanning for barcodes.
  126 + /// Upon calling this method, the necessary camera permission will be requested.
  127 + ///
  128 + /// Returns an instance of [MobileScannerArguments]
  129 + /// when the scanner was successfully started.
  130 + /// Returns null if the scanner is currently starting.
  131 + ///
  132 + /// Throws a [MobileScannerException] if starting the scanner failed.
120 Future<MobileScannerArguments?> start({ 133 Future<MobileScannerArguments?> start({
121 CameraFacing? cameraFacingOverride, 134 CameraFacing? cameraFacingOverride,
122 }) async { 135 }) async {
@@ -124,6 +137,7 @@ class MobileScannerController { @@ -124,6 +137,7 @@ class MobileScannerController {
124 debugPrint("Called start() while starting."); 137 debugPrint("Called start() while starting.");
125 return null; 138 return null;
126 } 139 }
  140 +
127 isStarting = true; 141 isStarting = true;
128 142
129 // Check authorization status 143 // Check authorization status
@@ -136,16 +150,17 @@ class MobileScannerController { @@ -136,16 +150,17 @@ class MobileScannerController {
136 await _methodChannel.invokeMethod('request') as bool? ?? false; 150 await _methodChannel.invokeMethod('request') as bool? ?? false;
137 if (!result) { 151 if (!result) {
138 isStarting = false; 152 isStarting = false;
139 - onPermissionSet?.call(result);  
140 - throw MobileScannerException('User declined camera permission.'); 153 + throw const MobileScannerException(
  154 + errorCode: MobileScannerErrorCode.permissionDenied,
  155 + );
141 } 156 }
142 break; 157 break;
143 case MobileScannerState.denied: 158 case MobileScannerState.denied:
144 isStarting = false; 159 isStarting = false;
145 - onPermissionSet?.call(false);  
146 - throw MobileScannerException('User declined camera permission.'); 160 + throw const MobileScannerException(
  161 + errorCode: MobileScannerErrorCode.permissionDenied,
  162 + );
147 case MobileScannerState.authorized: 163 case MobileScannerState.authorized:
148 - onPermissionSet?.call(true);  
149 break; 164 break;
150 } 165 }
151 } 166 }
@@ -158,18 +173,27 @@ class MobileScannerController { @@ -158,18 +173,27 @@ class MobileScannerController {
158 _argumentsToMap(cameraFacingOverride: cameraFacingOverride), 173 _argumentsToMap(cameraFacingOverride: cameraFacingOverride),
159 ); 174 );
160 } on PlatformException catch (error) { 175 } on PlatformException catch (error) {
161 - debugPrint('${error.code}: ${error.message}'); 176 + MobileScannerErrorCode errorCode = MobileScannerErrorCode.genericError;
  177 +
162 if (error.code == "MobileScannerWeb") { 178 if (error.code == "MobileScannerWeb") {
163 - onPermissionSet?.call(false); 179 + errorCode = MobileScannerErrorCode.permissionDenied;
164 } 180 }
165 isStarting = false; 181 isStarting = false;
166 - return null; 182 +
  183 + throw MobileScannerException(
  184 + errorCode: errorCode,
  185 + errorDetails: MobileScannerErrorDetails(
  186 + code: error.code,
  187 + details: error.details as Object?,
  188 + message: error.message,
  189 + ),
  190 + );
167 } 191 }
168 192
169 if (startResult == null) { 193 if (startResult == null) {
170 isStarting = false; 194 isStarting = false;
171 - throw MobileScannerException(  
172 - 'Failed to start mobileScanner, no response from platform side', 195 + throw const MobileScannerException(
  196 + errorCode: MobileScannerErrorCode.genericError,
173 ); 197 );
174 } 198 }
175 199
@@ -178,13 +202,6 @@ class MobileScannerController { @@ -178,13 +202,6 @@ class MobileScannerController {
178 torchState.value = TorchState.on; 202 torchState.value = TorchState.on;
179 } 203 }
180 204
181 - if (kIsWeb) {  
182 - // If we reach this line, it means camera permission has been granted  
183 - onPermissionSet?.call(  
184 - true,  
185 - );  
186 - }  
187 -  
188 isStarting = false; 205 isStarting = false;
189 return startArguments.value = MobileScannerArguments( 206 return startArguments.value = MobileScannerArguments(
190 size: kIsWeb 207 size: kIsWeb
@@ -210,14 +227,18 @@ class MobileScannerController { @@ -210,14 +227,18 @@ class MobileScannerController {
210 227
211 /// Switches the torch on or off. 228 /// Switches the torch on or off.
212 /// 229 ///
213 - /// Only works if torch is available. 230 + /// Does nothing if the device has no torch.
  231 + ///
  232 + /// Throws if the controller was not initialized.
214 Future<void> toggleTorch() async { 233 Future<void> toggleTorch() async {
215 - if (_hasTorch == null) {  
216 - throw MobileScannerException(  
217 - 'Cannot toggle torch if start() has never been called', 234 + final hasTorch = _hasTorch;
  235 +
  236 + if (hasTorch == null) {
  237 + throw const MobileScannerException(
  238 + errorCode: MobileScannerErrorCode.controllerUnititialized,
218 ); 239 );
219 - } else if (!_hasTorch!) {  
220 - throw MobileScannerException('Device has no torch'); 240 + } else if (!hasTorch) {
  241 + return;
221 } 242 }
222 243
223 torchState.value = 244 torchState.value =
@@ -258,7 +279,6 @@ class MobileScannerController { @@ -258,7 +279,6 @@ class MobileScannerController {
258 _barcodesController.close(); 279 _barcodesController.close();
259 if (hashCode == controllerHashcode) { 280 if (hashCode == controllerHashcode) {
260 controllerHashcode = null; 281 controllerHashcode = null;
261 - onPermissionSet = null;  
262 } 282 }
263 } 283 }
264 284
@@ -307,7 +327,10 @@ class MobileScannerController { @@ -307,7 +327,10 @@ class MobileScannerController {
307 ); 327 );
308 break; 328 break;
309 case 'error': 329 case 'error':
310 - throw MobileScannerException(data as String); 330 + throw MobileScannerException(
  331 + errorCode: MobileScannerErrorCode.genericError,
  332 + errorDetails: MobileScannerErrorDetails(message: data as String?),
  333 + );
311 default: 334 default:
312 throw UnimplementedError(name as String?); 335 throw UnimplementedError(name as String?);
313 } 336 }