imp: improve error handling, add scanner_error_widget.dart to lib and show error…
… messages when kdebugmode is true
Showing
7 changed files
with
78 additions
and
35 deletions
| @@ -8,19 +8,6 @@ class ScannerErrorWidget extends StatelessWidget { | @@ -8,19 +8,6 @@ class ScannerErrorWidget extends StatelessWidget { | ||
| 8 | 8 | ||
| 9 | @override | 9 | @override |
| 10 | Widget build(BuildContext context) { | 10 | Widget build(BuildContext context) { |
| 11 | - String errorMessage; | ||
| 12 | - | ||
| 13 | - switch (error.errorCode) { | ||
| 14 | - case MobileScannerErrorCode.controllerUninitialized: | ||
| 15 | - errorMessage = 'Controller not ready.'; | ||
| 16 | - case MobileScannerErrorCode.permissionDenied: | ||
| 17 | - errorMessage = 'Permission denied'; | ||
| 18 | - case MobileScannerErrorCode.unsupported: | ||
| 19 | - errorMessage = 'Scanning is unsupported on this device'; | ||
| 20 | - default: | ||
| 21 | - errorMessage = 'Generic Error'; | ||
| 22 | - } | ||
| 23 | - | ||
| 24 | return ColoredBox( | 11 | return ColoredBox( |
| 25 | color: Colors.black, | 12 | color: Colors.black, |
| 26 | child: Center( | 13 | child: Center( |
| @@ -32,11 +19,11 @@ class ScannerErrorWidget extends StatelessWidget { | @@ -32,11 +19,11 @@ class ScannerErrorWidget extends StatelessWidget { | ||
| 32 | child: Icon(Icons.error, color: Colors.white), | 19 | child: Icon(Icons.error, color: Colors.white), |
| 33 | ), | 20 | ), |
| 34 | Text( | 21 | Text( |
| 35 | - errorMessage, | 22 | + error.errorCode.message, |
| 36 | style: const TextStyle(color: Colors.white), | 23 | style: const TextStyle(color: Colors.white), |
| 37 | ), | 24 | ), |
| 38 | - Text( | ||
| 39 | - error.errorDetails?.message ?? '', | 25 | + if (error.errorDetails != null) Text( |
| 26 | + error.errorDetails!.message ?? '', | ||
| 40 | style: const TextStyle(color: Colors.white), | 27 | style: const TextStyle(color: Colors.white), |
| 41 | ), | 28 | ), |
| 42 | ], | 29 | ], |
| @@ -27,6 +27,23 @@ enum MobileScannerErrorCode { | @@ -27,6 +27,23 @@ enum MobileScannerErrorCode { | ||
| 27 | /// Scanning is unsupported on the current device. | 27 | /// Scanning is unsupported on the current device. |
| 28 | unsupported; | 28 | unsupported; |
| 29 | 29 | ||
| 30 | + String get message { | ||
| 31 | + switch (this) { | ||
| 32 | + case MobileScannerErrorCode.controllerUninitialized: | ||
| 33 | + return 'The MobileScannerController has not been initialized. Call start() before using it.'; | ||
| 34 | + case MobileScannerErrorCode.permissionDenied: | ||
| 35 | + return 'Camera permission denied.'; | ||
| 36 | + case MobileScannerErrorCode.unsupported: | ||
| 37 | + return 'Scanning is not supported on this device.'; | ||
| 38 | + case MobileScannerErrorCode.controllerAlreadyInitialized: | ||
| 39 | + return 'The MobileScannerController is already running. Stop it before starting again.'; | ||
| 40 | + case MobileScannerErrorCode.controllerDisposed: | ||
| 41 | + return 'The MobileScannerController was used after it was disposed.'; | ||
| 42 | + case MobileScannerErrorCode.genericError: | ||
| 43 | + return 'An unexpected error occurred.'; | ||
| 44 | + } | ||
| 45 | + } | ||
| 46 | + | ||
| 30 | /// Convert the given [PlatformException.code] to a [MobileScannerErrorCode]. | 47 | /// Convert the given [PlatformException.code] to a [MobileScannerErrorCode]. |
| 31 | factory MobileScannerErrorCode.fromPlatformException( | 48 | factory MobileScannerErrorCode.fromPlatformException( |
| 32 | PlatformException exception, | 49 | PlatformException exception, |
| @@ -80,10 +80,10 @@ class MethodChannelMobileScanner extends MobileScannerPlatform { | @@ -80,10 +80,10 @@ class MethodChannelMobileScanner extends MobileScannerPlatform { | ||
| 80 | ); | 80 | ); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | - throw const MobileScannerException( | ||
| 84 | - errorCode: MobileScannerErrorCode.genericError, | 83 | + throw MobileScannerException( |
| 84 | + errorCode: MobileScannerErrorCode.unsupported, | ||
| 85 | errorDetails: MobileScannerErrorDetails( | 85 | errorDetails: MobileScannerErrorDetails( |
| 86 | - message: 'Only Android, iOS and macOS are supported.', | 86 | + message:MobileScannerErrorCode.unsupported.message, |
| 87 | ), | 87 | ), |
| 88 | ); | 88 | ); |
| 89 | } | 89 | } |
| @@ -218,10 +218,10 @@ class MethodChannelMobileScanner extends MobileScannerPlatform { | @@ -218,10 +218,10 @@ class MethodChannelMobileScanner extends MobileScannerPlatform { | ||
| 218 | @override | 218 | @override |
| 219 | Future<MobileScannerViewAttributes> start(StartOptions startOptions) async { | 219 | Future<MobileScannerViewAttributes> start(StartOptions startOptions) async { |
| 220 | if (!_pausing && _textureId != null) { | 220 | if (!_pausing && _textureId != null) { |
| 221 | - throw const MobileScannerException( | 221 | + throw MobileScannerException( |
| 222 | errorCode: MobileScannerErrorCode.controllerAlreadyInitialized, | 222 | errorCode: MobileScannerErrorCode.controllerAlreadyInitialized, |
| 223 | errorDetails: MobileScannerErrorDetails( | 223 | errorDetails: MobileScannerErrorDetails( |
| 224 | - message: 'The scanner was already started.', | 224 | + message: MobileScannerErrorCode.controllerAlreadyInitialized.message, |
| 225 | ), | 225 | ), |
| 226 | ); | 226 | ); |
| 227 | } | 227 | } |
| @@ -6,6 +6,7 @@ import 'package:mobile_scanner/src/mobile_scanner_exception.dart'; | @@ -6,6 +6,7 @@ import 'package:mobile_scanner/src/mobile_scanner_exception.dart'; | ||
| 6 | import 'package:mobile_scanner/src/mobile_scanner_platform_interface.dart'; | 6 | import 'package:mobile_scanner/src/mobile_scanner_platform_interface.dart'; |
| 7 | import 'package:mobile_scanner/src/objects/barcode_capture.dart'; | 7 | import 'package:mobile_scanner/src/objects/barcode_capture.dart'; |
| 8 | import 'package:mobile_scanner/src/objects/mobile_scanner_state.dart'; | 8 | import 'package:mobile_scanner/src/objects/mobile_scanner_state.dart'; |
| 9 | +import 'package:mobile_scanner/src/objects/scanner_error_widget.dart'; | ||
| 9 | import 'package:mobile_scanner/src/scan_window_calculation.dart'; | 10 | import 'package:mobile_scanner/src/scan_window_calculation.dart'; |
| 10 | 11 | ||
| 11 | /// The function signature for the error builder. | 12 | /// The function signature for the error builder. |
| @@ -199,6 +200,8 @@ class _MobileScannerState extends State<MobileScanner> | @@ -199,6 +200,8 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 199 | return ValueListenableBuilder<MobileScannerState>( | 200 | return ValueListenableBuilder<MobileScannerState>( |
| 200 | valueListenable: controller, | 201 | valueListenable: controller, |
| 201 | builder: (BuildContext context, MobileScannerState value, Widget? child) { | 202 | builder: (BuildContext context, MobileScannerState value, Widget? child) { |
| 203 | + | ||
| 204 | + // If the controller is still initializing, show a black screen, or user provided placeholder | ||
| 202 | if (!value.isInitialized) { | 205 | if (!value.isInitialized) { |
| 203 | const Widget defaultPlaceholder = ColoredBox(color: Colors.black); | 206 | const Widget defaultPlaceholder = ColoredBox(color: Colors.black); |
| 204 | 207 | ||
| @@ -207,12 +210,9 @@ class _MobileScannerState extends State<MobileScanner> | @@ -207,12 +210,9 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 207 | } | 210 | } |
| 208 | 211 | ||
| 209 | final MobileScannerException? error = value.error; | 212 | final MobileScannerException? error = value.error; |
| 210 | - | 213 | + // If the controller encountered, show an error screen, or user provided placeholder |
| 211 | if (error != null) { | 214 | if (error != null) { |
| 212 | - const Widget defaultError = ColoredBox( | ||
| 213 | - color: Colors.black, | ||
| 214 | - child: Center(child: Icon(Icons.error, color: Colors.white)), | ||
| 215 | - ); | 215 | + final Widget defaultError = ScannerErrorWidget(error: error); |
| 216 | 216 | ||
| 217 | return widget.errorBuilder?.call(context, error, child) ?? | 217 | return widget.errorBuilder?.call(context, error, child) ?? |
| 218 | defaultError; | 218 | defaultError; |
| @@ -164,20 +164,20 @@ class MobileScannerController extends ValueNotifier<MobileScannerState> { | @@ -164,20 +164,20 @@ class MobileScannerController extends ValueNotifier<MobileScannerState> { | ||
| 164 | 164 | ||
| 165 | void _throwIfNotInitialized() { | 165 | void _throwIfNotInitialized() { |
| 166 | if (!value.isInitialized) { | 166 | if (!value.isInitialized) { |
| 167 | - throw const MobileScannerException( | 167 | + throw MobileScannerException( |
| 168 | errorCode: MobileScannerErrorCode.controllerUninitialized, | 168 | errorCode: MobileScannerErrorCode.controllerUninitialized, |
| 169 | errorDetails: MobileScannerErrorDetails( | 169 | errorDetails: MobileScannerErrorDetails( |
| 170 | - message: 'The MobileScannerController has not been initialized.', | 170 | + message: MobileScannerErrorCode.controllerUninitialized.message, |
| 171 | ), | 171 | ), |
| 172 | ); | 172 | ); |
| 173 | } | 173 | } |
| 174 | 174 | ||
| 175 | if (_isDisposed) { | 175 | if (_isDisposed) { |
| 176 | - throw const MobileScannerException( | 176 | + throw MobileScannerException( |
| 177 | errorCode: MobileScannerErrorCode.controllerDisposed, | 177 | errorCode: MobileScannerErrorCode.controllerDisposed, |
| 178 | errorDetails: MobileScannerErrorDetails( | 178 | errorDetails: MobileScannerErrorDetails( |
| 179 | message: | 179 | message: |
| 180 | - 'The MobileScannerController was used after it has been disposed.', | 180 | + MobileScannerErrorCode.controllerDisposed.message, |
| 181 | ), | 181 | ), |
| 182 | ); | 182 | ); |
| 183 | } | 183 | } |
| @@ -284,11 +284,10 @@ class MobileScannerController extends ValueNotifier<MobileScannerState> { | @@ -284,11 +284,10 @@ class MobileScannerController extends ValueNotifier<MobileScannerState> { | ||
| 284 | /// If the permission is denied on iOS, MacOS or Web, there is no way to request it again. | 284 | /// If the permission is denied on iOS, MacOS or Web, there is no way to request it again. |
| 285 | Future<void> start({CameraFacing? cameraDirection}) async { | 285 | Future<void> start({CameraFacing? cameraDirection}) async { |
| 286 | if (_isDisposed) { | 286 | if (_isDisposed) { |
| 287 | - throw const MobileScannerException( | 287 | + throw MobileScannerException( |
| 288 | errorCode: MobileScannerErrorCode.controllerDisposed, | 288 | errorCode: MobileScannerErrorCode.controllerDisposed, |
| 289 | errorDetails: MobileScannerErrorDetails( | 289 | errorDetails: MobileScannerErrorDetails( |
| 290 | - message: | ||
| 291 | - 'The MobileScannerController was used after it has been disposed.', | 290 | + message: MobileScannerErrorCode.controllerDisposed.message, |
| 292 | ), | 291 | ), |
| 293 | ); | 292 | ); |
| 294 | } | 293 | } |
lib/src/objects/scanner_error_widget.dart
0 → 100644
| 1 | +import 'package:flutter/foundation.dart'; | ||
| 2 | +import 'package:flutter/material.dart'; | ||
| 3 | +import 'package:mobile_scanner/mobile_scanner.dart'; | ||
| 4 | + | ||
| 5 | +class ScannerErrorWidget extends StatelessWidget { | ||
| 6 | + const ScannerErrorWidget({super.key, required this.error}); | ||
| 7 | + | ||
| 8 | + final MobileScannerException error; | ||
| 9 | + | ||
| 10 | + @override | ||
| 11 | + Widget build(BuildContext context) { | ||
| 12 | + return ColoredBox( | ||
| 13 | + color: Colors.black, | ||
| 14 | + child: Center( | ||
| 15 | + child: Column( | ||
| 16 | + mainAxisSize: MainAxisSize.min, | ||
| 17 | + children: [ | ||
| 18 | + const Padding( | ||
| 19 | + padding: EdgeInsets.only(bottom: 16), | ||
| 20 | + child: Icon(Icons.error, color: Colors.white), | ||
| 21 | + ), | ||
| 22 | + if (kDebugMode) ...[ | ||
| 23 | + Text( | ||
| 24 | + error.errorCode.message, | ||
| 25 | + style: const TextStyle(color: Colors.white), | ||
| 26 | + ), | ||
| 27 | + if (error.errorDetails != null) Text( | ||
| 28 | + error.errorDetails!.message ?? '', | ||
| 29 | + style: const TextStyle(color: Colors.white), | ||
| 30 | + ), | ||
| 31 | + ] else Text( | ||
| 32 | + MobileScannerErrorCode.genericError.message, | ||
| 33 | + style: const TextStyle(color: Colors.white), | ||
| 34 | + ), | ||
| 35 | + ], | ||
| 36 | + ), | ||
| 37 | + ), | ||
| 38 | + ); | ||
| 39 | + } | ||
| 40 | +} |
| @@ -273,10 +273,10 @@ class MobileScannerWeb extends MobileScannerPlatform { | @@ -273,10 +273,10 @@ class MobileScannerWeb extends MobileScannerPlatform { | ||
| 273 | ); | 273 | ); |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | - throw const MobileScannerException( | 276 | + throw MobileScannerException( |
| 277 | errorCode: MobileScannerErrorCode.controllerAlreadyInitialized, | 277 | errorCode: MobileScannerErrorCode.controllerAlreadyInitialized, |
| 278 | errorDetails: MobileScannerErrorDetails( | 278 | errorDetails: MobileScannerErrorDetails( |
| 279 | - message: 'The scanner was already started.', | 279 | + message: MobileScannerErrorCode.controllerAlreadyInitialized.message, |
| 280 | ), | 280 | ), |
| 281 | ); | 281 | ); |
| 282 | } | 282 | } |
-
Please register or login to post a comment