add error builder to mobile scanner widget; handle startup error
Showing
1 changed file
with
33 additions
and
2 deletions
| @@ -3,6 +3,7 @@ import 'dart:async'; | @@ -3,6 +3,7 @@ import 'dart:async'; | ||
| 3 | import 'package:flutter/foundation.dart'; | 3 | import 'package:flutter/foundation.dart'; |
| 4 | import 'package:flutter/material.dart'; | 4 | import 'package:flutter/material.dart'; |
| 5 | import 'package:mobile_scanner/src/mobile_scanner_controller.dart'; | 5 | import 'package:mobile_scanner/src/mobile_scanner_controller.dart'; |
| 6 | +import 'package:mobile_scanner/src/mobile_scanner_exception.dart'; | ||
| 6 | import 'package:mobile_scanner/src/objects/barcode_capture.dart'; | 7 | import 'package:mobile_scanner/src/objects/barcode_capture.dart'; |
| 7 | import 'package:mobile_scanner/src/objects/mobile_scanner_arguments.dart'; | 8 | import 'package:mobile_scanner/src/objects/mobile_scanner_arguments.dart'; |
| 8 | 9 | ||
| @@ -13,6 +14,13 @@ class MobileScanner extends StatefulWidget { | @@ -13,6 +14,13 @@ class MobileScanner extends StatefulWidget { | ||
| 13 | /// If this is null, the scanner will manage its own controller. | 14 | /// If this is null, the scanner will manage its own controller. |
| 14 | final MobileScannerController? controller; | 15 | final MobileScannerController? controller; |
| 15 | 16 | ||
| 17 | + /// The function that builds an error widget when the scanner | ||
| 18 | + /// could not be started. | ||
| 19 | + /// | ||
| 20 | + /// If this is null, defaults to a black [ColoredBox] | ||
| 21 | + /// with a centered white [Icons.error] icon. | ||
| 22 | + final Widget Function(BuildContext, Object, Widget?)? errorBuilder; | ||
| 23 | + | ||
| 16 | /// The [BoxFit] for the camera preview. | 24 | /// The [BoxFit] for the camera preview. |
| 17 | /// | 25 | /// |
| 18 | /// Defaults to [BoxFit.cover]. | 26 | /// Defaults to [BoxFit.cover]. |
| @@ -38,6 +46,7 @@ class MobileScanner extends StatefulWidget { | @@ -38,6 +46,7 @@ class MobileScanner extends StatefulWidget { | ||
| 38 | /// and [onBarcodeDetected] callback. | 46 | /// and [onBarcodeDetected] callback. |
| 39 | const MobileScanner({ | 47 | const MobileScanner({ |
| 40 | this.controller, | 48 | this.controller, |
| 49 | + this.errorBuilder, | ||
| 41 | this.fit = BoxFit.cover, | 50 | this.fit = BoxFit.cover, |
| 42 | required this.onDetect, | 51 | required this.onDetect, |
| 43 | @Deprecated('Use onScannerStarted() instead.') this.onStart, | 52 | @Deprecated('Use onScannerStarted() instead.') this.onStart, |
| @@ -62,6 +71,23 @@ class _MobileScannerState extends State<MobileScanner> | @@ -62,6 +71,23 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 62 | /// when the application comes back to the foreground. | 71 | /// when the application comes back to the foreground. |
| 63 | bool _resumeFromBackground = false; | 72 | bool _resumeFromBackground = false; |
| 64 | 73 | ||
| 74 | + MobileScannerException? _startException; | ||
| 75 | + | ||
| 76 | + Widget __buildPlaceholderOrError(BuildContext context, Widget? child) { | ||
| 77 | + final error = _startException; | ||
| 78 | + | ||
| 79 | + if (error != null) { | ||
| 80 | + return widget.errorBuilder?.call(context, error, child) ?? | ||
| 81 | + const ColoredBox( | ||
| 82 | + color: Colors.black, | ||
| 83 | + child: Center(child: Icon(Icons.error, color: Colors.white)), | ||
| 84 | + ); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + return widget.placeholderBuilder?.call(context, child) ?? | ||
| 88 | + const ColoredBox(color: Colors.black); | ||
| 89 | + } | ||
| 90 | + | ||
| 65 | /// Start the given [scanner]. | 91 | /// Start the given [scanner]. |
| 66 | void _startScanner(MobileScannerController scanner) { | 92 | void _startScanner(MobileScannerController scanner) { |
| 67 | if (!_controller.autoStart) { | 93 | if (!_controller.autoStart) { |
| @@ -74,6 +100,12 @@ class _MobileScannerState extends State<MobileScanner> | @@ -74,6 +100,12 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 74 | // ignore: deprecated_member_use_from_same_package | 100 | // ignore: deprecated_member_use_from_same_package |
| 75 | widget.onStart?.call(arguments); | 101 | widget.onStart?.call(arguments); |
| 76 | widget.onScannerStarted?.call(arguments); | 102 | widget.onScannerStarted?.call(arguments); |
| 103 | + }).catchError((error) { | ||
| 104 | + if (mounted) { | ||
| 105 | + setState(() { | ||
| 106 | + _startException = error as MobileScannerException; | ||
| 107 | + }); | ||
| 108 | + } | ||
| 77 | }); | 109 | }); |
| 78 | } | 110 | } |
| 79 | 111 | ||
| @@ -123,8 +155,7 @@ class _MobileScannerState extends State<MobileScanner> | @@ -123,8 +155,7 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 123 | valueListenable: _controller.startArguments, | 155 | valueListenable: _controller.startArguments, |
| 124 | builder: (context, value, child) { | 156 | builder: (context, value, child) { |
| 125 | if (value == null) { | 157 | if (value == null) { |
| 126 | - return widget.placeholderBuilder?.call(context, child) ?? | ||
| 127 | - const ColoredBox(color: Colors.black); | 158 | + return __buildPlaceholderOrError(context, child); |
| 128 | } | 159 | } |
| 129 | 160 | ||
| 130 | return ClipRect( | 161 | return ClipRect( |
-
Please register or login to post a comment